diff --git a/.gitignore b/.gitignore index 823b9d630a76df3a545868c262533a1dcbe86600..c04369b0c9dab84edb5c7b0c6b65dd95bdbde3de 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,6 @@ x509.genkey # Kconfig presets all.config + +# fetched Android config fragments +android/configs/android-*.cfg diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..4341e3a71dad646b30295dc450d3a1fdd4960a1a --- /dev/null +++ b/Android.bp @@ -0,0 +1,27 @@ +cc_binary_host { + name: "unifdef", + srcs: ["scripts/unifdef.c"], + sanitize: { + never: true, + } +} + +gensrcs { + name: "qseecom-kernel-includes", + + // move to out/ as root for header generation because of scripts/unifdef + // storage - at the expense of extra ../ references + cmd: "pushd out && mkdir -p scripts && rm -f scripts/unifdef && ln -s ../../$(location unifdef) scripts/unifdef && ../$(location scripts/headers_install.sh) `dirname ../$(out)` ../ $(in) && popd", + + tools: ["unifdef"], + tool_files: ["scripts/headers_install.sh"], + export_include_dirs: ["include/uapi"], + srcs: ["include/uapi/linux/qseecom.h"], + output_extension: "h", +} + +cc_library_headers { + name: "qseecom-kernel-headers", + generated_headers: ["qseecom-kernel-includes"], + export_generated_headers: ["qseecom-kernel-includes"], +} diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 3db9ac9f0bcb68b1e8d18e2198c6d21ab806971b..21b0a66c7b38233e921f1fe53d1bde19d3d56cc1 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -6,6 +6,13 @@ ifeq ($(KERNEL_TARGET),) INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel endif +TARGET_KERNEL_MAKE_ENV := $(strip $(TARGET_KERNEL_MAKE_ENV)) +ifeq ($(TARGET_KERNEL_MAKE_ENV),) +KERNEL_MAKE_ENV := +else +KERNEL_MAKE_ENV := $(TARGET_KERNEL_MAKE_ENV) +endif + TARGET_KERNEL_ARCH := $(strip $(TARGET_KERNEL_ARCH)) ifeq ($(TARGET_KERNEL_ARCH),) KERNEL_ARCH := arm @@ -88,8 +95,15 @@ endif ifeq ($(TARGET_KERNEL_APPEND_DTB), true) $(info Using appended DTB) TARGET_PREBUILT_INT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)-dtb +else +$(info Using DTB Image) +INSTALLED_DTBIMAGE_TARGET := $(PRODUCT_OUT)/dtb.img endif +# Creating a dtb.img once the kernel is compiled if TARGET_KERNEL_APPEND_DTB is set to be false +$(INSTALLED_DTBIMAGE_TARGET): $(INSTALLED_KERNEL_TARGET) + cat $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts/qcom/*.dtb > $@ + KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr KERNEL_MODULES_INSTALL := system KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules @@ -124,43 +138,43 @@ $(KERNEL_OUT): mkdir -p $(KERNEL_OUT) $(KERNEL_CONFIG): $(KERNEL_OUT) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) $(hide) echo "Building kernel..." $(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install $(mv-modules) $(clean-module-folder) $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi $(hide) if [ "$(KERNEL_HEADER_DEFCONFIG)" != "$(KERNEL_DEFCONFIG)" ]; then \ echo "Used a different defconfig for header generation"; \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG) env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig cp $(KERNEL_OUT)/defconfig $(TARGET_KERNEL_SOURCE)/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG) endif diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index acb9bfc89b4879c7f1f7c6815959baa4c819154b..0908fb43566de8ad38e3cb05fa4ae71d5ce57ae2 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -224,3 +224,50 @@ Description: Parameters for the Intel P-state driver frequency range. More details can be found in Documentation/cpu-freq/intel-pstate.txt + +What: /sys/devices/system/cpu/cpu*/cache/index*/ +Date: July 2014(documented, existed before August 2008) +Contact: Sudeep Holla + Linux kernel mailing list +Description: Parameters for the CPU cache attributes + + allocation_policy: + - WriteAllocate: allocate a memory location to a cache line + on a cache miss because of a write + - ReadAllocate: allocate a memory location to a cache line + on a cache miss because of a read + - ReadWriteAllocate: both writeallocate and readallocate + + attributes: LEGACY used only on IA64 and is same as write_policy + + coherency_line_size: the minimum amount of data in bytes that gets + transferred from memory to cache + + level: the cache hierarchy in the multi-level cache configuration + + number_of_sets: total number of sets in the cache, a set is a + collection of cache lines with the same cache index + + physical_line_partition: number of physical cache line per cache tag + + shared_cpu_list: the list of logical cpus sharing the cache + + shared_cpu_map: logical cpu mask containing the list of cpus sharing + the cache + + size: the total cache size in kB + + type: + - Instruction: cache that only holds instructions + - Data: cache that only caches data + - Unified: cache that holds both data and instructions + + ways_of_associativity: degree of freedom in placing a particular block + of memory in the cache + + write_policy: + - WriteThrough: data is written to both the cache line + and to the block in the lower-level memory + - WriteBack: data is written only to the cache line and + the modified cache line is written to main + memory only when it is replaced diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index f82da9bbb1fd731e1b1c6a3ee78d80f2ff3adb03..3bbb9fe9548c0f51207b3535a60e183ebfdc5a88 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -51,6 +51,14 @@ Description: Controls the dirty page count condition for the in-place-update policies. +What: /sys/fs/f2fs//min_seq_blocks +Date: August 2018 +Contact: "Jaegeuk Kim" +Description: + Controls the dirty page count condition for batched sequential + writes in ->writepages. + + What: /sys/fs/f2fs//min_hot_blocks Date: March 2017 Contact: "Jaegeuk Kim" diff --git a/Documentation/Changes b/Documentation/Changes index 1de131bb49fbfc9a48c25d118d78d52d0eab9842..9ad68f1819d333e8f2985d478c7c40a373c08bbf 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -25,7 +25,7 @@ o Gnu C 3.2 # gcc --version o Gnu make 3.80 # make --version o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version -o module-init-tools 0.9.10 # depmod -V +o kmod 13 # depmod -V o e2fsprogs 1.41.4 # e2fsck -V o jfsutils 1.1.3 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V @@ -119,12 +119,6 @@ is not build with CONFIG_KALLSYMS and you have no way to rebuild and reproduce the Oops with that option, then you can still decode that Oops with ksymoops. -Module-Init-Tools ------------------ - -A new module loader is now in the kernel that requires module-init-tools -to use. It is backward compatible with the 2.4.x series kernels. - Mkinitrd -------- @@ -302,14 +296,15 @@ Util-linux ---------- o +Kmod +---- +o +o + Ksymoops -------- o -Module-Init-Tools ------------------ -o - Mkinitrd -------- o diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt index 2f5173500bd953b32e55134012af50ac93e46ad8..2800b014a619ea92d88a72e1e4740240c1de3fac 100644 --- a/Documentation/device-mapper/thin-provisioning.txt +++ b/Documentation/device-mapper/thin-provisioning.txt @@ -112,9 +112,11 @@ $low_water_mark is expressed in blocks of size $data_block_size. If free space on the data device drops below this level then a dm event will be triggered which a userspace daemon should catch allowing it to extend the pool device. Only one such event will be sent. -Resuming a device with a new table itself triggers an event so the -userspace daemon can use this to detect a situation where a new table -already exceeds the threshold. + +No special event is triggered if a just resumed device's free space is below +the low water mark. However, resuming a device always triggers an +event; a userspace daemon should verify that free space exceeds the low +water mark when handling this event. A low water mark for the metadata device is maintained in the kernel and will trigger a dm event if free space on the metadata device drops below diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index d1655d2b441969fc0aa5262fcc351939a5faa9d4..4f93b6f7ad466c424df19f36b0131c05a0df92eb 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -102,6 +102,17 @@ fec_start This is the offset, in blocks, from the start of the FEC device to the beginning of the encoding data. +check_at_most_once + Verify data blocks only the first time they are read from the data device, + rather than every time. This reduces the overhead of dm-verity so that it + can be used on systems that are memory and/or CPU constrained. However, it + provides a reduced level of security because only offline tampering of the + data device's content will be detected, not online tampering. + + Hash blocks are still verified each time they are read from the hash device, + since verification of hash blocks is less performance critical than data + blocks, and a hash block will not be verified any more after all the data + blocks it covers have been verified anyway. Theory of operation =================== diff --git a/Documentation/devicetree/bindings/arm/davinci.txt b/Documentation/devicetree/bindings/arm/davinci.txt index cfaeda4274e6a7e6f74ddca527d73d04d597d709..e6f4b50da1f9267745b6d3055316f16723e69afb 100644 --- a/Documentation/devicetree/bindings/arm/davinci.txt +++ b/Documentation/devicetree/bindings/arm/davinci.txt @@ -9,6 +9,10 @@ EnBW AM1808 based CMC board Required root node properties: - compatible = "enbw,cmc", "ti,da850; +LEGO MINDSTORMS EV3 (AM1808 based) +Required root node properties: + - compatible = "lego,ev3", "ti,da850"; + Generic DaVinci Boards ---------------------- diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt index 5d376058a39c3210c647d6ba5d9b25971d8c40cf..c81ee698f107b9f5d0aff919e7168a661130cfc9 100644 --- a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt +++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt @@ -33,6 +33,7 @@ Required properties: "qcom,rpmcc-8916" "qcom,rpmcc-8936" "qcom,rpmcc-8909" + "qcom,rpmcc-8909-pm660" "qcom,cc-debug-8916" "qcom,cc-debug-8936" "qcom,cc-debug-8909" diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt index ecbf5a7319407c3519cc1b8d041f8bb09e91ed19..b2b7151f1bd09c6073ccacc1ac7c769d37d571eb 100644 --- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt +++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt @@ -96,6 +96,8 @@ Optional properties: or not for the drivers to prepare for cluster collapse. - qcom,hyp-psci: This property is used to determine if the cpu enters the low power mode within hypervisor. + - qcom,no-cache-flush: This boolean property will specify that cache + will not be flushed and will be in retention for this mode. - qcom,reset-level: This property is used to determine in this low power mode only control logic power collapse happens or memory logic power collapse aswell happens or retention state. diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt index de66152d650e721341d2f768bf46c402e43e76fd..5deb0e4ca08b428ece5077f73493e4dafeb17703 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt @@ -109,6 +109,12 @@ Optional properties DDR frequency restriction feature. It expects array of sensor id to be monitored, high threshold and low threshold for that sensor respectively. +- qcom,therm-dynamic-hw-sampling-info: If this optional property is defined, it enables + dynamic TSENS sampling feature. It expects array of + sensor id to be monitored, high threshold and low threshold + for that sensor, TSENS sampling level to be requested when + threshold is triggered and default sampling level for normal + temperature condition respectively. Optional child nodes - qcom,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request @@ -285,6 +291,10 @@ Example: vdd-cx-supply = <&pmd9635_s5_level>; qcom,online-hotplug-core; qcom,therm-ddr-lm-info = <1 90 75>; + qcom,therm-dynamic-hw-sampling-info = <4 60 45 0 1>; + /* ; + */ qcom,synchronous-cluster-id = <0 1>; /* Indicates cluster 0 and 1 are synchronous */ qcom,synchronous-cluster-map = <0 2 &CPU0 &CPU1>, <1 2 &CPU2 &CPU3>; diff --git a/Documentation/devicetree/bindings/arm/msm/qdss_mhi.txt b/Documentation/devicetree/bindings/arm/msm/qdss_mhi.txt new file mode 100644 index 0000000000000000000000000000000000000000..928a4f4269a3f718621500dfd77e829554e86c4d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qdss_mhi.txt @@ -0,0 +1,15 @@ +Qualcomm Technologies, Inc. QDSS bridge Driver + +This device will enable routing debug data from modem +subsystem to APSS host. + +Required properties: +-compatible : "qcom,qdss-mhi". +-qcom,mhi : phandle of MHI Device to connect to. + +Example: + qcom,qdss-mhi { + compatible = "qcom,qdss-mhi"; + qcom,mhi = <&mhi_0>; + }; + diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt index e9a2ed3feb26ee95c9a5d4fdb5a7e581e60c2f04..89c5e0b77ccbe3ecf15cd30d131615b419df9308 100644 --- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt +++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt @@ -45,6 +45,8 @@ Optional properties for only Non-PSCI targets index to send the PMIC data to - qcom,vctl-port: The PVC (PMIC Virtual Channel) port used for changing voltage +- qcom,vctl-port-ub: The PVC (PMIC Virtual Channel) port used for changing + voltage - qcom,phase-port: The PVC port used for changing the number of phases - qcom,pfm-port: The PVC port used for enabling PWM/PFM modes - qcom,cpu-vctl-mask: Mask of cpus, whose voltage the spm device can control. @@ -107,6 +109,8 @@ Optional properties for only PSCI targets: between AVS controller requests - qcom,vctl-port: The PVC (PMIC Virtual Channel) port used for changing voltage +- qcom,vctl-port-ub: The PVC (PMIC Virtual Channel) port used for changing + voltage - qcom,phase-port: The PVC port used for changing the number of phases - qcom,pfm-port: The PVC port used for enabling PWM/PFM modes - qcom,cpu-vctl-list: List of cpu node phandles, whose voltage the spm device diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ec1a880ac18bbe90a309e8f53aed410cda7e5a8 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt @@ -0,0 +1,46 @@ +THS8135 Video DAC +----------------- + +This is the binding for Texas Instruments THS8135 Video DAC bridge. + +Required properties: + +- compatible: Must be "ti,ths8135" + +Required nodes: + +This device has two video ports. Their connections are modelled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for RGB input +- Video port 1 for VGA output + +Example +------- + +vga-bridge { + compatible = "ti,ths8135"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + vga_bridge_in: endpoint { + remote-endpoint = <&lcdc_out_vga>; + }; + }; + + port@1 { + reg = <1>; + + vga_bridge_out: endpoint { + remote-endpoint = <&vga_con_in>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/dma/snps-dma.txt b/Documentation/devicetree/bindings/dma/snps-dma.txt index d58675ea1abf2e998af99b8d69f5a2b6b1b71e2a..f4bdc9d621307ec5d2415f12a792a43b23aff430 100644 --- a/Documentation/devicetree/bindings/dma/snps-dma.txt +++ b/Documentation/devicetree/bindings/dma/snps-dma.txt @@ -58,6 +58,6 @@ Example: interrupts = <0 35 0x4>; status = "disabled"; dmas = <&dmahost 12 0 1>, - <&dmahost 13 0 1 0>; + <&dmahost 13 1 0>; dma-names = "rx", "rx"; }; diff --git a/Documentation/devicetree/bindings/fb/mdss-spi-client.txt b/Documentation/devicetree/bindings/fb/mdss-spi-client.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d5fde838df7fb28b8ba69917e398f7f6f456f04 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-spi-client.txt @@ -0,0 +1,27 @@ +Qualcomm Technologies, Inc. mdss-spi-client + +mdss-spi-client is for SPI display to send the FB data to SPI master. + +Required properties: +- compatible : should be "qcom,mdss-spi-client" +- spi-max-frequency : Maximum SPI clocking speed of device in Hz + +Optional properties: +- label: A string used to describe the controller used. +- spi-cpol : Boolean property indicating device requires inverse + clock polarity (CPOL) mode +- spi-cpha : Empty property indicating device requires shifted + clock phase (CPHA) mode +- spi-cs-high : Empty property indicating device requires + chip select active high + +Example: +spi@78b9000 { /* BLSP1 QUP5 */ + qcom,mdss_spi_client { + reg = <0>; + compatible = "qcom,mdss-spi-client"; + label = "MDSS SPI QUP5 CLIENT"; + spi-max-frequency = <50000000>; + }; +}; + diff --git a/Documentation/devicetree/bindings/fb/mdss-spi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-spi-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..d46068f016950587eba3361d5874d703aa02d7b7 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-spi-panel.txt @@ -0,0 +1,203 @@ +Qualcomm Technologies, Inc. mdss-spi-panel + +mdss-spi-panel is a SPI panel device which supports panels that +are compatible with display serial interface specification. + +Required properties: +- qcom,mdss-spi-panel-controller: Specifies the phandle for the SPI controller that + this panel will be mapped to. +- qcom,mdss-spi-panel-width: Specifies panel width in pixels. +- qcom,mdss-spi-panel-height: Specifies panel height in pixels. +- qcom,mdss-spi-bpp: Specifies the panel bits per pixels. + 3 = for rgb111 + 8 = for rgb332 + 12 = for rgb444 + 16 = for rgb565 + 18 = for rgb666 + 24 = for rgb888 +- qcom,mdss-spi-panel-destination: A string that specifies the destination display for the panel. + "display_1" = DISPLAY_1 + "display_2" = DISPLAY_2 +- qcom,mdss-spi-on-command: A byte stream formed by multiple packets + byte 0: wait number of specified ms after command + transmitted + byte 1: 8 bits length in network byte order + byte 3 and beyond: number byte of payload +- qcom,mdss-spi-off-command: A byte stream formed by multiple packets + byte 0: wait number of specified ms after command + transmitted + byte 1: 8 bits length in network byte order + byte 3 and beyond: number byte of payload +Optional properties: +- qcom,mdss-spi-panel-name: A string used as a descriptive name of the panel +- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode. + If this property is specified, it is required to + to specify the memory reserved for the splash + screen using the qcom,memblock-reserve binding + for the framebuffer device attached to the panel. +- qcom,mdss-spi-h-back-porch: Horizontal back porch value in pixels. + 6 = default value. +- qcom,mdss-spi-h-front-porch: Horizontal front porch value in pixels. + 6 = default value. +- qcom,mdss-spi-h-pulse-width: Horizontal pulse width. + 2 = default value. +- qcom,mdss-spi-h-sync-skew: Horizontal sync skew value. + 0 = default value. +- qcom,mdss-spi-v-back-porch: Vertical back porch value in pixels. + 6 = default value. +- qcom,mdss-spi-v-front-porch: Vertical front porch value in pixels. + 6 = default value. +- qcom,mdss-spi-v-pulse-width: Vertical pulse width. + 2 = default value. +- qcom,mdss-spi-bl-pmic-control-type: A string that specifies the implementation of backlight + control for this panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + other: Unknown backlight control. (default) +- qcom,mdss-spi-bl-min-level: Specifies the min backlight level supported by the panel. + 0 = default value. +- qcom,mdss-spi-bl-max-level: Specifies the max backlight level supported by the panel. + 255 = default value. +- qcom,mdss-spi-panel-framerate: Specifies the frame rate for the panel. +- qcom,esd-check-enabled: Boolean used to enable ESD recovery feature. +- qcom,mdss-spi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. + "send_init_command" = send init code to recover panel status. + "reg_read" = Read register value to check the panel status. +- qcom,mdss-spi-panel-status-reg:Unsigned 8bits integer value to specifies the value + of panel status register address. +- qcom,mdss-spi-panel-status-read-length:Unsigned 8bits integer value that specifies + the expected read-back length of the panel register. +- qcom,mdss-spi-panel-status-value:An unsigned 8bits integer araray that specifies the + values of the panel status register which is used to + check the panel status. + The size of this array is specified by + qcom,mdss-dsi-panel-status-read-length. + +Example: +&mdss_mdp { + spi_gc9305_qvga_cmd: qcom,mdss_spi_gc9305_qvga_cmd { + qcom,mdss-spi-panel-name = "gc9305 qvga command mode spi panel"; + qcom,mdss-spi-panel-destination = "display_1"; + qcom,mdss-spi-panel-controller = <&mdss_spi>; + qcom,mdss-spi-panel-framerate = <30>; + qcom,mdss-spi-panel-width = <240>; + qcom,mdss-spi-panel-height = <320>; + qcom,mdss-spi-h-front-porch = <79>; + qcom,mdss-spi-h-back-porch = <59>; + qcom,mdss-spi-h-pulse-width = <60>; + qcom,mdss-spi-v-back-porch = <10>; + qcom,mdss-spi-v-front-porch = <7>; + qcom,mdss-spi-v-pulse-width = <2>; + qcom,mdss-spi-h-left-border = <0>; + qcom,mdss-spi-h-right-border = <0>; + qcom,mdss-spi-v-top-border = <0>; + qcom,mdss-spi-v-bottom-border = <0>; + qcom,mdss-spi-bpp = <16>; + qcom,mdss-spi-on-command = [00 01 FE + 00 01 EF + 00 02 36 48 + 00 02 3A 05 + 00 02 35 00 + 00 03 A4 44 44 + 00 03 A5 42 42 + 00 03 AA 88 88 + 00 03 E8 12 40 + 00 03 E3 01 10 + 00 02 FF 61 + 00 02 AC 00 + 00 03 A6 2A 2A + 00 03 A7 2B 2B + 00 03 A8 18 18 + 00 03 A9 2A 2A + 00 02 AD 33 + 00 02 AF 55 + 00 02 AE 2B + 00 05 2A 00 00 00 EF + 00 05 2B 00 00 01 3F + 00 01 2C + 00 07 F0 02 02 00 08 0C 10 + 00 07 F1 01 00 00 14 1D 0E + 00 07 F2 10 09 37 04 04 48 + 00 07 F3 10 0B 3F 05 05 4E + 00 07 F4 0D 19 17 1D 1E 0F + 00 07 F5 06 12 13 1A 1B 0F + 78 01 11 + 00 01 29 + 00 01 2C]; + qcom,mdss-spi-off-command = [20 01 28 + 20 01 10]; + qcom,mdss-spi-bl-min-level = <1>; + qcom,mdss-spi-bl-max-level = <4095>; + qcom,esd-check-enabled; + qcom,mdss-spi-panel-status-check-mode = "reg_read"; + qcom,mdss-spi-panel-status-reg = /bits/ 8 <0x09>; + qcom,mdss-spi-panel-status-read-length = <4>; + qcom,mdss-spi-panel-status-value = /bits/ 8 <0x52 0x29 0x83 0x00>; + }; +}; + +mdss-spi-display is a spi interface display which support send frame +data and command to panel, compatible with SPI interface specification. + +Required properties: +- compatible: This property applies to SPI panels only. + compatible = "qcom,mdss-spi-display". +- vdd-supply: Phandle for vdd regulator device node. +- vddio-supply: Phandle for vdd-io regulator device node. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the interface is mapped. +- qcom,mdss-mdp: pHandle that specifies the mdss-mdp device. +- qcom,panel-supply-entries: A node that lists the elements of the supply used to + power the DSI panel. There can be more than one instance + of this binding, in which case the entry would be appended + with the supply entry index. For a detailed description + fields in the supply entry, refer to the qcom,ctrl-supply-entries + binding above. +- qcom,platform-spi-dc-gpio: Pull down this gpio indicate current package is command, + Pull up this gpio indicate current package is parameter or pixels. + +Optional properties: +- label:A string used to describe the controller used. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + +Example: + mdss_spi: qcom,mdss_spi { + compatible = "qcom,mdss-spi-display"; + label = "mdss spi panel"; + + qcom,mdss-fb-map = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + vdd-supply = <&pm8909_l17>; + vddio-supply = <&pm8909_l6>; + qcom,platform-spi-dc-gpio = <&msm_gpio 110 0>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <2850000>; + qcom,supply-max-voltage = <2850000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/invn-iam20680.txt b/Documentation/devicetree/bindings/iio/imu/invn-iam20680.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5227841b5d9f054efafba6f2095dc3259464ead --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invn-iam20680.txt @@ -0,0 +1,83 @@ +The IAM20680 sensor is 6-axis gyroscope+accelerometer combo +device which is made by InvenSense Inc. + +Required properties: + + - compatible : Should be "invn,iam20680". + - reg : the I2C address which depends on the AD0 pin. + - gpios : INVENSENSE GPIO in the format described by ../gpio/gpio.txt + +Optional properties: + - inven,vdd_ana-supply : + - inven,vcc_i2c-supply : + - inven,gpio_int1 : + - axis_map_x : + - axis_map_y : + - axis_map_z : + - negate_x : + - negate_y : + - negate_z : + - fs_range : + - poll_interval : + - min_interval : + - inven,secondary_reg : + - inven,secondary_type : + - inven,secondary_name : + - inven,secondary_axis_map_x : + - inven,secondary_axis_map_y : + - inven,secondary_axis_map_z : + - inven,secondary_negate_x : + - inven,secondary_negate_y : + - inven,secondary_negate_z : + - inven,aux_type : + - inven,aux_name : + - inven,aux_reg : + - inven,read_only_slave_type : + - inven,read_only_slave_name : + - inven,read_only_slave_reg : + +Example: + iam20680@69 { + compatible = "inven,iam20680"; + reg = <0x69>; + pinctrl-names = "default"; + pinctrl-0 = <&int1_default>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <78 IRQ_TYPE_EDGE_RISING>; + inven,vdd_ana-supply = <&pm8941_l17>; + inven,vcc_i2c-supply = <&pm8941_lvs1>; + inven,gpio_int1 = <&msmgpio 73 0x00>; + axis_map_x = <1>; + axis_map_y = <0>; + axis_map_z = <2>; + negate_x = <1>; + negate_y = <0>; + negate_z = <0>; + fs_range = <0x00>; + poll_interval = <200>; + min_interval = <5>; + inven,secondary_reg = <0x0c>; + /* If no compass sensor, + * replace "compass" with "none" + */ + inven,secondary_type = "compass"; + inven,secondary_name = "ak09911"; + inven,secondary_axis_map_x = <1>; + inven,secondary_axis_map_y = <0>; + inven,secondary_axis_map_z = <2>; + inven,secondary_negate_x = <1>; + inven,secondary_negate_y = <1>; + inven,secondary_negate_z = <1>; + /* If no pressure sensor, + * replace "pressure" with "none" + */ + inven,aux_type = "pressure"; + inven,aux_name = "bmp280"; + inven,aux_reg = <0x76>; + /* If no ALS sensor + * replace "als" with "none" + */ + inven,read_only_slave_type = "als"; + inven,read_only_slave_name = "apds9930"; + inven,read_only_slave_reg = <0x39>; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c806f45a0ec5383be1dd0b09d23ebf70acbed71 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt @@ -0,0 +1,29 @@ +The ICM20602 sensor is 6-axis gyroscope+accelerometer combo +device which is made by InvenSense Inc. + +The datasheet can be found as the following link: +https://www.invensense.com/products/motion-tracking/6-axis/icm-20602/ + +Required properties: + + - compatible : Should be "invn,icm20602". + - reg : the I2C address which depends on the AD0 pin. + +Optional properties: + - invn,icm20602-irq: the irq gpio. This is not used if + using SMD to trigger. this is needed only if using the + device IRQ to trigger. Only using SMD to trigger can + support 8K sample rate. + +Example: + icm20602-i2c@068 { + compatible = "invn,icm20602"; + reg = <0x68>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0>; + invn,icm20602-irq = <&msm_gpio 13 0x0>; + pinctrl-names = "imu_active","imu_suspend"; + pinctrl-0 = <&imu_int_active>; + pinctrl-1 = <&imu_int_suspend>; + status = "okay"; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/st-asm330.txt b/Documentation/devicetree/bindings/iio/imu/st-asm330.txt new file mode 100644 index 0000000000000000000000000000000000000000..3833d59494e0118495fcbc6007c08baa9480001e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/st-asm330.txt @@ -0,0 +1,44 @@ +The ASM330 is a highly integrated, low power inertial measurement unit (IMU) +that provides precise acceleration and angular rate (gyroscopic) measurement. + +To enable driver probing, add the asm330lhh node to the platform device tree as described below. + +Required properties: + +- compatible: "st,asm330lhh" +- reg: the I2C address or SPI chip select the device will respond to +- interrupt-parent: phandle to the parent interrupt controller as documented in [interrupts][4] +- interrupts: interrupt mapping for IRQ as documented in [interrupts][4] + +Recommended properties for SPI bus usage: +- spi-max-frequency: maximum SPI bus frequency as documented in [SPI][3] + +Optional properties: +- st,drdy-int-pin: MEMS sensor interrupt line to use (default 1) + +I2C example (based on Raspberry PI 3): + + &i2c0 { + status = "ok"; + #address-cells = <0x1>; + #size-cells = <0x0>; + asm330lhh@6b { + compatible = "st,asm330lhh"; + reg = <0x6b>; + interrupt-parent = <&gpio>; + interrupts = <26 IRQ_TYPE_EDGE_RISING>; + }; + +SPI example (based on Raspberry PI 3): + + &spi0 { + status = "ok"; + #address-cells = <0x1>; + #size-cells = <0x0>; + asm330lhh@0 { + spi-max-frequency = <500000>; + compatible = "st,asm330lhh"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <26 IRQ_TYPE_EDGE_RISING>; + }; diff --git a/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf10122de8a861853da27fe2e79b0b114e3fbc1a --- /dev/null +++ b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt @@ -0,0 +1,36 @@ +STM VL53L0X Time-of-Flight ranging and gesture detection sensor driver + +Description: + +The VL53L0X is a new generation Time-of-Flight +(ToF) laser-ranging module housed in the +smallest package on the market today, providing +accurate distance measurement whatever the +target reflectances unlike conventional +technologies. It can measure absolute distances +up to 2m, setting a new benchmark in ranging +performance levels, opening the door to various +new applications. +The VL53L0X integrates a leading-edge SPAD +array (Single Photon Avalanche Diodes) and +embeds ST’s second generation FlightSenseTM +patented technology. +The VL53L0X’s 940 nm VCSEL emitter (Vertical +Cavity Surface-Emitting Laser), is totally invisible +to the human eye, coupled with internal physical +infrared filters, it enables longer ranging +distances, higher immunity to ambient light, and +better robustness to cover glass optical crosstalk. + +Required properties: + + - compatible : Should be "st,stmvl53l0". + - reg : i2c slave address of the device. + +Example: + i2c@f9925000 { + vl53l0x@52 { + compatible = "st,stmvl53l0"; + reg = <0x52>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech_ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..0174e3d45553395d06b30191276d7d616554a289 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/focaltech_ts.txt @@ -0,0 +1,54 @@ +FocalTech touch controller + +The focaltech controller is connected to host processor +via i2c. The controller generates interrupts when the +user touches the panel. The host controller is expected +to read the touch coordinates over i2c and pass the coordinates +to the rest of the system. + +Required properties: + + - compatible : should be "focaltech,fts". + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - vdd-supply : Power supply needed to power up the device. + - vcc-i2c-supply : Power source required to power up i2c bus. + - focaltech,irq-gpio : irq gpio which is to provide interrupts to host, + same as "interrupts" node. It will also + contain active low or active high information. + - focaltech,reset-gpio : reset gpio to control the reset of chip. + - focaltech,display-coords : display coordinates in pixels. It is a four + tuple consisting of min x, min y, max x and + max y values + +Optional properties: + - focaltech,max-touch-number : maximnum number of touch points supported. + - focaltech,have-key : specify whether virtual keys are present. + - focaltech,key-number : number of keys, maximum 3. + - focaltech,keys : array of key code. + - focaltech,key-y-coord : y coordinate for the keys. + - focaltech,key-x-coords : array of x coordinates for the keys. + - focaltech,wakeup-gestures-en : enable wakeup gestures. + +Example: + i2c@f9923000{ + focaltech@38{ + compatible = "focaltech,fts"; + reg = <0x38>; + interrupt-parent = <&msmgpio>; + interrupts = <98 0x2008>; + vdd-supply = <&pm8110_l19>; + vcc_i2c-supply = <&pm8110_l14>; + focaltech,reset-gpio = <&msmgpio 16 0x00>; + focaltech,irq-gpio = <&msmgpio 98 0x2008>; + focaltech,display-coords = <0 0 480 800>; + focaltech,max-touch-number = <2>; + focaltech,have-key; + focaltech,key-number = <3>; + focaltech,keys = <139 142 140>; + focaltech,key-y-coord = <700>; + focaltech,key-x-coords = <80 240 400>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..9889f55dd4bb044a7ab28a60dd30dd4310fa071a --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt @@ -0,0 +1,57 @@ +Himax touch controller + +Required properties: + + - compatible : should be "himax,hxcommon" + - reg : i2c slave address of the device + - interrupt-parent : parent of interrupt + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - himax,irq-gpio : irq gpio + - himax,reset-gpio : reset gpio + +Optional property: + - vdd-supply : Analog power supply needed to power device + - vcc_i2c-supply : Power source required to pull up i2c bus + - himax,i2c-pull-up : specify to indicate pull up is needed + - himax,disable-gpios : specify to disable gpios in suspend (power saving) + - himax,button-map : virtual key code mappings to be used + - himax,x-flip : modify orientation of the x axis + - himax,y-flip : modify orientation of the y axis + - himax,panel-coords : touch panel min x, min y, max x and + max y resolution + - himax,display-coords : display min x, min y, max x and + max y resolution + - himax,reset-delay : reset delay for controller (ms), default 100 + - himax,fw-image-name : name of firmware .img file in /etc/firmware + - himax,power-down : fully power down regulators in suspend + - himax,do-lockdown : perform one time lockdown procedure + +Example: + i2c@f9927000 { /* BLSP1 QUP5 */ + cell-index = <5>; + compatible = "himax,hxcommon"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0xf9927000 0x1000>; + interrupt-names = "qup_err_intr"; + interrupts = <0 99 0>; + gpios = <&msmgpio 19 0>, /* SCL */ + <&msmgpio 18 0>; /* SDA */ + qcom,i2c-bus-freq = <100000>; + qcom,i2c-src-freq = <19200000>; + + himax_ts@20 { + compatible = "himax,hxcommon" + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <255 0x2008>; + vdd-supply = <&pm8994_l15>; + avdd-supply = <&pm8994_l22>; + himax,panel-coords = <0 720 0 1440>; + himax,display-coords = <0 720 0 1440>; + himax,irq-gpio = <&tlmm 255 0x2008>; + himax,rst-gpio = <&tlmm 8 0x00>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt index f693d72442ffb3fb2b54507cc6334bd450fe3442..f7de07f57a8724945ec675eacbb76e12ccce7bed 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt @@ -18,13 +18,17 @@ Optional property: - vcc_i2c-supply : analog voltage power supply needed to power device. - synaptics,pwr-reg-name : power reg name of digital voltage. - synaptics,bus-reg-name : bus reg name of analog voltage. + - synaptics,do-not-disable-regulators : If specified, regulators cannot be disabled/enabled during suspend/resume. - synaptics,irq-on-state : status of irq gpio. - synaptics,cap-button-codes : virtual key code mappings to be used. - synaptics,vir-button-codes : virtual key code and the response region on panel. + - synaptics,wakeup-gestures-en: enable wakeup gestures. - synaptics,x-flip : modify orientation of the x axis. - synaptics,y-flip : modify orientation of the y axis. - synaptics,reset-delay-ms : reset delay for controller (ms), default 100. - synaptics,max-y-for-2d : maximal y value of the panel. + - synaptics,bus-lpm-cur-uA : I2C bus idle mode current setting. + - synaptics,fw-name : name of firmware .img file in /lib/firmware - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk" - clocks : Defined if 'clock-names' DT property is defined. These clocks are associated with the underlying I2C bus. diff --git a/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt b/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b0014e45b385a090168ee020088099dbf2240b0 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt @@ -0,0 +1,36 @@ +NXP LED segment driver devicetree bindings + +Required properties: + + - compatible : "nxp,pca9956b" for PCA9956b + - nxp,mode1 : MODE1 register + - nxp,mode2 : MODE2 register + - nxp,ledout0~5 : LED output state registers + - nxp,defaultiref : LED output gain control default value + +Optional properties: + +Example: +pca9956b { + /* I2C version */ + reg = <0x7d>; + + /* nxp-ledseg properties */ + + compatible = "nxp,pca9956b"; + + pinctrl-names = "default"; + pinctrl-0 = <&pca9956b_pins>; + + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xaa>; + pca9956b,ledout1 = <0xaa>; + pca9956b,ledout2 = <0xaa>; + pca9956b,ledout3 = <0xff>; + pca9956b,ledout4 = <0xff>; + pca9956b,ledout5 = <0xff>; + pca9956b,defaultiref = <0x2f>; +}; diff --git a/Documentation/devicetree/bindings/misc/qpnp-misc.txt b/Documentation/devicetree/bindings/misc/qpnp-misc.txt index 9de6857a2643033e3c2a7feeb73d857d207e6677..a80701a13fc2f20747f18b74fc41f749d92ec9d0 100644 --- a/Documentation/devicetree/bindings/misc/qpnp-misc.txt +++ b/Documentation/devicetree/bindings/misc/qpnp-misc.txt @@ -16,6 +16,13 @@ Optional properties: if a non-zero PWM source is specified under "qcom,pwm-sel" property. +- qcom,support-twm-config Enable configuration for TWM mode. + +- qcom,twm-mode The TWM mode which PMIC enters post power-off. + Valid only if 'qcom,support-twm-config' is + defined. If not specified, the default mode + is 3. + Example: qcom,spmi@fc4c0000 { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/net/neutrino_hsic.txt b/Documentation/devicetree/bindings/net/neutrino_hsic.txt index f9f775bb83b11308a08ba1bafa9898e828c09291..ea0978e7ce209e92cb491f9247cae83b6b211398 100644 --- a/Documentation/devicetree/bindings/net/neutrino_hsic.txt +++ b/Documentation/devicetree/bindings/net/neutrino_hsic.txt @@ -7,6 +7,12 @@ Required properties: - vdd-ntn-hsic-supply: Neutrino HSIC power supply - ntn-rst-gpio: Neutrino reset GPIO - ntn-phy-id: Neutrino PHY ID +Optional properties: + - ntn-timestamp-valid-window: Timestamp valid window in ms. + Each unit represents 16.75ms. + - ntn-timestamp-valid-window-disable: Disable Timestamp valid window feature. + if this property not set, then feature disabled + in driver. Example: qcom,ntn_hsic { @@ -16,4 +22,6 @@ Example: pinctrl-0 = <&ntn_rst_gpio_default>; ntn-rst-gpio = <&tlmm_pinmux 30 1>; ntn-phy-id = <7>; + ntn-timestamp-valid-window = <4>; + ntn-timestamp-valid-window-disable = <0>; }; diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index 968e8c347da23cdb04ed3f48ea6f070287b305db..b8a6ed3991a189c133bac3bd94014cd72bb7be0e 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -97,6 +97,9 @@ Optional Properties: and assign for each endpoint. - qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become stable after power on, before de-assert the PERST to the endpoint. + - qcom,switch-latency: The time (unit: ms) to wait for the PCIe endpoint's link + training with switch downstream port after the link between switch upstream + port and RC is up. - qcom,wr-halt-size: With base 2, this exponent determines the size of the data that PCIe core will halt on for each write transaction. - qcom,cpl-timeout: Completion timeout value. This value specifies the time range @@ -264,6 +267,7 @@ Example: qcom,smmu-exist; qcom,smmu-sid-base = <0x1480>; qcom,ep-latency = <100>; + qcom,switch-latency = <100>; qcom,wr-halt-size = <0xa>; /* 1KB */ qcom,cpl-timeout = <0x2>; diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt index caf297bee1fb4c34ef5151912656f9636fe1565e..c28d4eb83b7687fbb630af467c7b49fb5e7e25f7 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt @@ -35,6 +35,15 @@ Optional properties: - ti,palmas-enable-dvfs2: Enable DVFS2. Configure pins for DVFS2 mode. Selection primary or secondary function associated to GPADC_START and SYSEN2 pin/pad for DVFS2 interface +- ti,palmas-override-powerhold: This is applicable for PMICs for which + GPIO7 is configured in POWERHOLD mode which has higher priority + over DEV_ON bit and keeps the PMIC supplies on even after the DEV_ON + bit is turned off. This property enables driver to over ride the + POWERHOLD value to GPIO7 so as to turn off the PMIC in power off + scenarios. So for GPIO7 if ti,palmas-override-powerhold is set + then the GPIO_7 field should never be muxed to anything else. + It should be set to POWERHOLD by default and only in case of + power off scenarios the driver will over ride the mux value. This binding uses the following generic properties as defined in pinctrl-bindings.txt: diff --git a/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt index 81e17f5b5346442b8f16e5ace94d441e69cd9bb8..9f1c864537c99d5a6acd8b349baff63b016e7989 100644 --- a/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt +++ b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt @@ -22,6 +22,10 @@ Optional Properties: value is 0 or device mode if 1. - qcom,disable-device-mode: If present then don't treat GPIO high as Vbus high. And only notify host mode similar to ID line. +-qcom,id-det-gpio: If present, specifies a gpio that is tied to ID, switch + to host mode if value is 0. +-qcom,dpdm_switch_gpio: If present, specifies a gpio that drives a switch + which routes DPDM lines to different ports. Example: diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt index 73349250110dbe8212c4359aed6dc187d39bb088..562b9f5f150b4a7ed4ac87bed2e3ec60459a4aaa 100644 --- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt +++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt @@ -77,6 +77,10 @@ Optional properties: but this applies for the system shutdown case. - qcom,kpdpwr-sw-debounce Boolean property to enable the debounce logic on the KPDPWR_N rising edge. +- qcom,support-twm-config Boolean property to allow the PON module to be + configured to support TWM modes. +- qcom,pbs-client Phandle of the PBS client node. Should be + defined if 'qcom,support-twm-config' is present. All the below properties are in the sub-node section (properties of the child diff --git a/Documentation/devicetree/bindings/platform/msm/ssm.txt b/Documentation/devicetree/bindings/platform/msm/ssm.txt deleted file mode 100644 index 7df3efd66577485dcf38f11117b9aa3142a3a76d..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/platform/msm/ssm.txt +++ /dev/null @@ -1,13 +0,0 @@ -* Qualcomm Technologies, Inc. Secure Service Module driver - -This module enables framework to which a client can register itself -specifying different attributes and defining various permission levels -associated with different combination of attribute values and mode of the system. - -Required properties: -- compatible: Must be "qcom,ssm" - -Example: - qcom,ssm { - compatible = "qcom,ssm"; - }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt index 012368275db356eb457a3ddbbb2433ccb8470426..269f546ec364f5435599f7b6c14140c35f009a6d 100644 --- a/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt +++ b/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt @@ -104,6 +104,13 @@ First Level Node - FG Gen3 device this property is not specified, then the default value used will be 75mA. +- qcom,fg-cutoff-current + Usage: optional + Value type: + Definition: Minimum Battery current (in mA) used for cutoff SOC + estimate. If this property is not specified, then a default + value of 500 mA will be applied. + - qcom,fg-delta-soc-thr Usage: optional Value type: @@ -170,6 +177,14 @@ First Level Node - FG Gen3 device Element 0 - Retry value for timer Element 1 - Maximum value for timer +- qcom,fg-esr-timer-shutdown + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses at/after shutdwon. This is + defined when TWM (traditional watch mode) is supported. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + - qcom,fg-esr-pulse-thresh-ma Usage: optional Value type: @@ -301,6 +316,13 @@ First Level Node - FG Gen3 device is specified to make it fully functional. Value has no unit. Allowed range is 0 to 62200 in micro units. +- qcom,ki-coeff-full-dischg + Usage: optional + Value type: + Definition: Ki coefficient full SOC value that will be applied during + discharging. If not specified, a value of 0 will be set. + Allowed range is from 245 to 62256. + - qcom,fg-rconn-mohms Usage: optional Value type: @@ -385,6 +407,28 @@ First Level Node - FG Gen3 device property "qcom,slope-limit-temp-threshold" to make dynamic slope limit adjustment functional. +- qcom,fg-use-sw-esr + Usage: optional + Value type: + Definition: A boolean property when defined uses software based + ESR during charging. + +- qcom,fg-disable-esr-pull-dn + Usage: optional + Value type: + Definition: A boolean property which disables ESR pull-down. + This is to be used for debug purposes only. + +- qcom,fg-sync-sleep-threshold-ma + Usage: optional + Value type: + Definition: The minimum battery current for FG to enter into sync-sleep. + +- qcom,fg-disable-in-twm + Usage: optional + Value type: + Definition: A boolean property which disables FG during TWM entry. + ========================================================== Second Level Nodes - Peripherals managed by FG Gen3 driver ========================================================== diff --git a/Documentation/devicetree/bindings/power/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qpnp-smb2.txt index 468db388b0a6ab1218e018d2e9de04f56a37e4e7..1f98d0d69ce7be656adaf8882bd55812bb9bf93a 100644 --- a/Documentation/devicetree/bindings/power/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/qpnp-smb2.txt @@ -182,6 +182,11 @@ Charger specific properties: Definition: Specifies the deglitch interval for OTG detection. If the value is not present, 50 msec is used as default. +- qcom,pd-not-supported + Usage: optional + Value type: bool + Definition: Option to indicate if the platform supports USB PD (power delivery). + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= diff --git a/Documentation/devicetree/bindings/smcinvoke/smcinvoke.txt b/Documentation/devicetree/bindings/smcinvoke/smcinvoke.txt new file mode 100644 index 0000000000000000000000000000000000000000..22243f6b984ff8809cfdee65dd9e1f16dce818b6 --- /dev/null +++ b/Documentation/devicetree/bindings/smcinvoke/smcinvoke.txt @@ -0,0 +1,34 @@ +* SMCInvoke driver to provide transport between TZ and Linux + +Required properties: +- compatible : Should be "qcom,smcinvoke" +- reg : should contain memory region address reserved for loading secure apps. +- qcom, msm_bus,name: Should be "smcinvoke-noc" +- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling +- qcom, msm_bus,num_paths: The paths for source and destination ports +- qcom, msm_bus,vectors: Vectors for bus topology. +- qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target. + - qcom,clock-support : indicates clocks are handled by smcinvoke (could be handled by RPM) + +Example: + qcom_smcinvoke: smcinvoke@88000000 { + compatible = "qcom,smcinvoke"; + reg = <0x88000000 0x500000>; + qcom,clock-support; + qcom,msm-bus,name = "smcinvoke-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <47 512 0 0>, + <47 512 0 0>, + <47 512 120000 1200000>, + <47 512 393600 3936000>; + clocks = <&clock_gcc clk_crypto_clk_src>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + qcom,ce-opp-freq = <100000000>; + status = "ok"; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt new file mode 100644 index 0000000000000000000000000000000000000000..1417eb02c07c3c42ce0273bf67261fa5b3089c87 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt @@ -0,0 +1,20 @@ +Qualcomm Technologies Inc. bg-daemon + +BG-Daemon : When Modem goes down, to re-establish the connections, +BG-Daemon toggles the bg-reset gpio to reset BG. + +Required properties: +- compatible : should be "qcom,bg-daemon" +- qcom,bg-reset-gpio : gpio for the apps processor use to soft reset BG +- ssr-reg1-supply : Power supply needed to power up the BG device. + When BG brought up this regulator will be in normal power mode. +- ssr-reg2-supply : Power supply needed to power up the BG device. + When BG BG brought up this regulator will be in normal power mode. + +Example: + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt new file mode 100644 index 0000000000000000000000000000000000000000..26a13cd4aa37f178039e2094c3d3ed910c98aa42 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt @@ -0,0 +1,19 @@ +Qualcomm technologies Inc bg-rsb + +BG-RSB : bg-rsb is used to communicate with BG over Glink to +configure the RSB events. bg-rsb enable/disable LDO11 and LDO15 +before making any communication to BG regarding RSB. +It also provides an input device, which is used to send the RSB/Button +events to input framework. + +Required properties: +- compatible : should be "qcom,bg-rsb" +- vdd-ldo1-supply : pm660_l11 regulator +- vdd-ldo2-supply : for pm660_l15 regulator + +Example: + qcom,bg-rsb { + compatible = "qcom,bg-rsb"; + vdd-ldo1-supply = <&pm660_l11>; + vdd-ldo2-supply = <&pm660_l15>; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt old mode 100755 new mode 100644 index 80c8fd14ef9409157c9765eabfb8296a827dbed3..afe82d5465a56d1bd6b1fdf8da22f7e74dceb8aa --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -411,6 +411,9 @@ Required properties: Required properties: - compatible : "qcom,wcd-dsp-glink" + - qcom,msm-codec-glink-edge: Name of the glink edge which is used + for IPC. + If no name is set, it defaults to "wdsp" Example: @@ -689,6 +692,7 @@ Example: wcd_dsp_glink { compatible = "qcom,wcd-dsp-glink"; + qcom,msm-codec-glink-edge = "bg"; }; @@ -1216,6 +1220,26 @@ qcom,msm-audio-ion { memory-region = <&audio_mem>; }; +* msm-audio-ion-vm + +Required properties: + - compatible : "qcom,msm-audio-ion-vm" + +Optional properties: + - qcom,smmu-enabled: + It is possible that some MSM have SMMU in ADSP. While other + MSM use no SMMU. Audio lib introduce wrapper for ION APIs. + The wrapper needs presence of SMMU in ADSP to handle ION + APIs differently. Presence of this property means ADSP has + SMMU in it. + +Example: + +qcom,msm-audio-ion-vm { + compatible = "qcom,msm-audio-ion-vm; + qcom,smmu-enabled; +}; + * MSM8994 ASoC Machine driver Required properties: @@ -1371,6 +1395,16 @@ Required properties: When clock rate is set to zero, then external clock is assumed. + - qcom,msm-cpudai-tdm-afe-ebit-unsupported: Notify if ebit setting is needed + When this is set , alongwith + clock rate as zero then afe + is not configured for clock. + + - qcom,msm-cpudai-tdm-sec-port-start: For chipsets with the limitation where we need + to start both RX and TX AFE ports, this flag is + used to start TX/RX port for RX/TX streams. + + [Second Level Nodes] Required properties: @@ -1570,6 +1604,197 @@ Example: "SpkrRight", "SpkrLeft"; }; +* MSM8909 ASoC Machine driver + +Required properties: +- compatible : "qcom,msm8909-audio-codec" +- qcom,model : The user-visible name of this sound card. +- reg : Offset and length of the register region(s) for MI2S/PCM MUX +- reg-names : Register region name(s) referenced in reg above + Required register resource entries are: + "csr_gp_io_mux_mic_ctl": Physical address of MUX that controls + controls LPA IF tertiary, quad, PCM0, Digital Codec + and Secondary TLMM mux setting for mic path operation. + "csr_gp_io_mux_spkr_ctl": Physical address of MUX that controls + IF primary, secondary, Digital Codec and Primary TLMM + setting for speaker path operation. + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel": Physical address of MUX + that controls the mux between LPA IF Quad and PCM0 + path to secondary TLMM +- qcom,msm-hs-micbias-type : This property is used to recognize the headset + micbias type, internal or external. +- qcom,msm-ext-pa : This property is used to inform machine driver about + the connection of external PA over available MI2S interfaces, + following values can be given to this property. + primary -> Primary MI2S interface + secondary -> Secondary MI2S interface + tertiary -> Tertiary MI2S interface + quaternary -> Quaternary MI2S interface +- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL +switch type on target typically the switch type will be normally open or +normally close, value for this property 0 for normally close and 1 for +normally open. +- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND +switch type on target typically the switch type will be normally open or +normally close, value for this property 0 for normally close and 1 for +normally open. +- qcom,audio-routing : A list of the connections between audio components. +- qcom,msm-gpios : Lists down all the gpio sets that are supported. +- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets +mentioned in qcom,msm-gpios. +- pinctrl-names : The combinations of gpio sets from above that are supported in +the flavor. +- pinctrl-# : Pinctrl states as mentioned in pinctrl-names. + +Optional properties: +- qcom,msm-afe-clk-ver: Provides detail of AFE clock API version. +- qcom,hdmi-dba-codec-rx: Boolean. specifies if HDMI DBA audio support is enabled or not. +- qcom,split-a2dp: Boolean. specifies if split a2dp audio support is enabled or not. +- qcom,prim-auxpcm-gpio-clk : GPIO on which Primary AUXPCM clk signal is coming. +- qcom,prim-auxpcm-gpio-sync : GPIO on which Primary AUXPCM SYNC signal is coming. +- qcom,prim-auxpcm-gpio-din : GPIO on which Primary AUXPCM DIN signal is coming. +- qcom,prim-auxpcm-gpio-dout : GPIO on which Primary AUXPCM DOUT signal is coming. +- qcom,prim-auxpcm-gpio-set : set of GPIO lines used for Primary AUXPCM port +- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming. +- qcom,msm-micbias1-ext-cap : Boolean. Enable micbias1 external +capacitor mode. +- qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external +capacitor mode. +- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa. +- qcom,subsys-name: This value provides the subsystem name where codec + is present. This property enables the codec driver to + register and receive subsytem restart notification from subsystem + and follow appropriate steps to ensure codec is in proper state + after subsytem restart. By default codec driver register + with ADSP subsystem. + +To Configure External Audio Switch +- qcom,msm-ext-audio-switch : GPIO which controls external switch that switches + audio path between headset and speakers. +- ext-switch-vdd-supply : Power supply that control external audio switch +- qcom,ext-switch-vdd-voltage : Minimum and maximum voltage in uV to set for + power supply. +- qcom,ext-switch-vdd-op-mode : Maxmum # of uA current the switch will draw + from the power supply. +Example: + qcom,msm-ext-audio-switch = <&msm_gpio 2 0>; - gpio # and active_state + ext-switch-vdd-supply = <&pm8950_l13>; - Power Rail + qcom,ext-switch-vdd-voltage = <3075000 3075000>; - Min, Max uV voltage + qcom,ext-switch-vdd-op-mode = <5000>; - Operational current uA + Additional needs to add two additional qcom,audio-routings + "HEADPHONE", "VDD_EXT_AUDIO_SWITCH" + "SPK_OUT", "VDD_EXT_AUDIO_SWITCH" + +- qcom,msm-mclk-freq : This property is used to inform machine driver about +mclk frequency needs to be configured for internal and external PA. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- asoc-wsa-codec-names: This property contains list of wsa codec names. The names + should comply with the wsa nodes configurations. +- asoc-wsa-codec-prefixes: This property contains list of wsa codec prefixes. +- msm-vdd-wsa-switch-supply: WSA codec supply's regulator device tree node. +- qcom,msm-vdd-wsa-switch-voltage: WSA codec supply's voltage level in mV. +- qcom,msm-vdd-wsa-switch-current: WSA codec max current level in mA. + +Example: + sound { + compatible = "qcom,msm8909-audio-codec"; + qcom,model = "msm8909-snd-card"; + reg = <0xc051000 0x4>, + <0xc051004 0x4>, + <0xc055000 0x4>; + reg-names = "csr_gp_io_mux_mic_ctl", + "csr_gp_io_mux_spkr_ctl", + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel"; + qcom,msm-afe-clk-ver = <1>; + qcom,msm-ext-pa = "primary"; + qcom,hdmi-dba-codec-rx; + qcom,split-a2dp; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-hs-micbias-type = "internal"; + qcom,msm-micbias1-ext-cap; + qcom,audio-routing = + "RX_BIAS", "MCLK", + "SPK_RX_BIAS", "MCLK", + "INT_LDO_H", "MCLK", + "MIC BIAS External", "Handset Mic", + "MIC BIAS Internal2", "Headset Mic", + "MIC BIAS External", "Secondary Mic", + "AMIC1", "MIC BIAS External", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External"; + qcom,msm-gpios = + "pri_i2s", + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "pri_i2s_act", + "us_eu_gpio_act", + "pri_i2s_us_eu_gpio_act"; + pinctrl-names = + "all_off", + "pri_i2s_act", + "us_eu_gpio_act", + "pri_i2s_us_eu_gpio_act"; + pinctrl-0 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_sus>; + pinctrl-1 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_sus>; + pinctrl-2 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cross_conn_det_act>; + pinctrl-3 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cross_conn_det_act>; + qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>; + qcom,prim-auxpcm-gpio-clk = <&msm_gpio 63 0>; + qcom,prim-auxpcm-gpio-sync = <&msm_gpio 64 0>; + qcom,prim-auxpcm-gpio-din = <&msm_gpio 65 0>; + qcom,prim-auxpcm-gpio-dout = <&msm_gpio 66 0>; + qcom,prim-auxpcm-gpio-set = "prim-gpio-prim"; + qcom,tapan-codec-9302; + asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&lpa>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", + "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa"; + asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, + <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, + <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770"; + asoc-codec = <&stub>, <&pm8916_tombak_dig>; + asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; + asoc-wsa-codec-names = "wsa881x-i2c-codec.8-000f"; + asoc-wsa-codec-prefixes = "SpkrMono"; + }; + * MSM8952 ASoC Machine driver Required properties: @@ -1963,6 +2188,12 @@ Optional properties: - qcom,wsa-devs: This property contains list of wsa codec names. The names should comply with the wsa nodes configurations. - qcom,wsa-aux-dev-prefix: This property contains list of wsa codec prefixes. +- qcom,tdm-i2s-switch-enable: For chipsets where tdm mics are controlled by + switch, drive corresponding gpio to output high + to enable switch. +- qcom,tdm-mic-mute-enable: This property is used to mute/unmute TDM mics using + gpio, drive corresponding gpio to output low + to unmute TDM mics. Example: sound { @@ -2055,6 +2286,104 @@ Example: qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight"; }; +* MSM8909 BG ASoC Machine driver + +Required properties: +- compatible : "qcom,msm-bg-audio-codec" +- qcom,model : The user-visible name of this sound card. +- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets + mentioned in qcom,msm-gpios. Say we have 2^N combinations for N GPIOs, + this would list all the 2^N combinations. +- pinctrl-names : The combinations of gpio sets from above that are supported in + the flavor. This can be sometimes same as qcom,pinctrl-names i.e with 2^N + combinations or will have less incase if some combination is not supported. +- pinctrl-# : Pinctrl states as mentioned in pinctrl-names. +- qcom,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. + +Optional properties: +- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- vdd-spkr-supply: BG codec supply's speaker regulator device tree node. + +Example: + sound { + status = "disabled"; + compatible = "qcom,msm-bg-audio-codec"; + qcom,model = "msm-bg-snd-card"; + reg = <0x7702000 0x4>, + <0x7702004 0x4>, + <0x7702008 0x4>, + <0x770200c 0x4>; + reg-names = "csr_gp_io_mux_mic_ctl", + "csr_gp_io_mux_spkr_ctl", + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel", + "csr_gp_io_lpaif_sec_pcm_sec_mode_muxsel"; + qcom,msm-snd-card-id = <0>; + qcom,msm-ext-pa = "primary"; + qcom,tdm-audio-intf; + qcom,msm-afe-clk-ver = <1>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&lpa>, + <&voice_svc>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-pcm-lpa", + "msm-voice-svc"; + asoc-cpu = <&dai_pri_auxpcm>, + <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, + <&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>, + <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, + <&int_fm_rx>, <&int_fm_tx>, <&afe_pcm_rx>, + <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_tx_2>, + <&dai_pri_tdm_rx_3>, <&dai_pri_tdm_tx_3>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292", + "msm-dai-q6-dev.12293", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36868", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36871"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; + + + * MDM9607 ASoC Machine driver Required properties: @@ -2629,3 +2958,63 @@ sound { asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; }; + +* BG Codec Driver. + +Required properties: +- compatible : "qcom,bg-codec" +- qcom,bg-glink : Glink component required for the BG codec communication. + - compatible :"qcom,bg-cdc-glink" +- qcom,msm-glink-channels: Number of glink channels available to communicate + with the glink client +- vdd-spkr-supply: BG codec supply's speaker regulator device tree node. + +Optional properties: +- qcom,bg-speaker-connected: This flag will notify BG codec driver that speaker + is connected to target or not. Based on this flag BG + codec driver will send smart pa init params to BG. + +Example: + + bg_cdc: bg_codec { + status = "disabled"; + compatible = "qcom,bg-codec"; + qcom,bg-glink { + compatible = "qcom,bg-cdc-glink"; + qcom,msm-glink-channels = <4>; + }; + }; + +* Digital Codec Driver. + +Required properties: +- compatible : "qcom,msm-digital-codec" +- reg : This property provides the digital codec register address. +- cdc-vdd-digit-supply : Power supply that controls dmic and external + speaker. +- qcom,cdc-vdd-digit-voltage : dmic and external speaker supply's voltage + level in mV +- qcom,cdc-vdd-digit-current : dmic and external speaker max current level + in mA +- qcom,cdc-on-demand-supplies : List of supplies which can be enabled + dynamically. Supplies in this list are off by default. +- qcom,subsys-name: This value provides the subsystem name where codec + is present. This property enables the codec driver to + register and receive subsytem restart notification from subsystem + and follow appropriate steps to ensure codec is in proper state + after subsytem restart. By default codec driver register + with ADSP subsystem. + +Example: + + msm_digital_codec: msm-dig-codec@771c000 { + compatible = "qcom,msm-digital-codec"; + reg = <0x0771c000 0x0>; + + cdc-vdd-digital-supply = <&pm660_l11>; + qcom,cdc-vdd-digital-voltage = <1800000 1800000>; + qcom,cdc-vdd-digital-current = <5000>; + qcom,cdc-on-demand-supplies = "cdc-vdd-digital"; + + qcom,subsys-name = "modem"; + }; diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt index 90bef273363d3c0d2a37df2f8d6886d57125649f..5f8d2938b187b214a164861a334c5336f802bd1c 100644 --- a/Documentation/devicetree/bindings/sound/taiko_codec.txt +++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt @@ -536,6 +536,10 @@ Tasha audio CODEC in I2C mode - qcom,cdc-dmic-sample-rate - Specifies dmic sample rate. - qcom,cdc-variant - Specifies codec variant. + - qcom,wcd9xxx-mic-tristate: For chipsets where I2S TX line is shared between + the Codec and TDM mics, tristate the WCD mics to + avoid PCM interference as the end product uses + only TDM mics. Example: i2c_3: i2c@78B7000 { /* BLSP1 QUP3 */ diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 9f22c1d8be95ca3fa354f83677732926e549fc8b..dc2b1a2565fc33a3e43d477b426912819e5b7372 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -78,6 +78,7 @@ haoyu Haoyu Microelectronic Co. Ltd. hisilicon Hisilicon Limited. honeywell Honeywell hp Hewlett Packard +himax Himax Coroporation i2se I2SE GmbH ibm International Business Machines (IBM) idt Integrated Device Technologies, Inc. @@ -92,6 +93,7 @@ karo Ka-Ro electronics GmbH keymile Keymile GmbH lacie LaCie lantiq Lantiq Semiconductor +lego LEGO Systems A/S lenovo Lenovo Group Ltd. invn InvenSense Inc. isl Intersil @@ -199,6 +201,7 @@ xlnx Xilinx zyxel ZyXEL Communications Corp. zarlink Zarlink Semiconductor bosch-sensortec» Bosch Sensortec GmbH +inven InvenSense, Inc. lontium Lontium Semiconductor himax Himax Technologies, Inc. -hxcommon Himax Technologies, Inc. +hxcommon Himax Technologies, Inc. \ No newline at end of file diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 919a3293aaa4249f81f0d907d9867d6d80f9a135..04f7e4ad070b991ba117700f9f937c8d94deb63f 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt @@ -233,7 +233,7 @@ data_err=ignore(*) Just print an error message if an error occurs data_err=abort Abort the journal if an error occurs in a file data buffer in ordered mode. -grpid Give objects the same group ID as their creator. +grpid New objects have the group ID of their parent. bsdgroups nogrpid (*) New objects have the group ID of their creator. diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index 9342fde55982278a5ecf0794a1e19c2fd0310a32..30caa3635e4a1e171371e41c6f1a11dcd2ddb9f6 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -106,7 +106,11 @@ background_gc=%s Turn on/off cleaning operations, namely garbage Default value for this option is on. So garbage collection is on by default. disable_roll_forward Disable the roll-forward recovery routine -discard Issue discard/TRIM commands when a segment is cleaned. +norecovery Disable the roll-forward recovery routine, mounted read- + only (i.e., -o ro,disable_roll_forward) +discard/nodiscard Enable/disable real-time discard in f2fs, if discard is + enabled, f2fs will issue discard/TRIM commands when a + segment is cleaned. no_heap Disable heap-style segment allocation which finds free segments for data from the beginning of main area, while for node from the end of main area. @@ -120,8 +124,14 @@ active_logs=%u Support configuring the number of active logs. In the disable_ext_identify Disable the extension list configured by mkfs, so f2fs does not aware of cold files such as media files. inline_xattr Enable the inline xattrs feature. +noinline_xattr Disable the inline xattrs feature. inline_data Enable the inline data feature: New created small(<~3.4k) files can be written into inode block. +inline_dentry Enable the inline dir feature: data in new created + directory entries can be written into inode block. The + space of inode block which is used to store inline + dentries is limited to ~3.4k. +noinline_dentry Diable the inline dentry feature. flush_merge Merge concurrent cache_flush commands as much as possible to eliminate redundant command issues. If the underlying device handles the cache_flush command relatively slowly, @@ -144,6 +154,26 @@ noinline_data Disable the inline data feature, inline data feature is enabled by default. data_flush Enable data flushing before checkpoint in order to persist data of regular and symlink. +fault_injection=%d Enable fault injection in all supported types with + specified injection rate. +fault_type=%d Support configuring fault injection type, should be + enabled with fault_injection option, fault type value + is shown below, it supports single or combined type. + Type_Name Type_Value + FAULT_KMALLOC 0x000000001 + FAULT_KVMALLOC 0x000000002 + FAULT_PAGE_ALLOC 0x000000004 + FAULT_PAGE_GET 0x000000008 + FAULT_ALLOC_BIO 0x000000010 + FAULT_ALLOC_NID 0x000000020 + FAULT_ORPHAN 0x000000040 + FAULT_BLOCK 0x000000080 + FAULT_DIR_DEPTH 0x000000100 + FAULT_EVICT_INODE 0x000000200 + FAULT_TRUNCATE 0x000000400 + FAULT_IO 0x000000800 + FAULT_CHECKPOINT 0x000001000 + FAULT_DISCARD 0x000002000 mode=%s Control block allocation mode which supports "adaptive" and "lfs". In "lfs" mode, there should be no random writes towards main area. diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst new file mode 100644 index 0000000000000000000000000000000000000000..48b424de85bbca87f840774883132671aec50f02 --- /dev/null +++ b/Documentation/filesystems/fscrypt.rst @@ -0,0 +1,626 @@ +===================================== +Filesystem-level encryption (fscrypt) +===================================== + +Introduction +============ + +fscrypt is a library which filesystems can hook into to support +transparent encryption of files and directories. + +Note: "fscrypt" in this document refers to the kernel-level portion, +implemented in ``fs/crypto/``, as opposed to the userspace tool +`fscrypt `_. This document only +covers the kernel-level portion. For command-line examples of how to +use encryption, see the documentation for the userspace tool `fscrypt +`_. Also, it is recommended to use +the fscrypt userspace tool, or other existing userspace tools such as +`fscryptctl `_ or `Android's key +management system +`_, over +using the kernel's API directly. Using existing tools reduces the +chance of introducing your own security bugs. (Nevertheless, for +completeness this documentation covers the kernel's API anyway.) + +Unlike dm-crypt, fscrypt operates at the filesystem level rather than +at the block device level. This allows it to encrypt different files +with different keys and to have unencrypted files on the same +filesystem. This is useful for multi-user systems where each user's +data-at-rest needs to be cryptographically isolated from the others. +However, except for filenames, fscrypt does not encrypt filesystem +metadata. + +Unlike eCryptfs, which is a stacked filesystem, fscrypt is integrated +directly into supported filesystems --- currently ext4, F2FS, and +UBIFS. This allows encrypted files to be read and written without +caching both the decrypted and encrypted pages in the pagecache, +thereby nearly halving the memory used and bringing it in line with +unencrypted files. Similarly, half as many dentries and inodes are +needed. eCryptfs also limits encrypted filenames to 143 bytes, +causing application compatibility issues; fscrypt allows the full 255 +bytes (NAME_MAX). Finally, unlike eCryptfs, the fscrypt API can be +used by unprivileged users, with no need to mount anything. + +fscrypt does not support encrypting files in-place. Instead, it +supports marking an empty directory as encrypted. Then, after +userspace provides the key, all regular files, directories, and +symbolic links created in that directory tree are transparently +encrypted. + +Threat model +============ + +Offline attacks +--------------- + +Provided that userspace chooses a strong encryption key, fscrypt +protects the confidentiality of file contents and filenames in the +event of a single point-in-time permanent offline compromise of the +block device content. fscrypt does not protect the confidentiality of +non-filename metadata, e.g. file sizes, file permissions, file +timestamps, and extended attributes. Also, the existence and location +of holes (unallocated blocks which logically contain all zeroes) in +files is not protected. + +fscrypt is not guaranteed to protect confidentiality or authenticity +if an attacker is able to manipulate the filesystem offline prior to +an authorized user later accessing the filesystem. + +Online attacks +-------------- + +fscrypt (and storage encryption in general) can only provide limited +protection, if any at all, against online attacks. In detail: + +fscrypt is only resistant to side-channel attacks, such as timing or +electromagnetic attacks, to the extent that the underlying Linux +Cryptographic API algorithms are. If a vulnerable algorithm is used, +such as a table-based implementation of AES, it may be possible for an +attacker to mount a side channel attack against the online system. +Side channel attacks may also be mounted against applications +consuming decrypted data. + +After an encryption key has been provided, fscrypt is not designed to +hide the plaintext file contents or filenames from other users on the +same system, regardless of the visibility of the keyring key. +Instead, existing access control mechanisms such as file mode bits, +POSIX ACLs, LSMs, or mount namespaces should be used for this purpose. +Also note that as long as the encryption keys are *anywhere* in +memory, an online attacker can necessarily compromise them by mounting +a physical attack or by exploiting any kernel security vulnerability +which provides an arbitrary memory read primitive. + +While it is ostensibly possible to "evict" keys from the system, +recently accessed encrypted files will remain accessible at least +until the filesystem is unmounted or the VFS caches are dropped, e.g. +using ``echo 2 > /proc/sys/vm/drop_caches``. Even after that, if the +RAM is compromised before being powered off, it will likely still be +possible to recover portions of the plaintext file contents, if not +some of the encryption keys as well. (Since Linux v4.12, all +in-kernel keys related to fscrypt are sanitized before being freed. +However, userspace would need to do its part as well.) + +Currently, fscrypt does not prevent a user from maliciously providing +an incorrect key for another user's existing encrypted files. A +protection against this is planned. + +Key hierarchy +============= + +Master Keys +----------- + +Each encrypted directory tree is protected by a *master key*. Master +keys can be up to 64 bytes long, and must be at least as long as the +greater of the key length needed by the contents and filenames +encryption modes being used. For example, if AES-256-XTS is used for +contents encryption, the master key must be 64 bytes (512 bits). Note +that the XTS mode is defined to require a key twice as long as that +required by the underlying block cipher. + +To "unlock" an encrypted directory tree, userspace must provide the +appropriate master key. There can be any number of master keys, each +of which protects any number of directory trees on any number of +filesystems. + +Userspace should generate master keys either using a cryptographically +secure random number generator, or by using a KDF (Key Derivation +Function). Note that whenever a KDF is used to "stretch" a +lower-entropy secret such as a passphrase, it is critical that a KDF +designed for this purpose be used, such as scrypt, PBKDF2, or Argon2. + +Per-file keys +------------- + +Master keys are not used to encrypt file contents or names directly. +Instead, a unique key is derived for each encrypted file, including +each regular file, directory, and symbolic link. This has several +advantages: + +- In cryptosystems, the same key material should never be used for + different purposes. Using the master key as both an XTS key for + contents encryption and as a CTS-CBC key for filenames encryption + would violate this rule. +- Per-file keys simplify the choice of IVs (Initialization Vectors) + for contents encryption. Without per-file keys, to ensure IV + uniqueness both the inode and logical block number would need to be + encoded in the IVs. This would make it impossible to renumber + inodes, which e.g. ``resize2fs`` can do when resizing an ext4 + filesystem. With per-file keys, it is sufficient to encode just the + logical block number in the IVs. +- Per-file keys strengthen the encryption of filenames, where IVs are + reused out of necessity. With a unique key per directory, IV reuse + is limited to within a single directory. +- Per-file keys allow individual files to be securely erased simply by + securely erasing their keys. (Not yet implemented.) + +A KDF (Key Derivation Function) is used to derive per-file keys from +the master key. This is done instead of wrapping a randomly-generated +key for each file because it reduces the size of the encryption xattr, +which for some filesystems makes the xattr more likely to fit in-line +in the filesystem's inode table. With a KDF, only a 16-byte nonce is +required --- long enough to make key reuse extremely unlikely. A +wrapped key, on the other hand, would need to be up to 64 bytes --- +the length of an AES-256-XTS key. Furthermore, currently there is no +requirement to support unlocking a file with multiple alternative +master keys or to support rotating master keys. Instead, the master +keys may be wrapped in userspace, e.g. as done by the `fscrypt +`_ tool. + +The current KDF encrypts the master key using the 16-byte nonce as an +AES-128-ECB key. The output is used as the derived key. If the +output is longer than needed, then it is truncated to the needed +length. Truncation is the norm for directories and symlinks, since +those use the CTS-CBC encryption mode which requires a key half as +long as that required by the XTS encryption mode. + +Note: this KDF meets the primary security requirement, which is to +produce unique derived keys that preserve the entropy of the master +key, assuming that the master key is already a good pseudorandom key. +However, it is nonstandard and has some problems such as being +reversible, so it is generally considered to be a mistake! It may be +replaced with HKDF or another more standard KDF in the future. + +Encryption modes and usage +========================== + +fscrypt allows one encryption mode to be specified for file contents +and one encryption mode to be specified for filenames. Different +directory trees are permitted to use different encryption modes. +Currently, the following pairs of encryption modes are supported: + +- AES-256-XTS for contents and AES-256-CTS-CBC for filenames +- AES-128-CBC for contents and AES-128-CTS-CBC for filenames +- Speck128/256-XTS for contents and Speck128/256-CTS-CBC for filenames + +It is strongly recommended to use AES-256-XTS for contents encryption. +AES-128-CBC was added only for low-powered embedded devices with +crypto accelerators such as CAAM or CESA that do not support XTS. + +Similarly, Speck128/256 support was only added for older or low-end +CPUs which cannot do AES fast enough -- especially ARM CPUs which have +NEON instructions but not the Cryptography Extensions -- and for which +it would not otherwise be feasible to use encryption at all. It is +not recommended to use Speck on CPUs that have AES instructions. +Speck support is only available if it has been enabled in the crypto +API via CONFIG_CRYPTO_SPECK. Also, on ARM platforms, to get +acceptable performance CONFIG_CRYPTO_SPECK_NEON must be enabled. + +New encryption modes can be added relatively easily, without changes +to individual filesystems. However, authenticated encryption (AE) +modes are not currently supported because of the difficulty of dealing +with ciphertext expansion. + +For file contents, each filesystem block is encrypted independently. +Currently, only the case where the filesystem block size is equal to +the system's page size (usually 4096 bytes) is supported. With the +XTS mode of operation (recommended), the logical block number within +the file is used as the IV. With the CBC mode of operation (not +recommended), ESSIV is used; specifically, the IV for CBC is the +logical block number encrypted with AES-256, where the AES-256 key is +the SHA-256 hash of the inode's data encryption key. + +For filenames, the full filename is encrypted at once. Because of the +requirements to retain support for efficient directory lookups and +filenames of up to 255 bytes, a constant initialization vector (IV) is +used. However, each encrypted directory uses a unique key, which +limits IV reuse to within a single directory. Note that IV reuse in +the context of CTS-CBC encryption means that when the original +filenames share a common prefix at least as long as the cipher block +size (16 bytes for AES), the corresponding encrypted filenames will +also share a common prefix. This is undesirable; it may be fixed in +the future by switching to an encryption mode that is a strong +pseudorandom permutation on arbitrary-length messages, e.g. the HEH +(Hash-Encrypt-Hash) mode. + +Since filenames are encrypted with the CTS-CBC mode of operation, the +plaintext and ciphertext filenames need not be multiples of the AES +block size, i.e. 16 bytes. However, the minimum size that can be +encrypted is 16 bytes, so shorter filenames are NUL-padded to 16 bytes +before being encrypted. In addition, to reduce leakage of filename +lengths via their ciphertexts, all filenames are NUL-padded to the +next 4, 8, 16, or 32-byte boundary (configurable). 32 is recommended +since this provides the best confidentiality, at the cost of making +directory entries consume slightly more space. Note that since NUL +(``\0``) is not otherwise a valid character in filenames, the padding +will never produce duplicate plaintexts. + +Symbolic link targets are considered a type of filename and are +encrypted in the same way as filenames in directory entries. Each +symlink also uses a unique key; hence, the hardcoded IV is not a +problem for symlinks. + +User API +======== + +Setting an encryption policy +---------------------------- + +The FS_IOC_SET_ENCRYPTION_POLICY ioctl sets an encryption policy on an +empty directory or verifies that a directory or regular file already +has the specified encryption policy. It takes in a pointer to a +:c:type:`struct fscrypt_policy`, defined as follows:: + + #define FS_KEY_DESCRIPTOR_SIZE 8 + + struct fscrypt_policy { + __u8 version; + __u8 contents_encryption_mode; + __u8 filenames_encryption_mode; + __u8 flags; + __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; + }; + +This structure must be initialized as follows: + +- ``version`` must be 0. + +- ``contents_encryption_mode`` and ``filenames_encryption_mode`` must + be set to constants from ```` which identify the + encryption modes to use. If unsure, use + FS_ENCRYPTION_MODE_AES_256_XTS (1) for ``contents_encryption_mode`` + and FS_ENCRYPTION_MODE_AES_256_CTS (4) for + ``filenames_encryption_mode``. + +- ``flags`` must be set to a value from ```` which + identifies the amount of NUL-padding to use when encrypting + filenames. If unsure, use FS_POLICY_FLAGS_PAD_32 (0x3). + +- ``master_key_descriptor`` specifies how to find the master key in + the keyring; see `Adding keys`_. It is up to userspace to choose a + unique ``master_key_descriptor`` for each master key. The e4crypt + and fscrypt tools use the first 8 bytes of + ``SHA-512(SHA-512(master_key))``, but this particular scheme is not + required. Also, the master key need not be in the keyring yet when + FS_IOC_SET_ENCRYPTION_POLICY is executed. However, it must be added + before any files can be created in the encrypted directory. + +If the file is not yet encrypted, then FS_IOC_SET_ENCRYPTION_POLICY +verifies that the file is an empty directory. If so, the specified +encryption policy is assigned to the directory, turning it into an +encrypted directory. After that, and after providing the +corresponding master key as described in `Adding keys`_, all regular +files, directories (recursively), and symlinks created in the +directory will be encrypted, inheriting the same encryption policy. +The filenames in the directory's entries will be encrypted as well. + +Alternatively, if the file is already encrypted, then +FS_IOC_SET_ENCRYPTION_POLICY validates that the specified encryption +policy exactly matches the actual one. If they match, then the ioctl +returns 0. Otherwise, it fails with EEXIST. This works on both +regular files and directories, including nonempty directories. + +Note that the ext4 filesystem does not allow the root directory to be +encrypted, even if it is empty. Users who want to encrypt an entire +filesystem with one key should consider using dm-crypt instead. + +FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors: + +- ``EACCES``: the file is not owned by the process's uid, nor does the + process have the CAP_FOWNER capability in a namespace with the file + owner's uid mapped +- ``EEXIST``: the file is already encrypted with an encryption policy + different from the one specified +- ``EINVAL``: an invalid encryption policy was specified (invalid + version, mode(s), or flags) +- ``ENOTDIR``: the file is unencrypted and is a regular file, not a + directory +- ``ENOTEMPTY``: the file is unencrypted and is a nonempty directory +- ``ENOTTY``: this type of filesystem does not implement encryption +- ``EOPNOTSUPP``: the kernel was not configured with encryption + support for this filesystem, or the filesystem superblock has not + had encryption enabled on it. (For example, to use encryption on an + ext4 filesystem, CONFIG_EXT4_ENCRYPTION must be enabled in the + kernel config, and the superblock must have had the "encrypt" + feature flag enabled using ``tune2fs -O encrypt`` or ``mkfs.ext4 -O + encrypt``.) +- ``EPERM``: this directory may not be encrypted, e.g. because it is + the root directory of an ext4 filesystem +- ``EROFS``: the filesystem is readonly + +Getting an encryption policy +---------------------------- + +The FS_IOC_GET_ENCRYPTION_POLICY ioctl retrieves the :c:type:`struct +fscrypt_policy`, if any, for a directory or regular file. See above +for the struct definition. No additional permissions are required +beyond the ability to open the file. + +FS_IOC_GET_ENCRYPTION_POLICY can fail with the following errors: + +- ``EINVAL``: the file is encrypted, but it uses an unrecognized + encryption context format +- ``ENODATA``: the file is not encrypted +- ``ENOTTY``: this type of filesystem does not implement encryption +- ``EOPNOTSUPP``: the kernel was not configured with encryption + support for this filesystem + +Note: if you only need to know whether a file is encrypted or not, on +most filesystems it is also possible to use the FS_IOC_GETFLAGS ioctl +and check for FS_ENCRYPT_FL, or to use the statx() system call and +check for STATX_ATTR_ENCRYPTED in stx_attributes. + +Getting the per-filesystem salt +------------------------------- + +Some filesystems, such as ext4 and F2FS, also support the deprecated +ioctl FS_IOC_GET_ENCRYPTION_PWSALT. This ioctl retrieves a randomly +generated 16-byte value stored in the filesystem superblock. This +value is intended to used as a salt when deriving an encryption key +from a passphrase or other low-entropy user credential. + +FS_IOC_GET_ENCRYPTION_PWSALT is deprecated. Instead, prefer to +generate and manage any needed salt(s) in userspace. + +Adding keys +----------- + +To provide a master key, userspace must add it to an appropriate +keyring using the add_key() system call (see: +``Documentation/security/keys/core.rst``). The key type must be +"logon"; keys of this type are kept in kernel memory and cannot be +read back by userspace. The key description must be "fscrypt:" +followed by the 16-character lower case hex representation of the +``master_key_descriptor`` that was set in the encryption policy. The +key payload must conform to the following structure:: + + #define FS_MAX_KEY_SIZE 64 + + struct fscrypt_key { + u32 mode; + u8 raw[FS_MAX_KEY_SIZE]; + u32 size; + }; + +``mode`` is ignored; just set it to 0. The actual key is provided in +``raw`` with ``size`` indicating its size in bytes. That is, the +bytes ``raw[0..size-1]`` (inclusive) are the actual key. + +The key description prefix "fscrypt:" may alternatively be replaced +with a filesystem-specific prefix such as "ext4:". However, the +filesystem-specific prefixes are deprecated and should not be used in +new programs. + +There are several different types of keyrings in which encryption keys +may be placed, such as a session keyring, a user session keyring, or a +user keyring. Each key must be placed in a keyring that is "attached" +to all processes that might need to access files encrypted with it, in +the sense that request_key() will find the key. Generally, if only +processes belonging to a specific user need to access a given +encrypted directory and no session keyring has been installed, then +that directory's key should be placed in that user's user session +keyring or user keyring. Otherwise, a session keyring should be +installed if needed, and the key should be linked into that session +keyring, or in a keyring linked into that session keyring. + +Note: introducing the complex visibility semantics of keyrings here +was arguably a mistake --- especially given that by design, after any +process successfully opens an encrypted file (thereby setting up the +per-file key), possessing the keyring key is not actually required for +any process to read/write the file until its in-memory inode is +evicted. In the future there probably should be a way to provide keys +directly to the filesystem instead, which would make the intended +semantics clearer. + +Access semantics +================ + +With the key +------------ + +With the encryption key, encrypted regular files, directories, and +symlinks behave very similarly to their unencrypted counterparts --- +after all, the encryption is intended to be transparent. However, +astute users may notice some differences in behavior: + +- Unencrypted files, or files encrypted with a different encryption + policy (i.e. different key, modes, or flags), cannot be renamed or + linked into an encrypted directory; see `Encryption policy + enforcement`_. Attempts to do so will fail with EPERM. However, + encrypted files can be renamed within an encrypted directory, or + into an unencrypted directory. + +- Direct I/O is not supported on encrypted files. Attempts to use + direct I/O on such files will fall back to buffered I/O. + +- The fallocate operations FALLOC_FL_COLLAPSE_RANGE, + FALLOC_FL_INSERT_RANGE, and FALLOC_FL_ZERO_RANGE are not supported + on encrypted files and will fail with EOPNOTSUPP. + +- Online defragmentation of encrypted files is not supported. The + EXT4_IOC_MOVE_EXT and F2FS_IOC_MOVE_RANGE ioctls will fail with + EOPNOTSUPP. + +- The ext4 filesystem does not support data journaling with encrypted + regular files. It will fall back to ordered data mode instead. + +- DAX (Direct Access) is not supported on encrypted files. + +- The st_size of an encrypted symlink will not necessarily give the + length of the symlink target as required by POSIX. It will actually + give the length of the ciphertext, which will be slightly longer + than the plaintext due to NUL-padding and an extra 2-byte overhead. + +- The maximum length of an encrypted symlink is 2 bytes shorter than + the maximum length of an unencrypted symlink. For example, on an + EXT4 filesystem with a 4K block size, unencrypted symlinks can be up + to 4095 bytes long, while encrypted symlinks can only be up to 4093 + bytes long (both lengths excluding the terminating null). + +Note that mmap *is* supported. This is possible because the pagecache +for an encrypted file contains the plaintext, not the ciphertext. + +Without the key +--------------- + +Some filesystem operations may be performed on encrypted regular +files, directories, and symlinks even before their encryption key has +been provided: + +- File metadata may be read, e.g. using stat(). + +- Directories may be listed, in which case the filenames will be + listed in an encoded form derived from their ciphertext. The + current encoding algorithm is described in `Filename hashing and + encoding`_. The algorithm is subject to change, but it is + guaranteed that the presented filenames will be no longer than + NAME_MAX bytes, will not contain the ``/`` or ``\0`` characters, and + will uniquely identify directory entries. + + The ``.`` and ``..`` directory entries are special. They are always + present and are not encrypted or encoded. + +- Files may be deleted. That is, nondirectory files may be deleted + with unlink() as usual, and empty directories may be deleted with + rmdir() as usual. Therefore, ``rm`` and ``rm -r`` will work as + expected. + +- Symlink targets may be read and followed, but they will be presented + in encrypted form, similar to filenames in directories. Hence, they + are unlikely to point to anywhere useful. + +Without the key, regular files cannot be opened or truncated. +Attempts to do so will fail with ENOKEY. This implies that any +regular file operations that require a file descriptor, such as +read(), write(), mmap(), fallocate(), and ioctl(), are also forbidden. + +Also without the key, files of any type (including directories) cannot +be created or linked into an encrypted directory, nor can a name in an +encrypted directory be the source or target of a rename, nor can an +O_TMPFILE temporary file be created in an encrypted directory. All +such operations will fail with ENOKEY. + +It is not currently possible to backup and restore encrypted files +without the encryption key. This would require special APIs which +have not yet been implemented. + +Encryption policy enforcement +============================= + +After an encryption policy has been set on a directory, all regular +files, directories, and symbolic links created in that directory +(recursively) will inherit that encryption policy. Special files --- +that is, named pipes, device nodes, and UNIX domain sockets --- will +not be encrypted. + +Except for those special files, it is forbidden to have unencrypted +files, or files encrypted with a different encryption policy, in an +encrypted directory tree. Attempts to link or rename such a file into +an encrypted directory will fail with EPERM. This is also enforced +during ->lookup() to provide limited protection against offline +attacks that try to disable or downgrade encryption in known locations +where applications may later write sensitive data. It is recommended +that systems implementing a form of "verified boot" take advantage of +this by validating all top-level encryption policies prior to access. + +Implementation details +====================== + +Encryption context +------------------ + +An encryption policy is represented on-disk by a :c:type:`struct +fscrypt_context`. It is up to individual filesystems to decide where +to store it, but normally it would be stored in a hidden extended +attribute. It should *not* be exposed by the xattr-related system +calls such as getxattr() and setxattr() because of the special +semantics of the encryption xattr. (In particular, there would be +much confusion if an encryption policy were to be added to or removed +from anything other than an empty directory.) The struct is defined +as follows:: + + #define FS_KEY_DESCRIPTOR_SIZE 8 + #define FS_KEY_DERIVATION_NONCE_SIZE 16 + + struct fscrypt_context { + u8 format; + u8 contents_encryption_mode; + u8 filenames_encryption_mode; + u8 flags; + u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; + u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE]; + }; + +Note that :c:type:`struct fscrypt_context` contains the same +information as :c:type:`struct fscrypt_policy` (see `Setting an +encryption policy`_), except that :c:type:`struct fscrypt_context` +also contains a nonce. The nonce is randomly generated by the kernel +and is used to derive the inode's encryption key as described in +`Per-file keys`_. + +Data path changes +----------------- + +For the read path (->readpage()) of regular files, filesystems can +read the ciphertext into the page cache and decrypt it in-place. The +page lock must be held until decryption has finished, to prevent the +page from becoming visible to userspace prematurely. + +For the write path (->writepage()) of regular files, filesystems +cannot encrypt data in-place in the page cache, since the cached +plaintext must be preserved. Instead, filesystems must encrypt into a +temporary buffer or "bounce page", then write out the temporary +buffer. Some filesystems, such as UBIFS, already use temporary +buffers regardless of encryption. Other filesystems, such as ext4 and +F2FS, have to allocate bounce pages specially for encryption. + +Filename hashing and encoding +----------------------------- + +Modern filesystems accelerate directory lookups by using indexed +directories. An indexed directory is organized as a tree keyed by +filename hashes. When a ->lookup() is requested, the filesystem +normally hashes the filename being looked up so that it can quickly +find the corresponding directory entry, if any. + +With encryption, lookups must be supported and efficient both with and +without the encryption key. Clearly, it would not work to hash the +plaintext filenames, since the plaintext filenames are unavailable +without the key. (Hashing the plaintext filenames would also make it +impossible for the filesystem's fsck tool to optimize encrypted +directories.) Instead, filesystems hash the ciphertext filenames, +i.e. the bytes actually stored on-disk in the directory entries. When +asked to do a ->lookup() with the key, the filesystem just encrypts +the user-supplied name to get the ciphertext. + +Lookups without the key are more complicated. The raw ciphertext may +contain the ``\0`` and ``/`` characters, which are illegal in +filenames. Therefore, readdir() must base64-encode the ciphertext for +presentation. For most filenames, this works fine; on ->lookup(), the +filesystem just base64-decodes the user-supplied name to get back to +the raw ciphertext. + +However, for very long filenames, base64 encoding would cause the +filename length to exceed NAME_MAX. To prevent this, readdir() +actually presents long filenames in an abbreviated form which encodes +a strong "hash" of the ciphertext filename, along with the optional +filesystem-specific hash(es) needed for directory lookups. This +allows the filesystem to still, with a high degree of confidence, map +the filename given in ->lookup() back to a particular directory entry +that was previously listed by readdir(). See :c:type:`struct +fscrypt_digested_name` in the source for more details. + +Note that the precise way that filenames are presented to userspace +without the key is subject to change in the future. It is only meant +as a way to temporarily present valid filenames so that commands like +``rm -r`` work as expected on encrypted directories. diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index ab2d62245dfce9a259b35a87a3698e1c8b886951..efdbd28e6c654e9cd5f8543ad75a9867f2526c42 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -335,7 +335,7 @@ address perms offset dev inode pathname a7cb1000-a7cb2000 ---p 00000000 00:00 0 a7cb2000-a7eb2000 rw-p 00000000 00:00 0 a7eb2000-a7eb3000 ---p 00000000 00:00 0 -a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack:1001] +a7eb3000-a7ed5000 rw-p 00000000 00:00 0 a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6 a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6 a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6 @@ -367,7 +367,6 @@ is not associated with a file: [heap] = the heap of the program [stack] = the stack of the main process - [stack:1001] = the stack of the thread with tid 1001 [vdso] = the "virtual dynamic shared object", the kernel system call handler [anon:] = an anonymous mapping that has been @@ -375,34 +374,6 @@ is not associated with a file: or if empty, the mapping is anonymous. -The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint -of the individual tasks of a process. In this file you will see a mapping marked -as [stack] if that task sees it as a stack. This is a key difference from the -content of /proc/PID/maps, where you will see all mappings that are being used -as stack by all of those tasks. Hence, for the example above, the task-level -map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this: - -08048000-08049000 r-xp 00000000 03:00 8312 /opt/test -08049000-0804a000 rw-p 00001000 03:00 8312 /opt/test -0804a000-0806b000 rw-p 00000000 00:00 0 [heap] -a7cb1000-a7cb2000 ---p 00000000 00:00 0 -a7cb2000-a7eb2000 rw-p 00000000 00:00 0 -a7eb2000-a7eb3000 ---p 00000000 00:00 0 -a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack] -a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6 -a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6 -a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6 -a800b000-a800e000 rw-p 00000000 00:00 0 -a800e000-a8022000 r-xp 00000000 03:00 14462 /lib/libpthread.so.0 -a8022000-a8023000 r--p 00013000 03:00 14462 /lib/libpthread.so.0 -a8023000-a8024000 rw-p 00014000 03:00 14462 /lib/libpthread.so.0 -a8024000-a8027000 rw-p 00000000 00:00 0 -a8027000-a8043000 r-xp 00000000 03:00 8317 /lib/ld-linux.so.2 -a8043000-a8044000 r--p 0001b000 03:00 8317 /lib/ld-linux.so.2 -a8044000-a8045000 rw-p 0001c000 03:00 8317 /lib/ld-linux.so.2 -aff35000-aff4a000 rw-p 00000000 00:00 0 -ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] - The /proc/PID/smaps is an extension based on maps, showing the memory consumption for each of the process's mappings. For each of mappings there is a series of lines such as the following: diff --git a/Documentation/kcov.txt b/Documentation/kcov.txt deleted file mode 100644 index 779ff4ab1c1da09b98bed78b5df76436ad8d316a..0000000000000000000000000000000000000000 --- a/Documentation/kcov.txt +++ /dev/null @@ -1,111 +0,0 @@ -kcov: code coverage for fuzzing -=============================== - -kcov exposes kernel code coverage information in a form suitable for coverage- -guided fuzzing (randomized testing). Coverage data of a running kernel is -exported via the "kcov" debugfs file. Coverage collection is enabled on a task -basis, and thus it can capture precise coverage of a single system call. - -Note that kcov does not aim to collect as much coverage as possible. It aims -to collect more or less stable coverage that is function of syscall inputs. -To achieve this goal it does not collect coverage in soft/hard interrupts -and instrumentation of some inherently non-deterministic parts of kernel is -disbled (e.g. scheduler, locking). - -Usage: -====== - -Configure kernel with: - - CONFIG_KCOV=y - -CONFIG_KCOV requires gcc built on revision 231296 or later. -Profiling data will only become accessible once debugfs has been mounted: - - mount -t debugfs none /sys/kernel/debug - -The following program demonstrates kcov usage from within a test program: - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) -#define KCOV_ENABLE _IO('c', 100) -#define KCOV_DISABLE _IO('c', 101) -#define COVER_SIZE (64<<10) - -int main(int argc, char **argv) -{ - int fd; - unsigned long *cover, n, i; - - /* A single fd descriptor allows coverage collection on a single - * thread. - */ - fd = open("/sys/kernel/debug/kcov", O_RDWR); - if (fd == -1) - perror("open"), exit(1); - /* Setup trace mode and trace size. */ - if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) - perror("ioctl"), exit(1); - /* Mmap buffer shared between kernel- and user-space. */ - cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if ((void*)cover == MAP_FAILED) - perror("mmap"), exit(1); - /* Enable coverage collection on the current thread. */ - if (ioctl(fd, KCOV_ENABLE, 0)) - perror("ioctl"), exit(1); - /* Reset coverage from the tail of the ioctl() call. */ - __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); - /* That's the target syscal call. */ - read(-1, NULL, 0); - /* Read number of PCs collected. */ - n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); - for (i = 0; i < n; i++) - printf("0x%lx\n", cover[i + 1]); - /* Disable coverage collection for the current thread. After this call - * coverage can be enabled for a different thread. - */ - if (ioctl(fd, KCOV_DISABLE, 0)) - perror("ioctl"), exit(1); - /* Free resources. */ - if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) - perror("munmap"), exit(1); - if (close(fd)) - perror("close"), exit(1); - return 0; -} - -After piping through addr2line output of the program looks as follows: - -SyS_read -fs/read_write.c:562 -__fdget_pos -fs/file.c:774 -__fget_light -fs/file.c:746 -__fget_light -fs/file.c:750 -__fget_light -fs/file.c:760 -__fdget_pos -fs/file.c:784 -SyS_read -fs/read_write.c:562 - -If a program needs to collect coverage from several threads (independently), -it needs to open /sys/kernel/debug/kcov in each thread separately. - -The interface is fine-grained to allow efficient forking of test processes. -That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode, -mmaps coverage buffer and then forks child processes in a loop. Child processes -only need to enable coverage (disable happens automatically on thread end). diff --git a/Makefile b/Makefile index 6b4e5bab79fdb10ad77a1adb4a4aa5299acb4f8f..aa0072ef8704ce03bda80dc117f511d72a4e7eb9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 18 -SUBLEVEL = 71 +SUBLEVEL = 124 EXTRAVERSION = NAME = Diseased Newt @@ -218,8 +218,6 @@ VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) export srctree objtree VPATH -CCACHE := $(shell which ccache) - # SUBARCH tells the usermode build what the underlying arch is. That is set # first, and if a usermode build is happening, the "ARCH=um" on the command # line overrides the setting of ARCH below. If a native build is happening, @@ -300,16 +298,11 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) -HOSTCC = $(CCACHE) gcc -HOSTCXX = $(CCACHE) g++ +HOSTCC = gcc +HOSTCXX = g++ HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 HOSTCXXFLAGS = -O2 -ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) -HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \ - -Wno-missing-field-initializers -endif - # Decide whether to build built-in, modular, or both. # Normally, just do built-in. @@ -340,15 +333,6 @@ endif export KBUILD_MODULES KBUILD_BUILTIN export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD -ifneq ($(CC),) -ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1) -COMPILER := clang -else -COMPILER := gcc -endif -export COMPILER -endif - # Look for make include files relative to root of kernel src MAKEFLAGS += --include-dir=$(srctree) @@ -359,7 +343,7 @@ include $(srctree)/scripts/Kbuild.include # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld -CC = $(CCACHE) $(CROSS_COMPILE)gcc +CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm @@ -382,23 +366,6 @@ LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -fno-tree-loop-im -CFLAGS_KCOV = -fsanitize-coverage=trace-pc - - -ifeq ($(cc-name),clang) -ifneq ($(CROSS_COMPILE),) -CLANG_TRIPLE ?= $(CROSS_COMPILE) -CLANG_TARGET := -target $(notdir $(CLANG_TRIPLE:%-=%)) -GCC_TOOLCHAIN := $(realpath $(dir $(shell which $(LD)))/..) -endif -ifneq ($(GCC_TOOLCHAIN),) -CLANG_GCC_TC := -gcc-toolchain $(GCC_TOOLCHAIN) -endif -ifneq ($(CLANG_ENABLE_IA),1) -CLANG_IA_FLAG = -no-integrated-as -endif -CLANG_FLAGS := $(CLANG_TARGET) $(CLANG_GCC_TC) $(CLANG_IA_FLAG) -meabi gnu -endif # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ @@ -417,17 +384,17 @@ LINUXINCLUDE := \ -Iinclude \ $(USERINCLUDE) -KBUILD_CPPFLAGS := -D__KERNEL__ $(CLANG_FLAGS) +KBUILD_CPPFLAGS := -D__KERNEL__ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common -fshort-wchar \ -Werror-implicit-function-declaration \ -Wno-format-security \ - -std=gnu89 $(CLANG_FLAGS) + -std=gnu89 $(call cc-option,-fno-PIE) KBUILD_AFLAGS_KERNEL := KBUILD_CFLAGS_KERNEL := -KBUILD_AFLAGS := -D__ASSEMBLY__ $(CLANG_FLAGS) +KBUILD_AFLAGS := -D__ASSEMBLY__ $(call cc-option,-fno-PIE) KBUILD_AFLAGS_MODULE := -DMODULE KBUILD_CFLAGS_MODULE := -DMODULE KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds @@ -443,7 +410,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS -export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN +export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL @@ -628,24 +595,49 @@ endif # $(dot-config) # Defaults to vmlinux, but the arch makefile usually adds further targets all: vmlinux +ifeq ($(cc-name),clang) +ifneq ($(CROSS_COMPILE),) +CLANG_TRIPLE ?= $(CROSS_COMPILE) +CLANG_TARGET := --target=$(notdir $(CROSS_COMPILE:%-=%)) +GCC_TOOLCHAIN_DIR := $(dir $(shell which $(LD))) +CLANG_PREFIX := --prefix=$(GCC_TOOLCHAIN_DIR) +GCC_TOOLCHAIN := $(realpath $(GCC_TOOLCHAIN_DIR)/..) +endif +ifneq ($(GCC_TOOLCHAIN),) +CLANG_GCC_TC := --gcc-toolchain=$(GCC_TOOLCHAIN) +endif +KBUILD_CPPFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) $(CLANG_PREFIX) +KBUILD_CFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) $(CLANG_PREFIX) +KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) $(CLANG_PREFIX) +KBUILD_CFLAGS += $(call cc-option, -no-integrated-as) +KBUILD_AFLAGS += $(call cc-option, -no-integrated-as) +endif + include $(srctree)/arch/$(SRCARCH)/Makefile KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation) +KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) +KBUILD_CFLAGS += $(call cc-disable-warning, int-in-bool-context) +KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) +KBUILD_CFLAGS += $(call cc-disable-warning, attribute-alias) ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += $(call cc-option,-Oz,-Os) -KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) else ifeq ($(cc-name),clang) -KBUILD_CFLAGS += -O2 +KBUILD_CFLAGS += -O3 else KBUILD_CFLAGS += -O2 endif endif +ifdef CONFIG_CC_WERROR +KBUILD_CFLAGS += -Werror +endif + # Tell gcc to never replace conditional load with a non-conditional one KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) @@ -706,42 +698,29 @@ endif endif KBUILD_CFLAGS += $(stackp-flag) -ifdef CONFIG_KCOV - ifeq ($(call cc-option, $(CFLAGS_KCOV)),) - $(warning Cannot use CONFIG_KCOV: \ - -fsanitize-coverage=trace-pc is not supported by compiler) - CFLAGS_KCOV = - endif -endif - ifeq ($(cc-name),clang) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable) KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier) KBUILD_CFLAGS += $(call cc-disable-warning, gnu) -KBUILD_CFLAGS += $(call cc-disable-warning, pointer-bool-conversion) KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) KBUILD_CFLAGS += $(call cc-disable-warning, duplicate-decl-specifier) -KBUILD_CFLAGS += -Wno-asm-operand-widths -KBUILD_CFLAGS += -Wno-initializer-overrides -KBUILD_CFLAGS += -fno-builtin - +KBUILD_CFLAGS += $(call cc-disable-warning, pointer-bool-conversion) # Quiet clang warning: comparison of unsigned expression < 0 is always false - KBUILD_CFLAGS += $(call cc-disable-warning, tautological-compare) # CLANG uses a _MergedGlobals as optimization, but this breaks modpost, as the # source of a reference will be _MergedGlobals and not on of the whitelisted names. # See modpost pattern 2 KBUILD_CFLAGS += $(call cc-option, -mno-global-merge,) - +KBUILD_CFLAGS += $(call cc-option, -fcatch-undefined-behavior) +# Variable initialization +KBUILD_CFLAGS += $(call clang-ifversion, -ge, 0800, -ftrivial-auto-var-init=pattern, $(call cc-option, -fsanitize=local-init,)) else -KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) # These warnings generated too much noise in a regular build. # Use make W=1 to enable them (see scripts/Makefile.build) KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) endif +KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) ifdef CONFIG_FRAME_POINTER KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls @@ -804,9 +783,24 @@ KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) # disable pointer signed / unsigned warnings in gcc 4.0 KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign) +# disable stringop warnings in gcc 8+ +KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation) + # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) +# clang sets -fmerge-all-constants by default as optimization, but this +# is non-conforming behavior for C and in fact breaks the kernel, so we +# need to disable it here generally. +KBUILD_CFLAGS += $(call cc-option,-fno-merge-all-constants) + +# for gcc -fno-merge-all-constants disables everything, but it is fine +# to have actual conforming behavior enabled. +KBUILD_CFLAGS += $(call cc-option,-fmerge-constants) + +# Make sure -fstack-check isn't enabled (like gentoo apparently did) +KBUILD_CFLAGS += $(call cc-option,-fno-stack-check,) + # conserve stack if available KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) @@ -825,6 +819,12 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types) # Require designated initializers for all marked structures KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init) +# ensure -fcf-protection is disabled when using retpoline as it is +# incompatible with -mindirect-branch=thunk-extern +ifdef CONFIG_RETPOLINE +KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none) +endif + # use the deterministic mode of AR if available KBUILD_ARFLAGS := $(call ar-option,D) @@ -1072,6 +1072,12 @@ headerdep: $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \ $(srctree)/scripts/headerdep.pl -I$(srctree)/include +# --------------------------------------------------------------------------- + +PHONY += depend dep +depend dep: + @echo '*** Warning: make $@ is unnecessary now.' + # --------------------------------------------------------------------------- # Firmware install INSTALL_FW_PATH=$(INSTALL_MOD_PATH)/lib/firmware @@ -1310,8 +1316,8 @@ help: @echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)' @echo ' dir/ - Build all files in dir and below' @echo ' dir/file.[oisS] - Build specified target only' - @echo ' dir/file.ll - Build the LLVM bitcode file' - @echo ' (requires compiler support for LLVM bitcode generation)' + @echo ' dir/file.ll - Build the LLVM assembly file' + @echo ' (requires compiler support for LLVM assembly generation)' @echo ' dir/file.lst - Build specified mixed source/assembly target only' @echo ' (requires a recent binutils and recent build (System.map))' @echo ' dir/file.ko - Build module including final link' @@ -1485,6 +1491,7 @@ clean: $(clean-dirs) -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '*.symtypes' -o -name 'modules.order' \ -o -name modules.builtin -o -name '.tmp_*.o.*' \ + -o -name '*.ll' \ -o -name '*.gcno' \) -type f -print | xargs rm -f # Generate tags for editors @@ -1549,11 +1556,11 @@ image_name: # Clear a bunch of variables before executing the submake tools/: FORCE $(Q)mkdir -p $(objtree)/tools - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/ tools/%: FORCE $(Q)mkdir -p $(objtree)/tools - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ $* + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/ $* # Single targets # --------------------------------------------------------------------------- @@ -1590,8 +1597,6 @@ endif $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) %.ll: %.c prepare scripts FORCE $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -%.ll: %.S prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) # Modules /: prepare scripts FORCE diff --git a/android/configs/README b/android/configs/README deleted file mode 100644 index 8798731f89048e90e5b0e0becb5311b43fa0f5e1..0000000000000000000000000000000000000000 --- a/android/configs/README +++ /dev/null @@ -1,15 +0,0 @@ -The files in this directory are meant to be used as a base for an Android -kernel config. All devices should have the options in android-base.cfg enabled. -While not mandatory, the options in android-recommended.cfg enable advanced -Android features. - -Assuming you already have a minimalist defconfig for your device, a possible -way to enable these options would be: - - ARCH= scripts/kconfig/merge_config.sh /_defconfig android/configs/android-base.cfg android/configs/android-recommended.cfg - -This will generate a .config that can then be used to save a new defconfig or -compile a new kernel with Android features enabled. - -Because there is no tool to consistently generate these config fragments, -lets keep them alphabetically sorted instead of random. diff --git a/android/configs/android-base-arm64.cfg b/android/configs/android-base-arm64.cfg deleted file mode 100644 index 43f23d6b5391b1c875715b888029dd0756e8e81d..0000000000000000000000000000000000000000 --- a/android/configs/android-base-arm64.cfg +++ /dev/null @@ -1,5 +0,0 @@ -# KEEP ALPHABETICALLY SORTED -CONFIG_ARMV8_DEPRECATED=y -CONFIG_CP15_BARRIER_EMULATION=y -CONFIG_SETEND_EMULATION=y -CONFIG_SWP_EMULATION=y diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg deleted file mode 100644 index 15f44fc3c33f1a5ef01cc2e5e71913cb2accf8c0..0000000000000000000000000000000000000000 --- a/android/configs/android-base.cfg +++ /dev/null @@ -1,157 +0,0 @@ -# KEEP ALPHABETICALLY SORTED -# CONFIG_DEVKMEM is not set -# CONFIG_DEVMEM is not set -# CONFIG_FHANDLE is not set -# CONFIG_INET_LRO is not set -# CONFIG_NFSD is not set -# CONFIG_NFS_FS is not set -# CONFIG_OABI_COMPAT is not set -# CONFIG_SYSVIPC is not set -# CONFIG_USELIB is not set -CONFIG_ANDROID=y -CONFIG_ANDROID_BINDER_DEVICES=binder,hwbinder,vndbinder -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ASHMEM=y -CONFIG_AUDIT=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_CGROUPS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CGROUP_SCHED=y -CONFIG_DEFAULT_SECURITY_SELINUX=y -CONFIG_EMBEDDED=y -CONFIG_FB=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_INET=y -CONFIG_INET_DIAG_DESTROY=y -CONFIG_INET_ESP=y -CONFIG_INET_XFRM_MODE_TUNNEL=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_RAW=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IPV6=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_NAT=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODVERSIONS=y -CONFIG_NET=y -CONFIG_NETDEVICES=y -CONFIG_NETFILTER=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_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -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_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=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_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_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NET_CLS_ACT=y -CONFIG_NET_CLS_U32=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_KEY=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_NF_CONNTRACK_IPV6=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_SECMARK=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_NAT=y -CONFIG_NO_HZ=y -CONFIG_PACKET=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PPP=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PREEMPT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_RTC_CLASS=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SECCOMP=y -CONFIG_SECURITY=y -CONFIG_SECURITY_NETWORK=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY_SELINUX=y -CONFIG_STAGING=y -CONFIG_SWITCH=y -CONFIG_SYNC=y -CONFIG_TUN=y -CONFIG_UID_SYS_STATS=y -CONFIG_UNIX=y -CONFIG_USB_GADGET=y -CONFIG_XFRM_USER=y diff --git a/android/configs/android-fetch-configs.sh b/android/configs/android-fetch-configs.sh new file mode 100755 index 0000000000000000000000000000000000000000..30c544d6ebfdb115b1c18c637298a94502b50ec3 --- /dev/null +++ b/android/configs/android-fetch-configs.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +curl https://android.googlesource.com/kernel/configs/+archive/master/android-3.18.tar.gz | tar xzv + diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg deleted file mode 100644 index 766518d7a67d958a5350eb930b13f716f686f1da..0000000000000000000000000000000000000000 --- a/android/configs/android-recommended.cfg +++ /dev/null @@ -1,141 +0,0 @@ -# KEEP ALPHABETICALLY SORTED -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_NF_CONNTRACK_SIP is not set -# CONFIG_PM_WAKELOCKS_GC is not set -# CONFIG_VT is not set -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ARM_KERNMEM_PERMS=y -CONFIG_ARM64_SW_TTBR0_PAN=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BLK_DEV_DM=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_COMPACTION=y -CONFIG_CPU_SW_DOMAIN_PAN=y -CONFIG_DEBUG_RODATA=y -CONFIG_DM_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_DM_VERITY_FEC=y -CONFIG_DRAGONRISE_FF=y -CONFIG_ENABLE_DEFAULT_TRACERS=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_FUSE_FS=y -CONFIG_GREENASIA_FF=y -CONFIG_HIDRAW=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_EZKEY=y -CONFIG_HID_GREENASIA=y -CONFIG_HID_GYRATION=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WACOM=y -CONFIG_HID_WALTOP=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_JOYSTICK=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_KEYRESET=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_TABLET=y -CONFIG_INPUT_UINPUT=y -CONFIG_ION=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_KALLSYMS_ALL=y -CONFIG_KSM=y -CONFIG_LOGIG940_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGITECH_FF=y -CONFIG_MD=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MSDOS_FS=y -CONFIG_PANIC_TIMEOUT=5 -CONFIG_PANTHERLORD_FF=y -CONFIG_PERF_EVENTS=y -CONFIG_PKCS7_MESSAGE_PARSER=y -CONFIG_PKCS7_TEST_KEY=y -CONFIG_PM_DEBUG=y -CONFIG_PM_RUNTIME=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -CONFIG_POWER_SUPPLY=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_RAM=y -CONFIG_QFMT_V2=y -CONFIG_QUOTA=y -CONFIG_QUOTACTL=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -CONFIG_QUOTA_TREE=y -CONFIG_SCHEDSTATS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_SND=y -CONFIG_SOUND=y -CONFIG_SUSPEND_TIME=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y -CONFIG_TIMER_STATS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_UHID=y -CONFIG_UID_STAT=y -CONFIG_MEMORY_STATE_TIME=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_USBNET=y -CONFIG_VFAT_FS=y -CONFIG_X509_CERTIFICATE_PARSER=y diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h index 0ca9724597c1603024ff26d366013bc2da92387b..7081e52291d075f342c2c658f931bc55f49547f9 100644 --- a/arch/alpha/include/asm/xchg.h +++ b/arch/alpha/include/asm/xchg.h @@ -11,6 +11,10 @@ * Atomic exchange. * Since it can be used to implement critical sections * it must clobber "memory" (also for interrupts in UP). + * + * The leading and the trailing memory barriers guarantee that these + * operations are fully ordered. + * */ static inline unsigned long @@ -18,6 +22,7 @@ ____xchg(_u8, volatile char *m, unsigned long val) { unsigned long ret, tmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %4,7,%3\n" " insbl %1,%4,%1\n" @@ -42,6 +47,7 @@ ____xchg(_u16, volatile short *m, unsigned long val) { unsigned long ret, tmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %4,7,%3\n" " inswl %1,%4,%1\n" @@ -66,6 +72,7 @@ ____xchg(_u32, volatile int *m, unsigned long val) { unsigned long dummy; + smp_mb(); __asm__ __volatile__( "1: ldl_l %0,%4\n" " bis $31,%3,%1\n" @@ -86,6 +93,7 @@ ____xchg(_u64, volatile long *m, unsigned long val) { unsigned long dummy; + smp_mb(); __asm__ __volatile__( "1: ldq_l %0,%4\n" " bis $31,%3,%1\n" @@ -127,10 +135,12 @@ ____xchg(, volatile void *ptr, unsigned long x, int size) * store NEW in MEM. Return the initial value in MEM. Success is * indicated by comparing RETURN with OLD. * - * The memory barrier should be placed in SMP only when we actually - * make the change. If we don't change anything (so if the returned - * prev is equal to old) then we aren't acquiring anything new and - * we don't need any memory barrier as far I can tell. + * The leading and the trailing memory barriers guarantee that these + * operations are fully ordered. + * + * The trailing memory barrier is placed in SMP unconditionally, in + * order to guarantee that dependency ordering is preserved when a + * dependency is headed by an unsuccessful operation. */ static inline unsigned long @@ -138,6 +148,7 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) { unsigned long prev, tmp, cmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %5,7,%4\n" " insbl %1,%5,%1\n" @@ -149,8 +160,8 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) " or %1,%2,%2\n" " stq_c %2,0(%4)\n" " beq %2,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" @@ -165,6 +176,7 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) { unsigned long prev, tmp, cmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %5,7,%4\n" " inswl %1,%5,%1\n" @@ -176,8 +188,8 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) " or %1,%2,%2\n" " stq_c %2,0(%4)\n" " beq %2,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" @@ -192,6 +204,7 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) { unsigned long prev, cmp; + smp_mb(); __asm__ __volatile__( "1: ldl_l %0,%5\n" " cmpeq %0,%3,%1\n" @@ -199,8 +212,8 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) " mov %4,%1\n" " stl_c %1,%2\n" " beq %1,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" @@ -215,6 +228,7 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) { unsigned long prev, cmp; + smp_mb(); __asm__ __volatile__( "1: ldq_l %0,%5\n" " cmpeq %0,%3,%1\n" @@ -222,8 +236,8 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) " mov %4,%1\n" " stq_c %1,%2\n" " beq %1,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" diff --git a/arch/alpha/kernel/console.c b/arch/alpha/kernel/console.c index 6a61deed4a853ce8fdbb6b753070f2ca29aef08f..ab228ed45945acc2378e48db39942a996d073ea2 100644 --- a/arch/alpha/kernel/console.c +++ b/arch/alpha/kernel/console.c @@ -20,6 +20,7 @@ struct pci_controller *pci_vga_hose; static struct resource alpha_vga = { .name = "alpha-vga+", + .flags = IORESOURCE_IO, .start = 0x3C0, .end = 0x3DF }; diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index cb34a25a0168f96736f537b41f24f7a607b172aa..755554ebd9dc44a53cd9c9b735506d84d06370c5 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -525,24 +525,19 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path, SYSCALL_DEFINE1(osf_utsname, char __user *, name) { int error; + char tmp[5 * 32]; down_read(&uts_sem); - error = -EFAULT; - if (copy_to_user(name + 0, utsname()->sysname, 32)) - goto out; - if (copy_to_user(name + 32, utsname()->nodename, 32)) - goto out; - if (copy_to_user(name + 64, utsname()->release, 32)) - goto out; - if (copy_to_user(name + 96, utsname()->version, 32)) - goto out; - if (copy_to_user(name + 128, utsname()->machine, 32)) - goto out; + memcpy(tmp + 0 * 32, utsname()->sysname, 32); + memcpy(tmp + 1 * 32, utsname()->nodename, 32); + memcpy(tmp + 2 * 32, utsname()->release, 32); + memcpy(tmp + 3 * 32, utsname()->version, 32); + memcpy(tmp + 4 * 32, utsname()->machine, 32); + up_read(&uts_sem); - error = 0; - out: - up_read(&uts_sem); - return error; + if (copy_to_user(name, tmp, sizeof(tmp))) + return -EFAULT; + return 0; } SYSCALL_DEFINE0(getpagesize) @@ -560,24 +555,22 @@ SYSCALL_DEFINE0(getdtablesize) */ SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen) { - unsigned len; - int i; + int len, err = 0; + char *kname; + char tmp[32]; - if (!access_ok(VERIFY_WRITE, name, namelen)) - return -EFAULT; - - len = namelen; - if (len > 32) - len = 32; + if (namelen < 0 || namelen > 32) + namelen = 32; down_read(&uts_sem); - for (i = 0; i < len; ++i) { - __put_user(utsname()->domainname[i], name + i); - if (utsname()->domainname[i] == '\0') - break; - } + kname = utsname()->domainname; + len = strnlen(kname, namelen); + len = min(len + 1, namelen); + memcpy(tmp, kname, len); up_read(&uts_sem); + if (copy_to_user(name, tmp, len)) + return -EFAULT; return 0; } @@ -740,13 +733,14 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) }; unsigned long offset; const char *res; - long len, err = -EINVAL; + long len; + char tmp[__NEW_UTS_LEN + 1]; offset = command-1; if (offset >= ARRAY_SIZE(sysinfo_table)) { /* Digital UNIX has a few unpublished interfaces here */ printk("sysinfo(%d)", command); - goto out; + return -EINVAL; } down_read(&uts_sem); @@ -754,13 +748,11 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) len = strlen(res)+1; if ((unsigned long)len > (unsigned long)count) len = count; - if (copy_to_user(buf, res, len)) - err = -EFAULT; - else - err = 0; + memcpy(tmp, res, len); up_read(&uts_sem); - out: - return err; + if (copy_to_user(buf, tmp, len)) + return -EFAULT; + return 0; } SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer, diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h index 2b0ac429f5ebc4912e34b41029810fa914124479..412bb3c24f366f7e01e35a36c28f7fd0df4c3ec6 100644 --- a/arch/alpha/kernel/pci_impl.h +++ b/arch/alpha/kernel/pci_impl.h @@ -143,7 +143,8 @@ struct pci_iommu_arena }; #if defined(CONFIG_ALPHA_SRM) && \ - (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA)) + (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \ + defined(CONFIG_ALPHA_AVANTI)) # define NEED_SRM_SAVE_RESTORE #else # undef NEED_SRM_SAVE_RESTORE diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 1941a07b5811f925aed82e853aab4efb081f74ca..86c1c4fd5246e44f45d9c10691eaf3ec152f03c2 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -274,12 +274,13 @@ copy_thread(unsigned long clone_flags, unsigned long usp, application calling fork. */ if (clone_flags & CLONE_SETTLS) childti->pcb.unique = regs->r20; + else + regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */ childti->pcb.usp = usp ?: rdusp(); *childregs = *regs; childregs->r0 = 0; childregs->r19 = 0; childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ - regs->r20 = 0; stack = ((struct switch_stack *) regs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; diff --git a/arch/arc/include/asm/delay.h b/arch/arc/include/asm/delay.h index 43de302569815073bb4d4f23cb98b60a5e0c0552..ee08badc5b91d851e0024bba74cc0871222057ab 100644 --- a/arch/arc/include/asm/delay.h +++ b/arch/arc/include/asm/delay.h @@ -17,8 +17,11 @@ #ifndef __ASM_ARC_UDELAY_H #define __ASM_ARC_UDELAY_H +#include #include /* HZ */ +extern unsigned long loops_per_jiffy; + static inline void __delay(unsigned long loops) { __asm__ __volatile__( diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 9c8aa41e45c2248b0ee39a23c3802e4f7425d358..25f6583a7a2c8e28d04df9cd6477107fb2dd3534 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -97,7 +97,7 @@ typedef unsigned long pgtable_t; #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) /* Default Permissions for stack/heaps pages (Non Executable) */ -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE) +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define WANT_PAGE_VIRTUAL 1 diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 7670f33b9ce2c721d7c1d9ba77c4ac8513200b3d..0f12756d63891ba3262bb50e729e6a62a3eebddc 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -372,7 +372,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, /* Decode a PTE containing swap "identifier "into constituents */ #define __swp_type(pte_lookalike) (((pte_lookalike).val) & 0x1f) -#define __swp_offset(pte_lookalike) ((pte_lookalike).val << 13) +#define __swp_offset(pte_lookalike) ((pte_lookalike).val >> 13) /* NOPs, to keep generic kernel happy */ #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S index 83a046a7cd06c964d392380ac88f17fa0759d21a..51b419a00def0ab2e36ef10b1fa4da1c91cf2248 100644 --- a/arch/arc/kernel/entry.S +++ b/arch/arc/kernel/entry.S @@ -315,6 +315,12 @@ ENTRY(EV_MachineCheck) lr r0, [efa] mov r1, sp + ; hardware auto-disables MMU, re-enable it to allow kernel vaddr + ; access for say stack unwinding of modules for crash dumps + lr r3, [ARC_REG_PID] + or r3, r3, MMU_ENABLE + sr r3, [ARC_REG_PID] + lsr r3, r2, 8 bmsk r3, r3, 7 brne r3, ECR_C_MCHK_DUP_TLB, 1f diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c index 2147ca2bc1313e1090b06f064d08e05a3d476c57..51cba86e8cc929b56a6bc28278e4695916d27ee3 100644 --- a/arch/arc/mm/cache_arc700.c +++ b/arch/arc/mm/cache_arc700.c @@ -642,7 +642,7 @@ void flush_cache_mm(struct mm_struct *mm) void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr, unsigned long pfn) { - unsigned int paddr = pfn << PAGE_SHIFT; + phys_addr_t paddr = pfn << PAGE_SHIFT; u_vaddr &= PAGE_MASK; @@ -662,8 +662,9 @@ void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long u_vaddr) { /* TBD: do we really need to clear the kernel mapping */ - __flush_dcache_page(page_address(page), u_vaddr); - __flush_dcache_page(page_address(page), page_address(page)); + __flush_dcache_page((phys_addr_t)page_address(page), u_vaddr); + __flush_dcache_page((phys_addr_t)page_address(page), + (phys_addr_t)page_address(page)); } diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index 7f47d2a56f44374e00939e6742ed6717c452c58a..b7a0c44785c1dec2542dd3b78671998a7cd4025f 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -689,9 +689,6 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address, local_irq_save(flags); - /* re-enable the MMU */ - write_aux_reg(ARC_REG_PID, MMU_ENABLE | read_aux_reg(ARC_REG_PID)); - /* loop thru all sets of TLB */ for (set = 0; set < mmu->sets; set++) { diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu index aed66d5df7f1546ac48cf93ee9c4f2aeb91d5b76..b7576349528c12a8ef7533b6b66bc9a68b8dc9f9 100644 --- a/arch/arm/Kconfig-nommu +++ b/arch/arm/Kconfig-nommu @@ -34,8 +34,7 @@ config PROCESSOR_ID used instead of the auto-probing which utilizes the register. config REMAP_VECTORS_TO_RAM - bool 'Install vectors to the beginning of RAM' if DRAM_BASE - depends on DRAM_BASE + bool 'Install vectors to the beginning of RAM' help The kernel needs to change the hardware exception vectors. In nommu mode, the hardware exception vectors are normally diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index e9e0284fc8f2f4681cdf01e39d4bfce40e8b15b8..93ff12f1be6c9b22c332d26c31e23fcfddb89bd7 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -24,19 +24,19 @@ #if defined(CONFIG_DEBUG_ICEDCC) #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7) - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 .endm .macro writeb, ch, rb mcr p14, 0, \ch, c0, c5, 0 .endm #elif defined(CONFIG_CPU_XSCALE) - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 .endm .macro writeb, ch, rb mcr p14, 0, \ch, c8, c0, 0 .endm #else - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 .endm .macro writeb, ch, rb mcr p14, 0, \ch, c1, c0, 0 @@ -52,7 +52,7 @@ .endm #if defined(CONFIG_ARCH_SA1100) - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 mov \rb, #0x80000000 @ physical base address #ifdef CONFIG_DEBUG_LL_SER3 add \rb, \rb, #0x00050000 @ Ser3 @@ -61,8 +61,8 @@ #endif .endm #else - .macro loadsp, rb, tmp - addruart \rb, \tmp + .macro loadsp, rb, tmp1, tmp2 + addruart \rb, \tmp1, \tmp2 .endm #endif #endif @@ -1223,7 +1223,7 @@ phex: adr r3, phexbuf b 1b @ puts corrupts {r0, r1, r2, r3} -puts: loadsp r3, r1 +puts: loadsp r3, r2, r1 1: ldrb r2, [r0], #1 teq r2, #0 moveq pc, lr @@ -1240,8 +1240,8 @@ puts: loadsp r3, r1 @ putc corrupts {r0, r1, r2, r3} putc: mov r2, r0 + loadsp r3, r1, r0 mov r0, #0 - loadsp r3, r1 b 2b @ memdump corrupts {r0, r1, r2, r3, r10, r11, r12, lr} diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 87fc7a35e80261cad03261fd9cf8b047606fc286..8cc4c7eb7414b3720fc7f63155282def5c6a1cc6 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -646,6 +646,7 @@ ti,non-removable; bus-width = <4>; cap-power-off-card; + keep-power-in-suspend; pinctrl-names = "default"; pinctrl-0 = <&mmc2_pins>; diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 5a452fdd7c5d9711cec9f6d0196f90b0726fefc3..1f4b2033ba2b9d4d89b45764b0fb1611ae98501d 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -62,6 +62,11 @@ }; }; +/* Table Table 5-79 of the TRM shows 480ab000 is reserved */ +&usb_otg_hs { + status = "disabled"; +}; + &iva { status = "disabled"; }; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 46660ffd2b65bbe90100b2b251b29fb6528afe31..6b98998af81e1b7a39a86455a42866e5e067ad95 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -702,7 +702,8 @@ reg = <0x48038000 0x2000>, <0x46000000 0x400000>; reg-names = "mpu", "dat"; - interrupts = <80>, <81>; + interrupts = , + ; interrupt-names = "tx", "rx"; status = "disabled"; dmas = <&edma 8>, @@ -716,7 +717,8 @@ reg = <0x4803C000 0x2000>, <0x46400000 0x400000>; reg-names = "mpu", "dat"; - interrupts = <82>, <83>; + interrupts = , + ; interrupt-names = "tx", "rx"; status = "disabled"; dmas = <&edma 10>, diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 53bbfc90b26ae2711c96acdea36825f1be51d031..247ea36407cb6375562207cf948b860c45ca2af8 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -415,6 +415,8 @@ touchscreen-size-x = <480>; touchscreen-size-y = <272>; + + wakeup-source; }; tlv320aic3106: tlv320aic3106@1b { diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi index 17b879990914c8643bfc63cb98b634c112f4f454..d69cfb540a07981d9db758913a4308c9968ae610 100644 --- a/arch/arm/boot/dts/at91sam9g25.dtsi +++ b/arch/arm/boot/dts/at91sam9g25.dtsi @@ -20,7 +20,7 @@ atmel,mux-mask = < /* A B C */ 0xffffffff 0xffe0399f 0xc000001c /* pioA */ - 0x0007ffff 0x8000fe3f 0x00000000 /* pioB */ + 0x0007ffff 0x00047e3f 0x00000000 /* pioB */ 0x80000000 0x07c0ffff 0xb83fffff /* pioC */ 0x003fffff 0x003f8000 0x00000000 /* pioD */ >; diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi index 0bd98cd00816c752b6c8cd6cbf40e92649212524..4ef5c3410fcce8bc896dd063c4333263edcc2d9d 100644 --- a/arch/arm/boot/dts/da850.dtsi +++ b/arch/arm/boot/dts/da850.dtsi @@ -267,11 +267,7 @@ compatible = "ti,dm6441-gpio"; gpio-controller; reg = <0x226000 0x1000>; - interrupts = <42 IRQ_TYPE_EDGE_BOTH - 43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH - 45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH - 47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH - 49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>; + interrupts = <42 43 44 45 46 47 48 49 50>; ti,ngpio = <144>; ti,davinci-gpio-unbanked = <0>; status = "disabled"; diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index 1bd6c79f445e3a1565c40ef4d857d3dd4df8128e..7059462db333f323d590f725226ac49b545764bf 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts @@ -182,6 +182,8 @@ tps659038: tps659038@58 { compatible = "ti,tps659038"; reg = <0x58>; + ti,palmas-override-powerhold; + ti,system-power-controller; tps659038_pmic { compatible = "ti,tps659038-pmic"; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 8ba02cb2955f9bb06017d6529e74b59ee08178a3..68053ce2fd22e88c5bcd639550062b8ca55fe1ef 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -118,6 +118,7 @@ device_type = "pci"; ranges = <0x81000000 0 0 0x03000 0 0x00010000 0x82000000 0 0x20013000 0x13000 0 0xffed000>; + bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; ti,hwmods = "pcie1"; @@ -153,6 +154,7 @@ device_type = "pci"; ranges = <0x81000000 0 0 0x03000 0 0x00010000 0x82000000 0 0x30013000 0x13000 0 0xffed000>; + bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; ti,hwmods = "pcie2"; diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index 22c9fc0fbc9e2695f79b05a6420a99dbde3dba1a..862e00cfeea73e80a1a6fb1936fd05ee00e4209c 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -1206,7 +1206,7 @@ /* non-prefetchable memory */ 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; num-lanes = <1>; - interrupts = ; + interrupts = ; clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>, <&clks IMX6SX_CLK_PCIE_AXI>, <&clks IMX6SX_CLK_LVDS1_OUT>, diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts index d5e3bc518968b4acf5e4b811d2944a84d12b79b8..d57f48543f7618a52feb797f91f57f47aacc993a 100644 --- a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts +++ b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts @@ -53,7 +53,8 @@ }; pinctrl: pin-controller@10000 { - pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>; + pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header + &pmx_gpio_header_gpo>; pinctrl-names = "default"; pmx_uart0: pmx-uart0 { @@ -85,11 +86,16 @@ * ground. */ pmx_gpio_header: pmx-gpio-header { - marvell,pins = "mpp17", "mpp7", "mpp29", "mpp28", + marvell,pins = "mpp17", "mpp29", "mpp28", "mpp35", "mpp34", "mpp40"; marvell,function = "gpio"; }; + pmx_gpio_header_gpo: pxm-gpio-header-gpo { + marvell,pins = "mpp7"; + marvell,function = "gpo"; + }; + pmx_gpio_init: pmx-init { marvell,pins = "mpp38"; marvell,function = "gpio"; diff --git a/arch/arm/boot/dts/moxart-uc7112lx.dts b/arch/arm/boot/dts/moxart-uc7112lx.dts index 10d088df0c35177a573bd695337ac1010a2dc138..4a962a26482df2796b1627e304ea743f5ae32680 100644 --- a/arch/arm/boot/dts/moxart-uc7112lx.dts +++ b/arch/arm/boot/dts/moxart-uc7112lx.dts @@ -6,7 +6,7 @@ */ /dts-v1/; -/include/ "moxart.dtsi" +#include "moxart.dtsi" / { model = "MOXA UC-7112-LX"; diff --git a/arch/arm/boot/dts/moxart.dtsi b/arch/arm/boot/dts/moxart.dtsi index 1fd27ed65a01fc868d918a2a593534153bd45415..64f2f44235d02272dc1739f4fb03e40c8a706c98 100644 --- a/arch/arm/boot/dts/moxart.dtsi +++ b/arch/arm/boot/dts/moxart.dtsi @@ -6,6 +6,7 @@ */ /include/ "skeleton.dtsi" +#include / { compatible = "moxa,moxart"; @@ -36,8 +37,8 @@ ranges; intc: interrupt-controller@98800000 { - compatible = "moxa,moxart-ic"; - reg = <0x98800000 0x38>; + compatible = "moxa,moxart-ic", "faraday,ftintc010"; + reg = <0x98800000 0x100>; interrupt-controller; #interrupt-cells = <2>; interrupt-mask = <0x00080000>; @@ -59,7 +60,7 @@ timer: timer@98400000 { compatible = "moxa,moxart-timer"; reg = <0x98400000 0x42>; - interrupts = <19 1>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; clocks = <&clk_apb>; }; @@ -80,7 +81,7 @@ dma: dma@90500000 { compatible = "moxa,moxart-dma"; reg = <0x90500080 0x40>; - interrupts = <24 0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; #dma-cells = <1>; }; @@ -93,7 +94,7 @@ sdhci: sdhci@98e00000 { compatible = "moxa,moxart-sdhci"; reg = <0x98e00000 0x5C>; - interrupts = <5 0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk_apb>; dmas = <&dma 5>, <&dma 5>; @@ -120,7 +121,7 @@ mac0: mac@90900000 { compatible = "moxa,moxart-mac"; reg = <0x90900000 0x90>; - interrupts = <25 0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; phy-handle = <ðphy0>; phy-mode = "mii"; status = "disabled"; @@ -129,7 +130,7 @@ mac1: mac@92000000 { compatible = "moxa,moxart-mac"; reg = <0x92000000 0x90>; - interrupts = <27 0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; phy-handle = <ðphy1>; phy-mode = "mii"; status = "disabled"; @@ -138,7 +139,7 @@ uart0: uart@98200000 { compatible = "ns16550a"; reg = <0x98200000 0x20>; - interrupts = <31 8>; + interrupts = <31 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clock-frequency = <14745600>; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 57cb292b7788f594b555f9b35039281bbecfd6bd..252f32630a7bb0eb2ecd80ebd638950d7b5543d7 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -144,11 +144,11 @@ dtb-$(CONFIG_ARCH_MDM9640) += mdm9640-sim.dtb \ dtb-$(CONFIG_ARCH_MDM9650) += mdm9650-ttp.dtb \ mdm9650-pcie-ep-ttp.dtb \ - mdm9650-nand-dualwifi-mtp.dtb \ mdm9650-v1.1-emmc-cdp.dtb \ mdm9650-v1.1-nand-cdp.dtb \ mdm9650-v1.1-emmc-mtp.dtb \ mdm9650-v1.1-nand-mtp.dtb \ + mdm9650-v1.1-nand-dualwifi-mtp.dtb \ mdm9650-v1.1-nand-ccard-v2.dtb \ mdm9650-v1.1-emmc-pcie-ep-mtp.dtb \ mdm9650-v1.1-nand-pcie-ep-mtp.dtb \ @@ -237,9 +237,8 @@ dtb-$(CONFIG_ARCH_MSM8940) += msm8940-pmi8937-cdp.dtb \ msm8940-pmi8940-cdp.dtb \ msm8940-pmi8940-rcm.dtb \ msm8940-pmi8940-qrd-sku7.dtb - + ifeq ($(CONFIG_MACH_XIAOMI_MSM8953),y) -dtb-$(CONFIG_MACH_XIAOMI_MIDO) += msm8953-qrd-sku3-mido.dtb dtb-$(CONFIG_MACH_XIAOMI_MARKW) += msm8953-qrd-markw.dtb else dtb-$(CONFIG_ARCH_MSM8953) += msm8953-sim.dtb \ @@ -290,7 +289,8 @@ dtb-$(CONFIG_ARCH_MDM9607) += mdm9607-rumi.dtb \ mdm9206-mtp.dtb \ mdm9206-cdp.dtb \ mdm9206-mtp-sdcard.dtb \ - mdm9206-rcm.dtb + mdm9206-rcm.dtb \ + mdm9207c-mtp.dtb dtb-$(CONFIG_ARCH_MSM8916) += msm8952-qrd-skum.dtb \ msm8952-cdp.dtb \ @@ -302,31 +302,22 @@ dtb-$(CONFIG_ARCH_MSM8909) += msm8909-pm8916-mtp.dtb \ msm8909-1gb-qrd-skuc.dtb \ msm8909-1gb-qrd-skue.dtb \ msm8909-qrd-skue.dtb \ - msm8909w-wtp.dtb \ - apq8009w-wtp.dtb \ + sdw2100-msm8909w-wtp.dtb \ + sdw2100-apq8009w-wtp.dtb \ apq8009w-cdp.dtb \ - msm8909w-swoctp.dtb \ + sdw2100-msm8909w-swoctp.dtb \ msm8909w-swoctp-circpanel.dtb \ - apq8009w-swoctp.dtb \ apq8009w-swoctp-circpanel.dtb \ apq8009w-nowgr-swoctp.dtb \ - apq8009w-nowgr-swoctp-circpanel.dtb \ + sdw2100-apq8009w-nowgr-swoctp-circpanel.dtb \ msm8909-pm8916-cdp.dtb \ msm8909w-cdp.dtb \ - msm8909w-1gb-wtp.dtb \ - apq8009w-1gb-wtp.dtb \ - msm8909w-1gb-cdp.dtb \ - apq8009w-1gb-cdp.dtb \ - msm8909w-1gb-swoctp.dtb \ - msm8909w-1gb-swoctp-circpanel.dtb \ - apq8009w-1gb-swoctp.dtb \ - apq8009w-1gb-swoctp-circpanel.dtb \ - apq8009w-1gb-nowgr-swoctp.dtb \ - apq8009w-1gb-nowgr-swoctp-circpanel.dtb \ - msm8909w-bg-wtp-v1.dtb \ - msm8909w-bg-wtp-v2.dtb \ - apq8009w-bg-wtp-v1.dtb \ - apq8009w-bg-wtp-v2.dtb \ + sdw2100-msm8909w-1gb-swoctp-circpanel.dtb \ + sdw3100-msm8909w-wtp.dtb \ + sdw2500-msm8909w-wtp.dtb \ + sdw3100-apq8009w-wtp.dtb \ + sdw3100-apq8009w-alpha.dtb \ + sdw2500-apq8009w-wtp.dtb \ apq8009-mtp-wcd9326.dtb \ msm8909-mtp-wcd9326.dtb \ msm8909-mtp-wcd9326-refboard.dtb \ @@ -342,8 +333,10 @@ dtb-$(CONFIG_ARCH_MSM8909) += msm8909-pm8916-mtp.dtb \ apq8009-cdp-wcd9326-refboard.dtb \ apq8009-rcm-wcd9326-refboard.dtb \ apq8009-robot-refboard.dtb \ + apq8009-robot-som-refboard.dtb \ apq8009-robot-rome.dtb \ apq8009-mtp-drone.dtb \ + apq8009-mtp-wcd9326-excelpoint-refboard.dtb \ msm8909-mtp.dtb \ msm8909-1gb-mtp.dtb \ msm8909-1gb-rcm.dtb \ @@ -364,3 +357,4 @@ $(obj)/../%.dtb: $(src)/%.dts FORCE dtbs: $(addprefix $(obj)/,$(dtb-y)) endif +clean-files := *.dtb diff --git a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi index 57c3db93bb01a3c8b5e387840966e82711af53f3..c70e5ec90cec16b27badc42d33df13b440dc5123 100644 --- a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi @@ -25,7 +25,9 @@ qcom,model = "apq8009-tashalite-snd-card"; qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; + qcom,afe-rxtx-lb; qcom,msm-mclk-freq = <9600000>; + qcom,tdm-audio-intf; qcom,msm-hs-micbias-type = "internal"; qcom,audio-routing = "AIF4 VI", "MCLK", @@ -87,7 +89,9 @@ <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music_2_rx>, <&bt_sco_rx>, - <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>; + <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, + <&afe_loopback_tx>, <&dai_pri_tdm_rx_0>, + <&dai_pri_tdm_tx_0>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -101,7 +105,9 @@ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", - "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293"; + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "msm-dai-q6-dev.24577", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; qcom,wsa-max-devs = <2>; @@ -221,4 +227,44 @@ }; }; }; + + pri_tdm_rx: qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + pri_tdm_tx: qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/apq8009-dragon.dts b/arch/arm/boot/dts/qcom/apq8009-dragon.dts index 91ccaf2cf6a708af788728c3849acd8547f6c398..0c57c3638c5b9f36fa27df8bedbe9b379c55e89e 100644 --- a/arch/arm/boot/dts/qcom/apq8009-dragon.dts +++ b/arch/arm/boot/dts/qcom/apq8009-dragon.dts @@ -21,14 +21,3 @@ qcom,msm-id = <265 2>; qcom,board-id= <0x00010020 0>; }; - -&blsp1_uart2_hs { - status = "okay"; -}; - -&i2c_2 { - status = "disabled"; - nq@28 { - status = "disabled"; - }; -}; diff --git a/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi b/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi index 79563e0adf958a695c9ddb7c5e1684215c688086..a1be481958449ff9a0ce53fcdf17e725f1b76348 100644 --- a/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * 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 @@ -17,9 +17,15 @@ #include "msm8909-pm8916-mtp.dtsi" #include "apq8009-audio-external_codec.dtsi" +&audio_codec_mtp { + status = "disabled"; +}; + &soc { - ext-codec { - qcom,msm-mbhc-hphl-swh = <0>; + sound-9335 { + qcom,model = "apq8009-tashalite-snd-card-tdm"; + qcom,tdm-i2s-switch-enable = <&msm_gpio 88 0>; + qcom,wcd9xxx-mic-tristate; qcom,audio-routing = "AIF4 VI", "MCLK", "RX_BIAS", "MCLK", @@ -38,16 +44,31 @@ "SpkrRight IN", "SPK2 OUT"; }; - sound-9335 { - status = "disabled"; - }; - i2c@78b8000 { wcd9xxx_codec@d { - status = "disabled"; + qcom,cdc-reset-gpio = <&msm_gpio 23 0>; + + cdc-vdd-buck-supply = <&wcd_vdd_buck_1p8>; + qcom,cdc-vdd-buck-voltage = <0 0>; + qcom,cdc-vdd-buck-current = <250000>; + + cdc-buck-sido-supply = <&wcd_vdd_buck_1p8>; + qcom,cdc-buck-sido-voltage = <0 0>; + qcom,cdc-buck-sido-current = <250000>; }; }; + wcd_vdd_buck_1p8: wcd_vdd_buck_1p8 { + compatible = "regulator-fixed"; + regulator-name = "wcd_vdd_buck_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + status = "ok"; + enable-active-high; + gpio = <&pm8916_gpios 4 0>; + vin-supply = <&pm8916_s4>; + }; + vph_pwr_vreg: vph_pwr_vreg { compatible = "regulator-fixed"; status = "ok"; @@ -85,29 +106,30 @@ qcom,pronto@a21b000 { status = "disabled"; }; - - bluetooth: bt_qca9379 { - compatible = "qca,qca9379"; - qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ - }; }; -&blsp1_uart2_tx_active { - mux { - function = "blsp_uart2"; - }; -}; - -&blsp1_uart2_rxcts_active { - mux { - function = "blsp_uart2"; - }; -}; - - -&blsp1_uart2_rfr_active { - mux { - function = "blsp_uart2"; +&firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor_fstab: vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,verify"; + status = "ok"; + }; + system_fstab: system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,verify"; + status = "ok"; + }; + }; }; }; @@ -209,7 +231,25 @@ }; }; +&pm8916_gpios { + gpio@c300 { + qcom,mode = <1>; /* DIGITAL OUT */ + qcom,pull = <1>; /* No Pull */ + qcom,vin-sel = <2>; /* 1.8 */ + qcom,src-sel = <0>; /* CONSTANT */ + qcom,master-en = <1>; /* ENABLE GPIO */ + status = "okay"; + }; +}; + &pm8916_bms { status = "ok"; qcom,disable-bms; }; + +&pm8916_chg { + status = "ok"; + qcom,charging-disabled; + qcom,use-default-batt-values; +}; + diff --git a/arch/arm/boot/dts/qcom/apq8009-led-pca9956.dtsi b/arch/arm/boot/dts/qcom/apq8009-led-pca9956.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3749a2f498cad4e4db129c1814a20a7c2e0c3953 --- /dev/null +++ b/arch/arm/boot/dts/qcom/apq8009-led-pca9956.dtsi @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +&i2c_3 { + status = "ok"; + qcom,clk-freq-out = <100000>; + + /* PCA9956B LED Drivers */ + nxp-ledseg-i2c@4b { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9956b"; + reg = <0x4b>; + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xAA>; + pca9956b,ledout1 = <0xAA>; + pca9956b,ledout2 = <0xAA>; + pca9956b,ledout3 = <0xFF>; + pca9956b,ledout4 = <0xFF>; + pca9956b,ledout5 = <0xFF>; + pca9956b,defaultiref = <0x2f>; + }; +}; + diff --git a/arch/arm/boot/dts/qcom/apq8009-memory.dtsi b/arch/arm/boot/dts/qcom/apq8009-memory.dtsi index 4377ba8c440ffe6c93ebd949162942329d331206..d9fe3ae3973598236336f685d35162cb41df74f0 100644 --- a/arch/arm/boot/dts/qcom/apq8009-memory.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009-memory.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -23,6 +23,10 @@ reg = <0x0 0x89e00000 0x0 0x0700000>; }; +&qcom_seecom { + reg = <0x87a00000 0x200000>; +}; + &reserved_mem { linux,cma { compatible = "shared-dma-pool"; diff --git a/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-excelpoint-refboard.dts b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-excelpoint-refboard.dts new file mode 100644 index 0000000000000000000000000000000000000000..1982107f0fd3212887e8893e7218992ff4e46aef --- /dev/null +++ b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-excelpoint-refboard.dts @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * 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 "msm8909-mtp.dtsi" +#include "msm8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" +#include "apq8009-memory.dtsi" +#include "apq8009-led-pca9956.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 Excelpoint RefBoard"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0x14>; +}; + +&audio_codec_mtp { + status = "disabled"; +}; + +&pm8916_gpios { + gpio@c200 { + qcom,mode = <1>; + qcom,output-type = <0>; + qcom,src-sel = <0>; + qcom,pull = <5>; + qcom,master-en = <1>; + qcom,vin-sel = <1>; + qcom,out-strength = <3>; + status = "ok"; + }; +}; + +&msm_gpio { + hsuart_active: default { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <16>; + bias-disable; + }; + }; + + hsuart_sleep: sleep { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_vbus_detect: usb_vbus_detect { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_id_detect: usb_id_detect { + mux { + pins = "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio110"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pca9956b_reset_gpio_on: pca9956b_reset_gpio_on { + mux { + pins = "gpio35"; + function = "spare"; + }; + + config { + pins = "gpio35"; + drive-strength = <2>; + bias-pull-up; + output-high; + }; + }; + + button_active: button_active { + mux { + pins = "gpio87", "gpio90", "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio90", "gpio99"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_suspend: button_suspend { + mux { + pins = "gpio87", "gpio90", "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio90", "gpio99"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + mute_ctrl_active: mute_ctrl_active { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + mute_ctrl_suspend: mute_ctrl_suspend { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&soc { + /delete-node/ gpio_keys; + + gpio_keys { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "tlmm_gpio_key_active", "tlmm_gpio_key_suspend"; + pinctrl-0 = <&button_active>; + pinctrl-1 = <&button_suspend>; + + action { + label = "action"; + gpios = <&msm_gpio 87 0x1>; + linux,input-type = <1>; + linux,code = <148>; + debounce-interval = <15>; + }; + + vol_up { + label = "volume_up"; + gpios = <&msm_gpio 90 0x1>; + linux,input-type = <1>; + linux,code = <115>; + debounce-interval = <15>; + }; + + mute { + label = "mute"; + gpios = <&msm_gpio 99 0x1>; + linux,input-type = <1>; + linux,code = <248>; + debounce-interval = <15>; + }; + }; + + sound-9335 { + qcom,model = "apq8009-tashalite-snd-card-tdm"; + qcom,tdm-i2s-switch-enable = <&msm_gpio 88 0>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + }; + + i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0x78b7000 0x1000>; + interrupt-names = "qup_irq"; + interrupts = <0 97 0>; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; + clock-names = "iface_clk", "core_clk"; + qcom,clk-freq-out = <100000>; + qcom,clk-freq-in = <19200000>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_3_active &pca9956b_reset_gpio_on>; + pinctrl-1 = <&i2c_3_sleep>; + qcom,noise-rjct-scl = <0>; + qcom,noise-rjct-sda = <0>; + dmas = <&dma_blsp1 8 64 0x20000020 0x20>, + <&dma_blsp1 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + qcom,wcd9xxx-mic-tristate; + qcom,cdc-reset-gpio = <&msm_gpio 23 0>; + + cdc-vdd-buck-supply = <&wcd_vdd_buck_1p8>; + qcom,cdc-vdd-buck-voltage = <0 0>; + qcom,cdc-vdd-buck-current = <250000>; + + cdc-buck-sido-supply = <&wcd_vdd_buck_1p8>; + qcom,cdc-buck-sido-voltage = <0 0>; + qcom,cdc-buck-sido-current = <250000>; + }; + }; + + i2c@78b9000 { + synaptics@20 { + status = "disabled"; + }; + }; + + wcd_vdd_buck_1p8: wcd_vdd_buck_1p8 { + compatible = "regulator-fixed"; + regulator-name = "wcd_vdd_buck_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + status = "ok"; + enable-active-high; + gpio = <&pm8916_gpios 4 0>; + vin-supply = <&pm8916_s4>; + }; + + blsp1_uart2_hs: uart@78b0000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 108 0 + 1 &intc 0 238 0 + 2 &msm_gpio 21 0>; + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,msm-bus,name = "blsp1_uart2_hs"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "ok"; + }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + */ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; + + vbus_otg_supply: vbus_otg_supply { + compatible = "regulator-fixed"; + regulator-name = "vbus_otg"; + status = "ok"; + enable-active-high; + gpio = <&pm8916_gpios 3 0>; + }; + + usb_detect: qcom,gpio-usbdetect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&msm_gpio>; + interrupts = <97 0>; + interrupt-names = "vbus_det_irq"; + pinctrl-names = "usb_vbus_detect", "usb_id_detect"; + pinctrl-0 = <&usb_vbus_detect>; + pinctrl-1 = <&usb_id_detect>; + qcom,gpio-mode-sel = <&msm_gpio 97 0>; + qcom,id-det-gpio = <&msm_gpio 110 0>; + qcom,dpdm_switch_gpio = <&pm8916_gpios 3 0>; + }; +}; + +&wcnss { + status = "disabled"; +}; + +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 40 1>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + + status = "ok"; +}; + +&i2c_4 { + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupt-parent = <&msm_gpio>; + interrupts = <58 8>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default &mute_ctrl_active>; + pinctrl-1 = <&mute_ctrl_suspend>; + qcom,charging-disabled; + qcom,empty-soc-disabled; + qcom,chg-inhibit-disabled; + qcom,float-voltage-mv = <4200>; + qcom,iterm-ma = <200>; + qcom,recharge-thresh-mv = <100>; + qcom,thermal-mitigation = <1500 700 600 0>; + regulator-name = "smb1360_otg_vreg"; + }; +}; + +&pm8916_gpios { + gpio@c300 { + qcom,mode = <1>; /* DIGITAL OUT */ + qcom,pull = <1>; /* No Pull */ + qcom,vin-sel = <2>; /* 1.8 */ + qcom,src-sel = <0>; /* CONSTANT */ + qcom,master-en = <1>; /* ENABLE GPIO */ + status = "okay"; + }; +}; + +&pm8916_chg { + status = "ok"; + qcom,use-external-charger; +}; + +&pm8916_bms { + status = "ok"; + qcom,disable-bms; +}; + +&usb_otg { + interrupts = <0 134 0>, <0 140 0>; + interrupt-names = "core_irq", "async_irq"; + + qcom,hsusb-otg-mode = <3>; + vbus_otg-supply = <&vbus_otg_supply>; +}; + +&mdss_fb0 { + status = "disabled"; + /delete-node/ qcom,cont-splash-memory; +}; + +&mdss_mdp { + status = "disabled"; +}; + +&mdss_dsi0_pll { + status = "disabled"; +}; + +&mdss_dsi0 { + status = "disabled"; +}; + +&i2c_1 { + status = "disabled"; +}; + +&i2c_2 { + status = "disabled"; +}; + +&i2c_3 { + qcom,actuator@0 { + status = "disabled"; + }; + + qcom,eeprom@6c { + status = "disabled"; + }; + + led_flash0: qcom,led-flash@60 { + status = "disabled"; + }; + + qcom,camera@0 { + status = "disabled"; + }; + + qcom,camera@1 { + status = "disabled"; + }; + + qcom,camera@42 { + status = "disabled"; + }; +}; + +&i2c_5 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + +/delete-node/ &cont_splash_mem; diff --git a/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts index d5a6304165f69a4c685a5e56565c1a0386bd3f34..fbc8bb87ed31989f6555089e42177dad19859941 100644 --- a/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts +++ b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -30,8 +30,76 @@ status = "disabled"; }; +&pm8916_gpios { + gpio@c200 { + qcom,mode = <1>; + qcom,output-type = <0>; + qcom,src-sel = <0>; + qcom,pull = <5>; + qcom,master-en = <1>; + qcom,vin-sel = <1>; + qcom,out-strength = <3>; + status = "ok"; + }; +}; + +&msm_gpio { + hsuart_active: default { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <16>; + bias-disable; + }; + }; + + hsuart_sleep: sleep { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_vbus_detect: usb_vbus_detect { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_id_detect: usb_id_detect { + mux { + pins = "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio110"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + &soc { sound-9335 { + qcom,tdm-mic-mute-enable = <&msm_gpio 82 0>; qcom,audio-routing = "AIF4 VI", "MCLK", "RX_BIAS", "MCLK", @@ -61,6 +129,148 @@ status = "disabled"; }; }; + + blsp1_uart2_hs: uart@78b0000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 108 0 + 1 &intc 0 238 0 + 2 &msm_gpio 21 0>; + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,msm-bus,name = "blsp1_uart2_hs"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "ok"; + }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + */ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; + + vbus_otg_supply: vbus_otg_supply { + compatible = "regulator-fixed"; + regulator-name = "vbus_otg"; + status = "ok"; + enable-active-high; + gpio = <&pm8916_gpios 3 0>; + }; + + usb_detect: qcom,gpio-usbdetect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&msm_gpio>; + interrupts = <97 0>; + interrupt-names = "vbus_det_irq"; + pinctrl-names = "usb_vbus_detect", "usb_id_detect"; + pinctrl-0 = <&usb_vbus_detect>; + pinctrl-1 = <&usb_id_detect>; + qcom,gpio-mode-sel = <&msm_gpio 97 0>; + qcom,id-det-gpio = <&msm_gpio 110 0>; + qcom,dpdm_switch_gpio = <&pm8916_gpios 3 0>; + }; +}; + +&wcnss { + status = "disabled"; +}; + +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 40 1>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; }; &i2c_4 { @@ -93,11 +303,11 @@ }; &usb_otg { - interrupts = <0 134 0>,<0 140 0>,<0 136 0>; - interrupt-names = "core_irq", "async_irq", "phy_irq"; + interrupts = <0 134 0>, <0 140 0>; + interrupt-names = "core_irq", "async_irq"; qcom,hsusb-otg-mode = <3>; - vbus_otg-supply = <&smb1360_otg_supply>; + vbus_otg-supply = <&vbus_otg_supply>; }; &mdss_fb0 { @@ -117,4 +327,20 @@ status = "disabled"; }; +&i2c_1 { + status = "disabled"; +}; + +&i2c_2 { + status = "disabled"; +}; + +&i2c_5 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + /delete-node/ &cont_splash_mem; diff --git a/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326.dts b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326.dts index 739b17596f3b839b8f84a2acaf9250db5a55d678..dba32a7ddf638e4673a2c5071bac2649e593d7bd 100644 --- a/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326.dts +++ b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326.dts @@ -14,7 +14,6 @@ /dts-v1/; #include "msm8909-mtp.dtsi" -#include "msm8909-regulator.dtsi" #include "msm8909-pm8916.dtsi" #include "msm8909-pm8916-mtp.dtsi" #include "apq8009-audio-external_codec.dtsi" diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h b/arch/arm/boot/dts/qcom/apq8009-robot-som-refboard.dts similarity index 51% rename from drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h rename to arch/arm/boot/dts/qcom/apq8009-robot-som-refboard.dts index 7fc74a366a6c142d587f09d082dc272c81dc3a5a..2054db3b9634138443a6508e6ba76a24974d865f 100644 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h +++ b/arch/arm/boot/dts/qcom/apq8009-robot-som-refboard.dts @@ -1,4 +1,5 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * 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 @@ -10,37 +11,18 @@ * GNU General Public License for more details. */ -#ifndef MSM_CSIPHY_3_1_HWREG_H -#define MSM_CSIPHY_3_1_HWREG_H +/dts-v1/; -#include +#include "msm8909-mtp.dtsi" +#include "msm8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" +#include "apq8009-memory.dtsi" -struct csiphy_reg_parms_t csiphy_v3_1 = { - /* MIPI CSI PHY registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x1C, - 0x28, - 0x140, - 0x144, - 0x164, - 0x188, - 0x18C, - 0x1AC, - 0x3F, - 0x1AC, - 0x1CC, - 0x1CC, - 0x4, - 0x1EC, - 0x1F4, - 0x31, +/ { + model = "Qualcomm Technologies, Inc. APQ8009 Robot SOM refboard"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0x15>; }; -#endif + diff --git a/arch/arm/boot/dts/qcom/apq8009w-bg-memory.dtsi b/arch/arm/boot/dts/qcom/apq8009w-bg-memory.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fef9f4528f17e1c7d5945f446c468a4416ea1866 --- /dev/null +++ b/arch/arm/boot/dts/qcom/apq8009w-bg-memory.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * 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. + */ + +&external_image_mem { + reg = <0x0 0x87a00000 0x0 0x0600000>; +}; + +&modem_adsp_mem { + reg = <0x0 0x88000000 0x0 0x02300000>; +}; + +&peripheral_mem { + reg = <0x0 0x8a300000 0x0 0x0600000>; +}; + +&reserved_mem { + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xa0000000>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + linux,cma-default; + }; +}; diff --git a/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v1.dts b/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v1.dts index 55e9719d4a6160461dd9c141a2dff803fad9119b..a5fb8ffaad88358a1b46d96213bc7a4f26ffd074 100644 --- a/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v1.dts +++ b/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v1.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -18,7 +18,7 @@ #include "msm8909-pm8916.dtsi" #include "msm8909-pm8916-mtp.dtsi" #include "msm8909w.dtsi" -#include "apq8009w-memory.dtsi" +#include "apq8009w-bg-memory.dtsi" / { model = "Qualcomm Technologies, Inc. APQ8009W-PM8916 BLACKGHOST WTP"; @@ -63,6 +63,7 @@ qcom,blackghost { compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; qcom,firmware-name = "bg-wear"; /* GPIO inputs from blackghost */ qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; diff --git a/arch/arm/boot/dts/qcom/apq8009w-memory.dtsi b/arch/arm/boot/dts/qcom/apq8009w-memory.dtsi index f0293fc4d1807b8377f16c1d34f1a9ac8d0fbeac..9ca7566ce5716df042e97071a7f03518295915b7 100644 --- a/arch/arm/boot/dts/qcom/apq8009w-memory.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009w-memory.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * 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,7 +12,7 @@ */ &external_image_mem { - reg = <0x0 0x87b00000 0x0 0x0500000>; + reg = <0x0 0x87a00000 0x0 0x0600000>; }; &modem_adsp_mem { @@ -20,7 +20,7 @@ }; &peripheral_mem { - reg = <0x0 0x8a100000 0x0 0x0500000>; + reg = <0x0 0x8a100000 0x0 0x0600000>; }; &reserved_mem { diff --git a/arch/arm/boot/dts/qcom/apq8009w-nowgr-memory.dtsi b/arch/arm/boot/dts/qcom/apq8009w-nowgr-memory.dtsi index 36448cddc69f3ce727d7249972de12858f873970..af98362c654d62bc55b51e354695e5e41af22332 100644 --- a/arch/arm/boot/dts/qcom/apq8009w-nowgr-memory.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009w-nowgr-memory.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016,2019 The Linux Foundation. All rights reserved. * * 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,7 +12,7 @@ */ &external_image_mem { - reg = <0x0 0x87b00000 0x0 0x0500000>; + reg = <0x0 0x87a00000 0x0 0x0600000>; }; &modem_adsp_mem { diff --git a/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi b/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi index 8230eab26da21330ca2beb1a054b9e5ae5333f34..d7db7fb9b0e14b258004ff7f5d50dc727b6ad83c 100644 --- a/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi +++ b/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * 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,109 +36,6 @@ qcom,cam-vreg-op-mode = <80000>; }; - eeprom0: qcom,eeprom@0 { - cell-index = <0>; - compatible = "qcom,eeprom"; - reg = <0x0>; - qcom,cci-master = <0>; - cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&pm8953_l2>; - cam_vana-supply = <&pm8953_l17>; - qcom,cam-vreg-name = "cam_vio", "cam_vdig", - "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-op-mode = <105000 0 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default - &cam_sensor_rear_default - &cam_sensor_rear_vana>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep - &cam_sensor_rear_vana_sleep>; - gpios = <&tlmm 26 0>, - <&tlmm 40 0>, - <&tlmm 39 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_STANDBY0"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - qcom,clock-rates = <24000000 0>; - }; - - eeprom1: qcom,eeprom@1 { - cell-index = <1>; - compatible = "qcom,eeprom"; - reg = <0x1>; - qcom,cci-master = <0>; - cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&pm8953_l2>; - cam_vana-supply = <&pm8953_l17>; - qcom,cam-vreg-name = "cam_vio", "cam_vdig", - "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-op-mode = <105000 0 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default - &cam_sensor_front1_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep - &cam_sensor_front1_sleep>; - gpios = <&tlmm 27 0>, - <&tlmm 129 0>, - <&tlmm 130 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <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_STANDBY1"; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - qcom,clock-rates = <24000000 0>; - }; - - eeprom2: qcom,eeprom@2 { - cell-index = <2>; - compatible = "qcom,eeprom"; - reg = <0x2>; - qcom,cci-master = <0>; - cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&pm8953_l2>; - cam_vana-supply = <&pm8953_l17>; - qcom,cam-vreg-name = "cam_vio", "cam_vdig", - "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-op-mode = <105000 0 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_default - &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk2_sleep - &cam_sensor_front_sleep>; - gpios = <&tlmm 28 0>, - <&tlmm 131 0>, - <&tlmm 132 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <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", - "CAM_STANDBY2"; - clocks = <&clock_gcc clk_mclk2_clk_src>, - <&clock_gcc clk_gcc_camss_mclk2_clk>; - clock-names = "cam_src_clk", "cam_clk"; - qcom,clock-rates = <24000000 0>; - }; - camera0: qcom,camera@0 { cell-index = <0>; compatible = "qcom,camera"; @@ -148,14 +45,13 @@ qcom,mount-angle = <0>; /*qcom,led-flash-src = <&led_flash0>;*/ qcom,actuator-src = <&actuator0>; - qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&pm8953_l2>; + cam_vdig-supply = <&eldo_cam0_vreg>; cam_vana-supply = <&pm8953_l17>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-min-voltage = <1800000 1100000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1100000 2850000>; qcom,cam-vreg-op-mode = <105000 0 100000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_default @@ -190,15 +86,14 @@ qcom,csiphy-sd-index = <1>; qcom,csid-sd-index = <1>; qcom,mount-angle = <0>; - qcom,actuator-src = <&actuator0>; - qcom,eeprom-src = <&eeprom1>; + qcom,actuator-src = <&actuator1>; cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&pm8953_l2>; + cam_vdig-supply = <&eldo_cam1_vreg>; cam_vana-supply = <&pm8953_l17>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-min-voltage = <1800000 1100000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1100000 2850000>; qcom,cam-vreg-op-mode = <105000 0 100000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_default @@ -215,7 +110,7 @@ qcom,gpio-req-tbl-label = "CAMIF_MCLK1", "CAM_RESET1", "CAM_STANDBY1"; - qcom,sensor-position = <1>; + qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; status = "ok"; @@ -233,14 +128,13 @@ qcom,csid-sd-index = <2>; qcom,mount-angle = <0>; qcom,actuator-src = <&actuator0>; - qcom,eeprom-src = <&eeprom2>; cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&pm8953_l2>; + cam_vdig-supply = <&eldo_cam2_vreg>; cam_vana-supply = <&pm8953_l17>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-min-voltage = <1800000 1100000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1100000 2850000>; qcom,cam-vreg-op-mode = <105000 0 100000>; /*qcom,gpio-no-mux = <0>;*/ pinctrl-names = "cam_default", "cam_suspend"; diff --git a/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi index 8649b2000e70f372758a9b1786eaa70e4914ce07..d610d731208b3eac5719a3204d6eca8c6183ae42 100644 --- a/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * 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 @@ -173,23 +173,6 @@ /delete-property/ qcom,msm-vdd-wsa-switch-current; }; -&pm8953_l2 { - status = "okay"; - regulator-always-on; -}; - -&camera0 { - qcom,mount-angle = <90>; -}; - -&camera1 { - qcom,mount-angle = <90>; -}; - -&camera2{ - qcom,mount-angle = <90>; -}; - &pm8953_diangu_dig { status = "ok"; }; @@ -394,7 +377,7 @@ pinctrl-names = "active", "sleep"; pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on \ - &sdc2_cd_on &sdc2_wlan_gpio_on>; + &sdc2_wlan_gpio_on>; pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off \ &sdc2_wlan_gpio_off>; @@ -405,10 +388,11 @@ interrupt-map-mask = <0xffffffff>; interrupt-map = <0 &intc 0 125 0 1 &intc 0 221 0 - 2 &tlmm 133 0>; - interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + 2 &tlmm 114 0x1>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; - qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 177770000>; qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; status = "ok"; @@ -564,3 +548,28 @@ status = "disabled"; }; }; + +&firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/apq8053-lite.dtsi b/arch/arm/boot/dts/qcom/apq8053-lite.dtsi index d9685d06d8372284dfcc92a7e604d0bead9a6d9b..fc6391a6c85107f3fe2ea175a0e602e9a05e53f9 100644 --- a/arch/arm/boot/dts/qcom/apq8053-lite.dtsi +++ b/arch/arm/boot/dts/qcom/apq8053-lite.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. * * 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 +36,16 @@ < 600000000 7 >; /* Turbo */ }; +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; +}; + +&ipa_hw { + status = "disabled"; +}; + /* GPU Overrides*/ &msm_gpu { @@ -118,3 +128,28 @@ }; }; }; + +&firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts b/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts index c21b6d6cbc9e1a606b7e56fe35c134467f1da099..a30813f4be6c0220ad93c9bdeaf4c95aa6bbb408 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts index 74bb21eedf10ea6c4e91132638d23f9416717970..0f021e0ef4378e92d017cc099292f991834e6075 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts index 82030c493f8d1a8b6192aaeddae398b255aa3d45..4e683f632894290a5e6f35be000c7d1957707988 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts @@ -38,7 +38,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts index cd02dacbdcee9098296a8362d07d7238b10a3b6a..2be4f89c0cc7ed021b954b58d9e42df18947ec4e 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts index e2d4f2b9babe2579962bd10ba048d3b0bb58f941..fa0da0c237433947f97de67ca35a36dc6b846aaf 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts index fdea81eb93224048ad6e0c901426cd464e824692..3ee3238bae7b2cf35055d1543f6eb8b0cd8808c2 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts @@ -31,7 +31,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts index d5eb6031e37872f2e796f31bf2c5234cd97a4d31..15bd28865e64ce24c98d976e9ab871f23aafe5e0 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi index 7bd0150a92a8fe07a991df174a0718c8e2e597fb..ab1440f77e199cb7d0e43c53935849aeb3c6c74d 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -14,7 +14,7 @@ dsi_auo_390p_cmd: qcom,mdss_dsi_auo_390p_cmd { qcom,mdss-dsi-panel-name = "AUO 390p command mode dsi panel"; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; - qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-framerate = <45>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; qcom,mdss-dsi-panel-width = <390>; @@ -36,6 +36,8 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; + qcom,mdss-tear-check-frame-rate = <4500>; + qcom,mdss-dsi-idle-fps = <10>; qcom,mdss-dsi-on-command = [ 15 01 00 00 00 00 02 fe 01 15 01 00 00 00 00 02 0a f0 @@ -69,6 +71,10 @@ 29 01 00 00 00 00 05 2a 00 04 01 89 /* Reset row start address */ 29 01 00 00 00 00 05 2b 00 00 01 85 + 15 01 00 00 00 00 02 fe 01 + 15 01 00 00 00 00 02 04 00 + 15 01 00 00 00 00 02 fe 00 + 15 01 00 00 00 00 02 3a 77 ]; qcom,mdss-dsi-traffic-mode = "burst_mode"; qcom,mdss-dsi-lane-map = "lane_map_0123"; @@ -89,5 +95,9 @@ qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + /* clk = totlaH * totalV * bpp* 66fps */ + qcom,mdss-dsi-panel-clockrate = <276705792>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "te_signal_check"; }; }; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-auo-400p-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-auo-400p-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6aab05cba074e0d6bca9724064c349dd0cdbe384 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-auo-400p-cmd.dtsi @@ -0,0 +1,90 @@ +/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +&mdss_mdp { + dsi_auo_400p_cmd: qcom,mdss_dsi_auo_400p_cmd { + qcom,mdss-dsi-panel-name = "AUO 400p command mode dsi panel"; + 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 = <400>; + qcom,mdss-dsi-panel-height = <400>; + qcom,mdss-pan-physical-height-dimension = <29>; + qcom,mdss-pan-physical-width-dimension = <29>; + qcom,mdss-dsi-h-front-porch = <4>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + 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 = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 FE 05 + 15 01 00 00 00 00 02 05 00 + 15 01 00 00 00 00 02 FE 07 + 15 01 00 00 00 00 02 07 6D + 15 01 00 00 00 00 02 FE 0A + 15 01 00 00 00 00 02 1C 1B + 15 01 00 00 00 00 02 FE 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 00 00 02 11 00 + 32 01 00 00 FF 00 02 00 00 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 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-idle-on-command = [ + 05 01 00 00 00 00 01 39 /* Idle-Mode On */ + ]; + qcom,mdss-dsi-idle-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-idle-off-command = [ + 05 01 00 00 00 00 01 38 /* Idle-Mode Off */ + ]; + qcom,mdss-dsi-idle-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-idle-fps = <15>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-panel-timings = [ + 5F 12 0A 00 32 34 10 16 0F 03 04 00 + ]; + qcom,mdss-dsi-t-clk-post = <0x05>; + qcom,mdss-dsi-t-clk-pre = <0x11>; + qcom,mdss-dsi-bl-min-level = <1>; + 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 20>, <1 20>; + /* clk = totlaH * totalV * bpp* 84fps */ + qcom,mdss-dsi-panel-clockrate = <352171008>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-auo-cx-qvga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-auo-cx-qvga-cmd.dtsi index 948033a74b323ad1c344be4bc0dd79bd526589fc..fd5815936c90dd5786fbed6259216328a63bdc73 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-auo-cx-qvga-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-auo-cx-qvga-cmd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 @@ -39,6 +39,8 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-status-check-mode = "te_signal_check"; + qcom,esd-check-enabled; qcom,mdss-dsi-on-command = [ 39 01 00 00 00 00 06 F0 55 AA 52 08 00 39 01 00 00 00 00 06 BD 03 20 14 4B 00 @@ -89,6 +91,15 @@ ]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-idle-on-command = [ + 05 01 00 00 00 00 01 39 /* Idle-Mode On */ + ]; + qcom,mdss-dsi-idle-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-idle-off-command = [ + 05 01 00 00 00 00 01 38 /* Idle-Mode Off */ + ]; + qcom,mdss-dsi-idle-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-idle-fps = <30>; qcom,mdss-dsi-traffic-mode = "burst_mode"; qcom,mdss-dsi-lane-map = "lane_map_0123"; qcom,mdss-dsi-bllp-eof-power-mode; @@ -97,6 +108,7 @@ qcom,mdss-dsi-te-pin-select = <1>; qcom,mdss-dsi-te-dcs-command = <1>; qcom,mdss-dsi-te-using-te-pin; + /* qcom,mdss-dsi-te-check-enable; */ qcom,mdss-dsi-panel-timings = [5F 12 0A 00 32 34 10 16 0F 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x05>; qcom,mdss-dsi-t-clk-pre = <0x11>; @@ -106,7 +118,7 @@ qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; - /* clk = totlaH * totalV * bpp* 66fps */ - qcom,mdss-dsi-panel-clockrate = <180905472>; + /* clk = totlaH * totalV * bpp* 84fps */ + qcom,mdss-dsi-panel-clockrate = <230243328>; }; }; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi index 9ad11c4cf64d5282a729d264e12152618bb48ca5..c5b7575ef438440f74a05039875bda14b857dda5 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi @@ -39,11 +39,6 @@ qcom,mdss-dsi-on-command = [ 39 01 00 00 78 00 02 11 00 39 01 00 00 14 00 02 29 00 - 39 01 00 00 00 00 04 B9 83 10 0A - 39 01 00 00 00 00 08 C9 1F 00 08 1E 81 1E 00 - 39 01 00 00 00 00 02 53 24 - 39 01 00 00 05 00 02 55 02 - 39 01 00 00 00 00 0A CA 40 3C 38 34 33 32 30 2C 28 ]; qcom,mdss-dsi-off-command = [05 01 00 00 96 00 02 28 00 05 01 00 00 00 00 02 10 00]; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c7cecbca39298e74ef6c898232dc7c599bdf087d --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi @@ -0,0 +1,81 @@ +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * + * 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,ascent_3450mah { + /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Jan6th2017 */ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <3450>; + qcom,batt-id-kohm = <60>; + qcom,battery-beta = <3435>; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_jan6th2017"; + qcom,checksum = <0x96AC>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; + qcom,fg-profile-data = [ + 9C 1F 85 05 + 82 0A 73 FC + 2B 1D 72 EA + EE 03 66 0C + C8 17 F4 22 + E0 45 1F 52 + 5C 00 00 00 + 10 00 00 00 + 00 00 4A C4 + C7 BC 48 C2 + 0F 00 08 00 + E1 DA 5D ED + 8D FD B2 F3 + 96 E2 A7 12 + 7E F4 0E 3B + 24 06 09 20 + 27 00 14 00 + 83 1F EE 05 + 1F 0A 45 FD + 6B 1D 53 E5 + EC 0B 31 14 + 44 18 49 23 + 18 45 A6 53 + 55 00 00 00 + 0E 00 00 00 + 00 00 61 CC + B7 C3 0F BC + 0F 00 00 00 + 92 00 5D ED + E3 06 E0 00 + 75 FD 9C 03 + 47 DB B3 22 + CB 33 CC FF + 07 10 00 00 + 99 0D 99 45 + 0F 00 40 00 + AB 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/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..03801ee9058972f4bbfb3f5aa06808d27e511171 --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi @@ -0,0 +1,81 @@ +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * + * 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_3000mah { + /* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jan10th2017*/ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <3000>; + qcom,batt-id-kohm = <100>; + qcom,battery-beta = <3435>; + qcom,battery-type = "itech_b00826lf_3000mah_ver1660_jan10th2017"; + qcom,checksum = <0xFB8F>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; + qcom,fg-profile-data = [ + A4 1F 6E 05 + 9C 0A 2B FC + 32 1D 23 E5 + 60 0B 1B 15 + AD 17 8C 22 + EA 3C 89 4A + 5B 00 00 00 + 12 00 00 00 + 00 00 62 C2 + 0C CD D8 C2 + 19 00 08 00 + 85 EA C7 EC + E2 05 2F 01 + 9B F5 12 12 + 5E 05 88 3B + 22 06 09 20 + 27 00 14 00 + 7D 1F DD 05 + 3F 0A E5 FC + 72 1D E3 F5 + 6F 12 C0 1D + 88 18 FB 22 + 8D 45 C6 52 + 54 00 00 00 + 0F 00 00 00 + 00 00 BD CD + 55 C2 5D C5 + 14 00 00 00 + 7E 00 C7 EC + 60 06 BB 00 + 59 06 61 03 + D9 FC 75 1B + B3 33 CC FF + 07 10 00 00 + 3E 0B 99 45 + 14 00 40 00 + AE 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/fg-gen3-batterydata-palladium-1500mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..170f0397a5fb90f4af17f18118f7771fddf78940 --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi @@ -0,0 +1,81 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * 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,palladium_1500mah_averaged_masterslave_nov28th2017 { + /* #Palladium_1500mAh_averaged_MasterSlave_Nov28th2017*/ + qcom,max-voltage-uv = <4200000>; + qcom,fg-cc-cv-threshold-mv = <4180>; + qcom,fastchg-current-ma = <1500>; + qcom,batt-id-kohm = <75>; + qcom,battery-beta = <3435>; + qcom,battery-type = "palladium_1500mah_averaged_masterslave_nov28th2017"; + qcom,checksum = <0x1C13>; + qcom,gui-version = "PM660GUI - 0.0.0.45"; + qcom,fg-profile-data = [ + A6 1F B2 05 + 1F 0A F7 FC + 22 1D 32 F2 + B9 02 1C 0D + 25 11 FB 2B + 88 4C 0A 62 + 65 00 00 00 + 0E 00 00 00 + 00 00 3D C4 + 5D C5 A4 C2 + 2A 00 08 00 + 0F C5 76 D4 + 71 FC 36 F3 + 7D 06 C4 03 + EB DD F0 22 + 1E 06 09 20 + 27 00 14 00 + 47 1F 5F FC + 9B 03 BE 06 + EE 1C 17 02 + F6 0D 27 03 + 22 11 0B 32 + 6D 4C 19 62 + 7D 00 00 00 + 0E 00 00 00 + 00 00 6E CC + 03 CA FB BC + 26 00 00 00 + E9 DB 76 D4 + 41 FD 89 EB + 3E 06 A9 F3 + C3 05 F3 13 + 9C 33 CC FF + 07 10 00 00 + BD 05 33 43 + 26 00 40 00 + 35 02 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/mdm9206.dtsi b/arch/arm/boot/dts/qcom/mdm9206.dtsi index e7c6bc371b0d9ea31433a977c7a529593717748d..0c7c6e6417483085137c881bfcb00e5341e6e320 100644 --- a/arch/arm/boot/dts/qcom/mdm9206.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9206.dtsi @@ -29,6 +29,12 @@ &cnss_debug_mem { status = "disabled"; + reg = <0x82800000 0x200000>; +}; + +&cnss_sdio { + status = "disabled"; + reg = <0x82800000 0x200000>; }; &qcom_seecom { @@ -43,3 +49,7 @@ &qseecom_mem { status = "okay"; }; + +&qcom_tzlog { + status = "okay"; +}; diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.h b/arch/arm/boot/dts/qcom/mdm9207c-mtp.dts similarity index 62% rename from drivers/media/platform/msm/ais/sensor/msm_sensor_driver.h rename to arch/arm/boot/dts/qcom/mdm9207c-mtp.dts index 43c4507d49bcdddf393223d55ca81feab60b8c1d..94e7597cd3e42936c9b69bc1097cef510fb70cf2 100644 --- a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.h +++ b/arch/arm/boot/dts/qcom/mdm9207c-mtp.dts @@ -1,4 +1,5 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * 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 @@ -10,12 +11,13 @@ * GNU General Public License for more details. */ -#ifndef MSM_SENSOR_DRIVER_H -#define MSM_SENSOR_DRIVER_H +/dts-v1/; -#include "msm_sensor.h" +#include "mdm9607-mtp.dtsi" +#include "mdm9207c.dtsi" -int32_t msm_sensor_driver_probe(void *setting, - struct msm_sensor_info_t *probed_info, char *entity_name); - -#endif +/ { + model = "Qualcomm Technologies, Inc. MDM 9207c MTP"; + compatible = "qcom,mdm9607-mtp", "qcom,mdm9607", "qcom,mtp"; + qcom,board-id = <0x20008 0>; +}; diff --git a/drivers/media/platform/msm/ais/camera/camera.h b/arch/arm/boot/dts/qcom/mdm9207c.dtsi similarity index 65% rename from drivers/media/platform/msm/ais/camera/camera.h rename to arch/arm/boot/dts/qcom/mdm9207c.dtsi index 197991decb166ca7168ebd1fced1a4a08cf47106..1f1218b62d445378bb489357ff246d5d8fadd3cf 100644 --- a/drivers/media/platform/msm/ais/camera/camera.h +++ b/arch/arm/boot/dts/qcom/mdm9207c.dtsi @@ -1,4 +1,5 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * 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 @@ -10,14 +11,6 @@ * GNU General Public License for more details. */ -#ifndef _CAMERA_H -#define _CAMERA_H - -enum stream_state { - START_STREAM = 0, - STOP_STREAM, +/ { + qcom,msm-id = <322 0x10000>; }; - -int camera_init_v4l2(struct device *dev, unsigned int *session); - -#endif /*_CAMERA_H */ diff --git a/arch/arm/boot/dts/qcom/mdm9607-cdp.dtsi b/arch/arm/boot/dts/qcom/mdm9607-cdp.dtsi index 698a93526816e359034d8b764b5a77e8d16c804f..d959db9d5918a21c90fa04e751a7739cccf612a6 100644 --- a/arch/arm/boot/dts/qcom/mdm9607-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9607-cdp.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * 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 @@ -104,18 +104,6 @@ }; }; -&pm8019_gpios { - gpio@c300 { /* GPIO 4 */ - qcom,mode = <1>; /* Digital output */ - qcom,output-type = <0>; /* CMOS logic */ - qcom,invert = <0>; /* Output high */ - qcom,vin-sel = <0>; /* VPH_PWR */ - qcom,src-sel = <0>; /* GPIO */ - qcom,out-strength = <1>; /* Low drive strength */ - qcom,master-en = <1>; /* Enable GPIO */ - }; -}; - /* MPP pin 4 configs for SGMII */ &pm8019_mpps { mpp@a300 { /* MPP 4 */ diff --git a/arch/arm/boot/dts/qcom/mdm9607-mtp-sdcard.dts b/arch/arm/boot/dts/qcom/mdm9607-mtp-sdcard.dts index 96bce37b41bbad549234059f09d3bd08bfc40374..f2250a36a4de93384763d95acd4a3e0d23a5a3d8 100644 --- a/arch/arm/boot/dts/qcom/mdm9607-mtp-sdcard.dts +++ b/arch/arm/boot/dts/qcom/mdm9607-mtp-sdcard.dts @@ -43,3 +43,15 @@ status = "ok"; }; +&pm8019_gpios { + gpio@c300 { /* GPIO 4 */ + qcom,mode = <1>; /* Digital Output */ + qcom,output-type = <0>; /* CMOS Logic */ + qcom,invert = <0>; /* Output High */ + qcom,vin-sel = <0>; /* VPH_PWR */ + qcom,src-sel = <0>; /* GPIO */ + qcom,out-strength = <1>; /* Low Drive Strength */ + qcom,master-en = <1>; /* Enable GPIO */ + }; +}; + diff --git a/arch/arm/boot/dts/qcom/mdm9607-mtp.dtsi b/arch/arm/boot/dts/qcom/mdm9607-mtp.dtsi index b3e66eeeb957286fdbe212e1b54dba4881515652..e03677f0ac78c0d80d562b4beac52b27b18f6fb6 100644 --- a/arch/arm/boot/dts/qcom/mdm9607-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9607-mtp.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 +36,8 @@ pinctrl-0 = <&ntn_rst_gpio_default>; ntn-rst-gpio = <&tlmm_pinmux 30 1>; ntn-phy-id = <7>; + ntn-timestamp-valid-window = <4>; /* Each unit is 16.75ms */ + ntn-timestamp-valid-window-disable = <1>; /* 1: To Disable */ }; }; @@ -58,7 +60,7 @@ spi-max-frequency = <4800000>; reg = <0>; interrupt-parent = <&tlmm_pinmux>; - interrupts = <25 0>; + interrupts = <25 1>; reset-gpio = <&tlmm_pinmux 11 0x1>; pinctrl-names = "active", "sleep"; pinctrl-0 = <&can_rst_on>; @@ -141,18 +143,6 @@ status = "ok"; }; -&pm8019_gpios { - gpio@c300 { /* GPIO 4 */ - qcom,mode = <1>; /* Digital output */ - qcom,output-type = <0>; /* CMOS logic */ - qcom,invert = <0>; /* Output high */ - qcom,vin-sel = <0>; /* VPH_PWR */ - qcom,src-sel = <0>; /* GPIO */ - qcom,out-strength = <1>; /* Low drive strength */ - qcom,master-en = <1>; /* Enable GPIO */ - }; -}; - /* MPP pin 4 configs for SGMII */ &pm8019_mpps { mpp@a300 { /* MPP 4 */ diff --git a/arch/arm/boot/dts/qcom/mdm9607-pinctrl.dtsi b/arch/arm/boot/dts/qcom/mdm9607-pinctrl.dtsi index 86ab1890441077e23faedc15126e8ebee88f131b..4acd040664d58a07dbdc843946240e5e519b72bb 100644 --- a/arch/arm/boot/dts/qcom/mdm9607-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9607-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 @@ -61,6 +61,32 @@ }; }; + blsp1_uart5_active: blsp1_uart5_active { + mux { + pins = "gpio8", "gpio9", "gpio10", "gpio11"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio8", "gpio9", "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart5_sleep: blsp1_uart5_sleep { + mux { + pins = "gpio8", "gpio9", "gpio10", "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9", "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + spi1 { spi1_default: spi1_default { @@ -235,7 +261,7 @@ }; }; - bmi160_int1_default: bmi160_int1_default { + sensor_int1_default: sensor_int1_default { mux { pins = "gpio78"; function = "gpio"; @@ -247,7 +273,7 @@ }; }; - bmi160_int2_default: bmi160_int2_default { + sensor_int2_default: sensor_int2_default { mux { pins = "gpio79"; function = "gpio"; diff --git a/arch/arm/boot/dts/qcom/mdm9607-regulator.dtsi b/arch/arm/boot/dts/qcom/mdm9607-regulator.dtsi index a557d4a48475ae172234d629fad3cc532ec93ab2..38f5ee9e475d9dc2abdcb52ae7df3d9639127c70 100644 --- a/arch/arm/boot/dts/qcom/mdm9607-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9607-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * 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,7 +33,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-level; }; @@ -44,7 +44,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-level; }; @@ -55,7 +55,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-floor-level; qcom,always-send-voltage; }; @@ -67,7 +67,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-level; }; }; @@ -226,7 +226,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-level; }; @@ -237,7 +237,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-level; qcom,always-send-voltage; }; @@ -249,7 +249,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-level; }; @@ -260,7 +260,7 @@ regulator-min-microvolt = ; regulator-max-microvolt = - ; + ; qcom,use-voltage-floor-level; qcom,always-send-voltage; }; @@ -336,8 +336,8 @@ qcom,vdd-mx-vmin-method = <4>; qcom,vdd-mx-corner-map = < RPM_SMD_REGULATOR_LEVEL_SVS RPM_SMD_REGULATOR_LEVEL_NOM - RPM_SMD_REGULATOR_LEVEL_TURBO >; - qcom,vdd-mx-vmax = ; + RPM_SMD_REGULATOR_LEVEL_TURBO>; + qcom,vdd-mx-vmax = ; mem-acc-supply = <&mem_acc_vreg_corner>; diff --git a/arch/arm/boot/dts/qcom/mdm9607-ttp.dts b/arch/arm/boot/dts/qcom/mdm9607-ttp.dts index 8855fad49e3859936fd55f8cbf50f97acbb6242f..097a21ed16f58cbe0de26c78cf93c51074562600 100644 --- a/arch/arm/boot/dts/qcom/mdm9607-ttp.dts +++ b/arch/arm/boot/dts/qcom/mdm9607-ttp.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -15,7 +15,7 @@ #include "mdm9607-mtp.dtsi" / { - model = "Qualcomm Technologies, Inc. MDM 9206 TTP"; + model = "Qualcomm Technologies, Inc. MDM 9607 TTP"; compatible = "qcom,mdm9607-ttp", "qcom,mdm9607", "qcom,ttp"; qcom,board-id = <0x1E 0>; }; diff --git a/arch/arm/boot/dts/qcom/mdm9607.dtsi b/arch/arm/boot/dts/qcom/mdm9607.dtsi index 4f637e7cbf0d4d17103edd9e390e5d2aca86e883..1f5a1d2b9d63532d50e58c21e6c356aa4c406245 100644 --- a/arch/arm/boot/dts/qcom/mdm9607.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9607.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * 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 @@ -15,6 +15,7 @@ #include #include #include +#include / { model = "Qualcomm Technologies, Inc. MDM 9607"; @@ -36,13 +37,13 @@ modem_adsp_mem: modem_adsp_region@0 { compatible = "removed-dma-pool"; no-map-fixup; - reg = <0x82a00000 0x5000000>; + reg = <0x82c00000 0x5000000>; }; cnss_debug_mem: cnss_debug_region@0 { compatible = "removed-dma-pool"; no-map; - reg = <0x87a00000 0x200000>; + reg = <0x82a00000 0x200000>; }; external_image_mem: external_image_region@0 { @@ -51,6 +52,12 @@ reg = <0x87c00000 0x400000>; }; + tz_apps_mem: tz_apps_region@0 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x88000000 0x500000>; + }; + audio_mem: audio_region@0 { compatible = "shared-dma-pool"; reusable; @@ -63,7 +70,7 @@ reusable; alignment = <0x400000>; size = <0x0400000>; - status = "disabled"; + status = "ok"; }; }; @@ -71,6 +78,8 @@ /* smdtty devices */ smd7 = &smdtty_data1; smd8 = &smdtty_data4; + smd9 = &smdtty_data2; + smd10 = &smdtty_data3; smd11 = &smdtty_data11; smd21 = &smdtty_data21; smd36 = &smdtty_loopback; @@ -530,13 +539,41 @@ compatible = "bosch-sensortec,bmi160"; reg = <0x68>; pinctrl-names = "default"; - pinctrl-0 = <&bmi160_int1_default &bmi160_int2_default>; + pinctrl-0 = <&sensor_int1_default &sensor_int2_default>; interrupt-parent = <&tlmm_pinmux>; interrupts = <78 0x2002>; bmi,init-interval = <200>; bmi,place = <1>; bmi,gpio_irq = <&tlmm_pinmux 78 0x2002>; }; + + iam20680@69{ + compatible = "inven,iam20680"; + reg = <0x69>; + pinctrl-names = "default"; + pinctrl-0 = <&sensor_int1_default &sensor_int2_default>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <78 IRQ_TYPE_EDGE_RISING>; + axis_map_x = <1>; + axis_map_y = <0>; + axis_map_z = <2>; + negate_x = <1>; + negate_y = <0>; + negate_z = <0>; + inven,secondary_type = "none"; + inven,aux_type = "none"; + inven,read_only_slave_type = "none"; + }; + + asm330@6b{ + compatible = "st,asm330lhh"; + reg = <0x6b>; + pinctrl-names = "default"; + pinctrl-0 = <&sensor_int1_default &sensor_int2_default>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <78 IRQ_TYPE_EDGE_RISING>; + }; + }; blsp1_uart3: uart@78b1000 { @@ -575,9 +612,46 @@ status = "disabled"; }; - qcom,cnss-sdio { + blsp1_uart5_hs: uart@78b3000 { /* BLSP1 UART5 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b3000 0x200>, + <0x7884000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart5_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 121 0 + 1 &intc 0 238 0 + 2 &tlmm_pinmux 9 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xFD>; + + qcom,bam-tx-ep-pipe-index = <8>; + qcom,bam-rx-ep-pipe-index = <9>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart5_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart5_sleep>; + pinctrl-1 = <&blsp1_uart5_active>; + + qcom,msm-bus,name = "buart5"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + cnss_sdio: qcom,cnss-sdio { compatible = "qcom,cnss_sdio"; - reg = <0x87a00000 0x200000>; + reg = <0x82a00000 0x200000>; reg-names = "ramdump"; subsys-name = "AR6320"; vdd-wlan-supply = <&rome_vreg>; @@ -890,7 +964,9 @@ <&tx_capture_tx>, <&tx_playback_rx>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, - <&incall_record_tx>, <&incall_music_rx>; + <&incall_record_tx>, <&incall_music_rx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -898,7 +974,9 @@ "msm-dai-stub-dev.8", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", - "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773"; + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; }; @@ -1221,16 +1299,16 @@ qcom,mx-retention-min = ; vdd-mx-supply = <&mdm9607_l12_floor_level>; - qcom,vdd-restriction-temp = <5>; - qcom,vdd-restriction-temp-hysteresis = <10>; + qcom,vdd-restriction-temp = <10>; + qcom,vdd-restriction-temp-hysteresis = <15>; vdd-dig-supply = <&mdm9607_s3_floor_level>; qcom,therm-ddr-lm-info = <2 78 70>; qcom,vdd-dig-rstr{ qcom,vdd-rstr-reg = "vdd-dig"; - qcom,levels = ; + qcom,levels = ; qcom,min-level = ; }; @@ -1355,6 +1433,16 @@ qcom,smdtty-port-name = "DATA1"; }; + smdtty_data2: qcom,smdtty-data2 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA2"; + }; + + smdtty_data3: qcom,smdtty-data3 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA3"; + }; + smdtty_data4: qcom,smdtty-data4 { qcom,smdtty-remote = "modem"; qcom,smdtty-port-name = "DATA4"; @@ -1635,15 +1723,16 @@ qcom,ce-opp-freq = <100000000>; }; - qcom_seecom: qseecom@87a80000 { + qcom_seecom: qseecom@88000000{ compatible = "qcom,qseecom"; - reg = <0x87a80000 0x100000>; + reg = <0x88000000 0x500000>; reg-names = "secapp-region"; qcom,hlos-ce-hw-instance = <0>; qcom,qsee-ce-hw-instance = <0>; qcom,msm-bus,name = "qseecom-noc"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <1>; + qcom,support-bus-scaling; qcom,msm-bus,vectors-KBps = <47 512 0 0>, <47 512 0 0>, @@ -1656,7 +1745,33 @@ clock-names = "core_clk_src", "core_clk", "iface_clk", "bus_clk"; qcom,ce-opp-freq = <100000000>; - status = "disabled"; + status = "ok"; + }; + + qcom_smcinvoke: smcinvoke@88000000 { + compatible = "qcom,smcinvoke"; + reg = <0x88000000 0x500000>; + qcom,clock-support; + qcom,msm-bus,name = "smcinvoke-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <47 512 0 0>, + <47 512 393600 3936000>; + clocks = <&clock_gcc clk_crypto_clk_src>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + qcom,ce-opp-freq = <100000000>; + status = "ok"; + }; + + qcom_tzlog: tz-log@8600720 { + compatible = "qcom,tz-log"; + reg = <0x08600720 0x2000>; + status = "ok"; }; emac0: qcom,emac@7c40000 { @@ -1729,6 +1844,82 @@ gpios = <&tlmm_pinmux 53 0>; status = "okay"; }; + + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; }; #include "mdm9607-rpm-regulator.dtsi" diff --git a/arch/arm/boot/dts/qcom/mdm9650-blsp.dtsi b/arch/arm/boot/dts/qcom/mdm9650-blsp.dtsi index f2f1d8f89be8f050d9caccc6b43d1dabeb9d9032..2b636f3a507a3eb93be81113ebd6415483b0eb0f 100644 --- a/arch/arm/boot/dts/qcom/mdm9650-blsp.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650-blsp.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, 2019, The Linux Foundation. All rights reserved. * * 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 @@ -421,14 +421,14 @@ status = "disabled"; }; - blsp1_uart4_hs: uart@78B2000 { /* BLSP1 UART4 */ + blsp1_uart4a_hs: uarta@78B2000 { /* BLSP1 UART4 */ compatible = "qcom,msm-hsuart-v14"; reg = <0x78B2000 0x200>, <0x7884000 0x23000>; reg-names = "core_mem", "bam_mem"; interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; #address-cells = <0>; - interrupt-parent = <&blsp1_uart4_hs>; + interrupt-parent = <&blsp1_uart4a_hs>; interrupts = <0 1 2>; #interrupt-cells = <1>; interrupt-map-mask = <0xffffffff>; @@ -458,14 +458,14 @@ status = "disabled"; }; - blsp1_uart4b_hs: uart@78B2000 { /* BLSP1 UART4b */ + blsp1_uart4b_hs: uartb@78B2000 { /* BLSP1 UART4b */ compatible = "qcom,msm-hsuart-v14"; reg = <0x78B2000 0x200>, <0x7884000 0x23000>; reg-names = "core_mem", "bam_mem"; interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; #address-cells = <0>; - interrupt-parent = <&blsp1_uart4_hs>; + interrupt-parent = <&blsp1_uart4b_hs>; interrupts = <0 1 2>; #interrupt-cells = <1>; interrupt-map-mask = <0xffffffff>; diff --git a/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi index 3ab680127d643ba005455cc29a9038b723df1b5e..c32278a35ad1b99179a7545f96ed931c414d7af5 100644 --- a/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi @@ -613,7 +613,7 @@ reg = <0>; spi-max-frequency = <9600000>; interrupt-parent = <&tlmm_pinmux>; - interrupts = <87 0>; + interrupts = <87 2>; qcom,reset-gpio = <&tlmm_pinmux 89 0x1>; qcom,clk-freq-mhz = <20000000>; qcom,max-can-channels = <1>; diff --git a/arch/arm/boot/dts/qcom/mdm9650-cv2x.dtsi b/arch/arm/boot/dts/qcom/mdm9650-cv2x.dtsi index 037ac98cdbd943b2a62a55de2cb618db1360fc42..034e83ad59536e991f671efcd995e4d61bd819ac 100644 --- a/arch/arm/boot/dts/qcom/mdm9650-cv2x.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650-cv2x.dtsi @@ -106,7 +106,7 @@ spi-max-frequency = <4800000>; reg = <0>; interrupt-parent = <&tlmm_pinmux>; - interrupts = <68 0>; + interrupts = <68 IRQ_TYPE_EDGE_RISING>; reset-gpio = <&tlmm_pinmux 89 GPIO_ACTIVE_LOW>; pinctrl-names = "active", "sleep"; pinctrl-0 = <&can_rst_on>; @@ -330,3 +330,18 @@ qcom,vadc-thermal-node; }; }; + +&pmd9650_pon { + interrupts = <0x0 0x8 0x0>, <0x0 0x8 0x1>; + interrupt-names = "kpdpwr", "resin"; + qcom,s3-src = "resin"; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,support-reset = <1>; + qcom,s1-timer = <0>; + qcom,s2-timer = <2000>; + qcom,s2-type = <7>; + qcom,pull-up = <1>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/mdm9650-ttp.dts b/arch/arm/boot/dts/qcom/mdm9650-ttp.dts index 2e2173fed4187694b325c1a5ea9e430652d8407a..c237056f65baa9878f9d28dd147b8f96e86c37ef 100644 --- a/arch/arm/boot/dts/qcom/mdm9650-ttp.dts +++ b/arch/arm/boot/dts/qcom/mdm9650-ttp.dts @@ -71,6 +71,41 @@ }; }; +&cnss_sdio { + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&sdc_vreg>; + vdd-io-supply = <&pmd9650_l7>; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-always-on; + qcom,vdd-io-current-level = <200 10000>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-width = <4>; + qcom,core_3_0v_support; + qcom,nonremovable; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_wlan_gpio_active>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_wlan_gpio_sleep>; + #address-cells = <0>; + interrupt-parent = <&sdhc_1>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 123 0 + 1 &intc 0 138 0 + 2 &tlmm_pinmux 93 0x4>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + status = "ok"; +}; + &usb3 { cpe-gpio = <&tlmm_pinmux 87 0>; }; diff --git a/arch/arm/boot/dts/qcom/mdm9650-usb.dtsi b/arch/arm/boot/dts/qcom/mdm9650-usb.dtsi index fb665282185c73f6002d0a6ccb91e8d029cd892d..9b487166c80afa8e88363e1f9dea94543c7027a7 100644 --- a/arch/arm/boot/dts/qcom/mdm9650-usb.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650-usb.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 @@ -112,7 +112,7 @@ qcom,pm-qos-latency = <101 2001 30001>; qcom,supported-func = "ffs","audio","diag","serial", "mass_storage","rndis_gsi","ecm_gsi","rmnet_gsi", - "mbim_gsi","dpl_gsi","gps","qdss"; + "mbim_gsi","dpl_gsi","gps","qdss","rndis","ipc"; }; qusb_phy: qusb@79000 { diff --git a/arch/arm/boot/dts/qcom/mdm9650.dtsi b/arch/arm/boot/dts/qcom/mdm9650.dtsi index 94e02dc3239f603bdf4e1386d308ceca4eb4c63d..7052aacf096f21da0a641a7fbb6b5f88d67685f5 100644 --- a/arch/arm/boot/dts/qcom/mdm9650.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * 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 @@ -1066,6 +1066,7 @@ qcom,disable-vdd-mx; qcom,disable-psm; qcom,disable-ocr; + qcom,therm-dynamic-hw-sampling-info = <4 60 45 0 1>; qcom,vdd-dig-rstr{ qcom,vdd-rstr-reg = "vdd-dig"; @@ -1123,6 +1124,11 @@ qcom,sensor-type = "adc"; qcom,sensor-name = "xo_therm"; }; + + sensor_information8: qcom,sensor-information-8 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "pa_therm2"; + }; }; mitigation_profile0: qcom,limit_info-0 { @@ -1264,15 +1270,16 @@ "msm-pcm-afe", "msm-pcm-routing", "msm-pcm-dtmf", "msm-voice-host-pcm", "msm-compress-dsp"; - asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&mi2s_sec>, - <&dtmf_tx>, + asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&mi2s_prim>, <&mi2s_sec>,<&dtmf_tx>, <&rx_capture_tx>, <&rx_playback_rx>, <&tx_capture_tx>, <&tx_playback_rx>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, - <&dai_sec_auxpcm>; - asoc-cpu-names = "msm-dai-q6-auxpcm.1", + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1","msm-dai-q6-auxpcm.2", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", "msm-dai-stub-dev.6", "msm-dai-stub-dev.7", @@ -1280,7 +1287,8 @@ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", - "msm-dai-q6-auxpcm.2"; + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; qcom,wsa-max-devs = <1>; @@ -1515,6 +1523,8 @@ qcom,pm-qos-irq-cpu = <0>; qcom,pm-qos-irq-latency = <70>; + qcom,sdr104-wa; + status = "disabled"; }; @@ -1526,6 +1536,85 @@ status = "okay"; }; + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; }; &gdsc_usb30 { diff --git a/arch/arm/boot/dts/qcom/msm-pm660-rpm-regulator.dtsi b/arch/arm/boot/dts/qcom/msm-pm660-rpm-regulator.dtsi index 6bbfbfd703f45a9e94773a8c26b10c25311332e3..ff91250698624c996abef6eabec3cb085e227e8e 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660-rpm-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660-rpm-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -16,6 +16,7 @@ qcom,resource-name = "smpa"; qcom,resource-id = <2>; qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; status = "disabled"; regulator-s2 { @@ -31,6 +32,7 @@ qcom,resource-name = "smpa"; qcom,resource-id = <3>; qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; status = "disabled"; regulator-s3 { @@ -46,6 +48,7 @@ qcom,resource-name = "smpa"; qcom,resource-id = <4>; qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; status = "disabled"; regulator-s4 { @@ -61,6 +64,7 @@ qcom,resource-name = "smpa"; qcom,resource-id = <5>; qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; status = "disabled"; regulator-s5 { @@ -76,6 +80,7 @@ qcom,resource-name = "smpa"; qcom,resource-id = <6>; qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; status = "disabled"; regulator-s6 { @@ -91,6 +96,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <1>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l1 { @@ -106,6 +112,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <2>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l2 { @@ -121,6 +128,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <3>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l3 { @@ -136,6 +144,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <5>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l5 { @@ -151,6 +160,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <6>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l6 { @@ -166,6 +176,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <7>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l7 { @@ -181,6 +192,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <8>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l8 { @@ -196,6 +208,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <9>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l9 { @@ -211,6 +224,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <10>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l10 { @@ -226,6 +240,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <11>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l11 { @@ -241,6 +256,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <12>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l12 { @@ -256,6 +272,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <13>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l13 { @@ -271,6 +288,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <14>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l14 { @@ -286,6 +304,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <15>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l15 { @@ -301,6 +320,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <16>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l16 { @@ -316,6 +336,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <17>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l17 { @@ -331,6 +352,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <18>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l18 { @@ -346,6 +368,7 @@ qcom,resource-name = "ldoa"; qcom,resource-id = <19>; qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; status = "disabled"; regulator-l19 { diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi index 95c60691d68738c398ea8ee8d19a9c58c3f03838..899554edd954df00039685549aaf2222e8ccfbd5 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -30,7 +30,7 @@ reg = <0x900 0x100>; }; - qcom,power-on@800 { + pm660_pon: qcom,power-on@800 { compatible = "qcom,qpnp-power-on"; reg = <0x800 0x100>; interrupts = <0x0 0x8 0x0>, @@ -568,9 +568,9 @@ }; }; - pm660_pbs: qcom,pbs@7300 { + pm660_pbs: qcom,pbs@7400 { compatible = "qcom,qpnp-pbs"; - reg = <0x7300 0x100>; + reg = <0x7400 0x100>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/msm-pm8909.dtsi b/arch/arm/boot/dts/qcom/msm-pm8909.dtsi index 8a82925c50f2d23b2934f0dd189f3b2fb41a3cf4..77ffba06f31a63456f69a59d90896efdee6f35c2 100644 --- a/arch/arm/boot/dts/qcom/msm-pm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm8909.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2019, The Linux Foundation. All rights reserved. * * 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 @@ -281,7 +281,6 @@ qcom,low-voltage-calculate-soc-ms = <1000>; qcom,low-soc-calculate-soc-ms = <5000>; qcom,calculate-soc-ms = <20000>; - qcom,volatge-soc-timeout-ms = <60000>; qcom,low-voltage-threshold = <3450000>; qcom,s3-ocv-tolerence-uv = <1200>; qcom,s2-fifo-length = <5>; diff --git a/arch/arm/boot/dts/qcom/msm-pm8937.dtsi b/arch/arm/boot/dts/qcom/msm-pm8937.dtsi index e523cbdfb5dce76271bef4913dfa2e3e46d0fd2a..e7bfcd7411178217a2e664d52546e0ce00716dc0 100644 --- a/arch/arm/boot/dts/qcom/msm-pm8937.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm8937.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -35,6 +35,7 @@ "resin-bark", "kpdpwr-resin-bark"; qcom,pon-dbc-delay = <15625>; qcom,system-reset; + qcom,store-hard-reset-reason; qcom,pon_1 { qcom,pon-type = <0>; diff --git a/arch/arm/boot/dts/qcom/msm-pm8953.dtsi b/arch/arm/boot/dts/qcom/msm-pm8953.dtsi index 0c72a72457eb59c8b9dd7c5c9c5e76c74a72324b..f259342baf1dda07f9c64a53fe5409901b7da035 100644 --- a/arch/arm/boot/dts/qcom/msm-pm8953.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm8953.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -35,6 +35,7 @@ "resin-bark", "kpdpwr-resin-bark"; qcom,pon-dbc-delay = <15625>; qcom,system-reset; + qcom,store-hard-reset-reason; qcom,pon_1 { qcom,pon-type = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8909-audio-bg_codec.dtsi b/arch/arm/boot/dts/qcom/msm8909-audio-bg_codec.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cdcc74b921d96e7875e8ef40e27251948d2fef17 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909-audio-bg_codec.dtsi @@ -0,0 +1,197 @@ +/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * 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 { + audio_codec_bg: sound { + status = "disabled"; + compatible = "qcom,msm-bg-audio-codec"; + qcom,model = "msm-bg-snd-card"; + reg = <0x7702000 0x4>, + <0x7702004 0x4>, + <0x7702008 0x4>, + <0x770200c 0x4>; + reg-names = "csr_gp_io_mux_mic_ctl", + "csr_gp_io_mux_spkr_ctl", + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel", + "csr_gp_io_lpaif_sec_pcm_sec_mode_muxsel"; + + qcom,msm-snd-card-id = <0>; + qcom,msm-ext-pa = "primary"; + qcom,tdm-audio-intf; + qcom,msm-afe-clk-ver = <1>; + qcom,split-a2dp; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&lpa>, + <&voice_svc>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-pcm-lpa", + "msm-voice-svc"; + asoc-cpu = <&dai_pri_auxpcm>, + <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, + <&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>, + <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, + <&int_fm_rx>, <&int_fm_tx>, <&afe_pcm_rx>, + <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_tx_2>, + <&dai_pri_tdm_rx_3>, <&dai_pri_tdm_tx_3>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292", + "msm-dai-q6-dev.12293", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36868", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36871"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; + + pri_tdm_rx: qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>; + qcom,msm-cpudai-tdm-clk-rate = <0>; + qcom,msm-cpudai-tdm-afe-ebit-unsupported; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36866>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36868>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36870>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + pri_tdm_tx: qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>; + qcom,msm-cpudai-tdm-clk-rate = <0>; + qcom,msm-cpudai-tdm-afe-ebit-unsupported; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36867>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36869>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36871>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + wdsp_glink: qcom,wcd-dsp-glink { + compatible = "qcom,wcd-dsp-glink"; + qcom,msm-codec-glink-edge = "bg"; + }; + + bg_cdc: bg_codec { + status = "disabled"; + compatible = "qcom,bg-codec"; + qcom,subsys-name = "modem"; + qcom,bg-speaker-connected; + qcom,bg-glink { + compatible = "qcom,bg-cdc-glink"; + qcom,msm-glink-channels = <4>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi index 51529a2ee8b2e1eb03adb8fa4eb80dcfcbcbd003..21e1cdd9488485a57c77e28f6a668b5620d84596 100644 --- a/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi @@ -46,6 +46,7 @@ qcom,idle-timeout = <80>; //msec qcom,strtstp-sleepwake; + qcom,gpu-disable-fuse = <0x44 0x00000001 27>; /* * Clocks = KGSL_CLK_CORE | KGSL_CLK_IFACE | diff --git a/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi index bce3922040c7d233130dd5c6b61e2209413df7f5..da3f4f1033919ddff7ea2040c450dbfcf7c84e25 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * 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 @@ -23,6 +23,7 @@ #include "dsi-panel-auo-qvga-cmd.dtsi" #include "dsi-panel-auo-cx-qvga-cmd.dtsi" #include "dsi-panel-390p-auo-cmd.dtsi" +#include "dsi-panel-auo-400p-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { diff --git a/arch/arm/boot/dts/qcom/msm8909-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8909-mdss.dtsi index 84e593564dc24486943e4584796983c1e9c24a38..040b4b12fa4f62dd2cce8ada52e5e8d725656c6c 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mdss.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016,2018 The Linux Foundation. All rights reserved. * * 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 diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index e1620532654c61f668d3a07c84c2b360378a4372..b8e1d0383e264c723419519c9a23680b7bfcadd5 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * 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 @@ -429,6 +429,13 @@ qcom,mdss-pref-prim-intf = "dsi"; }; +&dsi_auo_400p_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &dsi_auo_cx_qvga_cmd { qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index c064cfec9d64eb80c7918bfa42e58ee278032abd..25688ff48824e2524ca97f97b9cd085d0120e6f0 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * 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 @@ -185,10 +185,33 @@ }; }; + uart_console2_active: uart_console2_active { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; + uart_console2_sleep: uart_console2_sleep { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-pull-down; + }; + }; + blsp1_uart2_tx_active: blsp1_uart2_tx_active { mux { pins = "gpio20"; - function = "blsp_uart2_a"; + function = "blsp_uart2"; }; config { @@ -214,7 +237,7 @@ blsp1_uart2_rxcts_active: blsp1_uart2_rxcts_active { mux { pins = "gpio21", "gpio111"; - function = "blsp_uart2_a"; + function = "blsp_uart2"; }; config { @@ -240,7 +263,7 @@ blsp1_uart2_rfr_active: blsp1_uart2_rfr_active { mux { pins = "gpio112"; - function = "blsp_uart2_a"; + function = "blsp_uart2"; }; config { @@ -521,6 +544,78 @@ }; nfc { + nfcw_int_active: nfcw_int_active { + mux { + pins = "gpio50"; + function = "gpio"; + }; + config { + pins = "gpio50"; + drive-strength = <6>; + bias-pull-up; + }; + }; + + nfcw_int_suspend: nfcw_int_suspend { + mux { + pins = "gpio50"; + function = "gpio"; + }; + config { + pins = "gpio50"; + drive-strength = <6>; + bias-pull-up; + }; + }; + + nfcw_disable_active: nfcw_disable_active { + mux { + pins = "gpio36"; + function = "gpio"; + }; + config { + pins = "gpio36"; + drive-strength = <6>; + bias-pull-up; + }; + }; + + nfcw_disable_suspend: nfcw_disable_suspend { + mux { + pins = "gpio36"; + function = "gpio"; + }; + config { + pins = "gpio36"; + drive-strength = <6>; + bias-disable; + }; + }; + + nfcv2k_disable_active: nfcv2k_disable_active { + mux { + pins = "gpio52"; + function = "gpio"; + }; + config { + pins = "gpio52"; + drive-strength = <6>; + bias-pull-up; + }; + }; + + nfcv2k_disable_suspend: nfcv2k_disable_suspend { + mux { + pins = "gpio52"; + function = "gpio"; + }; + config { + pins = "gpio52"; + drive-strength = <6>; + bias-disable; + }; + }; + nfc_int_active: nfc_int_active { mux { pins = "gpio21"; @@ -922,7 +1017,7 @@ gpio_key_suspend: gpio_key_suspend { mux { - pins = "gpio91", "gpio91", "gpio92"; + pins = "gpio90", "gpio91", "gpio92"; function = "gpio"; }; @@ -1793,6 +1888,60 @@ }; }; + cdc-dmic-lines { + cdc_dmic0_clk_act: dmic0_clk_on { + mux { + pins = "gpio4"; + function = "dmic0_clk"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; + bias-pull-none; + }; + }; + + cdc_dmic0_clk_sus: dmic0_clk_off { + mux { + pins = "gpio4"; + function = "gpio"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + bias-disable; + }; + }; + + cdc_dmic0_data_act: dmic0_data_on { + mux { + pins = "gpio5"; + function = "dmic0_data"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; + bias-pull-none; + }; + }; + + cdc_dmic0_data_sus: dmic0_data_off { + mux { + pins = "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + cdc-pdm-lines { cdc_pdm_lines_act: pdm_lines_on { mux { @@ -1998,7 +2147,6 @@ pins = "gpio0", "gpio1"; drive-strength = <8>; /* 8 MA */ bias-disable; /* No PULL */ - output-high; }; }; quat_mi2s_sleep: quat_mi2s_sleep { @@ -2025,6 +2173,7 @@ pins = "gpio2", "gpio3"; drive-strength = <8>; /* 8 MA */ bias-disable; /* No PULL */ + output-high; }; }; quat_mi2s_din_sleep: quat_mi2s_din_sleep { diff --git a/arch/arm/boot/dts/qcom/msm8909-pm660-pm.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm660-pm.dtsi index 3e09b6f41c74f86f0a231b4676d836f2e0c85d20..6e27fb59e770715e900a92e6bb200bb9ca9721e5 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm660-pm.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm660-pm.dtsi @@ -159,7 +159,7 @@ qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>; qcom,vctl-timeout-us = <500>; qcom,vctl-port = <0x0>; - qcom,phase-port = <0x1>; + qcom,vctl-port-ub = <0x1>; qcom,pfm-port = <0x2>; qcom,mode0 { qcom,label = "qcom,saw2-spm-cmd-ret"; @@ -175,9 +175,9 @@ }; qcom,mode2 { qcom,label = "qcom,saw2-spm-cmd-pc"; - qcom,sequence = [00 32 b0 10 e0 d0 6b c0 42 f0 11 - 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32 - 50 f0 0f]; /*APC_L2RAM_OFF */ + qcom,sequence = [00 20 32 b0 6b c0 e0 d0 42 11 07 + 01 b0 50 4e 02 02 d0 e0 c0 22 6b 02 32 52 + 0f]; /*APC_L2RAM_ON */ qcom,spm_en; qcom,pc_mode; }; @@ -228,6 +228,7 @@ qcom,time-overhead = <2500>; qcom,min-child-idx = <2>; qcom,notify-rpm; + qcom,no-cache-flush; qcom,reset-level = ; }; diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8916.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm8916.dtsi index 125b0b8409a9c77238f440cb57b8baae6cb2789f..939452fc7927cb08c260cc8426b6517e110aff55 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8916.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm8916.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -26,14 +26,40 @@ mem_acc_vreg_corner: regulator@1942130 { compatible = "qcom,mem-acc-regulator"; - reg = <0x1942130 0x4>; - reg-names = "acc-sel-l1"; regulator-name = "mem_acc_corner"; regulator-min-microvolt = <1>; regulator-max-microvolt = <3>; - qcom,acc-sel-l1-bit-pos = <0>; - qcom,corner-acc-map = <0 1 1>; + qcom,acc-reg-addr-list = + <0x1942130 0x1942120>; + + qcom,acc-init-reg-config = <1 0x1>, <2 0x0>; + qcom,num-acc-corners = <3>; + qcom,boot-acc-corner = <2>; + + qcom,corner1-reg-config = + /* SVS => SVS */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* SVS => NOM */ + < 1 0x0 >, < 2 0x09240000>, < 1 0x1 >, + /* SVS => TURBO */ + < 1 0x1 >, < 2 0x0>, < (-1) (-1) >; + + qcom,corner2-reg-config = + /* NOM => SVS */ + < 1 0x0 >, < 2 0x09240000>, < 2 0x0 >, + /* NOM => NOM */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* NOM => TURBO */ + < 1 0x1 >, < 2 0x08200000>, < 2 0x0 >; + + qcom,corner3-reg-config = + /* TURBO => SVS */ + < 1 0x0 >, < 2 0x0>, < (-1) (-1) >, + /* TURBO => NOM */ + < 1 0x1 >, < 2 0x08200000>, < 2 0x09240000 >, + /* TURBO => TURBO */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>; }; apc_vreg_corner: regulator@b018000 { diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi index 6a0554a6de57c5d09f761a0915fdce396113abf7..5daae7086ef1d09fb4c07aad4a9072ea51a35577 100644 --- a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi @@ -1,4 +1,5 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015,2018, The Linux Foundation. All rights + * reserved. * * 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 @@ -214,6 +215,9 @@ 1 &intc 0 221 0>; interrupt-names = "hc_irq", "pwr_irq"; /delete-property/ cd-gpios; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; }; &pm8909_mpps { diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd-skue.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd-skue.dtsi index 062ac1b684f7e9021f571728b135fad88b0a256e..cd5998945dc1b22f56dd023ccf605bd10ff7e658 100644 --- a/arch/arm/boot/dts/qcom/msm8909-qrd-skue.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd-skue.dtsi @@ -1,4 +1,5 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights + * reserved. * * 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 @@ -287,6 +288,9 @@ 1 &intc 0 221 0>; interrupt-names = "hc_irq", "pwr_irq"; /delete-property/ cd-gpios; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; }; &pm8909_mpps { diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index 34a8cccbd5a4b7343c92549d4fe0765f2fd30027..5798970160335d405c32046151c8c48623293a60 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -112,20 +112,12 @@ compatible = "android,firmware"; fstab { compatible = "android,fstab"; - vendor { + vendor_fstab: vendor { compatible = "android,vendor"; dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,verify"; status = "ok"; }; }; @@ -563,6 +555,8 @@ qcom,freq-mitigation-value = <400000>; qcom,online-hotplug-core; qcom,therm-reset-temp = <115>; + qcom,synchronous-cluster-id = <0>; + qcom,synchronous-cluster-map = <0 4 &CPU0 &CPU1 &CPU2 &CPU3>; qcom,disable-cx-phase-ctrl; qcom,disable-gfx-phase-ctrl; qcom,disable-vdd-mx; @@ -1727,6 +1721,11 @@ qcom,msm-dai-q6-dev-id = <240>; }; + afe_loopback_tx: qcom,msm-dai-q6-afe-loopback-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <24577>; + }; + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <32771>; diff --git a/arch/arm/boot/dts/qcom/msm8909w-bg-memory.dtsi b/arch/arm/boot/dts/qcom/msm8909w-bg-memory.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3389d298b276088858ff94812bbe328f2bee9073 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909w-bg-memory.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * 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. + */ + +&external_image_mem { + reg = <0x0 0x87a00000 0x0 0x0600000>; +}; + +&modem_adsp_mem { + reg = <0x0 0x88000000 0x0 0x05200000>; +}; + +&peripheral_mem { + reg = <0x0 0x8d200000 0x0 0x0600000>; +}; + +&reserved_mem { + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xa0000000>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + linux,cma-default; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v1.dts b/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v1.dts index 6812cb5469059caf1b07b500111524a1f6bca9f6..e201ff6bb2542964859af5cdafa4056dcc3fa190 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v1.dts +++ b/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v1.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -18,7 +18,8 @@ #include "msm8909-pm8916.dtsi" #include "msm8909-pm8916-mtp.dtsi" #include "msm8909w.dtsi" -#include "msm8909w-memory.dtsi" +#include "msm8909w-bg-memory.dtsi" +#include "msm8909-audio-bg_codec.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909W-PM8916 BLACKGHOST WTP"; @@ -65,6 +66,7 @@ qcom,blackghost { compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; qcom,firmware-name = "bg-wear"; /* GPIO inputs from blackghost */ qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; @@ -210,3 +212,15 @@ pins = "gpio98", "gpio16"; }; }; + +&audio_codec_mtp { + status = "disabled"; +}; + +&audio_codec_bg { + status = "ok"; +}; + +&bg_cdc { + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909w-memory.dtsi b/arch/arm/boot/dts/qcom/msm8909w-memory.dtsi index aa63881591a73a816ea6460870eadd8b5422fbea..b15fbfa2d1d2138aaa7cb87e732fbfe06f6e674f 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-memory.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909w-memory.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * 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,7 +12,7 @@ */ &external_image_mem { - reg = <0x0 0x87b00000 0x0 0x0500000>; + reg = <0x0 0x87a00000 0x0 0x0600000>; }; &modem_adsp_mem { @@ -20,7 +20,7 @@ }; &peripheral_mem { - reg = <0x0 0x8d000000 0x0 0x0500000>; + reg = <0x0 0x8d000000 0x0 0x0600000>; }; &reserved_mem { diff --git a/arch/arm/boot/dts/qcom/msm8909w-pm660-camera-sensor-wtp-v1.dtsi b/arch/arm/boot/dts/qcom/msm8909w-pm660-camera-sensor-wtp-v1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..11f705a810df3efeff7520c6e48acf42d450f41c --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909w-pm660-camera-sensor-wtp-v1.dtsi @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +&i2c_2 { + status = "okay"; + qcom,camera@2 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x2>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + cam_vdig-supply = <&pm660_l7>; + cam_vio-supply = <&pm660_l13>; + qcom,cam-vreg-type = <0 0>; + qcom,cam-vreg-name = "cam_vdig","cam_vio"; + qcom,cam-vreg-min-voltage = <1200000 1800000>; + qcom,cam-vreg-max-voltage = <1200000 1800000>; + qcom,cam-vreg-op-mode = <200000 0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&msm_gpio 26 0>, + <&msm_gpio 35 0>, + <&msm_gpio 34 0>, + <&msm_gpio 23 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-vana = <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_MCLK", + "CAM_STANDBY", + "CAM_RESET", + "CAM_VANA"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_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 = <0>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + cam_vio-supply = <&pm660_l13>; + qcom,cam-vreg-name = "cam_vio"; + qcom,cam-vreg-min-voltage = <1800000>; + qcom,cam-vreg-max-voltage = <1800000>; + qcom,cam-vreg-op-mode = <30000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_default + &cam_sensor_front_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; + gpios = <&msm_gpio 27 0>, + <&msm_gpio 28 0>, + <&msm_gpio 23 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_MCLK", + "CAM_RESET", + "CAM_VANA"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk1_clk_src>, + <&clock_gcc clk_gcc_camss_mclk1_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909w-pm660-camera.dtsi b/arch/arm/boot/dts/qcom/msm8909w-pm660-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fff81944062dac73c7dd87a53e8e2acfe00cf2b4 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909w-pm660-camera.dtsi @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * + * 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 { + qcom,msm-cam@1800000{ + compatible = "qcom,msm-cam"; + reg = <0x1b00000 0x40000>; + reg-names = "msm-cam"; + status = "ok"; + bus-vectors = "suspend", "svs", "nominal", "turbo"; + qcom,bus-votes = <0 320000000 640000000 640000000>; + }; + + qcom,csiphy@1b0ac00 { + cell-index = <0>; + compatible = "qcom,csiphy-v3.1", "qcom,csiphy"; + reg = <0x1b0ac00 0x200>, + <0x1b00030 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; + interrupts = <0 78 0>; + interrupt-names = "csiphy"; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_csi0phytimer_clk_src>, + <&clock_gcc clk_gcc_camss_csi0phytimer_clk>, + <&clock_gcc clk_camss_top_ahb_clk_src>, + <&clock_gcc clk_gcc_camss_csi0phy_clk>, + <&clock_gcc clk_gcc_camss_csi1phy_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "camss_top_ahb_clk", "ispif_ahb_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ahb_src", "csi0_phy_clk", "csi1_phy_clk", + "camss_ahb_clk"; + qcom,clock-rates = <0 0 200000000 0 0 0 0 0>; + }; + + qcom,csid@1b08000 { + cell-index = <0>; + compatible = "qcom,csid-v3.1", "qcom,csid"; + reg = <0x1b08000 0x100>; + reg-names = "csid"; + interrupts = <0 49 0>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm660_l2>; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi0_ahb_clk>, + <&clock_gcc clk_csi0_clk_src>, + <&clock_gcc clk_gcc_camss_csi0_clk>, + <&clock_gcc clk_gcc_camss_csi0pix_clk>, + <&clock_gcc clk_gcc_camss_csi0rdi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "ispif_ahb_clk", "camss_top_ahb_clk", + "csi_ahb_clk", "csi_src_clk", + "csi_clk", "csi_pix_clk", + "csi_rdi_clk", "camss_ahb_clk"; + qcom,clock-rates = <40000000 0 0 200000000 0 0 0 0>; + }; + + qcom,csid@1b08400 { + cell-index = <1>; + compatible = "qcom,csid-v3.1", "qcom,csid"; + reg = <0x1b08400 0x100>; + reg-names = "csid"; + interrupts = <0 50 0>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm660_l2>; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi1_ahb_clk>, + <&clock_gcc clk_csi1_clk_src>, + <&clock_gcc clk_gcc_camss_csi1_clk>, + <&clock_gcc clk_gcc_camss_csi1pix_clk>, + <&clock_gcc clk_gcc_camss_csi1rdi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi1phy_clk>; + clock-names = "ispif_ahb_clk", "camss_top_ahb_clk", + "csi_ahb_clk", "csi_src_clk", + "csi_clk", "csi_pix_clk", + "csi_rdi_clk", "camss_ahb_clk", "camss_csi1_phy"; + qcom,clock-rates = <40000000 0 0 200000000 0 0 0 0 0>; + }; + + qcom,ispif@1b0a000 { + cell-index = <0>; + compatible = "qcom,ispif"; + reg = <0x1b0a000 0x500>, + <0x1b00020 0x10>; + reg-names = "ispif", "csi_clk_mux"; + interrupts = <0 51 0>; + interrupt-names = "ispif"; + qcom,num-isps = <0x1>; + vfe0_vdd_supply = <&gdsc_vfe>; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + + <&clock_gcc clk_csi0_clk_src>, + <&clock_gcc clk_gcc_camss_csi0_clk>, + <&clock_gcc clk_gcc_camss_csi0rdi_clk>, + <&clock_gcc clk_gcc_camss_csi0pix_clk>, + <&clock_gcc clk_csi1_clk_src>, + <&clock_gcc clk_gcc_camss_csi1_clk>, + <&clock_gcc clk_gcc_camss_csi1rdi_clk>, + <&clock_gcc clk_gcc_camss_csi1pix_clk>, + <&clock_gcc clk_vfe0_clk_src>, + <&clock_gcc clk_gcc_camss_vfe0_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe0_clk>; + + clock-names = "camss_top_ahb_clk", "ispif_ahb_clk", + "csi0_src_clk", "csi0_clk", + "csi0_rdi_clk", "csi0_pix_clk", + "csi1_src_clk", "csi1_clk", + "csi1_rdi_clk", "csi1_pix_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", + "camss_csi_vfe0_clk"; + qcom,clock-rates = <0 40000000 + 200000000 0 0 0 + 200000000 0 0 0 + 0 0 0>; + qcom,clock-control = "NO_SET_RATE", "SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE"; + }; + + qcom,vfe@1b10000 { + cell-index = <0>; + compatible = "qcom,vfe32"; + reg = <0x1b10000 0x830>, + <0x1b40000 0x200>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 52 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe>; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_vfe0_clk_src>, + <&clock_gcc clk_gcc_camss_vfe0_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe0_clk>, + <&clock_gcc clk_gcc_camss_vfe_ahb_clk>, + <&clock_gcc clk_gcc_camss_vfe_axi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>; + clock-names = "camss_top_ahb_clk", "vfe_clk_src", + "camss_vfe_vfe_clk", "camss_csi_vfe_clk", "iface_clk", + "bus_clk", "camss_ahb_clk", "ispif_ahb_clk"; + qcom,clock-rates = <40000000 266670000 0 0 0 0 0 0>; + + qos-entries = <8>; + qos-regs = <0x7BC 0x7C0 0x7C4 0x7C8 0x7CC 0x7D0 + 0x7D4 0x798>; + qos-settings = <0xAAA5AAA5 0xAAA5AAA5 0xAAA5AAA5 + 0xAAA5AAA5 0xAAA5AAA5 0xAAA5AAA5 + 0xAAA5AAA5 0x00010000>; + vbif-entries = <1>; + vbif-regs = <0x04>; + vbif-settings = <0x1>; + ds-entries = <15>; + ds-regs = <0x7D8 0x7DC 0x7E0 0x7E4 0x7E8 + 0x7EC 0x7F0 0x7F4 0x7F8 0x7FC 0x800 + 0x804 0x808 0x80C 0x810>; + ds-settings = <0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0x00000103>; + + bus-util-factor = <1024>; + }; + + qcom,cam_smmu { + status = "ok"; + compatible = "qcom,msm-cam-smmu"; + msm_cam_smmu_cb1: msm_cam_smmu_cb1 { + compatible = "qcom,qsmmu-cam-cb"; + iommus = <&apps_iommu 0x400>; + label = "vfe"; + qcom,scratch-buf-support; + }; + }; + + qcom,irqrouter@1b00000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,irqrouter"; + reg = <0x1b00000 0x100>; + reg-names = "irqrouter"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909w-pm660-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909w-pm660-mtp.dtsi index 8ee54155f157657254dfaabda69f4673ba84439e..c548a6b4066f8e22742a1bc77af3528c83d565d4 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-pm660-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909w-pm660-mtp.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -40,6 +40,12 @@ qcom,iris-vddrfa-supply = <&pm660_l6>; qcom,iris-vdddig-supply = <&pm660_l13>; qcom,wcn-external-gpio-support; + + clocks = <&clock_rpm clk_xo_wlan_clk>, + <&clock_rpm clk_rf_clk1>, + <&clock_debug clk_gcc_debug_mux>, + <&clock_gcc clk_wcnss_m_clk>; + clock-names = "xo", "rf_clk", "measure", "wcnss_debug"; }; qcom,pronto@a21b000 { @@ -76,9 +82,33 @@ }; &i2c_1 { - mpu6050@68 { - /delete-property/ vdd-supply; - /delete-property/ vlogic-supply; + /delete-node/ mpu6050@68; + /delete-node/ avago@39; + /delete-node/ akm@c; +}; + +&msm_gpio { + /delete-node/ mpu6050_int_pin; + /delete-node/ apds99xx_int_pin; + /delete-node/ ak8963_int_pin; + + pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio25", "gpio37", "gpio59"; + }; + config { + pins = "gpio25", "gpio37", "gpio59"; + }; + }; + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio25", "gpio37", "gpio59"; + }; + config { + pins = "gpio25", "gpio37", "gpio59"; + }; + }; }; }; @@ -107,9 +137,6 @@ }; }; -&audio_codec_mtp { - /delete-property/ asoc-codec; -}; &sdhc_2 { /delete-property/ vdd-supply; @@ -166,6 +193,27 @@ qcom,clock-a7@0b011050 { cpu-vdd-supply = <&apc_vreg_corner>; }; + + qcom,rpmcc@1800000 { + compatible = "qcom,rpmcc-8909-pm660"; + }; + + qcom,sensor-information { + sensor_information9: qcom,sensor-information-9 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "emmc_therm"; + }; + + sensor_information10: qcom,sensor-information-10 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "msm_therm"; + }; + + sensor_information11: qcom,sensor-information-11 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "quiet_therm"; + }; + }; }; &sdhc_1 { @@ -199,6 +247,7 @@ &mdss_dsi0{ qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>; + qcom,platform-enable-gpio = <&msm_gpio 59 0>; }; &mdss_dsi0_pll { @@ -206,6 +255,15 @@ }; &pm660_gpios { + /* GPIO 4 (NFC_CLK_REQ) */ + gpio@c300 { + qcom,mode = <0>; + qcom,vin-sel = <1>; + qcom,src-sel = <0>; + qcom,master-en = <1>; + status = "okay"; + }; + gpio@cb00 { status = "ok"; qcom,mode = <1>; @@ -214,4 +272,56 @@ qcom,master-en = <1>; qcom,out-strength = <2>; }; + + gpio@c400 { + status = "ok"; + qcom,mode = <1>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,src-sel = <2>; + qcom,master-en = <1>; + qcom,out-strength = <2>; + }; +}; + +&pm660_misc { + qcom,support-twm-config; +}; + +&pm660_pbs { + status = "okay"; +}; + +&pm660_pon { + qcom,support-twm-config; + qcom,pbs-client = <&pm660_pbs>; +}; + +/ { + /delete-node/ qcom,battery-data; + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen3-batterydata-palladium-1500mah.dtsi" + }; +}; + +&pm660_charger { + qcom,pd-not-supported; +}; + +&pm660_fg { + qcom,battery-data = <&mtp_batterydata>; + qcom,fg-rsense-sel = <1>; /* External rsense */ + qcom,fg-cutoff-voltage = <3400>; + qcom,fg-recharge-voltage = <4100>; + + qcom,fg-use-sw-esr; + qcom,fg-esr-pulse-thresh-ma = <40>; + qcom,fg-esr-meas-curr-ma = <60>; + qcom,fg-cutoff-current = <50>; + + qcom,fg-esr-timer-shutdown = <2048 2048>; + qcom,fg-esr-timer-asleep = <512 512>; + qcom,fg-sync-sleep-threshold-ma = <30>; + qcom,fg-disable-in-twm; }; diff --git a/arch/arm/boot/dts/qcom/msm8909w-pm660-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8909w-pm660-regulator.dtsi index 449eda549b8de00a34d50122a925d8d0ffd4f2b9..1c3824e44445e1b968d453494cdee559bd4575c7 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-pm660-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909w-pm660-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -130,9 +130,9 @@ rpm-regulator-ldoa2 { status = "okay"; pm660_l2: regulator-l2 { - regulator-min-microvolt = <1300000>; - regulator-max-microvolt = <1300000>; - qcom,init-voltage = <1300000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; status = "okay"; }; }; @@ -326,25 +326,49 @@ reg = <0x1400 0x100>; regulator-min-microvolt = <1052000>; regulator-max-microvolt = <1352000>; - - /* TODO: remove after SAW support is enabled */ - qcom,bypass-spm; }; }; }; /* CPR controlled regulator */ &soc { + /delete-node/ regulator@1942130; mem_acc_vreg_corner: regulator@1942130 { compatible = "qcom,mem-acc-regulator"; - reg = <0x1942130 0x4>; - reg-names = "acc-sel-l1"; regulator-name = "mem_acc_corner"; regulator-min-microvolt = <1>; regulator-max-microvolt = <3>; - qcom,acc-sel-l1-bit-pos = <0>; - qcom,corner-acc-map = <0 1 1>; + qcom,acc-reg-addr-list = + <0x1942130 0x1942120>; + + qcom,acc-init-reg-config = <1 0x1>, <2 0x0>; + qcom,num-acc-corners = <3>; + qcom,boot-acc-corner = <2>; + + qcom,corner1-reg-config = + /* SVS => SVS */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* SVS => NOM */ + < 1 0x0 >, < 2 0x09240000>, < 1 0x1 >, + /* SVS => TURBO */ + < 1 0x1 >, < 2 0x0>, < (-1) (-1) >; + + qcom,corner2-reg-config = + /* NOM => SVS */ + < 1 0x0 >, < 2 0x09240000>, < 2 0x0 >, + /* NOM => NOM */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* NOM => TURBO */ + < 1 0x1 >, < 2 0x08200000>, < 2 0x0 >; + + qcom,corner3-reg-config = + /* TURBO => SVS */ + < 1 0x0 >, < 2 0x0>, < (-1) (-1) >, + /* TURBO => NOM */ + < 1 0x1 >, < 2 0x08200000>, < 2 0x09240000 >, + /* TURBO => TURBO */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>; }; apc_vreg_corner: regulator@b018000 { diff --git a/arch/arm/boot/dts/qcom/msm8909w.dtsi b/arch/arm/boot/dts/qcom/msm8909w.dtsi index 7fc0edd8c741cdbb6837644fbafd8841da8c219f..c5daaf04019092ada4baefa092525229b63de6ab 100644 --- a/arch/arm/boot/dts/qcom/msm8909w.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909w.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 @@ -14,6 +14,31 @@ chosen { bootargs="sched_enable_hmp=0"; }; + + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor_fstab: vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,verify"; + status = "ok"; + }; + system_fstab: system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,verify"; + status = "ok"; + }; + }; + }; + }; }; &soc { @@ -79,6 +104,10 @@ < 1267200 2929>; }; }; + + ssc_sensors: qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; }; &qcom_crypto { @@ -101,10 +130,6 @@ <55 512 393600 393600>; }; -&venus_qseecom_mem { - size = <0 0x0400000>; -}; - &mdss_dsi0 { qcom,dsi-pref-prim-pan = <&dsi_auo_cx_qvga_cmd>; pinctrl-names = "mdss_default", "mdss_sleep"; diff --git a/arch/arm/boot/dts/qcom/msm8917.dtsi b/arch/arm/boot/dts/qcom/msm8917.dtsi index 6b9427c25e8bd5ae35a4e2d283847d8e838aeabb..f0d67f5eb123f76388896b9448775822e7ad0b59 100644 --- a/arch/arm/boot/dts/qcom/msm8917.dtsi +++ b/arch/arm/boot/dts/qcom/msm8917.dtsi @@ -59,18 +59,9 @@ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,verify"; status = "ok"; }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8937.dtsi b/arch/arm/boot/dts/qcom/msm8937.dtsi index a1c0aba32cd5213769795e6b95f8b3fd836ef358..f937e656b7b32df85978a568d0c500844b004a1e 100644 --- a/arch/arm/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm/boot/dts/qcom/msm8937.dtsi @@ -35,18 +35,9 @@ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,verify"; status = "ok"; }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8953.dtsi b/arch/arm/boot/dts/qcom/msm8953.dtsi index 0bbaec9ddcfea97d0628d45126c200883499674c..5f467273c3a62aad816103cc03742d72335d1109 100644 --- a/arch/arm/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm/boot/dts/qcom/msm8953.dtsi @@ -36,18 +36,9 @@ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,verify"; status = "ok"; }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - }; }; }; @@ -93,7 +84,7 @@ compatible = "shared-dma-pool"; reusable; alignment = <0 0x400000>; - size = <0 0x09800000>; + size = <0 0x0b400000>; }; qseecom_mem: qseecom_region@0 { diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts index d4cf58f9b8eae1d47ba14c6b78f313b6ab3c030a..4ff449a45d1a5c2407c8dc58a7fb95fbbce88214 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts @@ -31,7 +31,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts index 33daf9d6f0e7048d75ef92039651b02ed6f0026a..250ce9289c70fa4d31d58b16545b6eb1ac3fcfac 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts @@ -43,7 +43,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts index d84b0d781b291cb2a5c46d2304ed6eb4a08928fa..cf1128b5d28329f7a0bc2633877782ab284c4179 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts @@ -28,7 +28,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996-vidc.dtsi b/arch/arm/boot/dts/qcom/msm8996-vidc.dtsi index 4cfe0c5adef6a726b0cb4e0a369155f11f853633..e0ce6e8fd9a75765d8861ac8dff2eed0a24a8529 100644 --- a/arch/arm/boot/dts/qcom/msm8996-vidc.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-vidc.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2019, The Linux Foundation. All rights reserved. * * 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 diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 5cad16762a75914aa63414593abd3bf054638e40..fc238f0b8c575221d9ebb722e4113e39980b6143 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -168,18 +168,9 @@ dev = "/dev/block/platform/soc/7464900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,verify"; status = "ok"; }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7464900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; - status = "ok"; - }; - }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts index 15b00af5f0f42a4d41521ff2eaccd45eac81b4e7..91f9ab654e51fc43ede09a39c04e52742c324624 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts @@ -31,7 +31,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts index 4a78a2fef835e40e89976041a504660f507feaf0..a4c0a051599517d0be149a49950311bf2ed40efd 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts index d75f56d12291bbf52a757c1333f9a5dc6cc92fcc..13a0e914cdfa805e152941d5fec7c76356585312 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/sda450-cdp.dts b/arch/arm/boot/dts/qcom/sda450-cdp.dts index b3643cccfafca45c4ff47a453175028b58f73ad2..bda8ae02d9d00252a568a75560df8318fbe2eb53 100644 --- a/arch/arm/boot/dts/qcom/sda450-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda450-cdp.dts @@ -22,7 +22,7 @@ / { model = "Qualcomm Technologies, Inc. SDA450 + PMI8950 CDP"; compatible = "qcom,sda450-cdp", "qcom,sda450", "qcom,cdp"; - qcom,board-id= <1 0>; + qcom,board-id = <1 0>; }; &pmi8950_charger { diff --git a/arch/arm/boot/dts/qcom/sda450-mtp.dts b/arch/arm/boot/dts/qcom/sda450-mtp.dts index 91280fa3c485da5370f8626729d28419f6c8aa6d..8567a484ad131fb302b6cee81f13eebe294a1423 100644 --- a/arch/arm/boot/dts/qcom/sda450-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda450-mtp.dts @@ -22,7 +22,7 @@ / { model = "Qualcomm Technologies, Inc. SDA450 + PMI8950 MTP"; compatible = "qcom,sda450-mtp", "qcom,sda450", "qcom,mtp"; - qcom,board-id= <8 0>; + qcom,board-id = <8 0>; qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/apq8009w-nowgr-swoctp-circpanel.dts b/arch/arm/boot/dts/qcom/sdw2100-apq8009w-nowgr-swoctp-circpanel.dts similarity index 95% rename from arch/arm/boot/dts/qcom/apq8009w-nowgr-swoctp-circpanel.dts rename to arch/arm/boot/dts/qcom/sdw2100-apq8009w-nowgr-swoctp-circpanel.dts index 547e75e17ed039583802236bb9213d9169d78fe7..bc7f815757f13f022d2440520d00aeb03b81b2d5 100644 --- a/arch/arm/boot/dts/qcom/apq8009w-nowgr-swoctp-circpanel.dts +++ b/arch/arm/boot/dts/qcom/sdw2100-apq8009w-nowgr-swoctp-circpanel.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -18,7 +18,7 @@ / { model = "Qualcomm Technologies, Inc. APQ8009W-PM8916 \ - SWOC CIRC PANEL NOWGR MTP"; + SWOC CIRC PANEL NOWGR MTP SDW2100"; compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; diff --git a/arch/arm/boot/dts/qcom/apq8009w-wtp.dts b/arch/arm/boot/dts/qcom/sdw2100-apq8009w-wtp.dts similarity index 93% rename from arch/arm/boot/dts/qcom/apq8009w-wtp.dts rename to arch/arm/boot/dts/qcom/sdw2100-apq8009w-wtp.dts index 34408674a7851229f376dcc1432bbc05f2cd2954..ec41dc87a7add8cb9e4a1dece130f023810494d1 100644 --- a/arch/arm/boot/dts/qcom/apq8009w-wtp.dts +++ b/arch/arm/boot/dts/qcom/sdw2100-apq8009w-wtp.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -21,7 +21,7 @@ #include "apq8009w-memory.dtsi" / { - model = "Qualcomm Technologies, Inc. APQ8009W-PM8916 MTP"; + model = "Qualcomm Technologies, Inc. APQ8009W-PM8916 MTP SDW2100"; compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; diff --git a/arch/arm/boot/dts/qcom/msm8909w-1gb-swoctp-circpanel.dts b/arch/arm/boot/dts/qcom/sdw2100-msm8909w-1gb-swoctp-circpanel.dts similarity index 95% rename from arch/arm/boot/dts/qcom/msm8909w-1gb-swoctp-circpanel.dts rename to arch/arm/boot/dts/qcom/sdw2100-msm8909w-1gb-swoctp-circpanel.dts index 10069eecb57330ae84c05caee6c1c8ec1a69d2f3..1640b96f908df314bfb4b00a16fe9cce2f46fecd 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-1gb-swoctp-circpanel.dts +++ b/arch/arm/boot/dts/qcom/sdw2100-msm8909w-1gb-swoctp-circpanel.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -17,7 +17,7 @@ / { model = "Qualcomm Technologies, Inc. MSM8909W-PM8916 \ - 1GB SWOC CIRC PANEL MTP"; + SWOC CIRC PANEL MTP SDW2100"; compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp"; qcom,msm-id = <245 0>, <258 0>, diff --git a/arch/arm/boot/dts/qcom/msm8909w-swoctp.dts b/arch/arm/boot/dts/qcom/sdw2100-msm8909w-swoctp.dts similarity index 82% rename from arch/arm/boot/dts/qcom/msm8909w-swoctp.dts rename to arch/arm/boot/dts/qcom/sdw2100-msm8909w-swoctp.dts index 06797ce8728aeb4a195bd1b5b7f697796c78909f..ebb15571b568fd190f0cf5c0aca3dc10f691e1ea 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-swoctp.dts +++ b/arch/arm/boot/dts/qcom/sdw2100-msm8909w-swoctp.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -16,7 +16,7 @@ #include "msm8909w-swoctp.dtsi" / { - model = "Qualcomm Technologies, Inc. MSM8909W-PM8916 SWOC MTP"; + model = "Qualcomm Technologies, Inc. MSM8909W-PM8916 SWOC MTP SDW2100"; compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp"; qcom,msm-id = <245 0>, <258 0>, diff --git a/arch/arm/boot/dts/qcom/msm8909w-wtp.dts b/arch/arm/boot/dts/qcom/sdw2100-msm8909w-wtp.dts similarity index 93% rename from arch/arm/boot/dts/qcom/msm8909w-wtp.dts rename to arch/arm/boot/dts/qcom/sdw2100-msm8909w-wtp.dts index f1c41b0fd1fef9aef7bba8910d14b8c5b1c59006..94a62405b79c06709a5e1cd1e94e25e68419cab3 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-wtp.dts +++ b/arch/arm/boot/dts/qcom/sdw2100-msm8909w-wtp.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -21,7 +21,7 @@ #include "msm8909w-memory.dtsi" / { - model = "Qualcomm Technologies, Inc. MSM8909W-PM8916 MTP"; + model = "Qualcomm Technologies, Inc. MSM8909W-PM8916 MTP SDW2100"; compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp"; qcom,msm-id = <245 0>, <258 0>, diff --git a/arch/arm/boot/dts/qcom/sdw2500-apq8009w-wtp.dts b/arch/arm/boot/dts/qcom/sdw2500-apq8009w-wtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..806f20498faf9d91fd0cf5968665ea2e03fb905d --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdw2500-apq8009w-wtp.dts @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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 "msm8909-mtp.dtsi" +#include "msm8909w-gpu.dtsi" +#include "msm8909w.dtsi" +#include "apq8009w-memory.dtsi" +#include "msm8909w-pm660-mtp.dtsi" +#include "msm8909w-pm660-camera.dtsi" +#include "msm8909w-pm660-camera-sensor-wtp-v1.dtsi" +#include "spi-panel-st7789v2-qvga-cmd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009W-PM660 WTP SDW2500"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 0>, + <301 0>; + qcom,board-id = <8 0x112>; + qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>, + <0x0001011b 0x0 0x0 0x0>; +}; + +&soc { + /delete-node/ qcom,msm-cpufreq; + qcom,msm-cpufreq { + reg = <0 4>; + compatible = "qcom,msm-cpufreq"; + clocks = <&clock_cpu clk_a7ssmux>, + <&clock_cpu clk_a7ssmux>, + <&clock_cpu clk_a7ssmux>, + <&clock_cpu clk_a7ssmux>; + clock-names = "cpu0_clk", "cpu1_clk", + "cpu2_clk", "cpu3_clk"; + qcom,cpufreq-table = + < 400000 >, + < 800000 >, + < 1094400 >, + < 1267200 >; + }; + + i2c@78b7000 { /* BLSP1 QUP3 */ + synaptics@20 { + compatible = "synaptics,dsx-i2c"; + reg = <0x20>; + interrupt-parent = <&msm_gpio>; + interrupts = <98 0x2008>; + vdd_ana-supply = <&pm660_l18>; + vcc_i2c-supply = <&pm660_l13>; + synaptics,pwr-reg-name = "vdd_ana"; + synaptics,bus-reg-name = "vcc_i2c"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,irq-gpio = <&msm_gpio 98 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,irq-flags = <0x2008>; + synaptics,power-delay-ms = <200>; + synaptics,max-y-for-2d = <389>; + synaptics,wakeup-gestures-en = <1>; + synaptics,resume-in-workqueue; + synaptics,fw-name = "PR1814809-s1222_30303032.img"; + synaptics,reset-gpio = <&msm_gpio 31 0x0>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + /delete-property/ synaptics,display-coords; + /delete-property/ synaptics,panel-coords; + /delete-property/ synaptics,power-down; + /delete-property/ synaptics,disable-gpios; + /delete-property/ synaptics,is_wake; + }; + + /delete-node/ it7260@46; + }; + + spi@78B8000 { /* BLSP1 QUP4 */ + status = "ok"; + qcom,mdss_spi_client { + reg = <0>; + compatible = "qcom,mdss-spi-client"; + label = "MDSS SPI QUP4 CLIENT"; + dc-gpio = <&msm_gpio 59 0>; + spi-max-frequency = <50000000>; + }; + }; + + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; + + qcom,msm-thermal { + vdd-dig-supply = <&pm660_s2_floor_corner>; + + msm_thermal_freq: qcom,vdd-apps-rstr { + qcom,vdd-rstr-reg = "vdd-apps"; + qcom,levels = <1094400>; + qcom,freq-req; + }; + }; + + qcom,bcl { + compatible = "qcom,bcl"; + qcom,bcl-enable; + qcom,bcl-framework-interface; + qcom,bcl-freq-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,bcl-hotplug-list = <&CPU2 &CPU3>; + qcom,bcl-soc-hotplug-list = <&CPU2 &CPU3>; + qcom,ibat-monitor { + qcom,low-threshold-uamp = <1000000>; + qcom,high-threshold-uamp = <2000000>; + qcom,mitigation-freq-khz = <1094400>; + qcom,vph-high-threshold-uv = <3500000>; + qcom,vph-low-threshold-uv = <3200000>; + qcom,soc-low-threshold = <10>; + qcom,thermal-handle = <&msm_thermal_freq>; + }; + }; + + msm_digital_codec: msm-dig-codec@771c000 { + compatible = "qcom,msm-digital-codec"; + reg = <0x0771c000 0x0>; + + cdc-vdd-digital-supply = <&pm660_l11>; + qcom,cdc-vdd-digital-voltage = <1800000 1800000>; + qcom,cdc-vdd-digital-current = <5000>; + qcom,cdc-on-demand-supplies = "cdc-vdd-digital"; + + qcom,subsys-name = "modem"; + }; + + mdss_spi: qcom,mdss_spi { + compatible = "qcom,mdss-spi-display"; + label = "mdss spi panel"; + + qcom,mdss-fb-map = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + vdd-supply = <&pm660_l18>; + vddio-supply = <&pm660_l11>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + }; +}; + +&qcom_seecom { + reg = <0x87a00000 0x200000>; + reg-names = "secapp-region"; + status = "okay"; +}; + +&external_image_mem { + reg = <0x0 0x87a00000 0x0 0x0600000>; +}; + +&modem_adsp_mem { + reg = <0x0 0x88000000 0x0 0x05600000>; +}; + +&peripheral_mem { + reg = <0x0 0x8d600000 0x0 0x0600000>; +}; + +&i2c_1 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + +&i2c_4 { + status = "disabled"; +}; + +&i2c_2 { + status = "okay"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&msm_gpio 50 0x00>; + qcom,nq-ven = <&msm_gpio 52 0x00>; + qcom,nq-firm = <&msm_gpio 38 0x00>; + qcom,nq-esepwr = <&msm_gpio 49 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,clk-src = "BBCLK3"; + interrupt-parent = <&msm_gpio>; + interrupts = <50 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active","nfc_suspend"; + pinctrl-0 = <&nfcw_int_active &nfcv2k_disable_active>; + pinctrl-1 = <&nfcw_int_suspend &nfcv2k_disable_suspend>; + clocks = <&clock_rpm clk_bb_clk3_pin>; + clock-names = "ref_clk"; + }; +}; + +&i2c_5 { + status = "disabled"; +}; + +&sdhc_2 { + status = "disabled"; +}; + +&blsp1_uart1 { + status = "disabled"; +}; + +&blsp1_uart2 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console2_sleep>; +}; + +/* Pinctrl dt nodes for interrupt & reset gpio for Synaptics touch controller */ +&ts_int_active { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + }; +}; + +&ts_int_suspend { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + }; +}; + +&ts_reset_active { + mux { + pins = "gpio31"; + }; + + config { + pins = "gpio31"; + }; +}; + +&ts_reset_suspend { + mux { + pins = "gpio31"; + }; + + config { + pins = "gpio31"; + }; +}; + +&ts_release { + mux { + pins = "gpio98", "gpio31"; + }; + + config { + pins = "gpio98", "gpio31"; + }; +}; + +&firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7824900.sdhci/ + by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/7824900.sdhci/ + by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + }; + }; +}; + +&mdss_dsi0{ + qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; + qcom,platform-bklight-en-gpio = <&msm_gpio 37 0>; +}; + +&spi_st7789v2_qvga_cmd { + qcom,panel-supply-entries = <&dsi_pm660_panel_pwr_supply>; + qcom,mdss-spi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-spi-bl-pmic-bank-select = <0>; + qcom,cont-splash-enabled; +}; + +&mdss_spi { + qcom,spi-pref-prim-pan = <&spi_st7789v2_qvga_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_te_active>; + pinctrl-1 = <&mdss_te_suspend>; + + qcom,platform-te-gpio = <&msm_gpio 24 0>; + qcom,platform-reset-gpio = <&msm_gpio 25 0>; + qcom,platform-spi-dc-gpio = <&msm_gpio 59 0>; + + vdd-supply = <&pm660_l18>; + vddio-supply = <&pm660_l11>; +}; + +&dai_mi2s3 { + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; +}; + +&audio_codec_mtp { + compatible = "qcom,msm8909-audio-codec"; + qcom,model = "msm8909w-wtp-snd-card"; + qcom,msm-ext-pa = "quaternary"; + qcom,split-a2dp; + qcom,audio-routing = + "CDC_CONN", "MCLK", + "QUAT_MI2S_RX", "DIGIT_REGULATOR", + "TX_I2S_CLK", "DIGIT_REGULATOR", + "DMIC1", "Digital Mic1", + "DMIC2", "Digital Mic2"; + qcom,msm-gpios = + "quat_i2s", + "dmic"; + qcom,pinctrl-names = + "all_off", + "quat_i2s_act", + "dmic_act", + "quat_i2s_dmic_act"; + pinctrl-names = + "all_off", + "quat_i2s_act", + "dmic_act", + "quat_i2s_dmic_act"; + pinctrl-0 = <&quat_mi2s_sleep &quat_mi2s_din_sleep + &cdc_dmic0_clk_sus &cdc_dmic0_data_sus>; + pinctrl-1 = <&quat_mi2s_active &quat_mi2s_din_active + &cdc_dmic0_clk_sus &cdc_dmic0_data_sus>; + pinctrl-2 = <&quat_mi2s_sleep &quat_mi2s_din_sleep + &cdc_dmic0_clk_act &cdc_dmic0_data_act>; + pinctrl-3 = <&quat_mi2s_active &quat_mi2s_din_active + &cdc_dmic0_clk_act &cdc_dmic0_data_act>; + /delete-property/qcom,cdc-us-euro-gpios; + + asoc-codec = <&stub_codec>, <&msm_digital_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec"; +}; + +&led_flash0{ + status = "disabled"; +}; + +&actuator0{ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/sdw2500-msm8909w-wtp.dts b/arch/arm/boot/dts/qcom/sdw2500-msm8909w-wtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..9b5d52a04dad6a887b4d854f239499efd03b1218 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdw2500-msm8909w-wtp.dts @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * 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 "msm8909-mtp.dtsi" +#include "msm8909w-gpu.dtsi" +#include "msm8909w.dtsi" +#include "msm8909w-memory.dtsi" +#include "msm8909w-pm660-mtp.dtsi" +#include "msm8909w-pm660-camera.dtsi" +#include "msm8909w-pm660-camera-sensor-wtp-v1.dtsi" +#include "spi-panel-st7789v2-qvga-cmd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8909W-PM660 WTP SDW2500"; + compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp"; + qcom,msm-id = <245 0>, + <258 0>, + <275 0>, + <300 0>; + qcom,board-id = <8 0x112>; + qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>, + <0x0001011b 0x0 0x0 0x0>; +}; + +&soc { + /delete-node/ qcom,msm-cpufreq; + qcom,msm-cpufreq { + reg = <0 4>; + compatible = "qcom,msm-cpufreq"; + clocks = <&clock_cpu clk_a7ssmux>, + <&clock_cpu clk_a7ssmux>, + <&clock_cpu clk_a7ssmux>, + <&clock_cpu clk_a7ssmux>; + clock-names = "cpu0_clk", "cpu1_clk", + "cpu2_clk", "cpu3_clk"; + qcom,cpufreq-table = + < 400000 >, + < 800000 >, + < 1094400 >, + < 1267200 >; + }; + + i2c@78b7000 { /* BLSP1 QUP3 */ + synaptics@20 { + compatible = "synaptics,dsx-i2c"; + reg = <0x20>; + interrupt-parent = <&msm_gpio>; + interrupts = <98 0x2008>; + vdd_ana-supply = <&pm660_l18>; + vcc_i2c-supply = <&pm660_l13>; + synaptics,pwr-reg-name = "vdd_ana"; + synaptics,bus-reg-name = "vcc_i2c"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,irq-gpio = <&msm_gpio 98 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,irq-flags = <0x2008>; + synaptics,power-delay-ms = <200>; + synaptics,max-y-for-2d = <389>; + synaptics,wakeup-gestures-en = <1>; + synaptics,resume-in-workqueue; + synaptics,fw-name = "PR1814809-s1222_30303032.img"; + synaptics,reset-gpio = <&msm_gpio 31 0x0>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + /delete-property/ synaptics,display-coords; + /delete-property/ synaptics,panel-coords; + /delete-property/ synaptics,power-down; + /delete-property/ synaptics,disable-gpios; + /delete-property/ synaptics,is_wake; + }; + + /delete-node/ it7260@46; + }; + + spi@78B8000 { /* BLSP1 QUP4 */ + status = "ok"; + qcom,mdss_spi_client { + reg = <0>; + compatible = "qcom,mdss-spi-client"; + label = "MDSS SPI QUP4 CLIENT"; + dc-gpio = <&msm_gpio 59 0>; + spi-max-frequency = <50000000>; + }; + }; + + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; + + qcom,msm-thermal { + vdd-dig-supply = <&pm660_s2_floor_corner>; + + msm_thermal_freq: qcom,vdd-apps-rstr { + qcom,vdd-rstr-reg = "vdd-apps"; + qcom,levels = <1094400>; + qcom,freq-req; + }; + }; + + qcom,bcl { + compatible = "qcom,bcl"; + qcom,bcl-enable; + qcom,bcl-framework-interface; + qcom,bcl-freq-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,bcl-hotplug-list = <&CPU2 &CPU3>; + qcom,bcl-soc-hotplug-list = <&CPU2 &CPU3>; + qcom,ibat-monitor { + qcom,low-threshold-uamp = <1000000>; + qcom,high-threshold-uamp = <2000000>; + qcom,mitigation-freq-khz = <1094400>; + qcom,vph-high-threshold-uv = <3500000>; + qcom,vph-low-threshold-uv = <3200000>; + qcom,soc-low-threshold = <10>; + qcom,thermal-handle = <&msm_thermal_freq>; + }; + }; + + msm_digital_codec: msm-dig-codec@771c000 { + compatible = "qcom,msm-digital-codec"; + reg = <0x0771c000 0x0>; + + cdc-vdd-digital-supply = <&pm660_l11>; + qcom,cdc-vdd-digital-voltage = <1800000 1800000>; + qcom,cdc-vdd-digital-current = <5000>; + qcom,cdc-on-demand-supplies = "cdc-vdd-digital"; + + qcom,subsys-name = "modem"; + }; + + mdss_spi: qcom,mdss_spi { + compatible = "qcom,mdss-spi-display"; + label = "mdss spi panel"; + + qcom,mdss-fb-map = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + vdd-supply = <&pm660_l18>; + vddio-supply = <&pm660_l11>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + }; +}; + +&qcom_seecom { + reg = <0x87a00000 0x200000>; + reg-names = "secapp-region"; + status = "okay"; +}; + +&external_image_mem { + reg = <0x0 0x87a00000 0x0 0x0600000>; +}; + +&modem_adsp_mem { + reg = <0x0 0x88000000 0x0 0x05600000>; +}; + +&peripheral_mem { + reg = <0x0 0x8d600000 0x0 0x0600000>; +}; + +&i2c_1 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + +&i2c_4 { + status = "disabled"; +}; + +&i2c_2 { + status = "okay"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&msm_gpio 50 0x00>; + qcom,nq-ven = <&msm_gpio 52 0x00>; + qcom,nq-firm = <&msm_gpio 38 0x00>; + qcom,nq-esepwr = <&msm_gpio 49 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,clk-src = "BBCLK3"; + interrupt-parent = <&msm_gpio>; + interrupts = <50 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active","nfc_suspend"; + pinctrl-0 = <&nfcw_int_active &nfcv2k_disable_active>; + pinctrl-1 = <&nfcw_int_suspend &nfcv2k_disable_suspend>; + clocks = <&clock_rpm clk_bb_clk3_pin>; + clock-names = "ref_clk"; + }; +}; + +&i2c_5 { + status = "disabled"; +}; + +&sdhc_2 { + status = "disabled"; +}; + +&blsp1_uart1 { + status = "disabled"; +}; + +&blsp1_uart2 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console2_sleep>; +}; + +/* Pinctrl dt nodes for interrupt & reset gpio for Synaptics touch controller */ +&ts_int_active { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + }; +}; + +&ts_int_suspend { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + }; +}; + +&ts_reset_active { + mux { + pins = "gpio31"; + }; + + config { + pins = "gpio31"; + }; +}; + +&ts_reset_suspend { + mux { + pins = "gpio31"; + }; + + config { + pins = "gpio31"; + }; +}; + +&ts_release { + mux { + pins = "gpio98", "gpio31"; + }; + + config { + pins = "gpio98", "gpio31"; + }; +}; + +&firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7824900.sdhci/ + by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/7824900.sdhci/ + by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + }; + }; +}; + +&mdss_dsi0{ + qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; + qcom,platform-bklight-en-gpio = <&msm_gpio 37 0>; +}; + +&spi_st7789v2_qvga_cmd { + qcom,panel-supply-entries = <&dsi_pm660_panel_pwr_supply>; + qcom,mdss-spi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-spi-bl-pmic-bank-select = <0>; + qcom,cont-splash-enabled; +}; + +&mdss_spi { + qcom,spi-pref-prim-pan = <&spi_st7789v2_qvga_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_te_active>; + pinctrl-1 = <&mdss_te_suspend>; + + qcom,platform-te-gpio = <&msm_gpio 24 0>; + qcom,platform-reset-gpio = <&msm_gpio 25 0>; + qcom,platform-spi-dc-gpio = <&msm_gpio 59 0>; + + vdd-supply = <&pm660_l18>; + vddio-supply = <&pm660_l11>; +}; + +&dai_mi2s3 { + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; +}; + +&audio_codec_mtp { + compatible = "qcom,msm8909-audio-codec"; + qcom,model = "msm8909w-wtp-snd-card"; + qcom,msm-ext-pa = "quaternary"; + qcom,split-a2dp; + qcom,audio-routing = + "CDC_CONN", "MCLK", + "QUAT_MI2S_RX", "DIGIT_REGULATOR", + "TX_I2S_CLK", "DIGIT_REGULATOR", + "DMIC1", "Digital Mic1", + "DMIC2", "Digital Mic2"; + qcom,msm-gpios = + "quat_i2s", + "dmic"; + qcom,pinctrl-names = + "all_off", + "quat_i2s_act", + "dmic_act", + "quat_i2s_dmic_act"; + pinctrl-names = + "all_off", + "quat_i2s_act", + "dmic_act", + "quat_i2s_dmic_act"; + pinctrl-0 = <&quat_mi2s_sleep &quat_mi2s_din_sleep + &cdc_dmic0_clk_sus &cdc_dmic0_data_sus>; + pinctrl-1 = <&quat_mi2s_active &quat_mi2s_din_active + &cdc_dmic0_clk_sus &cdc_dmic0_data_sus>; + pinctrl-2 = <&quat_mi2s_sleep &quat_mi2s_din_sleep + &cdc_dmic0_clk_act &cdc_dmic0_data_act>; + pinctrl-3 = <&quat_mi2s_active &quat_mi2s_din_active + &cdc_dmic0_clk_act &cdc_dmic0_data_act>; + /delete-property/qcom,cdc-us-euro-gpios; + + asoc-codec = <&stub_codec>, <&msm_digital_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec"; +}; + +&led_flash0{ + status = "disabled"; +}; + +&actuator0{ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/sdw3100-apq8009w-alpha.dts b/arch/arm/boot/dts/qcom/sdw3100-apq8009w-alpha.dts new file mode 100644 index 0000000000000000000000000000000000000000..92f5b7b8b305917f1530ff536d22053e987e91b7 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdw3100-apq8009w-alpha.dts @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * 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 "msm8909-mtp.dtsi" +#include "msm8909w-gpu.dtsi" +#include "msm8909w.dtsi" +#include "msm8909w-pm660-mtp.dtsi" +#include "apq8009w-bg-memory.dtsi" +#include "msm8909-audio-bg_codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG Alpha SDW3100"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 0>, + <301 0>; + qcom,board-id = <8 0x113>; + qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>, + <0x0001011b 0x0 0x0 0x0>; +}; + +&soc { + i2c@78b9000 { /* BLSP1 QUP5 */ + focaltech@38 { + compatible = "focaltech,fts"; + reg = <0x38>; + interrupt-parent = <&msm_gpio>; + interrupts = <98 0x2008>; + vdd-supply = <&pm660_l18>; + vcc-i2c-supply = <&pm660_l13>; + focaltech,irq-gpio = <&msm_gpio 98 0x2008>; + focaltech,reset-gpio = <&msm_gpio 16 0x00>;/**/ + focaltech,max-touch-number = <5>; + focaltech,display-coords = <0 0 390 390>;/**/ + focaltech,wakeup-gestures-en; + }; + + /delete-node/ it7260@46; + /delete-node/ synaptics@20; + }; + + qcom,blackghost { + compatible = "qcom,pil-blackghost"; + + qcom,pil-force-shutdown; + qcom,firmware-name = "bg-wear"; + /* GPIO inputs from blackghost */ + qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; + qcom,bg2ap-errfatal-gpio = <&msm_gpio 95 0>; + /* GPIO output to blackghost */ + qcom,ap2bg-status-gpio = <&msm_gpio 17 0>; + qcom,ap2bg-errfatal-gpio = <&msm_gpio 23 0>; + }; + + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; + + qcom,glink-bgcom-xprt-bg { + compatible = "qcom,glink-bgcom-xprt"; + label = "bg"; + qcom,qos-config = <&glink_qos_bg>; + qcom,ramp-time = <0x10>, + <0x20>, + <0x30>, + <0x40>; + }; + + glink_qos_bg: qcom,glink-qos-config-bg { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x80 0x0>, + <0x70 0x1>, + <0x60 0x2>, + <0x50 0x3>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-bg-daemon { + qcom,glinkpkt-transport = "bgcom"; + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "bg-daemon"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_daemon"; + }; + + qcom,glinkpkt-bg-display-ctrl { + qcom,glinkpkt-transport = "bgcom"; + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "display-ctrl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_display_ctrl"; + }; + + qcom,glinkpkt-bg-display-data { + qcom,glinkpkt-transport = "bgcom"; + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "display-data"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data"; + }; + + qcom,glinkpkt-bg-rsb-ctrl { + qcom,glinkpkt-transport = "bgcom"; + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "RSB_CTRL"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl"; + }; + }; + + spi@78B8000 { /* BLSP1 QUP4 */ + status = "ok"; + qcom,bg-spi { + compatible = "qcom,bg-spi"; + reg = <0>; + spi-max-frequency = <16000000>; + interrupt-parent = <&msm_gpio>; + qcom,irq-gpio = <&msm_gpio 110 1>; + }; + }; + + qcom,bg-rsb { + compatible = "qcom,bg-rsb"; + vdd-ldo1-supply = <&pm660_l11>; + vdd-ldo2-supply = <&pm660_l15>; + }; + + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; +}; + +&i2c_1 { + status = "okay"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&msm_gpio 50 0x00>; + qcom,nq-ven = <&msm_gpio 36 0x00>; + qcom,nq-firm = <&msm_gpio 38 0x00>; + qcom,nq-esepwr = <&msm_gpio 49 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,clk-src = "BBCLK3"; + interrupt-parent = <&msm_gpio>; + interrupts = <50 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active","nfc_suspend"; + pinctrl-0 = <&nfcw_int_active &nfcw_disable_active>; + pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>; + clock-names = "ref_clk"; + }; +}; + +&spi_0 { + status = "disabled"; +}; + +&i2c_3 { + status = "disabled"; +}; + +&i2c_4 { + status = "disabled"; +}; + +&i2c_2 { + status = "disabled"; +}; + +&sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_data_off { + config { + pins = "sdc1_data"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdhc_2 { + status = "disabled"; +}; + +&audio_codec_mtp { + status = "disabled"; +}; + +&audio_codec_bg { + status = "ok"; +}; + +&bg_cdc { + status = "ok"; + vdd-spkr-supply = <&pm660_l11>; +}; + +&blsp1_uart1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_sleep>; +}; + +/* Pinctrl dt nodes for interrupt and reset gpio for Synaptics controller */ +&ts_int_active { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + }; +}; + +&ts_int_suspend { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + }; +}; + +&ts_reset_active { + mux { + pins = "gpio16"; + }; + + config { + pins = "gpio16"; + }; +}; + +&ts_reset_suspend { + mux { + pins = "gpio16"; + }; + + config { + pins = "gpio16"; + }; +}; + +&ts_release { + mux { + pins = "gpio98", "gpio16"; + }; + + config { + pins = "gpio98", "gpio16"; + }; +}; + +&pm660_charger { + qcom,micro-usb; +}; + +&spi4_cs0_active { + mux { + pins = "gpio14"; + function = "blsp_spi4"; + }; + config { + pins = "gpio14"; + drive-strength = <2>; + bias-disable; /* No PULL */ + output-high; + }; +}; diff --git a/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm/boot/dts/qcom/sdw3100-apq8009w-wtp.dts similarity index 58% rename from arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v2.dts rename to arch/arm/boot/dts/qcom/sdw3100-apq8009w-wtp.dts index 46a3878d219b5beb4d1bdf3fccddf840dc0f1731..c5c7e59914b224918f193421aa850ecb324cc815 100644 --- a/arch/arm/boot/dts/qcom/apq8009w-bg-wtp-v2.dts +++ b/arch/arm/boot/dts/qcom/sdw3100-apq8009w-wtp.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * 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 @@ -17,11 +17,11 @@ #include "msm8909w-gpu.dtsi" #include "msm8909w.dtsi" #include "msm8909w-pm660-mtp.dtsi" -#include "apq8009w-memory.dtsi" -#include "msm8909-regulator.dtsi" +#include "apq8009w-bg-memory.dtsi" +#include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BLACKGHOST WTP"; + model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG WTP SDW3100"; compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; @@ -52,9 +52,11 @@ synaptics,power-delay-ms = <200>; synaptics,reset-delay-ms = <200>; synaptics,max-y-for-2d = <389>; + synaptics,bus-lpm-cur-uA = <450>; + synaptics,do-not-disable-regulators; + synaptics,wakeup-gestures-en; synaptics,resume-in-workqueue; - synaptics,x-flip; - synaptics,y-flip; + synaptics,fw-name = "PR1814809-s1222_30303032.img"; /delete-property/ synaptics,reset-gpio; /delete-property/ synaptics,display-coords; /delete-property/ synaptics,panel-coords; @@ -69,6 +71,7 @@ qcom,blackghost { compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; qcom,firmware-name = "bg-wear"; /* GPIO inputs from blackghost */ qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; @@ -125,6 +128,13 @@ qcom,glinkpkt-ch-name = "display-data"; qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data"; }; + + qcom,glinkpkt-bg-rsb-ctrl { + qcom,glinkpkt-transport = "bgcom"; + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "RSB_CTRL"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl"; + }; }; spi@78B8000 { /* BLSP1 QUP4 */ @@ -132,15 +142,45 @@ qcom,bg-spi { compatible = "qcom,bg-spi"; reg = <0>; - spi-max-frequency = <19200000>; + spi-max-frequency = <16000000>; interrupt-parent = <&msm_gpio>; qcom,irq-gpio = <&msm_gpio 110 1>; }; }; + + qcom,bg-rsb { + compatible = "qcom,bg-rsb"; + vdd-ldo1-supply = <&pm660_l11>; + vdd-ldo2-supply = <&pm660_l15>; + }; + + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; }; &i2c_1 { - status = "disabled"; + status = "okay"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&msm_gpio 50 0x00>; + qcom,nq-ven = <&msm_gpio 36 0x00>; + qcom,nq-firm = <&msm_gpio 38 0x00>; + qcom,nq-esepwr = <&msm_gpio 49 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,clk-src = "BBCLK3"; + interrupt-parent = <&msm_gpio>; + interrupts = <50 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active","nfc_suspend"; + pinctrl-0 = <&nfcw_int_active &nfcw_disable_active>; + pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>; + clock-names = "ref_clk"; + }; }; &spi_0 { @@ -159,12 +199,118 @@ status = "disabled"; }; +&sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_data_off { + config { + pins = "sdc1_data"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + &sdhc_2 { status = "disabled"; }; +&audio_codec_mtp { + status = "disabled"; +}; + +&audio_codec_bg { + status = "ok"; +}; + +&bg_cdc { + status = "ok"; + vdd-spkr-supply = <&pm660_l11>; +}; + &blsp1_uart1 { status = "ok"; pinctrl-names = "default"; pinctrl-0 = <&uart_console_sleep>; }; + +/* Pinctrl dt nodes for interrupt and reset gpio for Synaptics controller */ +&ts_int_active { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + }; +}; + +&ts_int_suspend { + mux { + pins = "gpio98"; + }; + + config { + pins = "gpio98"; + /delete-property/ bias-pull-down; + bias-disable; /* No PULL */ + }; +}; + +&ts_reset_active { + mux { + pins = "gpio16"; + }; + + config { + pins = "gpio16"; + }; +}; + +&ts_reset_suspend { + mux { + pins = "gpio16"; + }; + + config { + pins = "gpio16"; + }; +}; + +&ts_release { + mux { + pins = "gpio98", "gpio16"; + }; + + config { + pins = "gpio98", "gpio16"; + }; +}; + +&spi4_cs0_active { + mux { + pins = "gpio14"; + function = "blsp_spi4"; + }; + config { + pins = "gpio14"; + drive-strength = <2>; + bias-disable; /* No PULL */ + output-high; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm/boot/dts/qcom/sdw3100-msm8909w-wtp.dts similarity index 69% rename from arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v2.dts rename to arch/arm/boot/dts/qcom/sdw3100-msm8909w-wtp.dts index 9bff17303dc519cc557cf330dd1b81ca9e441650..6af3bcdef8beb68efeb3a0f9f63fba36687a8e2b 100644 --- a/arch/arm/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm/boot/dts/qcom/sdw3100-msm8909w-wtp.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * 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 @@ -16,12 +16,12 @@ #include "msm8909-mtp.dtsi" #include "msm8909w-gpu.dtsi" #include "msm8909w.dtsi" -#include "msm8909w-memory.dtsi" +#include "msm8909w-bg-memory.dtsi" #include "msm8909w-pm660-mtp.dtsi" -#include "msm8909-regulator.dtsi" +#include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BLACKGHOST WTP"; + model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BG WTP SDW3100"; compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp"; qcom,msm-id = <245 0>, <258 0>, @@ -54,9 +54,11 @@ synaptics,power-delay-ms = <200>; synaptics,reset-delay-ms = <200>; synaptics,max-y-for-2d = <389>; + synaptics,bus-lpm-cur-uA = <450>; + synaptics,do-not-disable-regulators; + synaptics,wakeup-gestures-en; synaptics,resume-in-workqueue; - synaptics,x-flip; - synaptics,y-flip; + synaptics,fw-name = "PR1814809-s1222_30303032.img"; /delete-property/ synaptics,reset-gpio; /delete-property/ synaptics,display-coords; /delete-property/ synaptics,panel-coords; @@ -71,6 +73,7 @@ qcom,blackghost { compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; qcom,firmware-name = "bg-wear"; /* GPIO inputs from blackghost */ qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; @@ -127,6 +130,13 @@ qcom,glinkpkt-ch-name = "display-data"; qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data"; }; + + qcom,glinkpkt-bg-rsb-ctrl { + qcom,glinkpkt-transport = "bgcom"; + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "RSB_CTRL"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl"; + }; }; spi@78B8000 { /* BLSP1 QUP4 */ @@ -134,7 +144,7 @@ qcom,bg-spi { compatible = "qcom,bg-spi"; reg = <0>; - spi-max-frequency = <19200000>; + spi-max-frequency = <16000000>; interrupt-parent = <&msm_gpio>; qcom,irq-gpio = <&msm_gpio 110 1>; }; @@ -150,6 +160,19 @@ }; }; + qcom,bg-rsb { + compatible = "qcom,bg-rsb"; + vdd-ldo1-supply = <&pm660_l11>; + vdd-ldo2-supply = <&pm660_l15>; + }; + + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; + qcom,bcl { compatible = "qcom,bcl"; qcom,bcl-enable; @@ -169,10 +192,41 @@ }; }; -&i2c_1 { +&audio_codec_mtp { status = "disabled"; }; +&audio_codec_bg { + status = "ok"; +}; + +&bg_cdc { + status = "ok"; + vdd-spkr-supply = <&pm660_l11>; +}; + +&i2c_1 { + status = "okay"; + qcom,clk-freq-out = <400000>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&msm_gpio 50 0x00>; + qcom,nq-ven = <&msm_gpio 36 0x00>; + qcom,nq-firm = <&msm_gpio 38 0x00>; + qcom,nq-esepwr = <&msm_gpio 49 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,clk-src = "BBCLK3"; + interrupt-parent = <&msm_gpio>; + interrupts = <50 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active","nfc_suspend"; + pinctrl-0 = <&nfcw_int_active &nfcw_disable_active>; + pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>; + clock-names = "ref_clk"; + }; +}; + &spi_0 { status = "disabled"; }; @@ -189,6 +243,33 @@ status = "disabled"; }; +&sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_data_off { + config { + pins = "sdc1_data"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + &sdhc_2 { status = "disabled"; }; @@ -217,6 +298,8 @@ config { pins = "gpio98"; + /delete-property/ bias-pull-down; + bias-disable; /* No PULL */ }; }; @@ -249,3 +332,16 @@ pins = "gpio98", "gpio16"; }; }; + +&spi4_cs0_active { + mux { + pins = "gpio14"; + function = "blsp_spi4"; + }; + config { + pins = "gpio14"; + drive-strength = <2>; + bias-disable; /* No PULL */ + output-high; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdx20.dtsi b/arch/arm/boot/dts/qcom/sdx20.dtsi index e7cda3babf4e71b13f93a4c20d4a728bc33bdf93..ac1febaf39ccac620f69c729df35ce3e7771c25b 100644 --- a/arch/arm/boot/dts/qcom/sdx20.dtsi +++ b/arch/arm/boot/dts/qcom/sdx20.dtsi @@ -110,6 +110,7 @@ compatible = "qcom,pil-tz-generic"; qcom,pas-id = <0xf>; qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; }; qcom,msm-cpufreq { diff --git a/arch/arm/boot/dts/qcom/spi-panel-st7789v2-qvga-cmd.dtsi b/arch/arm/boot/dts/qcom/spi-panel-st7789v2-qvga-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c65876f97b58dc3bf3da95d19896cf4ef3159f4e --- /dev/null +++ b/arch/arm/boot/dts/qcom/spi-panel-st7789v2-qvga-cmd.dtsi @@ -0,0 +1,67 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +&mdss_mdp { + spi_st7789v2_qvga_cmd: qcom,mdss_spi_st7789v2_qvga_cmd { + qcom,mdss-spi-panel-name = + "st7789v2 qvga command mode spi panel"; + qcom,mdss-spi-panel-destination = "display_1"; + qcom,mdss-spi-panel-controller = <&mdss_spi>; + qcom,mdss-spi-panel-framerate = <27>; + qcom,mdss-spi-panel-width = <240>; + qcom,mdss-spi-panel-height = <240>; + qcom,mdss-spi-h-front-porch = <79>; + qcom,mdss-spi-h-back-porch = <59>; + qcom,mdss-spi-h-pulse-width = <60>; + qcom,mdss-spi-v-back-porch = <10>; + qcom,mdss-spi-v-front-porch = <7>; + qcom,mdss-spi-v-pulse-width = <2>; + qcom,mdss-spi-h-left-border = <0>; + qcom,mdss-spi-h-right-border = <0>; + qcom,mdss-spi-v-top-border = <0>; + qcom,mdss-spi-v-bottom-border = <0>; + qcom,mdss-spi-bpp = <16>; + qcom,mdss-spi-on-command = [ + 96 01 11 + 00 02 36 00 + 00 02 3A 05 + 00 02 35 00 + 00 06 B2 0C 0C 00 33 33 + 00 02 B7 75 + 00 02 BB 3D + 00 02 C2 01 + 00 02 C3 19 + 00 02 04 20 + 00 02 C6 0F + 00 03 D0 A4 A1 + 00 0F E0 70 04 08 09 09 05 2A 33 + 41 07 13 13 29 2F + 00 0F E1 70 03 09 0A 09 06 2B 34 + 41 07 12 14 28 2E + 00 01 21 + 00 01 29 + 00 05 2A 00 00 00 EF + 00 05 2B 00 00 00 EF + 00 01 2C]; + qcom,mdss-spi-off-command = [20 01 28 + 20 01 10]; + qcom,mdss-spi-bl-min-level = <1>; + qcom,mdss-spi-bl-max-level = <255>; + qcom,mdss-spi-bl-pmic-control-type = "bl_gpio_pulse"; + qcom,mdss-spi-reset-sequence = <1 20>, <0 1>, <1 20>; + qcom,mdss-spi-panel-status-check-mode = "reg_read"; + qcom,mdss-spi-panel-status-reg = /bits/ 8 <0x0a>; + qcom,mdss-spi-panel-status-read-length = <1>; + qcom,mdss-spi-panel-max-error-count = <1>; + qcom,mdss-spi-panel-status-value = /bits/ 8 <0x9c>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts index 8ad7ca7f974330e7ad7898b4886d652d08060c45..05c977e1c5234c6136a5a2c532cc41f1c7cea8cd 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts @@ -111,10 +111,9 @@ asoc-codec-names = "msm-stub-codec.1"; }; - qcom,msm-audio-ion { - compatible = "qcom,msm-audio-ion"; + qcom,msm-audio-ion-vm { + compatible = "qcom,msm-audio-ion-vm"; qcom,smmu-enabled; - qcom,smmu-sid = <1>; }; pcm0: qcom,msm-pcm { diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index e20affe156c1c3349be801c446b48f944bcc5e98..2a4e5473241957f317b24cf33fade3d02ac7fce1 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -978,8 +978,11 @@ compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 516d62ac25a9948a3a1088b4e675d15545d7b6ae..297a19de3c669a394abc47cf3c4b57238e082f00 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -1001,8 +1001,11 @@ compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, diff --git a/arch/arm/boot/dts/s5pv210.dtsi b/arch/arm/boot/dts/s5pv210.dtsi index 8344a0ee2b86f554d4d674522fc0403d4edfb310..b03fe747b98ca64a718e7c7c9f1192ed6ded6d43 100644 --- a/arch/arm/boot/dts/s5pv210.dtsi +++ b/arch/arm/boot/dts/s5pv210.dtsi @@ -461,6 +461,7 @@ compatible = "samsung,exynos4210-ohci"; reg = <0xec300000 0x100>; interrupts = <23>; + interrupt-parent = <&vic1>; clocks = <&clocks CLK_USB_HOST>; clock-names = "usbhost"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 4472fd92685c4b84d54e9dfb0041646f709e3477..34ad313695472b2c686844855a1d192694d2d5d9 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -643,7 +643,7 @@ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0xfffec600 0x100>; - interrupts = <1 13 0xf04>; + interrupts = <1 13 0xf01>; clocks = <&mpu_periph_clk>; }; diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index d42c84b1df8d02aa4199ac01e68ee547458576d1..9cff28d476bea6c7c9be46b5356c3ad7db9d0347 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -349,7 +349,7 @@ spi0: spi@e0100000 { status = "okay"; num-cs = <3>; - cs-gpios = <&gpio1 7 0>, <&spics 0>, <&spics 1>; + cs-gpios = <&gpio1 7 0>, <&spics 0 0>, <&spics 1 0>; stmpe610@0 { compatible = "st,stmpe610"; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index 13e1aa33daa2e379bde1b3cbc2882b1816ba3a39..69bc407b4a5a87fd1a9bbaf70591218ffb30dca1 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -141,8 +141,8 @@ reg = <0xb4100000 0x1000>; interrupts = <0 105 0x4>; status = "disabled"; - dmas = <&dwdma0 0x600 0 0 1>, /* 0xC << 11 */ - <&dwdma0 0x680 0 1 0>; /* 0xD << 7 */ + dmas = <&dwdma0 12 0 1>, + <&dwdma0 13 1 0>; dma-names = "tx", "rx"; }; diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index a6eb5436d26d45f62f336b86fb0be8f06ea560bd..e6db110e991ba73610f5877b5a8244d68a989485 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -100,7 +100,7 @@ reg = <0xb2800000 0x1000>; interrupts = <0 29 0x4>; status = "disabled"; - dmas = <&dwdma0 0 0 0 0>; + dmas = <&dwdma0 0 0 0>; dma-names = "data"; }; @@ -288,8 +288,8 @@ #size-cells = <0>; interrupts = <0 31 0x4>; status = "disabled"; - dmas = <&dwdma0 0x2000 0 0 0>, /* 0x4 << 11 */ - <&dwdma0 0x0280 0 0 0>; /* 0x5 << 7 */ + dmas = <&dwdma0 4 0 0>, + <&dwdma0 5 0 0>; dma-names = "tx", "rx"; }; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index 9f60a7b6a42bf42e0b84584d94b48b7888ea58a0..bd379034993ca46164aad23bc311ba94f346484f 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -194,6 +194,7 @@ rtc@fc900000 { compatible = "st,spear600-rtc"; reg = <0xfc900000 0x1000>; + interrupt-parent = <&vic0>; interrupts = <10>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index a1b682ea01bd70ab94025cd12a4d5205d45f9db7..224a7605877e737efe1026f3ccddce5ad1b372b1 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -200,6 +200,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x70>; + reset-gpio = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/configs/apq8053_IoE-perf_defconfig b/arch/arm/configs/apq8053_IoE-perf_defconfig index e816739bd31f0fc1c954e9ce64e10ec5f8741cf3..5eaf7b55682594058811313351220bf64c05d5a6 100644 --- a/arch/arm/configs/apq8053_IoE-perf_defconfig +++ b/arch/arm/configs/apq8053_IoE-perf_defconfig @@ -4,6 +4,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y @@ -600,6 +603,9 @@ CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y @@ -608,7 +614,4 @@ CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM_NEON=y -CONFIG_CRYPTO_SHA2_ARM_CE=y CONFIG_CRYPTO_SHA512_ARM_NEON=y -CONFIG_CRYPTO_AES_ARM_BS=y -CONFIG_CRYPTO_AES_ARM_CE=y diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index e21ef830a48365a06db80d0127fa5a3f55f17f71..8cd6eae4e89b226f721e235ed48f80cb4639b9c7 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -33,6 +33,10 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_NET_KEY=y CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y CONFIG_RFKILL_REGULATOR=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y @@ -170,6 +174,9 @@ CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_CRAMFS=y CONFIG_ROMFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index e6b0007355f883eaca70e4ce4df5b6fcc9818ae4..0dfa0029470f2daa984fc10cc885937fb3d7dbd5 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -146,9 +146,11 @@ CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_CHIPIDEA_ULPI=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m +CONFIG_USB_ULPI_BUS=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y diff --git a/arch/arm/configs/mdm9607-perf_defconfig b/arch/arm/configs/mdm9607-perf_defconfig index b826967a072afe83f290f3f30c870591a8211396..fd232e7e83bc744a53ba4d2f627caf6f93f631d0 100644 --- a/arch/arm/configs/mdm9607-perf_defconfig +++ b/arch/arm/configs/mdm9607-perf_defconfig @@ -26,6 +26,7 @@ CONFIG_PREEMPT=y CONFIG_AEABI=y # CONFIG_HW_PERF_EVENTS is not set CONFIG_CMA=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_AUTO_ZRELADDR=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y @@ -34,6 +35,8 @@ CONFIG_VFP=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_PM_RUNTIME=y CONFIG_NET=y CONFIG_DISABLE_NET_SKB_FRAG_CACHE=y @@ -167,6 +170,7 @@ CONFIG_CFG80211_WEXT=y CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER_NODE_ID=2 CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=4 CONFIG_MTD=y @@ -214,6 +218,10 @@ CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m +CONFIG_BOSCH_DRIVER_LOG_FUNC=y +CONFIG_SENSORS_SMI_ACC2X2=y +CONFIG_SENSORS_SMI_ACC2X2_ENABLE_INT2=y +CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING=y CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM_HS=y @@ -257,6 +265,12 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MDM9607=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_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -334,17 +348,25 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_SPM=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_IPC_ROUTER_USB_XPRT=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_TRACER_PKT=y CONFIG_MSM_BAM_DMUX=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_IIO=y -CONFIG_IIO_BUFFER=y CONFIG_IIO_BUFFER_CB=y CONFIG_SENSORS_BMI160_IIO=y CONFIG_SENSORS_BMI160_IIO_RING=y CONFIG_ENABLE_ACC_GYRO_BUFFERING=y +CONFIG_INV_MPU_IIO_IAM20680=y +CONFIG_INV_MPU_IIO_I2C=y +CONFIG_INV_MPU_IIO_SPI=y +CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING=y +CONFIG_INV_TESTING=y +CONFIG_IIO_ST_ASM330LHH=y +CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_FUSE=y diff --git a/arch/arm/configs/mdm9607_defconfig b/arch/arm/configs/mdm9607_defconfig index f0d85ba839c549833750edc1cdbc05f260c621cf..443f0390200aef7e51b8455ea7b2d8d03672074c 100644 --- a/arch/arm/configs/mdm9607_defconfig +++ b/arch/arm/configs/mdm9607_defconfig @@ -26,6 +26,7 @@ CONFIG_PREEMPT=y CONFIG_AEABI=y # CONFIG_HW_PERF_EVENTS is not set CONFIG_CMA=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_AUTO_ZRELADDR=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y @@ -34,6 +35,8 @@ CONFIG_VFP=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_PM_RUNTIME=y CONFIG_NET=y CONFIG_DISABLE_NET_SKB_FRAG_CACHE=y @@ -166,6 +169,7 @@ CONFIG_CFG80211_WEXT=y CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER_NODE_ID=2 CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=4 CONFIG_MTD=y @@ -213,6 +217,10 @@ CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m +CONFIG_BOSCH_DRIVER_LOG_FUNC=y +CONFIG_SENSORS_SMI_ACC2X2=y +CONFIG_SENSORS_SMI_ACC2X2_ENABLE_INT2=y +CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING=y CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM_HS=y @@ -257,6 +265,12 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MDM9607=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_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -334,17 +348,25 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_SPM=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_IPC_ROUTER_USB_XPRT=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_TRACER_PKT=y CONFIG_MSM_BAM_DMUX=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_IIO=y -CONFIG_IIO_BUFFER=y CONFIG_IIO_BUFFER_CB=y CONFIG_SENSORS_BMI160_IIO=y CONFIG_SENSORS_BMI160_IIO_RING=y CONFIG_ENABLE_ACC_GYRO_BUFFERING=y +CONFIG_INV_MPU_IIO_IAM20680=y +CONFIG_INV_MPU_IIO_I2C=y +CONFIG_INV_MPU_IIO_SPI=y +CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING=y +CONFIG_INV_TESTING=y +CONFIG_IIO_ST_ASM330LHH=y +CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_FUSE=y @@ -359,6 +381,7 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_ETM=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_QPDI=y +CONFIG_MSM_TZ_LOG=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_UBIFS_FS=y @@ -384,6 +407,7 @@ CONFIG_MSM_RTB=y CONFIG_IPC_LOGGING=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y diff --git a/arch/arm/configs/mdm9640_defconfig b/arch/arm/configs/mdm9640_defconfig index 01b0e4580289227e249580fd29ce8ebabffae5e9..a128257d39ddaf989b3192bc409429cc662bd5f3 100644 --- a/arch/arm/configs/mdm9640_defconfig +++ b/arch/arm/configs/mdm9640_defconfig @@ -423,6 +423,7 @@ CONFIG_MSM_RTB=y CONFIG_IPC_LOGGING=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index a05a83bab61ff7a5f9f320d1953fa3889f97cf1d..7f9dc5f6cda32e559b29a1a053099788cc0c1d08 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -10,13 +10,10 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=16 CONFIG_CGROUPS=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y CONFIG_RESOURCE_COUNTERS=y -CONFIG_MEMCG=y -CONFIG_MEMCG_SWAP=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y @@ -26,9 +23,10 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y -# CONFIG_BASE_FULL is not set CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y @@ -38,6 +36,8 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MSM=y CONFIG_ARCH_MSM8909=y @@ -47,7 +47,6 @@ CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_HIGHMEM=y -# CONFIG_BOUNCE is not set CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y @@ -72,7 +71,6 @@ 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 @@ -81,9 +79,9 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set CONFIG_INET_DIAG_DESTROY=y @@ -95,9 +93,9 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y -CONFIG_NETLABEL=y CONFIG_NETFILTER=y CONFIG_NETFILTER_DEBUG=y CONFIG_BRIDGE_NETFILTER=y @@ -114,6 +112,7 @@ CONFIG_NF_CONNTRACK_IRC=y CONFIG_NF_CONNTRACK_NETBIOS_NS=y CONFIG_NF_CONNTRACK_PPTP=y CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CONNTRACK_TFTP=y CONFIG_NF_CT_NETLINK=y CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y @@ -126,7 +125,6 @@ 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 @@ -223,8 +221,10 @@ CONFIG_BT_BNEP=y CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_HIDP=y +CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y @@ -246,16 +246,8 @@ CONFIG_UID_STAT=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=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_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y @@ -343,6 +335,7 @@ CONFIG_SENSORS_QPNP_ADC_CURRENT=y CONFIG_THERMAL=y CONFIG_THERMAL_TSENS8974=y CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y @@ -387,28 +380,11 @@ CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MSM8909=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_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_ACM=y -CONFIG_USB_STORAGE=y -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y -CONFIG_USB_STORAGE_ISD200=y -CONFIG_USB_STORAGE_USBAT=y -CONFIG_USB_STORAGE_SDDR09=y -CONFIG_USB_STORAGE_SDDR55=y -CONFIG_USB_STORAGE_JUMPSHOT=y -CONFIG_USB_STORAGE_ALAUDA=y -CONFIG_USB_STORAGE_ONETOUCH=y -CONFIG_USB_STORAGE_KARMA=y -CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_GADGET=y @@ -428,9 +404,7 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_LEDS_GPIO=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_MSM_GPIO_FLASH=y -CONFIG_LEDS_AW2013=y +CONFIG_LEDS_PCA9956B=y CONFIG_LEDS_TRIGGERS=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y @@ -456,6 +430,7 @@ CONFIG_SPS=y CONFIG_USB_BAM=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_VIBRATOR=y +CONFIG_GPIO_USB_DETECT=y CONFIG_MSM_SPMI=y CONFIG_MSM_SPMI_PMIC_ARB=y CONFIG_MSM_QPNP_INT=y @@ -496,6 +471,16 @@ CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y CONFIG_PWM=y CONFIG_PWM_QPNP=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_FUSE=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TMC=y +CONFIG_CORESIGHT_TPIU=y +CONFIG_CORESIGHT_FUNNEL=y +CONFIG_CORESIGHT_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y CONFIG_SENSORS=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y @@ -517,11 +502,14 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_MEMORY_INIT=y CONFIG_PANIC_TIMEOUT=5 -# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_TIMER_STATS=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y @@ -530,8 +518,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 230bab172feb6af99c71c918a3e023fb357ad58d..0679a5329382be74923af14f41c4b40e977be6b5 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -14,8 +14,6 @@ CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y CONFIG_RESOURCE_COUNTERS=y -CONFIG_MEMCG=y -CONFIG_MEMCG_SWAP=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y @@ -75,7 +73,6 @@ 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 @@ -84,9 +81,9 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set CONFIG_INET_DIAG_DESTROY=y @@ -98,9 +95,9 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y -CONFIG_NETLABEL=y CONFIG_NETFILTER=y CONFIG_NETFILTER_DEBUG=y CONFIG_BRIDGE_NETFILTER=y @@ -117,6 +114,7 @@ CONFIG_NF_CONNTRACK_IRC=y CONFIG_NF_CONNTRACK_NETBIOS_NS=y CONFIG_NF_CONNTRACK_PPTP=y CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CONNTRACK_TFTP=y CONFIG_NF_CT_NETLINK=y CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y @@ -129,7 +127,6 @@ 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 @@ -251,16 +248,8 @@ CONFIG_UID_STAT=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=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_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y @@ -351,6 +340,7 @@ CONFIG_SENSORS_QPNP_ADC_CURRENT=y CONFIG_THERMAL=y CONFIG_THERMAL_TSENS8974=y CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y @@ -406,18 +396,6 @@ CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_ACM=y -CONFIG_USB_STORAGE=y -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y -CONFIG_USB_STORAGE_ISD200=y -CONFIG_USB_STORAGE_USBAT=y -CONFIG_USB_STORAGE_SDDR09=y -CONFIG_USB_STORAGE_SDDR55=y -CONFIG_USB_STORAGE_JUMPSHOT=y -CONFIG_USB_STORAGE_ALAUDA=y -CONFIG_USB_STORAGE_ONETOUCH=y -CONFIG_USB_STORAGE_KARMA=y -CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_GADGET=y @@ -429,6 +407,7 @@ CONFIG_USB_G_ANDROID=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_CLKGATE=y +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 @@ -437,9 +416,7 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_LEDS_GPIO=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_MSM_GPIO_FLASH=y -CONFIG_LEDS_AW2013=y +CONFIG_LEDS_PCA9956B=y CONFIG_LEDS_TRIGGERS=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y @@ -465,6 +442,7 @@ CONFIG_SPS=y CONFIG_USB_BAM=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_VIBRATOR=y +CONFIG_GPIO_USB_DETECT=y CONFIG_MSM_SPMI=y CONFIG_MSM_SPMI_PMIC_ARB=y CONFIG_MSM_QPNP_INT=y @@ -573,6 +551,7 @@ CONFIG_MSM_RTB_SEPARATE_CPUS=y CONFIG_IPC_LOGGING=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_DEBUG_SET_MODULE_RONX=y @@ -582,8 +561,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y diff --git a/arch/arm/configs/msm8909w-1gb-perf_defconfig b/arch/arm/configs/msm8909w-1gb-perf_defconfig index e79dc66a5fce562da2fc6446a4c2831a516e83a1..c00396f591108b8ea0fe4f6379873c89a7c00ef5 100644 --- a/arch/arm/configs/msm8909w-1gb-perf_defconfig +++ b/arch/arm/configs/msm8909w-1gb-perf_defconfig @@ -13,6 +13,7 @@ CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y +CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_QHMP=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set @@ -71,9 +72,10 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set CONFIG_IPV6=y @@ -84,6 +86,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -415,6 +418,7 @@ CONFIG_MSM_L2_SPM=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_BGRSB=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y @@ -447,6 +451,10 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y @@ -469,8 +477,8 @@ CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_AES_ARM_BS=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_ARM_CRYPTO=y -CONFIG_CRYPTO_AES_ARM_BS=y CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8909w-1gb_defconfig b/arch/arm/configs/msm8909w-1gb_defconfig index 38aba8cf3d65819fda92244aab8b34292ac52d83..e7735b9d440a8c5ee9724f72be032684b0b36b65 100644 --- a/arch/arm/configs/msm8909w-1gb_defconfig +++ b/arch/arm/configs/msm8909w-1gb_defconfig @@ -13,6 +13,7 @@ CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y +CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_QHMP=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set @@ -75,9 +76,10 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set CONFIG_IPV6=y @@ -88,6 +90,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -419,6 +422,7 @@ CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_BGRSB=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y @@ -454,6 +458,10 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y @@ -491,6 +499,7 @@ CONFIG_MSM_RTB=y CONFIG_MSM_RTB_SEPARATE_CPUS=y CONFIG_IPC_LOGGING=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_DEBUG_SET_MODULE_RONX=y @@ -498,8 +507,8 @@ CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_AES_ARM_BS=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_ARM_CRYPTO=y -CONFIG_CRYPTO_AES_ARM_BS=y CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 9649d7312af172274a7b813ade5f42867ad85c17..981c1adbda89a0ffd6376de8ce139843664cd893 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -1,7 +1,12 @@ CONFIG_EARLY_IOREMAP=y +CONFIG_LOCALVERSION="-perf" +# CONFIG_USELIB is not set CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -13,6 +18,7 @@ CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y +CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_QHMP=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set @@ -22,10 +28,10 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -CONFIG_KPROBES=y -CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -34,6 +40,7 @@ CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MSM=y CONFIG_ARCH_MSM8909=y +CONFIG_ARM_KERNMEM_PERMS=y CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y @@ -71,11 +78,13 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set +CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -84,6 +93,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -110,10 +120,8 @@ CONFIG_NETFILTER_XT_TARGET_CT=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NETMAP=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_REDIRECT=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y @@ -144,7 +152,6 @@ CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y CONFIG_NF_LOG_IPV4=y -CONFIG_NF_NAT_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -152,6 +159,10 @@ 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 @@ -198,6 +209,7 @@ CONFIG_BT_HIDP=y CONFIG_CFG80211=y CONFIG_NL80211_TESTMODE=y CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_NFC_NQ=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y @@ -208,14 +220,15 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_NAND=y CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y +CONFIG_QPNP_MISC=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_VERITY=y -CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_IFB=y @@ -234,7 +247,6 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y CONFIG_WCNSS_CORE=y CONFIG_WCNSS_CORE_PRONTO=y CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y @@ -255,6 +267,7 @@ CONFIG_TOUCHSCREEN_FT5X06_GESTURE=y CONFIG_TOUCHSCREEN_IT7260_I2C=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y +CONFIG_TOUCHSCREEN_FTS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m @@ -263,13 +276,12 @@ CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set # CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS=y @@ -299,6 +311,7 @@ CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y CONFIG_THERMAL_TSENS8974=y CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y @@ -333,25 +346,18 @@ CONFIG_FB_VIRTUAL=y CONFIG_FB_MSM=y CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_SPI_PANEL=y CONFIG_FB_MSM_MDSS_MDP3=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_SOUND=y CONFIG_SND=y -CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MSM8909=y CONFIG_UHID=y -CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_MON=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_ACM=y -CONFIG_USB_SERIAL=y -CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -388,10 +394,12 @@ CONFIG_MSM_BUS_SCALING=y CONFIG_BUS_TOPOLOGY_ADHOC=y CONFIG_QPNP_POWER_ON=y CONFIG_QPNP_REVID=y +CONFIG_QPNP_COINCELL=y CONFIG_SPS=y CONFIG_USB_BAM=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_VIBRATOR=y +CONFIG_QPNP_HAPTIC=y CONFIG_MSM_SPMI=y CONFIG_MSM_SPMI_PMIC_ARB=y CONFIG_MSM_QPNP_INT=y @@ -408,6 +416,7 @@ CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_SCM=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_SMEM=y +CONFIG_QPNP_PBS=y CONFIG_MSM_SMD=y CONFIG_MSM_SMD_DEBUG=y CONFIG_MSM_GLINK=y @@ -422,7 +431,9 @@ CONFIG_MSM_L2_SPM=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_BGRSB=y CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_SSR_BG=y @@ -455,7 +466,9 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y # CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y @@ -468,20 +481,26 @@ CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_RECURSIVE_FAULT=y -CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_KEYS=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_ARM_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256_ARM=y CONFIG_CRYPTO_SHA512_ARM_NEON=y -CONFIG_CRYPTO_AES_ARM_BS=y CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 2ba5655896111723cc00c1068bd265025e8ce07d..fd6bf07cc2018764938a84441ff9ce4674001c48 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -1,7 +1,11 @@ CONFIG_EARLY_IOREMAP=y +# CONFIG_USELIB is not set CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -13,6 +17,7 @@ CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y +CONFIG_SCHED_CORE_CTL=y CONFIG_SCHED_QHMP=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set @@ -25,7 +30,7 @@ CONFIG_EMBEDDED=y CONFIG_PROFILING=y CONFIG_OPROFILE=m CONFIG_KPROBES=y -CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -37,6 +42,7 @@ CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MSM=y CONFIG_ARCH_MSM8909=y +CONFIG_ARM_KERNMEM_PERMS=y CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y @@ -75,11 +81,13 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set +CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -88,6 +96,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -146,7 +155,6 @@ CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y CONFIG_NF_LOG_IPV4=y -CONFIG_NF_NAT_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -154,6 +162,10 @@ 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 @@ -200,6 +212,7 @@ CONFIG_BT_HIDP=y CONFIG_CFG80211=y CONFIG_NL80211_TESTMODE=y CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_NFC_NQ=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y @@ -210,6 +223,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_NAND=y CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_QSEECOM=y @@ -218,7 +232,6 @@ CONFIG_QPNP_MISC=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_VERITY=y -CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_IFB=y @@ -237,7 +250,6 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y CONFIG_WCNSS_CORE=y CONFIG_WCNSS_CORE_PRONTO=y CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y @@ -258,6 +270,7 @@ CONFIG_TOUCHSCREEN_FT5X06_GESTURE=y CONFIG_TOUCHSCREEN_IT7260_I2C=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y +CONFIG_TOUCHSCREEN_FTS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m @@ -273,6 +286,7 @@ CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS=y @@ -337,25 +351,18 @@ CONFIG_FB_VIRTUAL=y CONFIG_FB_MSM=y CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_SPI_PANEL=y CONFIG_FB_MSM_MDSS_MDP3=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_SOUND=y CONFIG_SND=y -CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MSM8909=y CONFIG_UHID=y -CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_MON=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_ACM=y -CONFIG_USB_SERIAL=y -CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -431,7 +438,9 @@ CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_BGRSB=y CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_SSR_BG=y @@ -467,7 +476,9 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y # CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y @@ -481,9 +492,6 @@ CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y CONFIG_DEBUG_PAGEALLOC=y CONFIG_SLUB_DEBUG_PANIC_ON=y -CONFIG_DEBUG_KMEMLEAK=y -CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 -CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_VM=y CONFIG_LOCKUP_DETECTOR=y @@ -505,17 +513,26 @@ CONFIG_MSM_RTB=y CONFIG_MSM_RTB_SEPARATE_CPUS=y CONFIG_IPC_LOGGING=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_ARM_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256_ARM=y CONFIG_CRYPTO_SHA512_ARM_NEON=y -CONFIG_CRYPTO_AES_ARM_BS=y CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 10a925098ff171b08bfdc3f954ea3e209c609858..b301aeaaee85dbeafbb94faecf9267653840ee9d 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -8,14 +8,11 @@ CONFIG_TASKSTATS=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y CONFIG_RCU_BOOST=y CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=16 CONFIG_CGROUPS=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y @@ -31,13 +28,14 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y -# CONFIG_BASE_FULL is not set CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -62,8 +60,8 @@ CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_HIGHMEM=y -# CONFIG_BOUNCE is not set CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y @@ -101,11 +99,14 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y @@ -115,6 +116,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -123,7 +125,6 @@ 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 @@ -169,6 +170,7 @@ 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_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -203,6 +205,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y @@ -250,7 +253,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_UID_STAT=y CONFIG_QSEECOM=y -CONFIG_UID_SYS_STATS=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_USB_EXT_TYPE_C_PERICOM=y @@ -586,6 +588,17 @@ CONFIG_DEVFREQ_SPDM=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_PANIC_HANDLER=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_FUSE=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_CTI_SAVE_DISABLE=y +CONFIG_CORESIGHT_TMC=y +CONFIG_CORESIGHT_TPIU=y +CONFIG_CORESIGHT_FUNNEL=y +CONFIG_CORESIGHT_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y @@ -610,8 +623,9 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_TIMER_STATS=y CONFIG_IPC_LOGGING=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_DEBUG_SET_MODULE_RONX=y @@ -621,10 +635,11 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y @@ -634,5 +649,3 @@ CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM_NEON=y CONFIG_CRYPTO_SHA512_ARM_NEON=y -CONFIG_CRYPTO_AES_ARM_BS=y -CONFIG_CRYPTO_AES_ARM_CE=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 7e10c9ceb2659a3ed50788deefb0710adc15a911..327870d108a9e4f26586fca7fe9b1c4596e2f699 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -36,7 +36,7 @@ CONFIG_EMBEDDED=y CONFIG_PROFILING=y CONFIG_OPROFILE=m CONFIG_KPROBES=y -CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -100,11 +100,14 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y @@ -114,6 +117,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -122,7 +126,6 @@ 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 @@ -168,6 +171,7 @@ 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_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -202,6 +206,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y @@ -488,6 +493,7 @@ CONFIG_USB_G_ANDROID=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_CLKGATE=y +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y @@ -672,6 +678,7 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_LKDTM=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_DEBUG_SET_MODULE_RONX=y @@ -681,10 +688,11 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y @@ -694,5 +702,3 @@ CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM_NEON=y CONFIG_CRYPTO_SHA512_ARM_NEON=y -CONFIG_CRYPTO_AES_ARM_BS=y -CONFIG_CRYPTO_AES_ARM_CE=y diff --git a/arch/arm/configs/msm_defconfig b/arch/arm/configs/msm_defconfig index dd18c9e527d647b0f9685285248764571e8d1d4a..76c437e2b895cdf34c902496ebe4596226cff166 100644 --- a/arch/arm/configs/msm_defconfig +++ b/arch/arm/configs/msm_defconfig @@ -24,7 +24,6 @@ CONFIG_HIGHMEM=y CONFIG_HIGHPTE=y CONFIG_CLEANCACHE=y CONFIG_AUTO_ZRELADDR=y -CONFIG_VFP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_NET=y CONFIG_PACKET=y @@ -48,7 +47,6 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y @@ -69,8 +67,6 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_MSM=y -CONFIG_SERIAL_MSM_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_I2C=y CONFIG_I2C_CHARDEV=y @@ -99,10 +95,6 @@ CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_RTC_CLASS=y CONFIG_STAGING=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y @@ -119,3 +111,4 @@ CONFIG_LOCKUP_DETECTOR=y # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_SCHED_DEBUG is not set CONFIG_TIMER_STATS=y +CONFIG_CRYPTO_GCM=y diff --git a/arch/arm/configs/msmcortex-perf_defconfig b/arch/arm/configs/msmcortex-perf_defconfig index 378119e357a02fba322edd1cf0a752ed05bb7d87..d94331ef007cdd40c4e795d40778b1783d9089c4 100644 --- a/arch/arm/configs/msmcortex-perf_defconfig +++ b/arch/arm/configs/msmcortex-perf_defconfig @@ -586,10 +586,6 @@ CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -610,7 +606,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y CONFIG_TIMER_STATS=y @@ -627,6 +622,9 @@ CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y @@ -635,7 +633,4 @@ CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM_NEON=y -CONFIG_CRYPTO_SHA2_ARM_CE=y CONFIG_CRYPTO_SHA512_ARM_NEON=y -CONFIG_CRYPTO_AES_ARM_BS=y -CONFIG_CRYPTO_AES_ARM_CE=y diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index c193a0eb7de599c4c9e0c5352197af9c3181de3d..cca2d815eb513fbc3f7e0222035f4bcf8c82d7e6 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -481,6 +481,7 @@ CONFIG_USB_G_ANDROID=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_CLKGATE=y +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 @@ -602,10 +603,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_QPDI=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -656,6 +653,7 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_LKDTM=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_KEYS_DEBUG_PROC_KEYS=y @@ -669,6 +667,9 @@ CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y @@ -677,7 +678,4 @@ CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM_NEON=y -CONFIG_CRYPTO_SHA2_ARM_CE=y CONFIG_CRYPTO_SHA512_ARM_NEON=y -CONFIG_CRYPTO_AES_ARM_BS=y -CONFIG_CRYPTO_AES_ARM_CE=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index a0e51bb68b2d5a4bdd59eaf8a797221ca78b74b3..85128b297ec1e82f7c16f3108f4317967f569b40 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -169,6 +169,7 @@ CONFIG_INPUT_TWL4030_PWRBUTTON=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=6 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index 1b5e88dfc1bc9fc5dc4baef04a507bc5fe681c5c..f25ea1bb63b18ac48b36dea6a752ea82a2d3844c 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -10,6 +10,8 @@ obj-$(CONFIG_CRYPTO_SHA2_ARM_CE) += sha2-arm-ce.o obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o +obj-$(CONFIG_CRYPTO_SHA2_ARM_CE) += sha2-arm-ce.o +obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o aes-arm-y := aes-armv4.o aes_glue.o aes-arm-bs-y := aesbs-core.o aesbs-glue.o @@ -20,6 +22,8 @@ sha256-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha256_neon_glue.o sha256-arm-y := sha256-core.o sha256_glue.o $(sha256-arm-neon-y) sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o aes-arm-ce-y := aes-ce-core.o aes-ce-glue.o +sha2-arm-ce-y := sha2-ce-core.o sha2-ce-glue.o +speck-neon-y := speck-neon-core.o speck-neon-glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@) diff --git a/arch/arm/crypto/aes-ce-core.S b/arch/arm/crypto/aes-ce-core.S index 8cfa468ee570b0bd0f2bb800fa1f7f21b66edaf6..14c68af74ff6766d18eee1a62959e2ef04988574 100644 --- a/arch/arm/crypto/aes-ce-core.S +++ b/arch/arm/crypto/aes-ce-core.S @@ -101,15 +101,14 @@ \dround q10, q11 blo 0f @ AES-128: 10 rounds vld1.8 {q10-q11}, [ip]! - beq 1f @ AES-192: 12 rounds \dround q12, q13 + beq 1f @ AES-192: 12 rounds vld1.8 {q12-q13}, [ip] \dround q10, q11 0: \fround q12, q13, q14 bx lr -1: \dround q12, q13 - \fround q10, q11, q14 +1: \fround q10, q11, q14 bx lr .endm @@ -124,6 +123,7 @@ * q9 : secound round key * ip : address of 3rd round key * q14 : final round key + * r2 : address of round key array * r3 : number of rounds */ .align 6 diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c index d2ee59157ec7041e20ea334f6b428e0d3b748698..297e375521c2f4d34cd3b0be7122b5de43730b93 100644 --- a/arch/arm/crypto/aes-ce-glue.c +++ b/arch/arm/crypto/aes-ce-glue.c @@ -87,8 +87,13 @@ static int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, u32 *rki = ctx->key_enc + (i * kwords); u32 *rko = rki + kwords; +#ifndef CONFIG_CPU_BIG_ENDIAN rko[0] = ror32(ce_aes_sub(rki[kwords - 1]), 8); rko[0] = rko[0] ^ rki[0] ^ rcon[i]; +#else + rko[0] = rol32(ce_aes_sub(rki[kwords - 1]), 8); + rko[0] = rko[0] ^ rki[0] ^ (rcon[i] << 24); +#endif rko[1] = rko[0] ^ rki[1]; rko[2] = rko[1] ^ rki[2]; rko[3] = rko[2] ^ rki[3]; @@ -279,7 +284,7 @@ static int ctr_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } - if (nbytes) { + if (walk.nbytes % AES_BLOCK_SIZE) { u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE; u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE; u8 __aligned(8) tail[AES_BLOCK_SIZE]; diff --git a/arch/arm/crypto/aesbs-glue.c b/arch/arm/crypto/aesbs-glue.c index 15468fbbdea393ed020510abbb30145b52bce396..68679cafe0bbc3e13de5406920565ffcd9d209fb 100644 --- a/arch/arm/crypto/aesbs-glue.c +++ b/arch/arm/crypto/aesbs-glue.c @@ -354,7 +354,7 @@ static struct crypto_alg aesbs_algs[] = { { }, { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-neonbs", - .cra_priority = 300, + .cra_priority = 250, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct async_helper_ctx), @@ -374,7 +374,7 @@ static struct crypto_alg aesbs_algs[] = { { }, { .cra_name = "ctr(aes)", .cra_driver_name = "ctr-aes-neonbs", - .cra_priority = 300, + .cra_priority = 250, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct async_helper_ctx), @@ -394,7 +394,7 @@ static struct crypto_alg aesbs_algs[] = { { }, { .cra_name = "xts(aes)", .cra_driver_name = "xts-aes-neonbs", - .cra_priority = 300, + .cra_priority = 250, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct async_helper_ctx), diff --git a/arch/arm/crypto/sha2-ce-glue.c b/arch/arm/crypto/sha2-ce-glue.c index 9ffe8ad274026f564a079ac1963f0b620c8c7342..0449eca3aab3958163f86f9b844becb5d9e98207 100644 --- a/arch/arm/crypto/sha2-ce-glue.c +++ b/arch/arm/crypto/sha2-ce-glue.c @@ -163,7 +163,7 @@ static struct shash_alg algs[] = { { .base = { .cra_name = "sha224", .cra_driver_name = "sha224-ce", - .cra_priority = 200, + .cra_priority = 300, .cra_flags = CRYPTO_ALG_TYPE_SHASH, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_module = THIS_MODULE, @@ -180,7 +180,7 @@ static struct shash_alg algs[] = { { .base = { .cra_name = "sha256", .cra_driver_name = "sha256-ce", - .cra_priority = 200, + .cra_priority = 300, .cra_flags = CRYPTO_ALG_TYPE_SHASH, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_module = THIS_MODULE, diff --git a/arch/arm/crypto/speck-neon-core.S b/arch/arm/crypto/speck-neon-core.S new file mode 100644 index 0000000000000000000000000000000000000000..3c1e203e53b9ccd752731f228b595a5678557782 --- /dev/null +++ b/arch/arm/crypto/speck-neon-core.S @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS + * + * Copyright (c) 2018 Google, Inc + * + * Author: Eric Biggers + */ + +#include + + .text + .fpu neon + + // arguments + ROUND_KEYS .req r0 // const {u64,u32} *round_keys + NROUNDS .req r1 // int nrounds + DST .req r2 // void *dst + SRC .req r3 // const void *src + NBYTES .req r4 // unsigned int nbytes + TWEAK .req r5 // void *tweak + + // registers which hold the data being encrypted/decrypted + X0 .req q0 + X0_L .req d0 + X0_H .req d1 + Y0 .req q1 + Y0_H .req d3 + X1 .req q2 + X1_L .req d4 + X1_H .req d5 + Y1 .req q3 + Y1_H .req d7 + X2 .req q4 + X2_L .req d8 + X2_H .req d9 + Y2 .req q5 + Y2_H .req d11 + X3 .req q6 + X3_L .req d12 + X3_H .req d13 + Y3 .req q7 + Y3_H .req d15 + + // the round key, duplicated in all lanes + ROUND_KEY .req q8 + ROUND_KEY_L .req d16 + ROUND_KEY_H .req d17 + + // index vector for vtbl-based 8-bit rotates + ROTATE_TABLE .req d18 + + // multiplication table for updating XTS tweaks + GF128MUL_TABLE .req d19 + GF64MUL_TABLE .req d19 + + // current XTS tweak value(s) + TWEAKV .req q10 + TWEAKV_L .req d20 + TWEAKV_H .req d21 + + TMP0 .req q12 + TMP0_L .req d24 + TMP0_H .req d25 + TMP1 .req q13 + TMP2 .req q14 + TMP3 .req q15 + + .align 4 +.Lror64_8_table: + .byte 1, 2, 3, 4, 5, 6, 7, 0 +.Lror32_8_table: + .byte 1, 2, 3, 0, 5, 6, 7, 4 +.Lrol64_8_table: + .byte 7, 0, 1, 2, 3, 4, 5, 6 +.Lrol32_8_table: + .byte 3, 0, 1, 2, 7, 4, 5, 6 +.Lgf128mul_table: + .byte 0, 0x87 + .fill 14 +.Lgf64mul_table: + .byte 0, 0x1b, (0x1b << 1), (0x1b << 1) ^ 0x1b + .fill 12 + +/* + * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time + * + * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for + * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes + * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64. + * + * The 8-bit rotates are implemented using vtbl instead of vshr + vsli because + * the vtbl approach is faster on some processors and the same speed on others. + */ +.macro _speck_round_128bytes n + + // x = ror(x, 8) + vtbl.8 X0_L, {X0_L}, ROTATE_TABLE + vtbl.8 X0_H, {X0_H}, ROTATE_TABLE + vtbl.8 X1_L, {X1_L}, ROTATE_TABLE + vtbl.8 X1_H, {X1_H}, ROTATE_TABLE + vtbl.8 X2_L, {X2_L}, ROTATE_TABLE + vtbl.8 X2_H, {X2_H}, ROTATE_TABLE + vtbl.8 X3_L, {X3_L}, ROTATE_TABLE + vtbl.8 X3_H, {X3_H}, ROTATE_TABLE + + // x += y + vadd.u\n X0, Y0 + vadd.u\n X1, Y1 + vadd.u\n X2, Y2 + vadd.u\n X3, Y3 + + // x ^= k + veor X0, ROUND_KEY + veor X1, ROUND_KEY + veor X2, ROUND_KEY + veor X3, ROUND_KEY + + // y = rol(y, 3) + vshl.u\n TMP0, Y0, #3 + vshl.u\n TMP1, Y1, #3 + vshl.u\n TMP2, Y2, #3 + vshl.u\n TMP3, Y3, #3 + vsri.u\n TMP0, Y0, #(\n - 3) + vsri.u\n TMP1, Y1, #(\n - 3) + vsri.u\n TMP2, Y2, #(\n - 3) + vsri.u\n TMP3, Y3, #(\n - 3) + + // y ^= x + veor Y0, TMP0, X0 + veor Y1, TMP1, X1 + veor Y2, TMP2, X2 + veor Y3, TMP3, X3 +.endm + +/* + * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time + * + * This is the inverse of _speck_round_128bytes(). + */ +.macro _speck_unround_128bytes n + + // y ^= x + veor TMP0, Y0, X0 + veor TMP1, Y1, X1 + veor TMP2, Y2, X2 + veor TMP3, Y3, X3 + + // y = ror(y, 3) + vshr.u\n Y0, TMP0, #3 + vshr.u\n Y1, TMP1, #3 + vshr.u\n Y2, TMP2, #3 + vshr.u\n Y3, TMP3, #3 + vsli.u\n Y0, TMP0, #(\n - 3) + vsli.u\n Y1, TMP1, #(\n - 3) + vsli.u\n Y2, TMP2, #(\n - 3) + vsli.u\n Y3, TMP3, #(\n - 3) + + // x ^= k + veor X0, ROUND_KEY + veor X1, ROUND_KEY + veor X2, ROUND_KEY + veor X3, ROUND_KEY + + // x -= y + vsub.u\n X0, Y0 + vsub.u\n X1, Y1 + vsub.u\n X2, Y2 + vsub.u\n X3, Y3 + + // x = rol(x, 8); + vtbl.8 X0_L, {X0_L}, ROTATE_TABLE + vtbl.8 X0_H, {X0_H}, ROTATE_TABLE + vtbl.8 X1_L, {X1_L}, ROTATE_TABLE + vtbl.8 X1_H, {X1_H}, ROTATE_TABLE + vtbl.8 X2_L, {X2_L}, ROTATE_TABLE + vtbl.8 X2_H, {X2_H}, ROTATE_TABLE + vtbl.8 X3_L, {X3_L}, ROTATE_TABLE + vtbl.8 X3_H, {X3_H}, ROTATE_TABLE +.endm + +.macro _xts128_precrypt_one dst_reg, tweak_buf, tmp + + // Load the next source block + vld1.8 {\dst_reg}, [SRC]! + + // Save the current tweak in the tweak buffer + vst1.8 {TWEAKV}, [\tweak_buf:128]! + + // XOR the next source block with the current tweak + veor \dst_reg, TWEAKV + + /* + * Calculate the next tweak by multiplying the current one by x, + * modulo p(x) = x^128 + x^7 + x^2 + x + 1. + */ + vshr.u64 \tmp, TWEAKV, #63 + vshl.u64 TWEAKV, #1 + veor TWEAKV_H, \tmp\()_L + vtbl.8 \tmp\()_H, {GF128MUL_TABLE}, \tmp\()_H + veor TWEAKV_L, \tmp\()_H +.endm + +.macro _xts64_precrypt_two dst_reg, tweak_buf, tmp + + // Load the next two source blocks + vld1.8 {\dst_reg}, [SRC]! + + // Save the current two tweaks in the tweak buffer + vst1.8 {TWEAKV}, [\tweak_buf:128]! + + // XOR the next two source blocks with the current two tweaks + veor \dst_reg, TWEAKV + + /* + * Calculate the next two tweaks by multiplying the current ones by x^2, + * modulo p(x) = x^64 + x^4 + x^3 + x + 1. + */ + vshr.u64 \tmp, TWEAKV, #62 + vshl.u64 TWEAKV, #2 + vtbl.8 \tmp\()_L, {GF64MUL_TABLE}, \tmp\()_L + vtbl.8 \tmp\()_H, {GF64MUL_TABLE}, \tmp\()_H + veor TWEAKV, \tmp +.endm + +/* + * _speck_xts_crypt() - Speck-XTS encryption/decryption + * + * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer + * using Speck-XTS, specifically the variant with a block size of '2n' and round + * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and + * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a + * nonzero multiple of 128. + */ +.macro _speck_xts_crypt n, decrypting + push {r4-r7} + mov r7, sp + + /* + * The first four parameters were passed in registers r0-r3. Load the + * additional parameters, which were passed on the stack. + */ + ldr NBYTES, [sp, #16] + ldr TWEAK, [sp, #20] + + /* + * If decrypting, modify the ROUND_KEYS parameter to point to the last + * round key rather than the first, since for decryption the round keys + * are used in reverse order. + */ +.if \decrypting +.if \n == 64 + add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #3 + sub ROUND_KEYS, #8 +.else + add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #2 + sub ROUND_KEYS, #4 +.endif +.endif + + // Load the index vector for vtbl-based 8-bit rotates +.if \decrypting + ldr r12, =.Lrol\n\()_8_table +.else + ldr r12, =.Lror\n\()_8_table +.endif + vld1.8 {ROTATE_TABLE}, [r12:64] + + // One-time XTS preparation + + /* + * Allocate stack space to store 128 bytes worth of tweaks. For + * performance, this space is aligned to a 16-byte boundary so that we + * can use the load/store instructions that declare 16-byte alignment. + */ + sub sp, #128 + bic sp, #0xf + +.if \n == 64 + // Load first tweak + vld1.8 {TWEAKV}, [TWEAK] + + // Load GF(2^128) multiplication table + ldr r12, =.Lgf128mul_table + vld1.8 {GF128MUL_TABLE}, [r12:64] +.else + // Load first tweak + vld1.8 {TWEAKV_L}, [TWEAK] + + // Load GF(2^64) multiplication table + ldr r12, =.Lgf64mul_table + vld1.8 {GF64MUL_TABLE}, [r12:64] + + // Calculate second tweak, packing it together with the first + vshr.u64 TMP0_L, TWEAKV_L, #63 + vtbl.u8 TMP0_L, {GF64MUL_TABLE}, TMP0_L + vshl.u64 TWEAKV_H, TWEAKV_L, #1 + veor TWEAKV_H, TMP0_L +.endif + +.Lnext_128bytes_\@: + + /* + * Load the source blocks into {X,Y}[0-3], XOR them with their XTS tweak + * values, and save the tweaks on the stack for later. Then + * de-interleave the 'x' and 'y' elements of each block, i.e. make it so + * that the X[0-3] registers contain only the second halves of blocks, + * and the Y[0-3] registers contain only the first halves of blocks. + * (Speck uses the order (y, x) rather than the more intuitive (x, y).) + */ + mov r12, sp +.if \n == 64 + _xts128_precrypt_one X0, r12, TMP0 + _xts128_precrypt_one Y0, r12, TMP0 + _xts128_precrypt_one X1, r12, TMP0 + _xts128_precrypt_one Y1, r12, TMP0 + _xts128_precrypt_one X2, r12, TMP0 + _xts128_precrypt_one Y2, r12, TMP0 + _xts128_precrypt_one X3, r12, TMP0 + _xts128_precrypt_one Y3, r12, TMP0 + vswp X0_L, Y0_H + vswp X1_L, Y1_H + vswp X2_L, Y2_H + vswp X3_L, Y3_H +.else + _xts64_precrypt_two X0, r12, TMP0 + _xts64_precrypt_two Y0, r12, TMP0 + _xts64_precrypt_two X1, r12, TMP0 + _xts64_precrypt_two Y1, r12, TMP0 + _xts64_precrypt_two X2, r12, TMP0 + _xts64_precrypt_two Y2, r12, TMP0 + _xts64_precrypt_two X3, r12, TMP0 + _xts64_precrypt_two Y3, r12, TMP0 + vuzp.32 Y0, X0 + vuzp.32 Y1, X1 + vuzp.32 Y2, X2 + vuzp.32 Y3, X3 +.endif + + // Do the cipher rounds + + mov r12, ROUND_KEYS + mov r6, NROUNDS + +.Lnext_round_\@: +.if \decrypting +.if \n == 64 + vld1.64 ROUND_KEY_L, [r12] + sub r12, #8 + vmov ROUND_KEY_H, ROUND_KEY_L +.else + vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12] + sub r12, #4 +.endif + _speck_unround_128bytes \n +.else +.if \n == 64 + vld1.64 ROUND_KEY_L, [r12]! + vmov ROUND_KEY_H, ROUND_KEY_L +.else + vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]! +.endif + _speck_round_128bytes \n +.endif + subs r6, r6, #1 + bne .Lnext_round_\@ + + // Re-interleave the 'x' and 'y' elements of each block +.if \n == 64 + vswp X0_L, Y0_H + vswp X1_L, Y1_H + vswp X2_L, Y2_H + vswp X3_L, Y3_H +.else + vzip.32 Y0, X0 + vzip.32 Y1, X1 + vzip.32 Y2, X2 + vzip.32 Y3, X3 +.endif + + // XOR the encrypted/decrypted blocks with the tweaks we saved earlier + mov r12, sp + vld1.8 {TMP0, TMP1}, [r12:128]! + vld1.8 {TMP2, TMP3}, [r12:128]! + veor X0, TMP0 + veor Y0, TMP1 + veor X1, TMP2 + veor Y1, TMP3 + vld1.8 {TMP0, TMP1}, [r12:128]! + vld1.8 {TMP2, TMP3}, [r12:128]! + veor X2, TMP0 + veor Y2, TMP1 + veor X3, TMP2 + veor Y3, TMP3 + + // Store the ciphertext in the destination buffer + vst1.8 {X0, Y0}, [DST]! + vst1.8 {X1, Y1}, [DST]! + vst1.8 {X2, Y2}, [DST]! + vst1.8 {X3, Y3}, [DST]! + + // Continue if there are more 128-byte chunks remaining, else return + subs NBYTES, #128 + bne .Lnext_128bytes_\@ + + // Store the next tweak +.if \n == 64 + vst1.8 {TWEAKV}, [TWEAK] +.else + vst1.8 {TWEAKV_L}, [TWEAK] +.endif + + mov sp, r7 + pop {r4-r7} + bx lr +.endm + +ENTRY(speck128_xts_encrypt_neon) + _speck_xts_crypt n=64, decrypting=0 +ENDPROC(speck128_xts_encrypt_neon) + +ENTRY(speck128_xts_decrypt_neon) + _speck_xts_crypt n=64, decrypting=1 +ENDPROC(speck128_xts_decrypt_neon) + +ENTRY(speck64_xts_encrypt_neon) + _speck_xts_crypt n=32, decrypting=0 +ENDPROC(speck64_xts_encrypt_neon) + +ENTRY(speck64_xts_decrypt_neon) + _speck_xts_crypt n=32, decrypting=1 +ENDPROC(speck64_xts_decrypt_neon) diff --git a/arch/arm/crypto/speck-neon-glue.c b/arch/arm/crypto/speck-neon-glue.c new file mode 100644 index 0000000000000000000000000000000000000000..ea36c3a6f1d950e9175e7903b9247d550e0893c7 --- /dev/null +++ b/arch/arm/crypto/speck-neon-glue.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS + * + * Copyright (c) 2018 Google, Inc + * + * Note: the NIST recommendation for XTS only specifies a 128-bit block size, + * but a 64-bit version (needed for Speck64) is fairly straightforward; the math + * is just done in GF(2^64) instead of GF(2^128), with the reducing polynomial + * x^64 + x^4 + x^3 + x + 1 from the original XEX paper (Rogaway, 2004: + * "Efficient Instantiations of Tweakable Blockciphers and Refinements to Modes + * OCB and PMAC"), represented as 0x1B. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The assembly functions only handle multiples of 128 bytes */ +#define SPECK_NEON_CHUNK_SIZE 128 + +/* Speck128 */ + +struct speck128_xts_tfm_ctx { + struct speck128_tfm_ctx main_key; + struct speck128_tfm_ctx tweak_key; +}; + +asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *, + u8 *, const u8 *); +typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *, + const void *, unsigned int, void *); + +static __always_inline int +__speck128_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, + speck128_crypt_one_t crypt_one, + speck128_xts_crypt_many_t crypt_many) +{ + struct crypto_blkcipher *tfm = desc->tfm; + const struct speck128_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct blkcipher_walk walk; + le128 tweak; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE); + + crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; + u8 *dst = walk.dst.virt.addr; + const u8 *src = walk.src.virt.addr; + + if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { + unsigned int count; + + count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); + kernel_neon_begin(); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); + kernel_neon_end(); + dst += count; + src += count; + nbytes -= count; + } + + /* Handle any remainder with generic code */ + while (nbytes >= sizeof(tweak)) { + le128_xor((le128 *)dst, (const le128 *)src, &tweak); + (*crypt_one)(&ctx->main_key, dst, dst); + le128_xor((le128 *)dst, (const le128 *)dst, &tweak); + gf128mul_x_ble((be128 *)&tweak, (const be128 *)&tweak); + + dst += sizeof(tweak); + src += sizeof(tweak); + nbytes -= sizeof(tweak); + } + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int speck128_xts_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return __speck128_xts_crypt(desc, dst, src, nbytes, + crypto_speck128_encrypt, + speck128_xts_encrypt_neon); +} + +static int speck128_xts_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return __speck128_xts_crypt(desc, dst, src, nbytes, + crypto_speck128_decrypt, + speck128_xts_decrypt_neon); +} + +static int speck128_xts_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct speck128_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + if (keylen % 2) + return -EINVAL; + + keylen /= 2; + + err = crypto_speck128_setkey(&ctx->main_key, key, keylen); + if (err) + return err; + + return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen); +} + +/* Speck64 */ + +struct speck64_xts_tfm_ctx { + struct speck64_tfm_ctx main_key; + struct speck64_tfm_ctx tweak_key; +}; + +asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *, + u8 *, const u8 *); +typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *, + const void *, unsigned int, void *); + +static __always_inline int +__speck64_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, + speck64_crypt_one_t crypt_one, + speck64_xts_crypt_many_t crypt_many) +{ + struct crypto_blkcipher *tfm = desc->tfm; + const struct speck64_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct blkcipher_walk walk; + __le64 tweak; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE); + + crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; + u8 *dst = walk.dst.virt.addr; + const u8 *src = walk.src.virt.addr; + + if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { + unsigned int count; + + count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); + kernel_neon_begin(); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); + kernel_neon_end(); + dst += count; + src += count; + nbytes -= count; + } + + /* Handle any remainder with generic code */ + while (nbytes >= sizeof(tweak)) { + *(__le64 *)dst = *(__le64 *)src ^ tweak; + (*crypt_one)(&ctx->main_key, dst, dst); + *(__le64 *)dst ^= tweak; + tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^ + ((tweak & cpu_to_le64(1ULL << 63)) ? + 0x1B : 0)); + dst += sizeof(tweak); + src += sizeof(tweak); + nbytes -= sizeof(tweak); + } + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int speck64_xts_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return __speck64_xts_crypt(desc, dst, src, nbytes, + crypto_speck64_encrypt, + speck64_xts_encrypt_neon); +} + +static int speck64_xts_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return __speck64_xts_crypt(desc, dst, src, nbytes, + crypto_speck64_decrypt, + speck64_xts_decrypt_neon); +} + +static int speck64_xts_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct speck64_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + if (keylen % 2) + return -EINVAL; + + keylen /= 2; + + err = crypto_speck64_setkey(&ctx->main_key, key, keylen); + if (err) + return err; + + return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen); +} + +static struct crypto_alg speck_algs[] = { + { + .cra_name = "xts(speck128)", + .cra_driver_name = "xts-speck128-neon", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SPECK128_BLOCK_SIZE, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx), + .cra_alignmask = 7, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * SPECK128_128_KEY_SIZE, + .max_keysize = 2 * SPECK128_256_KEY_SIZE, + .ivsize = SPECK128_BLOCK_SIZE, + .setkey = speck128_xts_setkey, + .encrypt = speck128_xts_encrypt, + .decrypt = speck128_xts_decrypt, + } + } + }, { + .cra_name = "xts(speck64)", + .cra_driver_name = "xts-speck64-neon", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SPECK64_BLOCK_SIZE, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx), + .cra_alignmask = 7, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * SPECK64_96_KEY_SIZE, + .max_keysize = 2 * SPECK64_128_KEY_SIZE, + .ivsize = SPECK64_BLOCK_SIZE, + .setkey = speck64_xts_setkey, + .encrypt = speck64_xts_encrypt, + .decrypt = speck64_xts_decrypt, + } + } + } +}; + +static int __init speck_neon_module_init(void) +{ + if (!(elf_hwcap & HWCAP_NEON)) + return -ENODEV; + return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +static void __exit speck_neon_module_exit(void) +{ + crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +module_init(speck_neon_module_init); +module_exit(speck_neon_module_exit); + +MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biggers "); +MODULE_ALIAS_CRYPTO("xts(speck128)"); +MODULE_ALIAS_CRYPTO("xts-speck128-neon"); +MODULE_ALIAS_CRYPTO("xts(speck64)"); +MODULE_ALIAS_CRYPTO("xts-speck64-neon"); diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 4531eb9801cd7309c18dd6c100f6ca4c71cf23df..9fe51e6d0f49c86b0c00bbc2472ccbe3230e6246 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -37,4 +37,3 @@ generic-y += termbits.h generic-y += termios.h generic-y += timex.h generic-y += trace_clock.h -generic-y += unaligned.h diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 700369a54b41f0ea876269e83842570fd819b73b..b73d9b8e14b1aa18739fa6d09ba1e4629f5057f8 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -495,4 +495,14 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm +#ifdef CONFIG_KPROBES +#define _ASM_NOKPROBE(entry) \ + .pushsection "_kprobe_blacklist", "aw" ; \ + .balign 4 ; \ + .long entry; \ + .popsection +#else +#define _ASM_NOKPROBE(entry) +#endif + #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h index 0a9d5dd932941a1f0635574904ecd47259b87295..6949c7d4481c46057161415e8f2c7a8a3d0aac04 100644 --- a/arch/arm/include/asm/kgdb.h +++ b/arch/arm/include/asm/kgdb.h @@ -76,7 +76,7 @@ extern int kgdb_fault_expected; #define KGDB_MAX_NO_CPUS 1 #define BUFMAX 400 -#define NUMREGBYTES (DBG_MAX_REG_NUM << 2) +#define NUMREGBYTES (GDB_MAX_REGS << 2) #define NUMCRITREGBYTES (32 << 2) #define _R0 0 diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h index 816db0bf2dd8addbd9844488b5a72d4495be72c7..4b9a3d09181f27cedec9a844b50b66ba65f42150 100644 --- a/arch/arm/include/asm/kvm_arm.h +++ b/arch/arm/include/asm/kvm_arm.h @@ -161,8 +161,7 @@ #else #define VTTBR_X (5 - KVM_T0SZ) #endif -#define VTTBR_BADDR_SHIFT (VTTBR_X - 1) -#define VTTBR_BADDR_MASK (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) +#define VTTBR_BADDR_MASK (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_X) #define VTTBR_VMID_SHIFT (48LLU) #define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT) @@ -208,6 +207,7 @@ #define HSR_EC_IABT_HYP (0x21) #define HSR_EC_DABT (0x24) #define HSR_EC_DABT_HYP (0x25) +#define HSR_EC_MAX (0x3f) #define HSR_WFI_IS_WFE (1U << 0) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index c5a51e79e74f73a3a5f4324c27af93bae5ee1e3f..1a5fe8f4797cd2c20965df72dc6d4741fa47ad7a 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -251,7 +251,7 @@ extern int __put_user_8(void *, unsigned long long); ({ \ unsigned long __limit = current_thread_info()->addr_limit - 1; \ const typeof(*(p)) __user *__tmp_p = (p); \ - register const typeof(*(p)) __r2 asm("r2") = (x); \ + register typeof(*(p)) __r2 asm("r2") = (x); \ register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \ register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ diff --git a/arch/arm/include/asm/unaligned.h b/arch/arm/include/asm/unaligned.h new file mode 100644 index 0000000000000000000000000000000000000000..ab905ffcf1930dd456601b21af4b9cd3b21c9ff6 --- /dev/null +++ b/arch/arm/include/asm/unaligned.h @@ -0,0 +1,27 @@ +#ifndef __ASM_ARM_UNALIGNED_H +#define __ASM_ARM_UNALIGNED_H + +/* + * We generally want to set CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS on ARMv6+, + * but we don't want to use linux/unaligned/access_ok.h since that can lead + * to traps on unaligned stm/ldm or strd/ldrd. + */ +#include + +#if defined(__LITTLE_ENDIAN) +# include +# include +# include +# define get_unaligned __get_unaligned_le +# define put_unaligned __put_unaligned_le +#elif defined(__BIG_ENDIAN) +# include +# include +# include +# define get_unaligned __get_unaligned_be +# define put_unaligned __put_unaligned_be +#else +# error need to define endianess +#endif + +#endif /* __ASM_ARM_UNALIGNED_H */ diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h index 8b1f37bfeeecf3c2d8af09ed15bcbc4cc8fa991f..b7aadab9b0e8a1c4f71d957ca148fe4d01f11d77 100644 --- a/arch/arm/include/asm/xen/events.h +++ b/arch/arm/include/asm/xen/events.h @@ -16,7 +16,7 @@ static inline int xen_irqs_disabled(struct pt_regs *regs) return raw_irqs_disabled_flags(regs->ARM_cpsr); } -#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr), \ +#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((long long*)(ptr),\ atomic64_t, \ counter), (val)) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 0edf561dd55dfe664e17347d0c1caa75d26b2bc0..3bbe258e3699feee467b1826d937bc0bf013cc99 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef CONFIG_NEED_RET_TO_USER #include @@ -33,6 +34,9 @@ ret_fast_syscall: UNWIND(.fnstart ) UNWIND(.cantunwind ) disable_irq @ disable interrupts + ldr r2, [tsk, #TI_ADDR_LIMIT] + cmp r2, #TASK_SIZE + blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing tst r1, #_TIF_SYSCALL_WORK bne __sys_trace_return @@ -69,6 +73,9 @@ ENTRY(ret_to_user) ret_slow_syscall: disable_irq @ disable interrupts ENTRY(ret_to_user_from_irq) + ldr r2, [tsk, #TI_ADDR_LIMIT] + cmp r2, #TASK_SIZE + blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne work_pending diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 81d104cd58b796628970134756257d099604882d..a84caf7f826704e8134217606f6a36da0d01e8e0 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -639,3 +640,9 @@ struct page *get_signal_page(void) return page; } + +/* Defer to generic check */ +asmlinkage void addr_limit_check_failed(void) +{ + addr_limit_user_check(); +} diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 04541e05da3ffeefba90237c9e42b597f1eb2b57..0fc3de708d78f212f960c31ed5f5420f7742fb8b 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -135,30 +136,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, set_fs(fs); } -static void dump_instr(const char *lvl, struct pt_regs *regs) +static void __dump_instr(const char *lvl, struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); const int thumb = thumb_mode(regs); const int width = thumb ? 4 : 8; - mm_segment_t fs; char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; int i; /* - * We need to switch to kernel mode so that we can use __get_user - * to safely read from kernel space. Note that we now dump the - * code first, just in case the backtrace kills us. + * Note that we now dump the code first, just in case the backtrace + * kills us. */ - fs = get_fs(); - set_fs(KERNEL_DS); for (i = -4; i < 1 + !!thumb; i++) { unsigned int val, bad; if (thumb) - bad = __get_user(val, &((u16 *)addr)[i]); + bad = get_user(val, &((u16 *)addr)[i]); else - bad = __get_user(val, &((u32 *)addr)[i]); + bad = get_user(val, &((u32 *)addr)[i]); if (!bad) p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", @@ -169,8 +166,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) } } printk("%sCode: %s\n", lvl, str); +} - set_fs(fs); +static void dump_instr(const char *lvl, struct pt_regs *regs) +{ + mm_segment_t fs; + + if (!user_mode(regs)) { + fs = get_fs(); + set_fs(KERNEL_DS); + __dump_instr(lvl, regs); + set_fs(fs); + } else { + __dump_instr(lvl, regs); + } } #ifdef CONFIG_ARM_UNWIND @@ -390,7 +399,8 @@ void unregister_undef_hook(struct undef_hook *hook) raw_spin_unlock_irqrestore(&undef_lock, flags); } -static int call_undef_hook(struct pt_regs *regs, unsigned int instr) +static nokprobe_inline +int call_undef_hook(struct pt_regs *regs, unsigned int instr) { struct undef_hook *hook; unsigned long flags; @@ -465,6 +475,7 @@ die_sig: arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6); } +NOKPROBE_SYMBOL(do_undefinstr) /* * Handle FIQ similarly to NMI on x86 systems. diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index a96a8043277c3de69cc460a5b2a3f83a36fc30ed..b6ac50b85d726b86c3af1d51a7a7b44471ab0d23 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c @@ -98,7 +98,19 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } +static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + + kvm_pr_unimpl("Unknown exception class: hsr: %#08x\n", + hsr); + + kvm_inject_undefined(vcpu); + return 1; +} + static exit_handle_fn arm_exit_handlers[] = { + [0 ... HSR_EC_MAX] = kvm_handle_unknown_ec, [HSR_EC_WFI] = kvm_handle_wfx, [HSR_EC_CP15_32] = kvm_handle_cp15_32, [HSR_EC_CP15_64] = kvm_handle_cp15_64, @@ -120,13 +132,6 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) { u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu); - if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) || - !arm_exit_handlers[hsr_ec]) { - kvm_err("Unknown exception class: hsr: %#08x\n", - (unsigned int)kvm_vcpu_get_hsr(vcpu)); - BUG(); - } - return arm_exit_handlers[hsr_ec]; } diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 70ccd1ea5ba18298f2e4e34fb92bcf96639451b1..70b4254674a2b9c244b6f5b946b089a67b9e3b2b 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -841,19 +841,35 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache pmd = stage2_get_pmd(kvm, cache, addr); VM_BUG_ON(!pmd); - /* - * Mapping in huge pages should only happen through a fault. If a - * page is merged into a transparent huge page, the individual - * subpages of that huge page should be unmapped through MMU - * notifiers before we get here. - * - * Merging of CompoundPages is not supported; they should become - * splitting first, unmapped, merged, and mapped back in on-demand. - */ - VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd)); - old_pmd = *pmd; if (pmd_present(old_pmd)) { + /* + * Multiple vcpus faulting on the same PMD entry, can + * lead to them sequentially updating the PMD with the + * same value. Following the break-before-make + * (pmd_clear() followed by tlb_flush()) process can + * hinder forward progress due to refaults generated + * on missing translations. + * + * Skip updating the page table if the entry is + * unchanged. + */ + if (pmd_val(old_pmd) == pmd_val(*new_pmd)) + return 0; + + /* + * Mapping in huge pages should only happen through a + * fault. If a page is merged into a transparent huge + * page, the individual subpages of that huge page + * should be unmapped through MMU notifiers before we + * get here. + * + * Merging of CompoundPages is not supported; they + * should become splitting first, unmapped, merged, + * and mapped back in on-demand. + */ + VM_BUG_ON(pmd_pfn(old_pmd) != pmd_pfn(*new_pmd)); + pmd_clear(pmd); kvm_tlb_flush_vmid_ipa(kvm, addr); } else { @@ -898,6 +914,10 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, /* Create 2nd stage page table mapping - Level 3 */ old_pte = *pte; if (pte_present(old_pte)) { + /* Skip page table update if there is no change */ + if (pte_val(old_pte) == pte_val(*new_pte)) + return 0; + kvm_set_pte(pte, __pte(0)); kvm_tlb_flush_vmid_ipa(kvm, addr); } else { diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 2c8e3b6dead08a66fae7090415b92750ea276fd0..7a11923cf04c9c28062fa1131968617bc8e2bc3b 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S @@ -85,7 +85,11 @@ .pushsection .fixup,"ax" .align 4 9001: mov r4, #-EFAULT +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + ldr r5, [sp, #9*4] @ *err_ptr +#else ldr r5, [sp, #8*4] @ *err_ptr +#endif str r4, [r5] ldmia sp, {r1, r2} @ retrieve dst, len add r2, r2, r1 diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 8ecfd15c3a0248db29667fe3dc6ec6429fc9fc7c..6ffa59e373b19889953482a4be436afc617eec0b 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -38,6 +38,7 @@ ENTRY(__get_user_1) mov r0, #0 ret lr ENDPROC(__get_user_1) +_ASM_NOKPROBE(__get_user_1) ENTRY(__get_user_2) check_uaccess r0, 2, r1, r2, __get_user_bad @@ -58,6 +59,7 @@ rb .req r0 mov r0, #0 ret lr ENDPROC(__get_user_2) +_ASM_NOKPROBE(__get_user_2) ENTRY(__get_user_4) check_uaccess r0, 4, r1, r2, __get_user_bad @@ -65,6 +67,7 @@ ENTRY(__get_user_4) mov r0, #0 ret lr ENDPROC(__get_user_4) +_ASM_NOKPROBE(__get_user_4) ENTRY(__get_user_8) check_uaccess r0, 8, r1, r2, __get_user_bad @@ -78,6 +81,7 @@ ENTRY(__get_user_8) mov r0, #0 ret lr ENDPROC(__get_user_8) +_ASM_NOKPROBE(__get_user_8) #ifdef __ARMEB__ ENTRY(__get_user_32t_8) @@ -91,6 +95,7 @@ ENTRY(__get_user_32t_8) mov r0, #0 ret lr ENDPROC(__get_user_32t_8) +_ASM_NOKPROBE(__get_user_32t_8) ENTRY(__get_user_64t_1) check_uaccess r0, 1, r1, r2, __get_user_bad8 @@ -98,6 +103,7 @@ ENTRY(__get_user_64t_1) mov r0, #0 ret lr ENDPROC(__get_user_64t_1) +_ASM_NOKPROBE(__get_user_64t_1) ENTRY(__get_user_64t_2) check_uaccess r0, 2, r1, r2, __get_user_bad8 @@ -114,6 +120,7 @@ rb .req r0 mov r0, #0 ret lr ENDPROC(__get_user_64t_2) +_ASM_NOKPROBE(__get_user_64t_2) ENTRY(__get_user_64t_4) check_uaccess r0, 4, r1, r2, __get_user_bad8 @@ -121,6 +128,7 @@ ENTRY(__get_user_64t_4) mov r0, #0 ret lr ENDPROC(__get_user_64t_4) +_ASM_NOKPROBE(__get_user_64t_4) #endif __get_user_bad8: @@ -131,6 +139,8 @@ __get_user_bad: ret lr ENDPROC(__get_user_bad) ENDPROC(__get_user_bad8) +_ASM_NOKPROBE(__get_user_bad) +_ASM_NOKPROBE(__get_user_bad8) .pushsection __ex_table, "a" .long 1b, __get_user_bad diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 06d63d5651f3342be529dc0bc15d1e95b1341e0e..86b51f38e296bfbe96c066068d35e33c10778b73 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -170,11 +171,16 @@ static struct resource dm355evm_dm9000_rsrc[] = { }, }; +static struct dm9000_plat_data dm335evm_dm9000_platdata; + static struct platform_device dm355evm_dm9000 = { .name = "dm9000", .id = -1, .resource = dm355evm_dm9000_rsrc, .num_resources = ARRAY_SIZE(dm355evm_dm9000_rsrc), + .dev = { + .platform_data = &dm335evm_dm9000_platdata, + }, }; static struct tvp514x_platform_data tvp5146_pdata = { diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index ae129bc4927381f44759eb2b745d97e0a1ea9e34..91ed570745ea27aa2ef944ec7213928afff617d7 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -538,7 +538,7 @@ static struct vpif_display_config dm646x_vpif_display_config = { .outputs = dm6467_ch0_outputs, .output_count = ARRAY_SIZE(dm6467_ch0_outputs), }, - .card_name = "DM646x EVM", + .card_name = "DM646x EVM Video Display", }; /** @@ -696,6 +696,7 @@ static struct vpif_capture_config dm646x_vpif_capture_cfg = { .fid_pol = 0, }, }, + .card_name = "DM646x EVM Video Capture", }; static void __init evm_init_video(void) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index b85b781b05fdf7d89d7a3c256727ea9024b6d0d8..e83874ba6e6dcc06072af02a894030dbbb721b81 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -761,6 +761,8 @@ static struct platform_device da8xx_dsp = { .resource = da8xx_rproc_resources, }; +static bool rproc_mem_inited __initdata; + #if IS_ENABLED(CONFIG_DA8XX_REMOTEPROC) static phys_addr_t rproc_base __initdata; @@ -799,6 +801,8 @@ void __init da8xx_rproc_reserve_cma(void) ret = dma_declare_contiguous(&da8xx_dsp.dev, rproc_size, rproc_base, 0); if (ret) pr_err("%s: dma_declare_contiguous failed %d\n", __func__, ret); + else + rproc_mem_inited = true; } #else @@ -813,6 +817,12 @@ int __init da8xx_register_rproc(void) { int ret; + if (!rproc_mem_inited) { + pr_warn("%s: memory not reserved for DSP, not registering DSP device\n", + __func__); + return -ENOMEM; + } + ret = platform_device_register(&da8xx_dsp); if (ret) pr_err("%s: can't register DSP device: %d\n", __func__, ret); diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c index 84e6919f68c7316f3b866a0ba61087066eaa111d..f31b4d99b5fb451cf3c2ac0ff433dba5b4c0724d 100644 --- a/arch/arm/mach-hisi/hotplug.c +++ b/arch/arm/mach-hisi/hotplug.c @@ -145,13 +145,20 @@ static int hi3xxx_hotplug_init(void) struct device_node *node; node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); - if (node) { - ctrl_base = of_iomap(node, 0); - id = HI3620_CTRL; - return 0; + if (!node) { + id = ERROR_CTRL; + return -ENOENT; } - id = ERROR_CTRL; - return -ENOENT; + + ctrl_base = of_iomap(node, 0); + of_node_put(node); + if (!ctrl_base) { + id = ERROR_CTRL; + return -ENOMEM; + } + + id = HI3620_CTRL; + return 0; } void hi3xxx_set_cpu(int cpu, bool enable) @@ -170,11 +177,15 @@ static bool hix5hd2_hotplug_init(void) struct device_node *np; np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl"); - if (np) { - ctrl_base = of_iomap(np, 0); - return true; - } - return false; + if (!np) + return false; + + ctrl_base = of_iomap(np, 0); + of_node_put(np); + if (!ctrl_base) + return false; + + return true; } void hix5hd2_set_cpu(int cpu, bool enable) diff --git a/arch/arm/mach-keystone/pm_domain.c b/arch/arm/mach-keystone/pm_domain.c index ca79ddac38bcd6ff1e00457a858006271762c861..2c95d5706717470363136b73b1a89ff24ee698ac 100644 --- a/arch/arm/mach-keystone/pm_domain.c +++ b/arch/arm/mach-keystone/pm_domain.c @@ -59,6 +59,7 @@ static struct dev_pm_domain keystone_pm_domain = { static struct pm_clk_notifier_block platform_domain_notifier = { .pm_domain = &keystone_pm_domain, + .con_ids = { NULL }, }; static struct of_device_id of_keystone_table[] = { diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index c1e4567a5ab3ed8cfc10da7340beb624a7e0713c..2d0cc0d8863946461c0d5142c3af0d0b3d01d2e8 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -37,7 +37,7 @@ config MACH_ARMADA_370 config MACH_ARMADA_375 bool "Marvell Armada 375 boards" if ARCH_MULTI_V7 select ARM_ERRATA_720789 - select ARM_ERRATA_753970 + select PL310_ERRATA_753970 select ARM_GIC select ARMADA_375_CLK select HAVE_ARM_SCU @@ -52,7 +52,7 @@ config MACH_ARMADA_375 config MACH_ARMADA_38X bool "Marvell Armada 380/385 boards" if ARCH_MULTI_V7 select ARM_ERRATA_720789 - select ARM_ERRATA_753970 + select PL310_ERRATA_753970 select ARM_GIC select ARMADA_38X_CLK select HAVE_ARM_SCU diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 6f8a85c5965c05303a3b8ae4a8ccce02edfca4b9..7bbe32e56bbc5af14833aae660da6ace2279c75e 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -117,8 +117,8 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); } -extern unsigned char mvebu_boot_wa_start; -extern unsigned char mvebu_boot_wa_end; +extern unsigned char mvebu_boot_wa_start[]; +extern unsigned char mvebu_boot_wa_end[]; /* * This function sets up the boot address workaround needed for SMP @@ -131,7 +131,7 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, phys_addr_t resume_addr_reg) { void __iomem *sram_virt_base; - u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start; + u32 code_len = mvebu_boot_wa_end - mvebu_boot_wa_start; mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); mvebu_mbus_add_window_by_id(crypto_eng_target, crypto_eng_attribute, diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 4f5fd4a084c06971e2faa21a255bae822a295043..034b89499bd72ff152ec9c0ce4593b069987986b 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -1031,17 +1031,17 @@ static int clk_debugfs_register_one(struct clk *c) return -ENOMEM; c->dent = d; - d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount); + d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount); if (!d) { err = -ENOMEM; goto err_out; } - d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); + d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate); if (!d) { err = -ENOMEM; goto err_out; } - d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); + d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags); if (!d) { err = -ENOMEM; goto err_out; diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c index 4be601b638d7aa8c0d35b7fa5924eb54aa6e2534..8129e5f9c94d0e95c5f44bdc46428beb037b6a27 100644 --- a/arch/arm/mach-omap1/dma.c +++ b/arch/arm/mach-omap1/dma.c @@ -31,7 +31,6 @@ #include #define OMAP1_DMA_BASE (0xfffed800) -#define OMAP1_LOGICAL_DMA_CH_COUNT 17 static u32 enable_1510_mode; @@ -311,8 +310,6 @@ static int __init omap1_system_dma_init(void) goto exit_iounmap; } - d->lch_count = OMAP1_LOGICAL_DMA_CH_COUNT; - /* Valid attributes for omap1 plus processors */ if (cpu_is_omap15xx()) d->dev_caps = ENABLE_1510_MODE; @@ -329,13 +326,14 @@ static int __init omap1_system_dma_init(void) d->dev_caps |= CLEAR_CSR_ON_READ; d->dev_caps |= IS_WORD_16; - if (cpu_is_omap15xx()) - d->chan_count = 9; - else if (cpu_is_omap16xx() || cpu_is_omap7xx()) { - if (!(d->dev_caps & ENABLE_1510_MODE)) - d->chan_count = 16; + /* available logical channels */ + if (cpu_is_omap15xx()) { + d->lch_count = 9; + } else { + if (d->dev_caps & ENABLE_1510_MODE) + d->lch_count = 9; else - d->chan_count = 9; + d->lch_count = 16; } p = dma_plat_info; diff --git a/arch/arm/mach-omap2/clockdomains7xx_data.c b/arch/arm/mach-omap2/clockdomains7xx_data.c index 7581e036bda62e5b58c01140929d08705f7bbb8e..70e3b711e79c621faf2583109526c9c83912efd2 100644 --- a/arch/arm/mach-omap2/clockdomains7xx_data.c +++ b/arch/arm/mach-omap2/clockdomains7xx_data.c @@ -524,7 +524,7 @@ static struct clockdomain pcie_7xx_clkdm = { .dep_bit = DRA7XX_PCIE_STATDEP_SHIFT, .wkdep_srcs = pcie_wkup_sleep_deps, .sleepdep_srcs = pcie_wkup_sleep_deps, - .flags = CLKDM_CAN_HWSUP_SWSUP, + .flags = CLKDM_CAN_SWSUP, }; static struct clockdomain atl_7xx_clkdm = { diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index cb034dd6754507e9f382e8fe65eebfff1434a2f2..23196dc030faa50c4f36bffeac6bcfe4048d1a38 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -340,7 +340,6 @@ static void pdata_quirks_check(struct pdata_init *quirks) if (of_machine_is_compatible(quirks->compatible)) { if (quirks->fn) quirks->fn(); - break; } quirks++; } diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 58920bc8807bce963536296bc7914db421c2b6aa..3d876bde8c859884fa66bb3a76e38c83fece96f6 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -231,7 +231,7 @@ static void omap_pm_end(void) cpu_idle_poll_ctrl(false); } -static void omap_pm_finish(void) +static void omap_pm_wake(void) { if (cpu_is_omap34xx()) omap_prcm_irq_complete(); @@ -241,7 +241,7 @@ static const struct platform_suspend_ops omap_pm_ops = { .begin = omap_pm_begin, .end = omap_pm_end, .enter = omap_pm_enter, - .finish = omap_pm_finish, + .wake = omap_pm_wake, .valid = suspend_valid_only_mem, }; diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 62709cd2f9c579cb896fc030ebbcc213db0b9263..1b774985997e29787853553deab27e16daa32fe2 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -165,17 +165,6 @@ static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm) return v; } -static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) -{ - u32 v; - - v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); - v &= AM33XX_LASTPOWERSTATEENTERED_MASK; - v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT; - - return v; -} - static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) { am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK, @@ -329,7 +318,6 @@ struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, .pwrdm_read_pwrst = am33xx_pwrdm_read_pwrst, - .pwrdm_read_prev_pwrst = am33xx_pwrdm_read_prev_pwrst, .pwrdm_set_logic_retst = am33xx_pwrdm_set_logic_retst, .pwrdm_read_logic_pwrst = am33xx_pwrdm_read_logic_pwrst, .pwrdm_read_logic_retst = am33xx_pwrdm_read_logic_retst, diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 0eecd83c624e3d98573d542efb834e7371cffc00..d7f382856c4216496a9d19512819ed1176981393 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -160,7 +160,7 @@ static int pxa_irq_suspend(void) { int i; - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { + for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) { void __iomem *base = irq_base(i); saved_icmr[i] = __raw_readl(base + ICMR); @@ -179,7 +179,7 @@ static void pxa_irq_resume(void) { int i; - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { + for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) { void __iomem *base = irq_base(i); __raw_writel(saved_icmr[i], base + ICMR); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index b46dc09b3a6458dc5754b2c95c9372294ed5ccb7..4a215a0bd192f0e32ed562c5e069078b7084b068 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -864,13 +864,31 @@ static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_add __arm_dma_free(dev, size, cpu_addr, handle, attrs, true); } +/* + * The whole dma_get_sgtable() idea is fundamentally unsafe - it seems + * that the intention is to allow exporting memory allocated via the + * coherent DMA APIs through the dma_buf API, which only accepts a + * scattertable. This presents a couple of problems: + * 1. Not all memory allocated via the coherent DMA APIs is backed by + * a struct page + * 2. Passing coherent DMA memory into the streaming APIs is not allowed + * as we will try to flush the memory through a different alias to that + * actually being used (and the flushes are redundant.) + */ int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr, dma_addr_t handle, size_t size, struct dma_attrs *attrs) { - struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); + unsigned long pfn = dma_to_pfn(dev, handle); + struct page *page; int ret; + /* If the PFN is not valid, we do not have a struct page */ + if (!pfn_valid(pfn)) + return -ENXIO; + + page = pfn_to_page(pfn); + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); if (unlikely(ret)) return ret; diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c index 59424937e52b8839c4fb4504aedbc93584b4304e..e223322fc71ba7348f46e9228fd08ed3b437e2df 100644 --- a/arch/arm/mm/dump.c +++ b/arch/arm/mm/dump.c @@ -126,8 +126,8 @@ static const struct prot_bits section_bits[] = { .val = PMD_SECT_USER, .set = "USR", }, { - .mask = L_PMD_SECT_RDONLY, - .val = L_PMD_SECT_RDONLY, + .mask = L_PMD_SECT_RDONLY | PMD_SECT_AP2, + .val = L_PMD_SECT_RDONLY | PMD_SECT_AP2, .set = "ro", .clear = "RW", #elif __LINUX_ARM_ARCH__ >= 6 diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 6e563bde7a294b93193bba3e50b96906d7199d9c..c71ed6f896e159e4195a171b4c85d5f5907e9a1f 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -240,7 +240,11 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max_low, #ifdef CONFIG_HAVE_ARCH_PFN_VALID int pfn_valid(unsigned long pfn) { - return memblock_is_memory(__pfn_to_phys(pfn)); + phys_addr_t addr = __pfn_to_phys(pfn); + + if (__phys_to_pfn(addr) != pfn) + return 0; + return memblock_is_memory(addr); } EXPORT_SYMBOL(pfn_valid); #endif diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index db10169a08de78980d0ad17b71224f96bbfb1d5c..609eceaf06ad651b96ab98cdd1b54e35213b0010 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -853,11 +853,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev) timer->irq = irq->start; timer->pdev = pdev; - /* Skip pm_runtime_enable for OMAP1 */ - if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { - pm_runtime_enable(dev); - pm_runtime_irq_safe(dev); - } + pm_runtime_enable(dev); + pm_runtime_irq_safe(dev); if (!timer->reserved) { pm_runtime_get_sync(dev); diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c index f8a576b1d9bb00071158178408807dee021b4cff..5409d70ffe6fb3f824e1642301dfdce2c4050a7a 100644 --- a/arch/arm/xen/mm.c +++ b/arch/arm/xen/mm.c @@ -59,6 +59,7 @@ static struct dma_map_ops xen_swiotlb_dma_ops = { .unmap_page = xen_swiotlb_unmap_page, .dma_supported = xen_swiotlb_dma_supported, .set_dma_mask = xen_swiotlb_set_dma_mask, + .mmap = xen_swiotlb_dma_mmap, }; int __init xen_mm_init(void) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 62739dcd54e78e853d6591ad617368bb0930f080..435c59f4bd82f3e212d760b1ff79db4d3242d9ba 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -64,6 +64,7 @@ config ARM64 select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_GENERIC_DMA_COHERENT + select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IRQ_TIME_ACCOUNTING select HAVE_MEMBLOCK select HAVE_PATA_PLATFORM diff --git a/arch/arm64/configs/apq8053_IoE-perf_defconfig b/arch/arm64/configs/apq8053_IoE-perf_defconfig index beb2ade9603262e41c606920ed1013b77ebfbed4..a7ac083097a12b50d2316d7b77c531d1ed15920f 100644 --- a/arch/arm64/configs/apq8053_IoE-perf_defconfig +++ b/arch/arm64/configs/apq8053_IoE-perf_defconfig @@ -3,6 +3,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y @@ -543,7 +546,6 @@ CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_ICNSS=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_KERNEL_PROTECT=y diff --git a/arch/arm64/configs/markw_defconfig b/arch/arm64/configs/markw_defconfig index f44fc1fc874a2293fb759161b99ce419e3a9efb0..238ace8f2725422050a2619856ef6ea70bfb622f 100644 --- a/arch/arm64/configs/markw_defconfig +++ b/arch/arm64/configs/markw_defconfig @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm64 3.18.71 Kernel Configuration +# Linux/arm64 3.18.124 Kernel Configuration # CONFIG_ARM64=y CONFIG_64BIT=y @@ -43,7 +43,7 @@ CONFIG_BUILDTIME_EXTABLE_SORT=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_CROSS_COMPILE="" # CONFIG_COMPILE_TEST is not set -CONFIG_LOCALVERSION="-Nosgoth_V7" +CONFIG_LOCALVERSION="-Nosgoth_V8-Q" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_DEFAULT_HOSTNAME="(none)" CONFIG_SWAP=y @@ -601,8 +601,6 @@ CONFIG_XFRM_IPCOMP=y CONFIG_NET_KEY=y # CONFIG_NET_KEY_MIGRATE is not set CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y # CONFIG_IP_FIB_TRIE_STATS is not set diff --git a/arch/arm64/configs/msm-auto-gvm_defconfig b/arch/arm64/configs/msm-auto-gvm_defconfig index b9ce1edbbf1e1ec8f107add21b1bc33767ae18ca..959eae1a4727c67cfb54585dc74131a33f53c903 100644 --- a/arch/arm64/configs/msm-auto-gvm_defconfig +++ b/arch/arm64/configs/msm-auto-gvm_defconfig @@ -266,6 +266,7 @@ CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_KERNEL_TEXT_RDONLY=y diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 72af00e39cba704b9c374611f0de691e52f17481..19aa7ac7b77f955e7150712ece8b94d80f02fc7c 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -5,6 +5,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -384,12 +387,8 @@ CONFIG_SOC_CAMERA_PLATFORM=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y -CONFIG_MSM_AIS=y -CONFIG_MSM_AIS_DEBUG=y -CONFIG_MSM_AIS_CAMERA_SENSOR=y CONFIG_RADIO_SILABS=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -CONFIG_VIDEO_ADV7481=y CONFIG_MSM_KGSL=y CONFIG_FB=y CONFIG_FB_MSM=y @@ -453,6 +452,8 @@ CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH=y CONFIG_LEDS_QPNP_WLED=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index 390cfc4aa1e5c4bb111fce44f317aed8e1bd6a96..a4b0d7d9bccecb7916f52cc4b60d83ebb5da2b3c 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -4,6 +4,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -387,12 +390,8 @@ CONFIG_SOC_CAMERA_PLATFORM=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y -CONFIG_MSM_AIS=y -CONFIG_MSM_AIS_DEBUG=y -CONFIG_MSM_AIS_CAMERA_SENSOR=y CONFIG_RADIO_SILABS=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -CONFIG_VIDEO_ADV7481=y CONFIG_MSM_KGSL=y CONFIG_FB=y CONFIG_FB_MSM=y @@ -456,6 +455,8 @@ CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH=y CONFIG_LEDS_QPNP_WLED=y @@ -643,6 +644,7 @@ CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index d51f8ff950852531adc6b39c385f5446bf179a7b..94cbe80423799860e0e21cd37953267b2213fd3f 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -590,10 +590,6 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_QPDI=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -633,8 +629,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y # CONFIG_INTEGRITY is not set -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index e4cb9404e644275d87020dc7f12c0252822c55ff..068e3a054a6a5423721c52911f2a75ffea4aef3c 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -96,11 +96,14 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y @@ -110,6 +113,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -117,7 +121,6 @@ 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 @@ -162,6 +165,7 @@ 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_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -196,6 +200,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y @@ -602,10 +607,6 @@ CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -628,7 +629,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y CONFIG_TIMER_STATS=y @@ -642,8 +642,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index 2c5f551c9d0e5b1386551f01421847de4623fc9b..722aa8827fbfa053c5f778b62e5773d6d67c7043 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -95,11 +95,14 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y @@ -109,6 +112,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -116,7 +120,6 @@ 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 @@ -161,6 +164,7 @@ 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_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -195,6 +199,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y @@ -483,6 +488,7 @@ CONFIG_USB_G_ANDROID=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_CLKGATE=y +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y @@ -617,10 +623,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_QPDI=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -682,6 +684,7 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_LKDTM=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_DEBUG_RODATA=y @@ -691,8 +694,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index fb769c1cde09e8d1d6c245c1413c2e78e507fe36..27c2720ca82b24410ca9ed37111fe3836ecf6645 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -610,10 +610,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_QPDI=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -677,6 +673,7 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_LKDTM=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y @@ -689,8 +686,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y # CONFIG_INTEGRITY is not set -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 0bbd7446b9d21209d8ead4d56b6b3bc02253ac25..c9b16d8adba0c801efe1b9b5cbac1e8b1fa6eb2e 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -92,6 +92,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -106,6 +107,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -566,7 +568,6 @@ CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_ICNSS=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_KERNEL_PROTECT=y @@ -606,7 +607,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y CONFIG_TIMER_STATS=y @@ -620,8 +620,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 677786640691599b48472cf5ac8535537af1115d..407e340e1643e0c46e4c773532ff2235db647f65 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -91,6 +91,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -105,6 +106,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -484,6 +486,7 @@ CONFIG_USB_G_ANDROID=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_CLKGATE=y +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_TEST=m @@ -593,7 +596,6 @@ CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_TRACER_PKT=y -CONFIG_ICNSS=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_KERNEL_PROTECT=y @@ -624,10 +626,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_QPDI=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -682,6 +680,7 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_LKDTM=y CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_DEBUG_RODATA=y @@ -692,8 +691,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index 5562652c5316629089fbbecdabd24f03a1f302c6..a59e603d238cc8a08fc379dc6736a03748cd7951 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -50,4 +50,10 @@ config CRYPTO_AES_ARM64_NEON_BLK select CRYPTO_AES select CRYPTO_ABLK_HELPER +config CRYPTO_SPECK_NEON + tristate "NEON accelerated Speck cipher algorithms" + depends on KERNEL_MODE_NEON + select CRYPTO_BLKCIPHER + select CRYPTO_GF128MUL + select CRYPTO_SPECK endif diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index a3f935fde97527d2189fb7f6afffc9dc5102ba57..5b1166a68cbdddc64de91543726af16d495231e5 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -29,6 +29,9 @@ aes-ce-blk-y := aes-glue-ce.o aes-ce.o obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o aes-neon-blk-y := aes-glue-neon.o aes-neon.o +obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o +speck-neon-y := speck-neon-core.o speck-neon-glue.o + AFLAGS_aes-ce.o := -DINTERLEAVE=2 -DINTERLEAVE_INLINE AFLAGS_aes-neon.o := -DINTERLEAVE=4 diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher.c index 2075e1acae6b745ed9b8de2a828f449cfb8f08fa..28c05484cf24855714de410775e7c9d21a3360d5 100644 --- a/arch/arm64/crypto/aes-ce-cipher.c +++ b/arch/arm64/crypto/aes-ce-cipher.c @@ -127,7 +127,7 @@ static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_driver_name = "aes-ce", - .cra_priority = 300, + .cra_priority = 250, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypto_aes_ctx), diff --git a/arch/arm64/crypto/speck-neon-core.S b/arch/arm64/crypto/speck-neon-core.S new file mode 100644 index 0000000000000000000000000000000000000000..b14463438b0966b6bc37f2f7784b0285c51ce290 --- /dev/null +++ b/arch/arm64/crypto/speck-neon-core.S @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM64 NEON-accelerated implementation of Speck128-XTS and Speck64-XTS + * + * Copyright (c) 2018 Google, Inc + * + * Author: Eric Biggers + */ + +#include + + .text + + // arguments + ROUND_KEYS .req x0 // const {u64,u32} *round_keys + NROUNDS .req w1 // int nrounds + NROUNDS_X .req x1 + DST .req x2 // void *dst + SRC .req x3 // const void *src + NBYTES .req w4 // unsigned int nbytes + TWEAK .req x5 // void *tweak + + // registers which hold the data being encrypted/decrypted + // (underscores avoid a naming collision with ARM64 registers x0-x3) + X_0 .req v0 + Y_0 .req v1 + X_1 .req v2 + Y_1 .req v3 + X_2 .req v4 + Y_2 .req v5 + X_3 .req v6 + Y_3 .req v7 + + // the round key, duplicated in all lanes + ROUND_KEY .req v8 + + // index vector for tbl-based 8-bit rotates + ROTATE_TABLE .req v9 + ROTATE_TABLE_Q .req q9 + + // temporary registers + TMP0 .req v10 + TMP1 .req v11 + TMP2 .req v12 + TMP3 .req v13 + + // multiplication table for updating XTS tweaks + GFMUL_TABLE .req v14 + GFMUL_TABLE_Q .req q14 + + // next XTS tweak value(s) + TWEAKV_NEXT .req v15 + + // XTS tweaks for the blocks currently being encrypted/decrypted + TWEAKV0 .req v16 + TWEAKV1 .req v17 + TWEAKV2 .req v18 + TWEAKV3 .req v19 + TWEAKV4 .req v20 + TWEAKV5 .req v21 + TWEAKV6 .req v22 + TWEAKV7 .req v23 + + .align 4 +.Lror64_8_table: + .octa 0x080f0e0d0c0b0a090007060504030201 +.Lror32_8_table: + .octa 0x0c0f0e0d080b0a090407060500030201 +.Lrol64_8_table: + .octa 0x0e0d0c0b0a09080f0605040302010007 +.Lrol32_8_table: + .octa 0x0e0d0c0f0a09080b0605040702010003 +.Lgf128mul_table: + .octa 0x00000000000000870000000000000001 +.Lgf64mul_table: + .octa 0x0000000000000000000000002d361b00 + +/* + * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time + * + * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for + * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes + * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64. + * 'lanes' is the lane specifier: "2d" for Speck128 or "4s" for Speck64. + */ +.macro _speck_round_128bytes n, lanes + + // x = ror(x, 8) + tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b + tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b + tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b + tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b + + // x += y + add X_0.\lanes, X_0.\lanes, Y_0.\lanes + add X_1.\lanes, X_1.\lanes, Y_1.\lanes + add X_2.\lanes, X_2.\lanes, Y_2.\lanes + add X_3.\lanes, X_3.\lanes, Y_3.\lanes + + // x ^= k + eor X_0.16b, X_0.16b, ROUND_KEY.16b + eor X_1.16b, X_1.16b, ROUND_KEY.16b + eor X_2.16b, X_2.16b, ROUND_KEY.16b + eor X_3.16b, X_3.16b, ROUND_KEY.16b + + // y = rol(y, 3) + shl TMP0.\lanes, Y_0.\lanes, #3 + shl TMP1.\lanes, Y_1.\lanes, #3 + shl TMP2.\lanes, Y_2.\lanes, #3 + shl TMP3.\lanes, Y_3.\lanes, #3 + sri TMP0.\lanes, Y_0.\lanes, #(\n - 3) + sri TMP1.\lanes, Y_1.\lanes, #(\n - 3) + sri TMP2.\lanes, Y_2.\lanes, #(\n - 3) + sri TMP3.\lanes, Y_3.\lanes, #(\n - 3) + + // y ^= x + eor Y_0.16b, TMP0.16b, X_0.16b + eor Y_1.16b, TMP1.16b, X_1.16b + eor Y_2.16b, TMP2.16b, X_2.16b + eor Y_3.16b, TMP3.16b, X_3.16b +.endm + +/* + * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time + * + * This is the inverse of _speck_round_128bytes(). + */ +.macro _speck_unround_128bytes n, lanes + + // y ^= x + eor TMP0.16b, Y_0.16b, X_0.16b + eor TMP1.16b, Y_1.16b, X_1.16b + eor TMP2.16b, Y_2.16b, X_2.16b + eor TMP3.16b, Y_3.16b, X_3.16b + + // y = ror(y, 3) + ushr Y_0.\lanes, TMP0.\lanes, #3 + ushr Y_1.\lanes, TMP1.\lanes, #3 + ushr Y_2.\lanes, TMP2.\lanes, #3 + ushr Y_3.\lanes, TMP3.\lanes, #3 + sli Y_0.\lanes, TMP0.\lanes, #(\n - 3) + sli Y_1.\lanes, TMP1.\lanes, #(\n - 3) + sli Y_2.\lanes, TMP2.\lanes, #(\n - 3) + sli Y_3.\lanes, TMP3.\lanes, #(\n - 3) + + // x ^= k + eor X_0.16b, X_0.16b, ROUND_KEY.16b + eor X_1.16b, X_1.16b, ROUND_KEY.16b + eor X_2.16b, X_2.16b, ROUND_KEY.16b + eor X_3.16b, X_3.16b, ROUND_KEY.16b + + // x -= y + sub X_0.\lanes, X_0.\lanes, Y_0.\lanes + sub X_1.\lanes, X_1.\lanes, Y_1.\lanes + sub X_2.\lanes, X_2.\lanes, Y_2.\lanes + sub X_3.\lanes, X_3.\lanes, Y_3.\lanes + + // x = rol(x, 8) + tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b + tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b + tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b + tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b +.endm + +.macro _next_xts_tweak next, cur, tmp, n +.if \n == 64 + /* + * Calculate the next tweak by multiplying the current one by x, + * modulo p(x) = x^128 + x^7 + x^2 + x + 1. + */ + sshr \tmp\().2d, \cur\().2d, #63 + and \tmp\().16b, \tmp\().16b, GFMUL_TABLE.16b + shl \next\().2d, \cur\().2d, #1 + ext \tmp\().16b, \tmp\().16b, \tmp\().16b, #8 + eor \next\().16b, \next\().16b, \tmp\().16b +.else + /* + * Calculate the next two tweaks by multiplying the current ones by x^2, + * modulo p(x) = x^64 + x^4 + x^3 + x + 1. + */ + ushr \tmp\().2d, \cur\().2d, #62 + shl \next\().2d, \cur\().2d, #2 + tbl \tmp\().16b, {GFMUL_TABLE.16b}, \tmp\().16b + eor \next\().16b, \next\().16b, \tmp\().16b +.endif +.endm + +/* + * _speck_xts_crypt() - Speck-XTS encryption/decryption + * + * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer + * using Speck-XTS, specifically the variant with a block size of '2n' and round + * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and + * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a + * nonzero multiple of 128. + */ +.macro _speck_xts_crypt n, lanes, decrypting + + /* + * If decrypting, modify the ROUND_KEYS parameter to point to the last + * round key rather than the first, since for decryption the round keys + * are used in reverse order. + */ +.if \decrypting + mov NROUNDS, NROUNDS /* zero the high 32 bits */ +.if \n == 64 + add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #3 + sub ROUND_KEYS, ROUND_KEYS, #8 +.else + add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #2 + sub ROUND_KEYS, ROUND_KEYS, #4 +.endif +.endif + + // Load the index vector for tbl-based 8-bit rotates +.if \decrypting + ldr ROTATE_TABLE_Q, .Lrol\n\()_8_table +.else + ldr ROTATE_TABLE_Q, .Lror\n\()_8_table +.endif + + // One-time XTS preparation +.if \n == 64 + // Load first tweak + ld1 {TWEAKV0.16b}, [TWEAK] + + // Load GF(2^128) multiplication table + ldr GFMUL_TABLE_Q, .Lgf128mul_table +.else + // Load first tweak + ld1 {TWEAKV0.8b}, [TWEAK] + + // Load GF(2^64) multiplication table + ldr GFMUL_TABLE_Q, .Lgf64mul_table + + // Calculate second tweak, packing it together with the first + ushr TMP0.2d, TWEAKV0.2d, #63 + shl TMP1.2d, TWEAKV0.2d, #1 + tbl TMP0.8b, {GFMUL_TABLE.16b}, TMP0.8b + eor TMP0.8b, TMP0.8b, TMP1.8b + mov TWEAKV0.d[1], TMP0.d[0] +.endif + +.Lnext_128bytes_\@: + + // Calculate XTS tweaks for next 128 bytes + _next_xts_tweak TWEAKV1, TWEAKV0, TMP0, \n + _next_xts_tweak TWEAKV2, TWEAKV1, TMP0, \n + _next_xts_tweak TWEAKV3, TWEAKV2, TMP0, \n + _next_xts_tweak TWEAKV4, TWEAKV3, TMP0, \n + _next_xts_tweak TWEAKV5, TWEAKV4, TMP0, \n + _next_xts_tweak TWEAKV6, TWEAKV5, TMP0, \n + _next_xts_tweak TWEAKV7, TWEAKV6, TMP0, \n + _next_xts_tweak TWEAKV_NEXT, TWEAKV7, TMP0, \n + + // Load the next source blocks into {X,Y}[0-3] + ld1 {X_0.16b-Y_1.16b}, [SRC], #64 + ld1 {X_2.16b-Y_3.16b}, [SRC], #64 + + // XOR the source blocks with their XTS tweaks + eor TMP0.16b, X_0.16b, TWEAKV0.16b + eor Y_0.16b, Y_0.16b, TWEAKV1.16b + eor TMP1.16b, X_1.16b, TWEAKV2.16b + eor Y_1.16b, Y_1.16b, TWEAKV3.16b + eor TMP2.16b, X_2.16b, TWEAKV4.16b + eor Y_2.16b, Y_2.16b, TWEAKV5.16b + eor TMP3.16b, X_3.16b, TWEAKV6.16b + eor Y_3.16b, Y_3.16b, TWEAKV7.16b + + /* + * De-interleave the 'x' and 'y' elements of each block, i.e. make it so + * that the X[0-3] registers contain only the second halves of blocks, + * and the Y[0-3] registers contain only the first halves of blocks. + * (Speck uses the order (y, x) rather than the more intuitive (x, y).) + */ + uzp2 X_0.\lanes, TMP0.\lanes, Y_0.\lanes + uzp1 Y_0.\lanes, TMP0.\lanes, Y_0.\lanes + uzp2 X_1.\lanes, TMP1.\lanes, Y_1.\lanes + uzp1 Y_1.\lanes, TMP1.\lanes, Y_1.\lanes + uzp2 X_2.\lanes, TMP2.\lanes, Y_2.\lanes + uzp1 Y_2.\lanes, TMP2.\lanes, Y_2.\lanes + uzp2 X_3.\lanes, TMP3.\lanes, Y_3.\lanes + uzp1 Y_3.\lanes, TMP3.\lanes, Y_3.\lanes + + // Do the cipher rounds + mov x6, ROUND_KEYS + mov w7, NROUNDS +.Lnext_round_\@: +.if \decrypting + ld1r {ROUND_KEY.\lanes}, [x6] + sub x6, x6, #( \n / 8 ) + _speck_unround_128bytes \n, \lanes +.else + ld1r {ROUND_KEY.\lanes}, [x6], #( \n / 8 ) + _speck_round_128bytes \n, \lanes +.endif + subs w7, w7, #1 + bne .Lnext_round_\@ + + // Re-interleave the 'x' and 'y' elements of each block + zip1 TMP0.\lanes, Y_0.\lanes, X_0.\lanes + zip2 Y_0.\lanes, Y_0.\lanes, X_0.\lanes + zip1 TMP1.\lanes, Y_1.\lanes, X_1.\lanes + zip2 Y_1.\lanes, Y_1.\lanes, X_1.\lanes + zip1 TMP2.\lanes, Y_2.\lanes, X_2.\lanes + zip2 Y_2.\lanes, Y_2.\lanes, X_2.\lanes + zip1 TMP3.\lanes, Y_3.\lanes, X_3.\lanes + zip2 Y_3.\lanes, Y_3.\lanes, X_3.\lanes + + // XOR the encrypted/decrypted blocks with the tweaks calculated earlier + eor X_0.16b, TMP0.16b, TWEAKV0.16b + eor Y_0.16b, Y_0.16b, TWEAKV1.16b + eor X_1.16b, TMP1.16b, TWEAKV2.16b + eor Y_1.16b, Y_1.16b, TWEAKV3.16b + eor X_2.16b, TMP2.16b, TWEAKV4.16b + eor Y_2.16b, Y_2.16b, TWEAKV5.16b + eor X_3.16b, TMP3.16b, TWEAKV6.16b + eor Y_3.16b, Y_3.16b, TWEAKV7.16b + mov TWEAKV0.16b, TWEAKV_NEXT.16b + + // Store the ciphertext in the destination buffer + st1 {X_0.16b-Y_1.16b}, [DST], #64 + st1 {X_2.16b-Y_3.16b}, [DST], #64 + + // Continue if there are more 128-byte chunks remaining + subs NBYTES, NBYTES, #128 + bne .Lnext_128bytes_\@ + + // Store the next tweak and return +.if \n == 64 + st1 {TWEAKV_NEXT.16b}, [TWEAK] +.else + st1 {TWEAKV_NEXT.8b}, [TWEAK] +.endif + ret +.endm + +ENTRY(speck128_xts_encrypt_neon) + _speck_xts_crypt n=64, lanes=2d, decrypting=0 +ENDPROC(speck128_xts_encrypt_neon) + +ENTRY(speck128_xts_decrypt_neon) + _speck_xts_crypt n=64, lanes=2d, decrypting=1 +ENDPROC(speck128_xts_decrypt_neon) + +ENTRY(speck64_xts_encrypt_neon) + _speck_xts_crypt n=32, lanes=4s, decrypting=0 +ENDPROC(speck64_xts_encrypt_neon) + +ENTRY(speck64_xts_decrypt_neon) + _speck_xts_crypt n=32, lanes=4s, decrypting=1 +ENDPROC(speck64_xts_decrypt_neon) diff --git a/arch/arm64/crypto/speck-neon-glue.c b/arch/arm64/crypto/speck-neon-glue.c new file mode 100644 index 0000000000000000000000000000000000000000..c7d18569d408efee989dcf21dc3dc19c712cffb6 --- /dev/null +++ b/arch/arm64/crypto/speck-neon-glue.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS + * (64-bit version; based on the 32-bit version) + * + * Copyright (c) 2018 Google, Inc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The assembly functions only handle multiples of 128 bytes */ +#define SPECK_NEON_CHUNK_SIZE 128 + +/* Speck128 */ + +struct speck128_xts_tfm_ctx { + struct speck128_tfm_ctx main_key; + struct speck128_tfm_ctx tweak_key; +}; + +asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *, + u8 *, const u8 *); +typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *, + const void *, unsigned int, void *); + +static __always_inline int +__speck128_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, + speck128_crypt_one_t crypt_one, + speck128_xts_crypt_many_t crypt_many) +{ + struct crypto_blkcipher *tfm = desc->tfm; + const struct speck128_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct blkcipher_walk walk; + le128 tweak; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE); + + crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; + u8 *dst = walk.dst.virt.addr; + const u8 *src = walk.src.virt.addr; + + if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { + unsigned int count; + + count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); + kernel_neon_begin(); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); + kernel_neon_end(); + dst += count; + src += count; + nbytes -= count; + } + + /* Handle any remainder with generic code */ + while (nbytes >= sizeof(tweak)) { + le128_xor((le128 *)dst, (const le128 *)src, &tweak); + (*crypt_one)(&ctx->main_key, dst, dst); + le128_xor((le128 *)dst, (const le128 *)dst, &tweak); + gf128mul_x_ble((be128 *)&tweak, (const be128 *)&tweak); + + dst += sizeof(tweak); + src += sizeof(tweak); + nbytes -= sizeof(tweak); + } + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int speck128_xts_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return __speck128_xts_crypt(desc, dst, src, nbytes, + crypto_speck128_encrypt, + speck128_xts_encrypt_neon); +} + +static int speck128_xts_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return __speck128_xts_crypt(desc, dst, src, nbytes, + crypto_speck128_decrypt, + speck128_xts_decrypt_neon); +} + +static int speck128_xts_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct speck128_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + if (keylen % 2) + return -EINVAL; + + keylen /= 2; + + err = crypto_speck128_setkey(&ctx->main_key, key, keylen); + if (err) + return err; + + return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen); +} + +/* Speck64 */ + +struct speck64_xts_tfm_ctx { + struct speck64_tfm_ctx main_key; + struct speck64_tfm_ctx tweak_key; +}; + +asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *, + u8 *, const u8 *); +typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *, + const void *, unsigned int, void *); + +static __always_inline int +__speck64_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, + speck64_crypt_one_t crypt_one, + speck64_xts_crypt_many_t crypt_many) +{ + struct crypto_blkcipher *tfm = desc->tfm; + const struct speck64_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct blkcipher_walk walk; + __le64 tweak; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE); + + crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; + u8 *dst = walk.dst.virt.addr; + const u8 *src = walk.src.virt.addr; + + if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { + unsigned int count; + + count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); + kernel_neon_begin(); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); + kernel_neon_end(); + dst += count; + src += count; + nbytes -= count; + } + + /* Handle any remainder with generic code */ + while (nbytes >= sizeof(tweak)) { + *(__le64 *)dst = *(__le64 *)src ^ tweak; + (*crypt_one)(&ctx->main_key, dst, dst); + *(__le64 *)dst ^= tweak; + tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^ + ((tweak & cpu_to_le64(1ULL << 63)) ? + 0x1B : 0)); + dst += sizeof(tweak); + src += sizeof(tweak); + nbytes -= sizeof(tweak); + } + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int speck64_xts_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return __speck64_xts_crypt(desc, dst, src, nbytes, + crypto_speck64_encrypt, + speck64_xts_encrypt_neon); +} + +static int speck64_xts_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return __speck64_xts_crypt(desc, dst, src, nbytes, + crypto_speck64_decrypt, + speck64_xts_decrypt_neon); +} + +static int speck64_xts_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct speck64_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + if (keylen % 2) + return -EINVAL; + + keylen /= 2; + + err = crypto_speck64_setkey(&ctx->main_key, key, keylen); + if (err) + return err; + + return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen); +} + +static struct crypto_alg speck_algs[] = { + { + .cra_name = "xts(speck128)", + .cra_driver_name = "xts-speck128-neon", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SPECK128_BLOCK_SIZE, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx), + .cra_alignmask = 7, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * SPECK128_128_KEY_SIZE, + .max_keysize = 2 * SPECK128_256_KEY_SIZE, + .ivsize = SPECK128_BLOCK_SIZE, + .setkey = speck128_xts_setkey, + .encrypt = speck128_xts_encrypt, + .decrypt = speck128_xts_decrypt, + } + } + }, { + .cra_name = "xts(speck64)", + .cra_driver_name = "xts-speck64-neon", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SPECK64_BLOCK_SIZE, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx), + .cra_alignmask = 7, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * SPECK64_96_KEY_SIZE, + .max_keysize = 2 * SPECK64_128_KEY_SIZE, + .ivsize = SPECK64_BLOCK_SIZE, + .setkey = speck64_xts_setkey, + .encrypt = speck64_xts_encrypt, + .decrypt = speck64_xts_decrypt, + } + } + } +}; + +static int __init speck_neon_module_init(void) +{ + if (!(elf_hwcap & HWCAP_ASIMD)) + return -ENODEV; + return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +static void __exit speck_neon_module_exit(void) +{ + crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +module_init(speck_neon_module_init); +module_exit(speck_neon_module_exit); + +MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biggers "); +MODULE_ALIAS_CRYPTO("xts(speck128)"); +MODULE_ALIAS_CRYPTO("xts-speck128-neon"); +MODULE_ALIAS_CRYPTO("xts(speck64)"); +MODULE_ALIAS_CRYPTO("xts-speck64-neon"); diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index 2d510cc42e4baf22d6467e3fc1c7c37e6e1e5e70..2a9d938f2d1ddaf3aba96ed48677d99e1340bc7c 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -21,6 +21,7 @@ #include +#include #include #include diff --git a/arch/arm64/include/asm/cachetype.h b/arch/arm64/include/asm/cachetype.h index 4c631a0a3609af25e68810afeb1a2ec03cbf3222..da2fc9e3cedd8960f5cb05b865e6507ba66a1199 100644 --- a/arch/arm64/include/asm/cachetype.h +++ b/arch/arm64/include/asm/cachetype.h @@ -39,24 +39,41 @@ extern unsigned long __icache_flags; +/* + * NumSets, bits[27:13] - (Number of sets in cache) - 1 + * Associativity, bits[12:3] - (Associativity of cache) - 1 + * LineSize, bits[2:0] - (Log2(Number of words in cache line)) - 2 + */ +#define CCSIDR_EL1_WRITE_THROUGH BIT(31) +#define CCSIDR_EL1_WRITE_BACK BIT(30) +#define CCSIDR_EL1_READ_ALLOCATE BIT(29) +#define CCSIDR_EL1_WRITE_ALLOCATE BIT(28) #define CCSIDR_EL1_LINESIZE_MASK 0x7 #define CCSIDR_EL1_LINESIZE(x) ((x) & CCSIDR_EL1_LINESIZE_MASK) - +#define CCSIDR_EL1_ASSOCIATIVITY_SHIFT 3 +#define CCSIDR_EL1_ASSOCIATIVITY_MASK 0x3ff +#define CCSIDR_EL1_ASSOCIATIVITY(x) \ + (((x) >> CCSIDR_EL1_ASSOCIATIVITY_SHIFT) & CCSIDR_EL1_ASSOCIATIVITY_MASK) #define CCSIDR_EL1_NUMSETS_SHIFT 13 -#define CCSIDR_EL1_NUMSETS_MASK (0x7fff << CCSIDR_EL1_NUMSETS_SHIFT) +#define CCSIDR_EL1_NUMSETS_MASK 0x7fff #define CCSIDR_EL1_NUMSETS(x) \ - (((x) & CCSIDR_EL1_NUMSETS_MASK) >> CCSIDR_EL1_NUMSETS_SHIFT) + (((x) >> CCSIDR_EL1_NUMSETS_SHIFT) & CCSIDR_EL1_NUMSETS_MASK) + +#define CACHE_LINESIZE(x) (16 << CCSIDR_EL1_LINESIZE(x)) +#define CACHE_NUMSETS(x) (CCSIDR_EL1_NUMSETS(x) + 1) +#define CACHE_ASSOCIATIVITY(x) (CCSIDR_EL1_ASSOCIATIVITY(x) + 1) -extern u64 __attribute_const__ icache_get_ccsidr(void); +extern u64 __attribute_const__ cache_get_ccsidr(u64 csselr); +/* Helpers for Level 1 Instruction cache csselr = 1L */ static inline int icache_get_linesize(void) { - return 16 << CCSIDR_EL1_LINESIZE(icache_get_ccsidr()); + return CACHE_LINESIZE(cache_get_ccsidr(1L)); } static inline int icache_get_numsets(void) { - return 1 + CCSIDR_EL1_NUMSETS(icache_get_ccsidr()); + return CACHE_NUMSETS(cache_get_ccsidr(1L)); } /* diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index e8272c475bb5e4e9ef0c5dcae82c25d46945e706..7e97248ae745ce04e3ee79f8b7aca65e6fb56e43 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -49,16 +49,16 @@ do { \ } while (0) static inline int -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) { int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; + int oparg = (int)(encoded_op << 8) >> 20; + int cmparg = (int)(encoded_op << 20) >> 20; int oldval = 0, ret, tmp; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; + oparg = 1U << (oparg & 0x1f); if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 8afb863f5a9e3a7651a415c80057e1a5c4b592c6..333ddd45dd1f5f7b9d1b606b9fbffd88e6d98856 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -160,8 +160,7 @@ #define VTTBR_X (37 - VTCR_EL2_T0SZ_40B) #endif -#define VTTBR_BADDR_SHIFT (VTTBR_X - 1) -#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) +#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_X) #define VTTBR_VMID_SHIFT (UL(48)) #define VTTBR_VMID_MASK (UL(0xFF) << VTTBR_VMID_SHIFT) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 3cb4c856b10da40a73c88138d97a2586b21eb6ff..ec5f6b6d1dd0ebb33ccd92dceac71fe747189660 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -38,6 +38,11 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu); void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); +static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu) +{ + return !(vcpu->arch.hcr_el2 & HCR_RW); +} + static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) { vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS; diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 8e6e413adc70bd9095d34f65be44add3204f0282..45b2ba6db6c738019cfc31ffac7e3d507905ec5a 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -135,6 +135,7 @@ static inline void *phys_to_virt(phys_addr_t x) #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) #define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys(x)) +#define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x)) /* * virt_to_page(k) convert a _valid_ virtual address to struct page * diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h index c15053902942e0a3a34ba4882545c5b6d163c23c..ff98585d085aa5737c9c17478555f22b11261f2f 100644 --- a/arch/arm64/include/asm/pgalloc.h +++ b/arch/arm64/include/asm/pgalloc.h @@ -42,11 +42,20 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) free_page((unsigned long)pmd); } -static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot) { - set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); + set_pud(pud, __pud(pmd | prot)); } +static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + __pud_populate(pud, __pa(pmd), PMD_TYPE_TABLE); +} +#else +static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot) +{ + BUILD_BUG(); +} #endif /* CONFIG_PGTABLE_LEVELS > 2 */ #if CONFIG_PGTABLE_LEVELS > 3 @@ -62,11 +71,20 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud) free_page((unsigned long)pud); } -static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) +static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot) { - set_pgd(pgd, __pgd(__pa(pud) | PUD_TYPE_TABLE)); + set_pgd(pgdp, __pgd(pud | prot)); } +static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) +{ + __pgd_populate(pgd, __pa(pud), PUD_TYPE_TABLE); +} +#else +static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot) +{ + BUILD_BUG(); +} #endif /* CONFIG_PGTABLE_LEVELS > 3 */ extern pgd_t *pgd_alloc(struct mm_struct *mm); diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index e7ddb5411902c2dafd48d6eb59a05c2be116d670..6bf8ac65f04a06eced816e2294c0576bd4940a9a 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -31,6 +31,7 @@ #include #include +#include #include #include diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h index eeaa97559babffa2fa3e4cf74d084789e59cbf5e..81abea0b7650867d86385fc0c4fc145fefd24c46 100644 --- a/arch/arm64/include/asm/signal32.h +++ b/arch/arm64/include/asm/signal32.h @@ -22,8 +22,6 @@ #define AARCH32_KERN_SIGRET_CODE_OFFSET 0x500 -extern const compat_ulong_t aarch32_sigret_code[6]; - int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set, struct pt_regs *regs); int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 756cbf10d5ab0f06ecf3e57ac9e3e989524c03a0..570ce48355f96d043a83ab17631f9a646c848055 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -126,6 +126,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NEED_RESCHED 1 #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */ +#define TIF_FSCHECK 4 /* Check FS is USER_DS on return */ #define TIF_NOHZ 7 #define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_AUDIT 9 @@ -148,10 +149,12 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_FSCHECK (1 << TIF_FSCHECK) #define _TIF_32BIT (1 << TIF_32BIT) #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ - _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE) + _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ + _TIF_FSCHECK) #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 998ca85840dffef7ed2978ef0a69f8d46302cd8d..afc5b3f6e00b891038d4968e0e57a59e5299f954 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -71,6 +71,9 @@ static inline void set_fs(mm_segment_t fs) { current_thread_info()->addr_limit = fs; + /* On user-mode return, check fs is correct */ + set_thread_flag(TIF_FSCHECK); + /* * Enable/disable UAO so that copy_to_user() etc can access * kernel memory with the unprivileged instructions. diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 47a98a59763394e03152779a129aa64656e004ec..7ca6f766dd04a15a0341fb99171f0f2eca6925f1 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -20,7 +20,7 @@ arm64-obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ hyp-stub.o psci.o cpu_ops.o insn.o \ return_address.o cpuinfo.o cpu_errata.o \ cpufeature.o alternative.o psci-call.o \ - smp.o smp_spin_table.o topology.o + smp.o smp_spin_table.o topology.o cacheinfo.o arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ sys_compat.o \ diff --git a/arch/arm64/kernel/cacheinfo.c b/arch/arm64/kernel/cacheinfo.c new file mode 100644 index 0000000000000000000000000000000000000000..b8629d52fba940739c076cbcb021f73f2aa855f3 --- /dev/null +++ b/arch/arm64/kernel/cacheinfo.c @@ -0,0 +1,128 @@ +/* + * ARM64 cacheinfo support + * + * Copyright (C) 2015 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_CACHE_LEVEL 7 /* Max 7 level supported */ +/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */ +#define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1)) +#define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level)) +#define CLIDR_CTYPE(clidr, level) \ + (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level)) + +static inline enum cache_type get_cache_type(int level) +{ + u64 clidr; + + if (level > MAX_CACHE_LEVEL) + return CACHE_TYPE_NOCACHE; + asm volatile ("mrs %x0, clidr_el1" : "=r" (clidr)); + return CLIDR_CTYPE(clidr, level); +} + +/* + * Cache Size Selection Register(CSSELR) selects which Cache Size ID + * Register(CCSIDR) is accessible by specifying the required cache + * level and the cache type. We need to ensure that no one else changes + * CSSELR by calling this in non-preemtible context + */ +u64 __attribute_const__ cache_get_ccsidr(u64 csselr) +{ + u64 ccsidr; + + WARN_ON(preemptible()); + + /* Put value into CSSELR */ + asm volatile("msr csselr_el1, %x0" : : "r" (csselr)); + isb(); + /* Read result out of CCSIDR */ + asm volatile("mrs %x0, ccsidr_el1" : "=r" (ccsidr)); + + return ccsidr; +} + +static void ci_leaf_init(struct cacheinfo *this_leaf, + enum cache_type type, unsigned int level) +{ + bool is_icache = type & CACHE_TYPE_INST; + u64 tmp = cache_get_ccsidr((level - 1) << 1 | is_icache); + + this_leaf->level = level; + this_leaf->type = type; + this_leaf->coherency_line_size = CACHE_LINESIZE(tmp); + this_leaf->number_of_sets = CACHE_NUMSETS(tmp); + this_leaf->ways_of_associativity = CACHE_ASSOCIATIVITY(tmp); + this_leaf->size = this_leaf->number_of_sets * + this_leaf->coherency_line_size * this_leaf->ways_of_associativity; + this_leaf->attributes = + ((tmp & CCSIDR_EL1_WRITE_THROUGH) ? CACHE_WRITE_THROUGH : 0) | + ((tmp & CCSIDR_EL1_WRITE_BACK) ? CACHE_WRITE_BACK : 0) | + ((tmp & CCSIDR_EL1_READ_ALLOCATE) ? CACHE_READ_ALLOCATE : 0) | + ((tmp & CCSIDR_EL1_WRITE_ALLOCATE) ? CACHE_WRITE_ALLOCATE : 0); +} + +static int __init_cache_level(unsigned int cpu) +{ + unsigned int ctype, level, leaves; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + + for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) { + ctype = get_cache_type(level); + if (ctype == CACHE_TYPE_NOCACHE) { + level--; + break; + } + /* Separate instruction and data caches */ + leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1; + } + + this_cpu_ci->num_levels = level; + this_cpu_ci->num_leaves = leaves; + return 0; +} + +static int __populate_cache_leaves(unsigned int cpu) +{ + unsigned int level, idx; + enum cache_type type; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; + + for (idx = 0, level = 1; level <= this_cpu_ci->num_levels && + idx < this_cpu_ci->num_leaves; idx++, level++) { + type = get_cache_type(level); + if (type == CACHE_TYPE_SEPARATE) { + ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level); + ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level); + } else { + ci_leaf_init(this_leaf++, type, level); + } + } + return 0; +} + +DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level) +DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves) diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index f50585e764fc6ddcdf0602c83756512b861eb6fe..abebd052661d8dbbfbb5c56d9e67c3ca0d12a34e 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -261,15 +261,3 @@ void __init cpuinfo_store_boot_cpu(void) boot_cpu_data = *info; init_cpu_features(&boot_cpu_data); } - -u64 __attribute_const__ icache_get_ccsidr(void) -{ - u64 ccsidr; - - WARN_ON(preemptible()); - - /* Select L1 I-cache and read its size ID register */ - asm("msr csselr_el1, %1; isb; mrs %0, ccsidr_el1" - : "=r"(ccsidr) : "r"(1L)); - return ccsidr; -} diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 07403f50381805855fd32959f91dd10a1b852cd6..98c116c315cf63cbc0f5bbe79f4b58626ab7c616 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -845,6 +845,9 @@ work_pending: bl do_notify_resume b ret_to_user work_resched: +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off // the IRQs are off here, inform the tracing code +#endif bl schedule /* diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index bcf174f26937fe8839031963e4ce8a963badc167..e34584fd690d04db77838a84ea27920c1a591d4a 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -490,6 +490,7 @@ ENDPROC(__mmap_switched) * booted in EL1 or EL2 respectively. */ ENTRY(el2_setup) + msr SPsel, #1 // We want to use SP_EL{1,2} mrs x0, CurrentEL cmp x0, #CurrentEL_EL2 b.ne 1f diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c index d07a5ad25cb72dc9ca3f54f884a972efa0a2cfef..80e7bb1a0303a92dd760a2b2ec886de32d991607 100644 --- a/arch/arm64/kernel/io.c +++ b/arch/arm64/kernel/io.c @@ -27,7 +27,7 @@ */ void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) { - while (count && (!IO_CHECK_ALIGN(from, 8) || !IO_CHECK_ALIGN(to, 8))) { + while (count && !IS_ALIGNED((unsigned long)from, 8)) { *(u8 *)to = readb_relaxed_no_log(from); from++; to++; @@ -56,27 +56,24 @@ EXPORT_SYMBOL(__memcpy_fromio); */ void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) { - void *p = (void __force *)to; - - __iowmb(); - while (count && (!IO_CHECK_ALIGN(p, 8) || !IO_CHECK_ALIGN(from, 8))) { - writeb_relaxed_no_log(*(volatile u8 *)from, p); + while (count && !IS_ALIGNED((unsigned long)to, 8)) { + writeb_relaxed_no_log(*(u8 *)from, to); from++; - p++; + to++; count--; } while (count >= 8) { - writeq_relaxed_no_log(*(volatile u64 *)from, p); + writeq_relaxed_no_log(*(u64 *)from, to); from += 8; - p += 8; + to += 8; count -= 8; } while (count) { - writeb_relaxed_no_log(*(volatile u8 *)from, p); + writeb_relaxed_no_log(*(u8 *)from, to); from++; - p++; + to++; count--; } } @@ -87,29 +84,27 @@ EXPORT_SYMBOL(__memcpy_toio); */ void __memset_io(volatile void __iomem *dst, int c, size_t count) { - void *p = (void __force *)dst; - u64 qc = c; + u64 qc = (u8)c; qc |= qc << 8; qc |= qc << 16; qc |= qc << 32; - __iowmb(); - while (count && !IO_CHECK_ALIGN(p, 8)) { - writeb_relaxed_no_log(c, p); - p++; + while (count && !IS_ALIGNED((unsigned long)dst, 8)) { + writeb_relaxed_no_log(c, dst); + dst++; count--; } while (count >= 8) { - writeq_relaxed_no_log(qc, p); - p += 8; + writeq_relaxed_no_log(qc, dst); + dst += 8; count -= 8; } while (count) { - writeb_relaxed_no_log(c, p); - p++; + writeb_relaxed_no_log(c, dst); + dst++; count--; } } diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index ca450c42b83ac800a714f305aeb4c4c816bc7ddc..f4bc779e62e887547b7a17b7672487f0851e1479 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index eff22af8c01b955c4bd1698ecb71cfb9855d857b..4db258a022547fd67fd02fc226df97af65192341 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -315,6 +315,15 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); + /* + * In case p was allocated the same task_struct pointer as some + * other recently-exited task, make sure p is disassociated from + * any cpu that may have run that now-exited task recently. + * Otherwise we could erroneously skip reloading the FPSIMD + * registers for p. + */ + fpsimd_flush_task_state(p); + if (likely(!(p->flags & PF_KTHREAD))) { *childregs = *current_pt_regs(); childregs->regs[0] = 0; diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 95fcbd53802d4168e313f64e39fbbfbe54e8147a..163e2bc643ea6d175e3e53e4a9086ed7869b2304 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -982,9 +982,7 @@ static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num, { int ret; u32 kdata; - mm_segment_t old_fs = get_fs(); - set_fs(KERNEL_DS); /* Watchpoint */ if (num < 0) { ret = compat_ptrace_hbp_get(NT_ARM_HW_WATCH, tsk, num, &kdata); @@ -995,7 +993,6 @@ static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num, } else { ret = compat_ptrace_hbp_get(NT_ARM_HW_BREAK, tsk, num, &kdata); } - set_fs(old_fs); if (!ret) ret = put_user(kdata, data); @@ -1008,7 +1005,6 @@ static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num, { int ret; u32 kdata = 0; - mm_segment_t old_fs = get_fs(); if (num == 0) return 0; @@ -1017,12 +1013,10 @@ static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num, if (ret) return ret; - set_fs(KERNEL_DS); if (num < 0) ret = compat_ptrace_hbp_set(NT_ARM_HW_WATCH, tsk, num, &kdata); else ret = compat_ptrace_hbp_set(NT_ARM_HW_BREAK, tsk, num, &kdata); - set_fs(old_fs); return ret; } diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 660ccf9f7524cb665e3318b32fa23bfe06577e05..3e26c788eb90047f13b898f9694708a880094e27 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -409,6 +410,9 @@ static void do_signal(struct pt_regs *regs) asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int thread_flags) { + /* Check valid user FS if needed */ + addr_limit_user_check(); + if (thread_flags & _TIF_SIGPENDING) do_signal(regs); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index d51ae08268c427a00746b45aaf6433c9a4851730..27e7d8161457567bab56d9b12311d9e59e8008e1 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -140,7 +140,7 @@ static void smp_store_cpu_info(unsigned int cpuid) * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. */ -asmlinkage void secondary_start_kernel(void) +asmlinkage notrace void secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; unsigned int cpu = smp_processor_id(); diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c index 0d9afcfcae92a0ea562f1c66fd5e589fc138e2e1..f189668566cafcae1511daead823787dc9fb95ff 100644 --- a/arch/arm64/kernel/smp_spin_table.c +++ b/arch/arm64/kernel/smp_spin_table.c @@ -25,6 +25,7 @@ #include #include #include +#include #include static phys_addr_t cpu_release_addr[NR_CPUS]; diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 2bcea95c342320d8294f42a783eb50530486b4d6..79a483a8f4d20beece30ff57c0ff73723fa9bbc2 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -51,7 +51,7 @@ static const char *handler[]= { "Error" }; -int show_unhandled_signals = 1; +int show_unhandled_signals = 0; /* * Dump out the contents of some memory nicely... @@ -111,7 +111,7 @@ static void __dump_instr(const char *lvl, struct pt_regs *regs) for (i = -4; i < 1; i++) { unsigned int val, bad; - bad = __get_user(val, &((u32 *)addr)[i]); + bad = get_user(val, &((u32 *)addr)[i]); if (!bad) p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val); @@ -419,19 +419,6 @@ static void cntfrq_read_handler(unsigned int esr, struct pt_regs *regs) regs->pc += 4; } -static void cntpct_read_handler(unsigned int esr, struct pt_regs *regs) -{ - int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT; - - isb(); - if (rt != 31) - regs->regs[rt] = arch_counter_get_cntpct(); - regs->pc += 4; -} - -#define ESR_ELx_SYS64_ISS_SYS_CNTPCT (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 1, 14, 0) | \ - ESR_ELx_SYS64_ISS_DIR_READ) - asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs) { if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTVCT) { @@ -440,9 +427,6 @@ asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs) } else if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTFRQ) { cntfrq_read_handler(esr, regs); return; - } else if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTPCT) { - cntpct_read_handler(esr, regs); - return; } do_undefinstr(regs); diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index 71766af43b701eac4504a9a0c1117d202470acab..844de955a8aa77cf306423e6f2d8149938a6b281 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -114,6 +114,7 @@ static struct vm_special_mapping vdso_spec[2]; static int __init vdso_init(void) { int i; + unsigned long pfn; if (memcmp(&vdso_start, "\177ELF", 4)) { pr_err("vDSO is not a valid ELF object!\n"); @@ -131,11 +132,13 @@ static int __init vdso_init(void) return -ENOMEM; /* Grab the vDSO data page. */ - vdso_pagelist[0] = virt_to_page(vdso_data); + vdso_pagelist[0] = phys_to_page(__pa_symbol(vdso_data)); /* Grab the vDSO code pages. */ + pfn = sym_to_pfn(&vdso_start); + for (i = 0; i < vdso_pages; i++) - vdso_pagelist[i + 1] = virt_to_page(&vdso_start + i * PAGE_SIZE); + vdso_pagelist[i + 1] = pfn_to_page(pfn + i); /* Populate the special mapping structures */ vdso_spec[0] = (struct vm_special_mapping) { @@ -215,11 +218,10 @@ void update_vsyscall(struct timekeeper *tk) if (!use_syscall) { /* tkr_mono.cycle_last == tkr_raw.cycle_last */ vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; - vdso_data->raw_time_sec = tk->raw_time.tv_sec; - vdso_data->raw_time_nsec = tk->raw_time.tv_nsec; + vdso_data->raw_time_sec = tk->raw_sec; + vdso_data->raw_time_nsec = tk->tkr_raw.xtime_nsec; vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; - /* tkr_raw.xtime_nsec == 0 */ vdso_data->cs_mono_mult = tk->tkr_mono.mult; vdso_data->cs_raw_mult = tk->tkr_raw.mult; /* tkr_mono.shift == tkr_raw.shift */ diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S index 1f8bba27e2f36a3a45e1101931e09b811343d474..c39872a7b03c3e152315781c753f3e6b186524ed 100644 --- a/arch/arm64/kernel/vdso/gettimeofday.S +++ b/arch/arm64/kernel/vdso/gettimeofday.S @@ -256,7 +256,6 @@ monotonic_raw: seqcnt_check fail=monotonic_raw /* All computations are done with left-shifted nsecs. */ - lsl x14, x14, x12 get_nsec_per_sec res=x9 lsl x9, x9, x12 @@ -297,8 +296,6 @@ ENDPROC(__kernel_clock_gettime) /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */ ENTRY(__kernel_clock_getres) .cfi_startproc - cbz w1, 3f - cmp w0, #CLOCK_REALTIME ccmp w0, #CLOCK_MONOTONIC, #0x4, ne ccmp w0, #CLOCK_MONOTONIC_RAW, #0x4, ne @@ -312,6 +309,7 @@ ENTRY(__kernel_clock_getres) b.ne 4f ldr x2, 6f 2: + cbz x1, 3f stp xzr, x2, [x1] 3: /* res == NULL. */ diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 61ec16bd528bcc0d93186eaa63f6dc66b8adb31f..286453f462df21204365195c4d594240b20dbe39 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -46,6 +46,45 @@ static u64 core_reg_offset_from_id(u64 id) return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); } +static int validate_core_offset(const struct kvm_one_reg *reg) +{ + u64 off = core_reg_offset_from_id(reg->id); + int size; + + switch (off) { + case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... + KVM_REG_ARM_CORE_REG(regs.regs[30]): + case KVM_REG_ARM_CORE_REG(regs.sp): + case KVM_REG_ARM_CORE_REG(regs.pc): + case KVM_REG_ARM_CORE_REG(regs.pstate): + case KVM_REG_ARM_CORE_REG(sp_el1): + case KVM_REG_ARM_CORE_REG(elr_el1): + case KVM_REG_ARM_CORE_REG(spsr[0]) ... + KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]): + size = sizeof(__u64); + break; + + case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... + KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): + size = sizeof(__uint128_t); + break; + + case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): + case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): + size = sizeof(__u32); + break; + + default: + return -EINVAL; + } + + if (KVM_REG_SIZE(reg->id) == size && + IS_ALIGNED(off, size / sizeof(__u32))) + return 0; + + return -EINVAL; +} + static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { /* @@ -65,6 +104,9 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) return -ENOENT; + if (validate_core_offset(reg)) + return -EINVAL; + if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id))) return -EFAULT; @@ -87,6 +129,9 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) return -ENOENT; + if (validate_core_offset(reg)) + return -EINVAL; + if (KVM_REG_SIZE(reg->id) > sizeof(tmp)) return -EINVAL; @@ -96,17 +141,25 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) } if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) { - u32 mode = (*(u32 *)valp) & COMPAT_PSR_MODE_MASK; + u64 mode = (*(u64 *)valp) & COMPAT_PSR_MODE_MASK; switch (mode) { case COMPAT_PSR_MODE_USR: + if ((read_cpuid(ID_AA64PFR0_EL1) & 0xf) != 2) + return -EINVAL; + break; case COMPAT_PSR_MODE_FIQ: case COMPAT_PSR_MODE_IRQ: case COMPAT_PSR_MODE_SVC: case COMPAT_PSR_MODE_ABT: case COMPAT_PSR_MODE_UND: + if (!vcpu_el1_is_32bit(vcpu)) + return -EINVAL; + break; case PSR_MODE_EL0t: case PSR_MODE_EL1t: case PSR_MODE_EL1h: + if (vcpu_el1_is_32bit(vcpu)) + return -EINVAL; break; default: err = -EINVAL; diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 34b8bd0711e94295b3b8d629e2e032db8d8bce33..e738bff5eec19393cad252850bd52df83ee380a0 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -34,7 +34,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = kvm_psci_call(vcpu); if (ret < 0) { - kvm_inject_undefined(vcpu); + *vcpu_reg(vcpu, 0) = ~0UL; return 1; } @@ -43,7 +43,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) { - kvm_inject_undefined(vcpu); + *vcpu_reg(vcpu, 0) = ~0UL; return 1; } diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c index bf69601be54659374cefe2748252230d40e92bd6..d7f71f87c8ed9a21e8dc3a1332ec031a49971ea8 100644 --- a/arch/arm64/mm/dump.c +++ b/arch/arm64/mm/dump.c @@ -15,6 +15,7 @@ */ #include #include +#include #include #include #include diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index becb916c1f47dcbd8710fb9a9f016712b0f2ae0f..f23887c11664d27af5d0a6df8d2268d9577f0459 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -114,11 +114,13 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) } #ifdef CONFIG_HAVE_ARCH_PFN_VALID -#define PFN_MASK ((1UL << (64 - PAGE_SHIFT)) - 1) - int pfn_valid(unsigned long pfn) { - return (pfn & PFN_MASK) == pfn && memblock_is_memory(pfn << PAGE_SHIFT); + phys_addr_t addr = pfn << PAGE_SHIFT; + + if ((addr >> PAGE_SHIFT) != pfn) + return 0; + return memblock_is_memory(addr); } EXPORT_SYMBOL(pfn_valid); #endif @@ -176,6 +178,8 @@ void __init arm64_memblock_init(void) /* 4GB maximum for 32-bit only capable devices */ if (IS_ENABLED(CONFIG_ZONE_DMA)) dma_phys_limit = max_zone_dma_phys(); + + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; dma_contiguous_reserve(dma_phys_limit); memblock_allow_resize(); @@ -200,7 +204,6 @@ void __init bootmem_init(void) sparse_init(); zone_sizes_init(min, max); - high_memory = __va((max << PAGE_SHIFT) - 1) + 1; max_pfn = max_low_pfn = max; } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index b6932813ee8ef3dfb955eaac8bebf8be6603fc00..fc1433a38569e23754420b6217b68d6dace4632b 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -569,7 +569,11 @@ static noinline void __init split_and_set_pmd(pmd_t *pmd, unsigned long addr, pte = start_pte; do { - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); + if (((unsigned long)_stext <= addr) && + (addr < (unsigned long)__init_end)) + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); + else + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); pfn++; } while (pte++, addr += PAGE_SIZE, addr != end); diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index af76634f8d9897fe61ae64a2b956d9ce07951c0c..934573cc1134792dc59a0cbfc360678bb8a8b2f0 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -318,11 +318,14 @@ config BF53x config GPIO_ADI def_bool y + depends on !PINCTRL depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561) -config PINCTRL +config PINCTRL_BLACKFIN_ADI2 def_bool y - depends on BF54x || BF60x + depends on (BF54x || BF60x) + select PINCTRL + select PINCTRL_ADI2 config MEM_MT48LC64M4A2FB_7E bool diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index f3337ee03621d5f79a31af217bbd4bdf99dee79b..a93cf06a4d6fde552a284c6d48377e9636d41160 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -17,6 +17,7 @@ config DEBUG_VERBOSE config DEBUG_MMRS tristate "Generate Blackfin MMR tree" + depends on !PINCTRL select DEBUG_FS help Create a tree of Blackfin MMRs via the debugfs tree. If diff --git a/arch/hexagon/include/asm/bitops.h b/arch/hexagon/include/asm/bitops.h index 5e4a59b3ec1bb042f25de860a8489340a7add291..2691a1857d203db2522ae178fe744225c71d2da9 100644 --- a/arch/hexagon/include/asm/bitops.h +++ b/arch/hexagon/include/asm/bitops.h @@ -211,7 +211,7 @@ static inline long ffz(int x) * This is defined the same way as ffs. * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. */ -static inline long fls(int x) +static inline int fls(int x) { int r; @@ -232,7 +232,7 @@ static inline long fls(int x) * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ -static inline long ffs(int x) +static inline int ffs(int x) { int r; diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index 66f5e9a61efca05782cd45d4fec819a4993cfb15..7288e31d37139d0f5c6beb637b5f24fcf7de3f7b 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -216,6 +216,12 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, memcpy((void *) dst, src, count); } +static inline void memset_io(volatile void __iomem *addr, int value, + size_t size) +{ + memset((void __force *)addr, value, size); +} + #define PCI_IO_ADDR (volatile void __iomem *) /* diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c index b74f9bae31a3b9e81204d3c86b51acd3dcfe65c6..5a821e1c4b9b58ea1355db7412d99daf0e966c3f 100644 --- a/arch/hexagon/kernel/dma.c +++ b/arch/hexagon/kernel/dma.c @@ -79,7 +79,7 @@ static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size, panic("Can't create %s() memory pool!", __func__); else gen_pool_add(coherent_pool, - pfn_to_virt(max_low_pfn), + (unsigned long)pfn_to_virt(max_low_pfn), hexagon_coherent_pool_size, -1); } diff --git a/arch/hexagon/lib/checksum.c b/arch/hexagon/lib/checksum.c index 8169f78a46a70f5bc0359b4fa006070772116d59..5d72fb9b0040039bd587e9629e7b8d7b14793af4 100644 --- a/arch/hexagon/lib/checksum.c +++ b/arch/hexagon/lib/checksum.c @@ -201,3 +201,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) memcpy(dst, src, len); return csum_partial(dst, len, sum); } +EXPORT_SYMBOL(csum_partial_copy_nocheck); diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 24603be24c14acbbcb29874b45fb55518fed3cc7..67f09b93dab7fc943a3fbf91b7bebc0f65984f04 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -153,7 +153,7 @@ slot (const struct insn *insn) static int apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) { - if (slot(insn) != 2) { + if (slot(insn) != 1 && slot(insn) != 2) { printk(KERN_ERR "%s: invalid slot number %d for IMM64\n", mod->name, slot(insn)); return 0; @@ -165,7 +165,7 @@ apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) static int apply_imm60 (struct module *mod, struct insn *insn, uint64_t val) { - if (slot(insn) != 2) { + if (slot(insn) != 1 && slot(insn) != 2) { printk(KERN_ERR "%s: invalid slot number %d for IMM60\n", mod->name, slot(insn)); return 0; diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c index 71ea4c02795d45438727059b708731b0babbf220..8a2dc0af4cadb604f76b2c2553c0779cfc74b554 100644 --- a/arch/m68k/coldfire/device.c +++ b/arch/m68k/coldfire/device.c @@ -135,7 +135,11 @@ static struct platform_device mcf_fec0 = { .id = 0, .num_resources = ARRAY_SIZE(mcf_fec0_resources), .resource = mcf_fec0_resources, - .dev.platform_data = FEC_PDATA, + .dev = { + .dma_mask = &mcf_fec0.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = FEC_PDATA, + } }; #ifdef MCFFEC_BASE1 @@ -167,7 +171,11 @@ static struct platform_device mcf_fec1 = { .id = 1, .num_resources = ARRAY_SIZE(mcf_fec1_resources), .resource = mcf_fec1_resources, - .dev.platform_data = FEC_PDATA, + .dev = { + .dma_mask = &mcf_fec1.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = FEC_PDATA, + } }; #endif /* MCFFEC_BASE1 */ #endif /* CONFIG_FEC */ diff --git a/arch/m68k/include/asm/mcf_pgalloc.h b/arch/m68k/include/asm/mcf_pgalloc.h index f9924fbcfe42b8f279d83758e4fc987cb32da409..456e3f75ef3b7aa55558d421dd8d944cc68fff3f 100644 --- a/arch/m68k/include/asm/mcf_pgalloc.h +++ b/arch/m68k/include/asm/mcf_pgalloc.h @@ -43,6 +43,7 @@ extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address) static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page, unsigned long address) { + pgtable_page_dtor(page); __free_page(page); } @@ -73,8 +74,9 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, return page; } -extern inline void pte_free(struct mm_struct *mm, struct page *page) +static inline void pte_free(struct mm_struct *mm, struct page *page) { + pgtable_page_dtor(page); __free_page(page); } diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c index 6e4955bc542bfc591721aa23fdac1fdbaf66b586..fcd52cefee29619ce2f90913dd5b546a50183bbe 100644 --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c @@ -88,7 +88,8 @@ static inline void free_io_area(void *addr) for (p = &iolist ; (tmp = *p) ; p = &tmp->next) { if (tmp->addr == addr) { *p = tmp->next; - __iounmap(tmp->addr, tmp->size); + /* remove gap added in get_io_area() */ + __iounmap(tmp->addr, tmp->size - IO_SIZE); kfree(tmp); return; } diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 8e211cc28dac77594c108fee34d789205f8a3efa..e0f2afb9809847186b4bc857d8bd7174304fc69a 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -21,18 +21,20 @@ $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE quiet_cmd_cp = CP $< $@$2 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) -quiet_cmd_strip = STRIP $@ +quiet_cmd_strip = STRIP $< $@$2 cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \ - -K _fdt_start vmlinux -o $@ + -K _fdt_start $< -o $@$2 UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR) +UIMAGE_IN = $@ +UIMAGE_OUT = $@.ub $(obj)/simpleImage.%: vmlinux FORCE $(call if_changed,cp,.unstrip) $(call if_changed,objcopy) $(call if_changed,uimage) - $(call if_changed,strip) - @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' + $(call if_changed,strip,.strip) + @echo 'Kernel: $(UIMAGE_OUT) is ready' ' (#'`cat .version`')' clean-files += simpleImage.*.unstrip linux.bin.ub diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index 7e2356fd5fd65eee45fe5838730a772bfcd2aeb8..131f3eeb8c0b2dbb2f57426dbb9683b5680c3d96 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -581,6 +581,7 @@ static int __init ar7_register_uarts(void) uart_port.type = PORT_AR7; uart_port.uartclk = clk_get_rate(bus_clk) / 2; uart_port.iotype = UPIO_MEM32; + uart_port.flags = UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF; uart_port.regshift = 2; uart_port.line = 0; diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index 64807a4809d0a4b6f367ad52f15fe2fcbfc6a843..2b3b66780152f81758286bee72d1a24d3100e884 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -40,6 +40,7 @@ static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; static void ath79_restart(char *command) { + local_irq_disable(); ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); for (;;) if (cpu_wait) diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c index 903a656d4119f580f0a564fb39dd977befdda1ed..2e2a7cf14ac121bf256be064749a08641cd6525d 100644 --- a/arch/mips/bcm47xx/leds.c +++ b/arch/mips/bcm47xx/leds.c @@ -323,7 +323,7 @@ bcm47xx_leds_linksys_wrt54g3gv2[] __initconst = { /* Verified on: WRT54GS V1.0 */ static const struct gpio_led bcm47xx_leds_linksys_wrt54g_type_0101[] __initconst = { - BCM47XX_GPIO_LED(0, "green", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(0, "green", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), BCM47XX_GPIO_LED(1, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), BCM47XX_GPIO_LED(7, "green", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), }; diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 7c26b28bf2526856f7a96e1a2c39c61b78bf4e59..859cf7048347bf4b0ebad1f619507202976f74b3 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -54,7 +54,8 @@ .align 2; \ .type symbol, @function; \ .ent symbol, 0; \ -symbol: .frame sp, 0, ra +symbol: .frame sp, 0, ra; \ + .insn /* * NESTED - declare nested routine entry point @@ -63,8 +64,9 @@ symbol: .frame sp, 0, ra .globl symbol; \ .align 2; \ .type symbol, @function; \ - .ent symbol, 0; \ -symbol: .frame sp, framesize, rpc + .ent symbol, 0; \ +symbol: .frame sp, framesize, rpc; \ + .insn /* * END - mark end of function @@ -86,7 +88,7 @@ symbol: #define FEXPORT(symbol) \ .globl symbol; \ .type symbol, @function; \ -symbol: +symbol: .insn /* * ABS - export absolute symbol diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 933b50e125a0f30d7fc526a252d7774d31243df5..b6e49c4cd5d2f911ec1ead4349dd32954caed94a 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -141,14 +141,14 @@ static inline void * phys_to_virt(unsigned long address) /* * ISA I/O bus memory addresses are 1:1 with the physical address. */ -static inline unsigned long isa_virt_to_bus(volatile void * address) +static inline unsigned long isa_virt_to_bus(volatile void *address) { - return (unsigned long)address - PAGE_OFFSET; + return virt_to_phys(address); } -static inline void * isa_bus_to_virt(unsigned long address) +static inline void *isa_bus_to_virt(unsigned long address) { - return (void *)(address + PAGE_OFFSET); + return phys_to_virt(address); } #define isa_page_to_bus page_to_phys @@ -375,6 +375,8 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ BUG(); \ } \ \ + /* prevent prefetching of coherent DMA data prematurely */ \ + rmb(); \ return pfx##ioswab##bwlq(__mem, __val); \ } @@ -410,6 +412,8 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ __val = *__addr; \ slow; \ \ + /* prevent prefetching of coherent DMA data prematurely */ \ + rmb(); \ return pfx##ioswab##bwlq(__addr, __val); \ } diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h index daba1f9a4f7939070dd0a75c00ac67979055737e..174aedce3167ae783816a230c0487c725f04c757 100644 --- a/arch/mips/include/asm/kprobes.h +++ b/arch/mips/include/asm/kprobes.h @@ -40,7 +40,8 @@ typedef union mips_instruction kprobe_opcode_t; #define flush_insn_slot(p) \ do { \ - flush_icache_range((unsigned long)p->addr, \ + if (p->addr) \ + flush_icache_range((unsigned long)p->addr, \ (unsigned long)p->addr + \ (MAX_INSN_SIZE * sizeof(kprobe_opcode_t))); \ } while (0) diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index cd41e93bc1d80170330a26d6219b6fe6260619f7..19e5142bb9cc394e4dcba58df2961cd9e104e15d 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -167,7 +167,7 @@ #define AR71XX_AHB_DIV_MASK 0x7 #define AR724X_PLL_REG_CPU_CONFIG 0x00 -#define AR724X_PLL_REG_PCIE_CONFIG 0x18 +#define AR724X_PLL_REG_PCIE_CONFIG 0x10 #define AR724X_PLL_DIV_SHIFT 0 #define AR724X_PLL_DIV_MASK 0x3ff diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h index 1557934aaca973d25e4a0d2bcc97e5e1d39f926a..39a10a136f532801c8d8577c6204ee4b4ca12e35 100644 --- a/arch/mips/include/asm/mach-ath79/ath79.h +++ b/arch/mips/include/asm/mach-ath79/ath79.h @@ -132,6 +132,7 @@ static inline u32 ath79_pll_rr(unsigned reg) static inline void ath79_reset_wr(unsigned reg, u32 val) { __raw_writel(val, ath79_reset_base + reg); + (void) __raw_readl(ath79_reset_base + reg); /* flush */ } static inline u32 ath79_reset_rr(unsigned reg) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 6a9d2dd005cad8755e77b6a21fc187070312bf86..79c882be9d176c2dfc624fe223dd9599c4125447 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -173,8 +173,8 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_BASE_GCRBASE_MSK (_ULCAST_(0x1ffff) << 15) #define CM_GCR_BASE_CMDEFTGT_SHF 0 #define CM_GCR_BASE_CMDEFTGT_MSK (_ULCAST_(0x3) << 0) -#define CM_GCR_BASE_CMDEFTGT_DISABLED 0 -#define CM_GCR_BASE_CMDEFTGT_MEM 1 +#define CM_GCR_BASE_CMDEFTGT_MEM 0 +#define CM_GCR_BASE_CMDEFTGT_RESERVED 1 #define CM_GCR_BASE_CMDEFTGT_IOCU0 2 #define CM_GCR_BASE_CMDEFTGT_IOCU1 3 diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 578ece1e4a99604180b15daccedadcd3ed2e657c..351a5a9e4f52d4f3a30e5bf2433c52f1de493771 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -143,7 +143,7 @@ struct mips_fpu_struct { #define NUM_DSP_REGS 6 -typedef __u32 dspreg_t; +typedef unsigned long dspreg_t; struct mips_dsp_state { dspreg_t dspr[NUM_DSP_REGS]; diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 2f7c734771f4e0ad283bb6bf5ee11a0f4b57d707..0df911e772ae0f55f0f46c964b1d1d699566b05b 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -116,10 +116,20 @@ ftrace_stub: NESTED(_mcount, PT_SIZE, ra) PTR_LA t1, ftrace_stub PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */ - bne t1, t2, static_trace + beq t1, t2, fgraph_trace nop + MCOUNT_SAVE_REGS + + move a0, ra /* arg1: self return address */ + jalr t2 /* (1) call *ftrace_trace_function */ + move a1, AT /* arg2: parent's return address */ + + MCOUNT_RESTORE_REGS + +fgraph_trace: #ifdef CONFIG_FUNCTION_GRAPH_TRACER + PTR_LA t1, ftrace_stub PTR_L t3, ftrace_graph_return bne t1, t3, ftrace_graph_caller nop @@ -128,24 +138,11 @@ NESTED(_mcount, PT_SIZE, ra) bne t1, t3, ftrace_graph_caller nop #endif - b ftrace_stub -#ifdef CONFIG_32BIT - addiu sp, sp, 8 -#else - nop -#endif -static_trace: - MCOUNT_SAVE_REGS - - move a0, ra /* arg1: self return address */ - jalr t2 /* (1) call *ftrace_trace_function */ - move a1, AT /* arg2: parent's return address */ - - MCOUNT_RESTORE_REGS #ifdef CONFIG_32BIT addiu sp, sp, 8 #endif + .globl ftrace_stub ftrace_stub: RETURN_BACK diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 7d09efd25b5608f9d41cf6612e3889047ed18e03..750e679fbbdc82532c8a11e237bf8aeaa2335e6d 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -87,7 +87,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs, *regs = current_pt_regs(); unsigned long childksp; - p->set_child_tid = p->clear_child_tid = NULL; childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 29a56858f0e07ff0eb29bf1dfd0f7ad02cbcb572..0b16f07ada9fa30439a4b898e832384e8f52180d 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -400,25 +400,38 @@ static int gpr64_set(struct task_struct *target, #endif /* CONFIG_64BIT */ -static int fpr_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * !CONFIG_CPU_HAS_MSA variant. FP context's general register slots + * correspond 1:1 to buffer slots. Only general registers are copied. + */ +static int fpr_get_fpa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + void **kbuf, void __user **ubuf) { - unsigned i; - int err; - u64 fpr_val; - - /* XXX fcr31 */ + return user_regset_copyout(pos, count, kbuf, ubuf, + &target->thread.fpu, + 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} - if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu, - 0, sizeof(elf_fpregset_t)); +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * CONFIG_CPU_HAS_MSA variant. Only lower 64 bits of FP context's + * general register slots are copied to buffer slots. Only general + * registers are copied. + */ +static int fpr_get_msa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + void **kbuf, void __user **ubuf) +{ + unsigned int i; + u64 fpr_val; + int err; + BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); for (i = 0; i < NUM_FPU_REGS; i++) { fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); - err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + err = user_regset_copyout(pos, count, kbuf, ubuf, &fpr_val, i * sizeof(elf_fpreg_t), (i + 1) * sizeof(elf_fpreg_t)); if (err) @@ -428,25 +441,71 @@ static int fpr_get(struct task_struct *target, return 0; } -static int fpr_set(struct task_struct *target, +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer. + * Choose the appropriate helper for general registers, and then copy + * the FCSR and FIR registers separately. + */ +static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) + void *kbuf, void __user *ubuf) { - unsigned i; + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); + const int fir_pos = fcr31_pos + sizeof(u32); int err; - u64 fpr_val; - /* XXX fcr31 */ + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf); + else + err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf); + if (err) + return err; + + err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fpu.fcr31, + fcr31_pos, fcr31_pos + sizeof(u32)); + if (err) + return err; + + err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &boot_cpu_data.fpu_id, + fir_pos, fir_pos + sizeof(u32)); + + return err; +} + +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * !CONFIG_CPU_HAS_MSA variant. Buffer slots correspond 1:1 to FP + * context's general register slots. Only general registers are copied. + */ +static int fpr_set_fpa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + return user_regset_copyin(pos, count, kbuf, ubuf, + &target->thread.fpu, + 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} - if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) - return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu, - 0, sizeof(elf_fpregset_t)); +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64 + * bits only of FP context's general register slots. Only general + * registers are copied. + */ +static int fpr_set_msa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + unsigned int i; + u64 fpr_val; + int err; BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); - for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) { - err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { + err = user_regset_copyin(pos, count, kbuf, ubuf, &fpr_val, i * sizeof(elf_fpreg_t), (i + 1) * sizeof(elf_fpreg_t)); if (err) @@ -457,6 +516,58 @@ static int fpr_set(struct task_struct *target, return 0; } +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context. + * Choose the appropriate helper for general registers, and then copy + * the FCSR register separately. Ignore the incoming FIR register + * contents though, as the register is read-only. + * + * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', + * which is supposed to have been guaranteed by the kernel before + * calling us, e.g. in `ptrace_regset'. We enforce that requirement, + * so that we can safely avoid preinitializing temporaries for + * partial register writes. + */ +static int fpr_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); + const int fir_pos = fcr31_pos + sizeof(u32); + u32 fcr31; + int err; + + BUG_ON(count % sizeof(elf_fpreg_t)); + + if (pos + count > sizeof(elf_fpregset_t)) + return -EIO; + + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf); + else + err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf); + if (err) + return err; + + if (count > 0) { + err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &fcr31, + fcr31_pos, fcr31_pos + sizeof(u32)); + if (err) + return err; + + target->thread.fpu.fcr31 = fcr31 & ~FPU_CSR_ALL_X; + } + + if (count > 0) + err = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + fir_pos, + fir_pos + sizeof(u32)); + + return err; +} + enum mips_regset { REGSET_GPR, REGSET_FPR, @@ -522,6 +633,19 @@ static const struct user_regset_view user_mips64_view = { .n = ARRAY_SIZE(mips64_regsets), }; +#ifdef CONFIG_MIPS32_N32 + +static const struct user_regset_view user_mipsn32_view = { + .name = "mipsn32", + .e_flags = EF_MIPS_ABI2, + .e_machine = ELF_ARCH, + .ei_osabi = ELF_OSABI, + .regsets = mips64_regsets, + .n = ARRAY_SIZE(mips64_regsets), +}; + +#endif /* CONFIG_MIPS32_N32 */ + #endif /* CONFIG_64BIT */ const struct user_regset_view *task_user_regset_view(struct task_struct *task) @@ -532,6 +656,10 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #ifdef CONFIG_MIPS32_O32 if (test_tsk_thread_flag(task, TIF_32BIT_REGS)) return &user_mips_view; +#endif +#ifdef CONFIG_MIPS32_N32 + if (test_tsk_thread_flag(task, TIF_32BIT_ADDR)) + return &user_mipsn32_view; #endif return &user_mips64_view; #endif @@ -574,7 +702,7 @@ long arch_ptrace(struct task_struct *child, long request, fregs = get_fpu_regs(child); #ifdef CONFIG_32BIT - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even @@ -585,7 +713,7 @@ long arch_ptrace(struct task_struct *child, long request, break; } #endif - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; @@ -623,7 +751,7 @@ long arch_ptrace(struct task_struct *child, long request, goto out; } dregs = __get_dsp_regs(child); - tmp = (unsigned long) (dregs[addr - DSP_BASE]); + tmp = dregs[addr - DSP_BASE]; break; } case DSP_CONTROL: @@ -668,7 +796,7 @@ long arch_ptrace(struct task_struct *child, long request, child->thread.fpu.fcr31 = 0; } #ifdef CONFIG_32BIT - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 283b5a1967d1461298bf065b2073d62c6296dc1d..286ec2d24d47bd441ab63b26bca4158c6868497f 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -97,7 +97,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; } fregs = get_fpu_regs(child); - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even @@ -107,7 +107,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, addr & 1); break; } - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; @@ -140,7 +140,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, goto out; } dregs = __get_dsp_regs(child); - tmp = (unsigned long) (dregs[addr - DSP_BASE]); + tmp = dregs[addr - DSP_BASE]; break; } case DSP_CONTROL: @@ -203,7 +203,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, sizeof(child->thread.fpu)); child->thread.fpu.fcr31 = 0; } - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f3b635f86c39c085ac67126929d4a7cec89e9702..e9f330a864af751ad3977a9c31085aad623ba360 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -427,6 +427,10 @@ static void __init bootmem_init(void) continue; default: /* Not usable memory */ + if (start > min_low_pfn && end < max_low_pfn) + reserve_bootmem(boot_mem_map.map[i].addr, + boot_mem_map.map[i].size, + BOOTMEM_DEFAULT); continue; } diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 06bb5ed6d80a68728b56329db41a6531d377eca8..747bcb3641a830a32a3a8299235bab3cf1012a27 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -159,11 +159,11 @@ static void bmips_prepare_cpus(unsigned int max_cpus) return; } - if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, - "smp_ipi0", NULL)) + if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, + IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi0", NULL)) panic("Can't request IPI0 interrupt"); - if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, - "smp_ipi1", NULL)) + if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, + IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi1", NULL)) panic("Can't request IPI1 interrupt"); } diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 3b46f7ce9ca75bc5f81f9bb2939880277289bd20..77733b403c0946c410f0fa4a2fe440bf40cd9dce 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -141,7 +141,7 @@ SECTIONS * Force .bss to 64K alignment so that .bss..swapper_pg_dir * gets that alignment. .sbss should be empty, so there will be * no holes after __init_end. */ - BSS_SECTION(0, 0x10000, 0) + BSS_SECTION(0, 0x10000, 8) _end = . ; diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 26059bf34b1a848c786245fb98abc827e8458aae..8ac533c100de9962a0062876b3a249b7d21091e3 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -39,7 +39,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "cache", VCPU_STAT(cache_exits), KVM_STAT_VCPU }, { "signal", VCPU_STAT(signal_exits), KVM_STAT_VCPU }, { "interrupt", VCPU_STAT(int_exits), KVM_STAT_VCPU }, - { "cop_unsuable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU }, + { "cop_unusable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU }, { "tlbmod", VCPU_STAT(tlbmod_exits), KVM_STAT_VCPU }, { "tlbmiss_ld", VCPU_STAT(tlbmiss_ld_exits), KVM_STAT_VCPU }, { "tlbmiss_st", VCPU_STAT(tlbmiss_st_exits), KVM_STAT_VCPU }, diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 7b0e5462ca517ac2c8411ef35d06f35b7867d73d..1e178c4ae06fee0cd6346f996f1bb33cb1e8dcb3 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -178,7 +178,7 @@ 1: PTR_ADDIU a0, 1 /* fill bytewise */ R10KCBARRIER(0(ra)) bne t1, a0, 1b - sb a1, -1(a0) + EX(sb, a1, -1(a0), .Lsmall_fixup\@) 2: jr ra /* done */ move a2, zero @@ -204,13 +204,18 @@ PTR_L t0, TI_TASK($28) andi a2, STORMASK LONG_L t0, THREAD_BUADDR(t0) - LONG_ADDU a2, t1 + LONG_ADDU a2, a0 jr ra LONG_SUBU a2, t0 .Llast_fixup\@: jr ra - andi v1, a2, STORMASK + nop + +.Lsmall_fixup\@: + PTR_SUBU a2, t1, a0 + jr ra + PTR_ADDIU a2, 1 .endm diff --git a/arch/mips/loongson/common/cs5536/cs5536_ohci.c b/arch/mips/loongson/common/cs5536/cs5536_ohci.c index f7c905e50dc415e21eb258b08a69cc61525bd67b..92dc6bafc1271795b3c66b7c21467f3c22214fd0 100644 --- a/arch/mips/loongson/common/cs5536/cs5536_ohci.c +++ b/arch/mips/loongson/common/cs5536/cs5536_ohci.c @@ -138,7 +138,7 @@ u32 pci_ohci_read_reg(int reg) break; case PCI_OHCI_INT_REG: _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo); - if ((lo & 0x00000f00) == CS5536_USB_INTR) + if (((lo >> PIC_YSEL_LOW_USB_SHIFT) & 0xf) == CS5536_USB_INTR) conf_data = 1; break; default: diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index fbcd8674ff1d598538052129c0a90995c0dcd6a1..af126fda630c527631a6b852f390e6f3e5cef2f2 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -703,7 +703,8 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) { /* Catch bad driver code */ - BUG_ON(size == 0); + if (WARN_ON(size == 0)) + return; preempt_disable(); if (cpu_has_inclusive_pcaches) { @@ -736,7 +737,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) { /* Catch bad driver code */ - BUG_ON(size == 0); + if (WARN_ON(size == 0)) + return; preempt_disable(); if (cpu_has_inclusive_pcaches) { diff --git a/arch/mips/mm/pgtable-32.c b/arch/mips/mm/pgtable-32.c index adc6911ba748915bda5b2575fc03b76891f1fb21..b19a3c506b1e9d203cbacb0da71513d8f21868b1 100644 --- a/arch/mips/mm/pgtable-32.c +++ b/arch/mips/mm/pgtable-32.c @@ -51,15 +51,15 @@ void __init pagetable_init(void) /* * Fixed mappings: */ - vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - fixrange_init(vaddr, vaddr + FIXADDR_SIZE, pgd_base); + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1); + fixrange_init(vaddr & PMD_MASK, vaddr + FIXADDR_SIZE, pgd_base); #ifdef CONFIG_HIGHMEM /* * Permanent kmaps: */ vaddr = PKMAP_BASE; - fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + fixrange_init(vaddr & PMD_MASK, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); pgd = swapper_pg_dir + __pgd_offset(vaddr); pud = pud_offset(pgd, vaddr); diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c index 8399ddf03a0235c5ce9d5ee28ed5007c9986a8ab..cab124e0572d03e209f09f27a8096d84c942341e 100644 --- a/arch/mips/mm/uasm-micromips.c +++ b/arch/mips/mm/uasm-micromips.c @@ -83,7 +83,7 @@ static struct insn insn_table_MM[] = { { insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS }, { insn_lb, M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, { insn_ld, 0, 0 }, - { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM }, + { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM }, { insn_lld, 0, 0 }, { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM }, diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c index ab6404c343cc70e914fbe9721f9462292ce68d0f..ab88beca2d21e14ac5a2a1b052e407e61fc9faa7 100644 --- a/arch/mips/net/bpf_jit.c +++ b/arch/mips/net/bpf_jit.c @@ -562,7 +562,8 @@ static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset) u32 sflags, tmp_flags; /* Adjust the stack pointer */ - emit_stack_offset(-align_sp(offset), ctx); + if (offset) + emit_stack_offset(-align_sp(offset), ctx); if (ctx->flags & SEEN_CALL) { /* Argument save area */ @@ -641,7 +642,8 @@ static void restore_bpf_jit_regs(struct jit_ctx *ctx, emit_load_stack_reg(r_ra, r_sp, real_off, ctx); /* Restore the sp and discard the scrach memory */ - emit_stack_offset(align_sp(offset), ctx); + if (offset) + emit_stack_offset(align_sp(offset), ctx); } static unsigned int get_stack_depth(struct jit_ctx *ctx) @@ -689,8 +691,14 @@ static void build_prologue(struct jit_ctx *ctx) if (ctx->flags & SEEN_X) emit_jit_reg_move(r_X, r_zero, ctx); - /* Do not leak kernel data to userspace */ - if (bpf_needs_clear_a(&ctx->skf->insns[0])) + /* + * Do not leak kernel data to userspace, we only need to clear + * r_A if it is ever used. In fact if it is never used, we + * will not save/restore it, so clearing it in this case would + * corrupt the state of the caller. + */ + if (bpf_needs_clear_a(&ctx->skf->insns[0]) && + (ctx->flags & SEEN_A)) emit_jit_reg_move(r_A, r_zero, ctx); } diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index c100b9afa0abe85fe31555a06bcc25186345eacd..48b43ee0d1990eff3eb95ae59abcf98f667483e3 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -275,7 +275,7 @@ asmlinkage void plat_irq_dispatch(void) do_IRQ(nlm_irq_to_xirq(node, i)); } -#ifdef CONFIG_OF +#ifdef CONFIG_CPU_XLP static const struct irq_domain_ops xlp_pic_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; @@ -348,7 +348,7 @@ void __init arch_init_irq(void) #if defined(CONFIG_CPU_XLR) nlm_setup_fmn_irq(); #endif -#if defined(CONFIG_OF) +#ifdef CONFIG_CPU_XLP of_irq_init(xlp_pic_irq_ids); #endif } diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c index 2da5f25f98bc5a37869429f790fbf47bb35159ed..e802259b2a59d2eab41ddee044074e9323ee02e3 100644 --- a/arch/mips/txx9/rbtx4939/setup.c +++ b/arch/mips/txx9/rbtx4939/setup.c @@ -186,7 +186,7 @@ static void __init rbtx4939_update_ioc_pen(void) #define RBTX4939_MAX_7SEGLEDS 8 -#if IS_ENABLED(CONFIG_LEDS_CLASS) +#if IS_BUILTIN(CONFIG_LEDS_CLASS) static u8 led_val[RBTX4939_MAX_7SEGLEDS]; struct rbtx4939_led_data { struct led_classdev cdev; @@ -262,7 +262,7 @@ static inline void rbtx4939_led_setup(void) static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val) { -#if IS_ENABLED(CONFIG_LEDS_CLASS) +#if IS_BUILTIN(CONFIG_LEDS_CLASS) unsigned long flags; local_irq_save(flags); /* bit7: reserved for LED class */ diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c index b9920b1edd5a7848180876783d39ae20f261011f..70cef54dc40f823d9842bccebc6abaa2498300f9 100644 --- a/arch/mn10300/mm/misalignment.c +++ b/arch/mn10300/mm/misalignment.c @@ -437,7 +437,7 @@ transfer_failed: info.si_signo = SIGSEGV; info.si_errno = 0; - info.si_code = 0; + info.si_code = SEGV_MAPERR; info.si_addr = (void *) regs->pc; force_sig_info(SIGSEGV, &info, current); return; diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h index d441480a4af4804c64d0c35fb8a3c235b054f05f..6f6b1036e064af2e63db9c28b448b576c72801e1 100644 --- a/arch/openrisc/include/asm/uaccess.h +++ b/arch/openrisc/include/asm/uaccess.h @@ -215,7 +215,7 @@ do { \ case 1: __get_user_asm(x, ptr, retval, "l.lbz"); break; \ case 2: __get_user_asm(x, ptr, retval, "l.lhz"); break; \ case 4: __get_user_asm(x, ptr, retval, "l.lwz"); break; \ - case 8: __get_user_asm2(x, ptr, retval); \ + case 8: __get_user_asm2(x, ptr, retval); break; \ default: (x) = __get_user_bad(); \ } \ } while (0) diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index 386af258591dbe7084867f88b79c3eef980ce15b..62d9bb2dbd829f9fdddff9b2241c020222e0cd8e 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -152,8 +152,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, top_of_kernel_stack = sp; - p->set_child_tid = p->clear_child_tid = NULL; - /* Locate userspace context on stack... */ sp -= STACK_FRAME_OVERHEAD; /* redzone */ sp -= sizeof(struct pt_regs); diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index 3d3f6062f49ccee5ae47ec0505101fad7f5d147d..605a284922fb7f1eab5203fbf732f3d96f371320 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -302,12 +302,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) siginfo_t info; if (user_mode(regs)) { - /* Send a SIGSEGV */ - info.si_signo = SIGSEGV; + /* Send a SIGBUS */ + info.si_signo = SIGBUS; info.si_errno = 0; - /* info.si_code has been set above */ - info.si_addr = (void *)address; - force_sig_info(SIGSEGV, &info, current); + info.si_code = BUS_ADRALN; + info.si_addr = (void __user *)address; + force_sig_info(SIGBUS, &info, current); } else { printk("KERNEL: Unaligned Access 0x%.8lx\n", address); show_registers(regs); diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index dba508fe1683d8153ed9ca7a0539246f7f6d52a2..4f7060ec687504cb18904e7457997a848697b634 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -648,6 +648,10 @@ static int match_pci_device(struct device *dev, int index, (modpath->mod == PCI_FUNC(devfn))); } + /* index might be out of bounds for bc[] */ + if (index >= 6) + return 0; + id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5); return (modpath->bc[index] == id); } diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index ba0c053e25ae9d66cf536ab87ce1cca9eef53dbf..2a2fff407ac487ccb1774d9c30f8e79bbfe47a5d 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -39,7 +39,7 @@ * the PDC INTRIGUE calls. This is done to eliminate bugs introduced * in various PDC revisions. The code is much more maintainable * and reliable this way vs having to debug on every version of PDC - * on every box. + * on every box. */ #include @@ -195,8 +195,8 @@ static int perf_config(uint32_t *image_ptr); static int perf_release(struct inode *inode, struct file *file); static int perf_open(struct inode *inode, struct file *file); static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos); -static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos); +static ssize_t perf_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos); static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static void perf_start_counters(void); static int perf_stop_counters(uint32_t *raddr); @@ -222,7 +222,7 @@ extern void perf_intrigue_disable_perf_counters (void); /* * configure: * - * Configure the cpu with a given data image. First turn off the counters, + * Configure the cpu with a given data image. First turn off the counters, * then download the image, then turn the counters back on. */ static int perf_config(uint32_t *image_ptr) @@ -234,7 +234,7 @@ static int perf_config(uint32_t *image_ptr) error = perf_stop_counters(raddr); if (error != 0) { printk("perf_config: perf_stop_counters = %ld\n", error); - return -EINVAL; + return -EINVAL; } printk("Preparing to write image\n"); @@ -242,7 +242,7 @@ printk("Preparing to write image\n"); error = perf_write_image((uint64_t *)image_ptr); if (error != 0) { printk("perf_config: DOWNLOAD = %ld\n", error); - return -EINVAL; + return -EINVAL; } printk("Preparing to start counters\n"); @@ -254,7 +254,7 @@ printk("Preparing to start counters\n"); } /* - * Open the device and initialize all of its memory. The device is only + * Open the device and initialize all of its memory. The device is only * opened once, but can be "queried" by multiple processes that know its * file descriptor. */ @@ -298,8 +298,8 @@ static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t * called on the processor that the download should happen * on. */ -static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) +static ssize_t perf_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { int err; size_t image_size; @@ -307,11 +307,11 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun uint32_t interface_type; uint32_t test; - if (perf_processor_interface == ONYX_INTF) + if (perf_processor_interface == ONYX_INTF) image_size = PCXU_IMAGE_SIZE; - else if (perf_processor_interface == CUDA_INTF) + else if (perf_processor_interface == CUDA_INTF) image_size = PCXW_IMAGE_SIZE; - else + else return -EFAULT; if (!capable(CAP_SYS_ADMIN)) @@ -331,22 +331,22 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun /* First check the machine type is correct for the requested image */ - if (((perf_processor_interface == CUDA_INTF) && - (interface_type != CUDA_INTF)) || - ((perf_processor_interface == ONYX_INTF) && - (interface_type != ONYX_INTF))) + if (((perf_processor_interface == CUDA_INTF) && + (interface_type != CUDA_INTF)) || + ((perf_processor_interface == ONYX_INTF) && + (interface_type != ONYX_INTF))) return -EINVAL; /* Next check to make sure the requested image is valid */ - if (((interface_type == CUDA_INTF) && + if (((interface_type == CUDA_INTF) && (test >= MAX_CUDA_IMAGES)) || - ((interface_type == ONYX_INTF) && - (test >= MAX_ONYX_IMAGES))) + ((interface_type == ONYX_INTF) && + (test >= MAX_ONYX_IMAGES))) return -EINVAL; /* Copy the image into the processor */ - if (interface_type == CUDA_INTF) + if (interface_type == CUDA_INTF) return perf_config(cuda_images[test]); else return perf_config(onyx_images[test]); @@ -360,7 +360,7 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun static void perf_patch_images(void) { #if 0 /* FIXME!! */ -/* +/* * NOTE: this routine is VERY specific to the current TLB image. * If the image is changed, this routine might also need to be changed. */ @@ -368,9 +368,9 @@ static void perf_patch_images(void) extern void $i_dtlb_miss_2_0(); extern void PA2_0_iva(); - /* + /* * We can only use the lower 32-bits, the upper 32-bits should be 0 - * anyway given this is in the kernel + * anyway given this is in the kernel */ uint32_t itlb_addr = (uint32_t)&($i_itlb_miss_2_0); uint32_t dtlb_addr = (uint32_t)&($i_dtlb_miss_2_0); @@ -378,21 +378,21 @@ static void perf_patch_images(void) if (perf_processor_interface == ONYX_INTF) { /* clear last 2 bytes */ - onyx_images[TLBMISS][15] &= 0xffffff00; + onyx_images[TLBMISS][15] &= 0xffffff00; /* set 2 bytes */ onyx_images[TLBMISS][15] |= (0x000000ff&((dtlb_addr) >> 24)); onyx_images[TLBMISS][16] = (dtlb_addr << 8)&0xffffff00; onyx_images[TLBMISS][17] = itlb_addr; /* clear last 2 bytes */ - onyx_images[TLBHANDMISS][15] &= 0xffffff00; + onyx_images[TLBHANDMISS][15] &= 0xffffff00; /* set 2 bytes */ onyx_images[TLBHANDMISS][15] |= (0x000000ff&((dtlb_addr) >> 24)); onyx_images[TLBHANDMISS][16] = (dtlb_addr << 8)&0xffffff00; onyx_images[TLBHANDMISS][17] = itlb_addr; /* clear last 2 bytes */ - onyx_images[BIG_CPI][15] &= 0xffffff00; + onyx_images[BIG_CPI][15] &= 0xffffff00; /* set 2 bytes */ onyx_images[BIG_CPI][15] |= (0x000000ff&((dtlb_addr) >> 24)); onyx_images[BIG_CPI][16] = (dtlb_addr << 8)&0xffffff00; @@ -405,24 +405,24 @@ static void perf_patch_images(void) } else if (perf_processor_interface == CUDA_INTF) { /* Cuda interface */ - cuda_images[TLBMISS][16] = + cuda_images[TLBMISS][16] = (cuda_images[TLBMISS][16]&0xffff0000) | ((dtlb_addr >> 8)&0x0000ffff); - cuda_images[TLBMISS][17] = + cuda_images[TLBMISS][17] = ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff); cuda_images[TLBMISS][18] = (itlb_addr << 16)&0xffff0000; - cuda_images[TLBHANDMISS][16] = + cuda_images[TLBHANDMISS][16] = (cuda_images[TLBHANDMISS][16]&0xffff0000) | ((dtlb_addr >> 8)&0x0000ffff); - cuda_images[TLBHANDMISS][17] = + cuda_images[TLBHANDMISS][17] = ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff); cuda_images[TLBHANDMISS][18] = (itlb_addr << 16)&0xffff0000; - cuda_images[BIG_CPI][16] = + cuda_images[BIG_CPI][16] = (cuda_images[BIG_CPI][16]&0xffff0000) | ((dtlb_addr >> 8)&0x0000ffff); - cuda_images[BIG_CPI][17] = + cuda_images[BIG_CPI][17] = ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff); cuda_images[BIG_CPI][18] = (itlb_addr << 16)&0xffff0000; } else { @@ -434,7 +434,7 @@ static void perf_patch_images(void) /* * ioctl routine - * All routines effect the processor that they are executed on. Thus you + * All routines effect the processor that they are executed on. Thus you * must be running on the processor that you wish to change. */ @@ -460,7 +460,7 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } /* copy out the Counters */ - if (copy_to_user((void __user *)arg, raddr, + if (copy_to_user((void __user *)arg, raddr, sizeof (raddr)) != 0) { error = -EFAULT; break; @@ -488,7 +488,7 @@ static const struct file_operations perf_fops = { .open = perf_open, .release = perf_release }; - + static struct miscdevice perf_dev = { MISC_DYNAMIC_MINOR, PA_PERF_DEV, @@ -595,7 +595,7 @@ static int perf_stop_counters(uint32_t *raddr) /* OR sticky2 (bit 1496) to counter2 bit 32 */ tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000; raddr[2] = (uint32_t)tmp64; - + /* Counter3 is bits 1497 to 1528 */ tmp64 = (userbuf[23] >> 7) & 0x00000000ffffffff; /* OR sticky3 (bit 1529) to counter3 bit 32 */ @@ -617,7 +617,7 @@ static int perf_stop_counters(uint32_t *raddr) userbuf[22] = 0; userbuf[23] = 0; - /* + /* * Write back the zeroed bytes + the image given * the read was destructive. */ @@ -625,13 +625,13 @@ static int perf_stop_counters(uint32_t *raddr) } else { /* - * Read RDR-15 which contains the counters and sticky bits + * Read RDR-15 which contains the counters and sticky bits */ if (!perf_rdr_read_ubuf(15, userbuf)) { return -13; } - /* + /* * Clear out the counters */ perf_rdr_clear(15); @@ -644,7 +644,7 @@ static int perf_stop_counters(uint32_t *raddr) raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL); raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL); } - + return 0; } @@ -682,7 +682,7 @@ static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer) i = tentry->num_words; while (i--) { buffer[i] = 0; - } + } /* Check for bits an even number of 64 */ if ((xbits = width & 0x03f) != 0) { @@ -808,18 +808,22 @@ static int perf_write_image(uint64_t *memaddr) } runway = ioremap_nocache(cpu_device->hpa.start, 4096); + if (!runway) { + pr_err("perf_write_image: ioremap failed!\n"); + return -ENOMEM; + } /* Merge intrigue bits into Runway STATUS 0 */ tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful; - __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), + __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), runway + RUNWAY_STATUS); - + /* Write RUNWAY DEBUG registers */ for (i = 0; i < 8; i++) { __raw_writeq(*memaddr++, runway + RUNWAY_DEBUG); } - return 0; + return 0; } /* @@ -843,7 +847,7 @@ printk("perf_rdr_write\n"); perf_rdr_shift_out_U(rdr_num, buffer[i]); } else { perf_rdr_shift_out_W(rdr_num, buffer[i]); - } + } } printk("perf_rdr_write done\n"); } diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 8f13c7facdd7b2ba94d5298829cded90f651a5d2..196395a0ac9179402565c305c9a4b3bf49c4781e 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -479,11 +479,6 @@ lws_start: comiclr,>> __NR_lws_entries, %r20, %r0 b,n lws_exit_nosys - /* WARNING: Trashing sr2 and sr3 */ - mfsp %sr7,%r1 /* get userspace into sr3 */ - mtsp %r1,%sr3 - mtsp %r0,%sr2 /* get kernel space into sr2 */ - /* Load table start */ ldil L%lws_table, %r1 ldo R%lws_table(%r1), %r28 /* Scratch use of r28 */ @@ -632,9 +627,9 @@ cas_action: stw %r1, 4(%sr2,%r20) #endif /* The load and store could fail */ -1: ldw,ma 0(%sr3,%r26), %r28 +1: ldw,ma 0(%r26), %r28 sub,<> %r28, %r25, %r0 -2: stw,ma %r24, 0(%sr3,%r26) +2: stw,ma %r24, 0(%r26) /* Free lock */ stw,ma %r20, 0(%sr2,%r20) #if ENABLE_LWS_DEBUG @@ -693,15 +688,15 @@ cas_action: /* ELF32 Process entry path */ lws_compare_and_swap_2: #ifdef CONFIG_64BIT - /* Clip the input registers */ + /* Clip the input registers. We don't need to clip %r23 as we + only use it for word operations */ depdi 0, 31, 32, %r26 depdi 0, 31, 32, %r25 depdi 0, 31, 32, %r24 - depdi 0, 31, 32, %r23 #endif /* Check the validity of the size pointer */ - subi,>>= 4, %r23, %r0 + subi,>>= 3, %r23, %r0 b,n lws_exit_nosys /* Jump to the functions which will load the old and new values into @@ -711,9 +706,9 @@ lws_compare_and_swap_2: nop /* 8bit load */ -4: ldb 0(%sr3,%r25), %r25 +4: ldb 0(%r25), %r25 b cas2_lock_start -5: ldb 0(%sr3,%r24), %r24 +5: ldb 0(%r24), %r24 nop nop nop @@ -721,9 +716,9 @@ lws_compare_and_swap_2: nop /* 16bit load */ -6: ldh 0(%sr3,%r25), %r25 +6: ldh 0(%r25), %r25 b cas2_lock_start -7: ldh 0(%sr3,%r24), %r24 +7: ldh 0(%r24), %r24 nop nop nop @@ -731,9 +726,9 @@ lws_compare_and_swap_2: nop /* 32bit load */ -8: ldw 0(%sr3,%r25), %r25 +8: ldw 0(%r25), %r25 b cas2_lock_start -9: ldw 0(%sr3,%r24), %r24 +9: ldw 0(%r24), %r24 nop nop nop @@ -742,14 +737,14 @@ lws_compare_and_swap_2: /* 64bit load */ #ifdef CONFIG_64BIT -10: ldd 0(%sr3,%r25), %r25 -11: ldd 0(%sr3,%r24), %r24 +10: ldd 0(%r25), %r25 +11: ldd 0(%r24), %r24 #else - /* Load new value into r22/r23 - high/low */ -10: ldw 0(%sr3,%r25), %r22 -11: ldw 4(%sr3,%r25), %r23 + /* Load old value into r22/r23 - high/low */ +10: ldw 0(%r25), %r22 +11: ldw 4(%r25), %r23 /* Load new value into fr4 for atomic store later */ -12: flddx 0(%sr3,%r24), %fr4 +12: flddx 0(%r24), %fr4 #endif cas2_lock_start: @@ -799,30 +794,30 @@ cas2_action: ldo 1(%r0),%r28 /* 8bit CAS */ -13: ldb,ma 0(%sr3,%r26), %r29 +13: ldb,ma 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -14: stb,ma %r24, 0(%sr3,%r26) +14: stb,ma %r24, 0(%r26) b cas2_end copy %r0, %r28 nop nop /* 16bit CAS */ -15: ldh,ma 0(%sr3,%r26), %r29 +15: ldh,ma 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -16: sth,ma %r24, 0(%sr3,%r26) +16: sth,ma %r24, 0(%r26) b cas2_end copy %r0, %r28 nop nop /* 32bit CAS */ -17: ldw,ma 0(%sr3,%r26), %r29 +17: ldw,ma 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -18: stw,ma %r24, 0(%sr3,%r26) +18: stw,ma %r24, 0(%r26) b cas2_end copy %r0, %r28 nop @@ -830,22 +825,22 @@ cas2_action: /* 64bit CAS */ #ifdef CONFIG_64BIT -19: ldd,ma 0(%sr3,%r26), %r29 +19: ldd,ma 0(%r26), %r29 sub,*= %r29, %r25, %r0 b,n cas2_end -20: std,ma %r24, 0(%sr3,%r26) +20: std,ma %r24, 0(%r26) copy %r0, %r28 #else /* Compare first word */ -19: ldw,ma 0(%sr3,%r26), %r29 +19: ldw 0(%r26), %r29 sub,= %r29, %r22, %r0 b,n cas2_end /* Compare second word */ -20: ldw,ma 4(%sr3,%r26), %r29 +20: ldw 4(%r26), %r29 sub,= %r29, %r23, %r0 b,n cas2_end /* Perform the store */ -21: fstdx %fr4, 0(%sr3,%r26) +21: fstdx %fr4, 0(%r26) copy %r0, %r28 #endif diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 70e105d62423f5c8bde7588d6a8a4afa4c67e646..d2d2946c586acc0aa189e9e17f5173ae4a3e3f80 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -246,7 +246,7 @@ static int __init rtc_init(void) } module_init(rtc_init); -void read_persistent_clock(struct timespec *ts) +void read_persistent_clock64(struct timespec64 *ts) { static struct pdc_tod tod_data; if (pdc_tod_read(&tod_data) == 0) { diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 33c84664ac796dbef32bf6177e377e7af28a9a98..e0b1a734cf9bec5526a35ef6b869a3d12ae65c45 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -1071,11 +1071,6 @@ source "arch/powerpc/Kconfig.debug" source "security/Kconfig" -config KEYS_COMPAT - bool - depends on COMPAT && KEYS - default y - source "crypto/Kconfig" config PPC_LIB_RHEAP diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h index bab79a110c7b05ceb8a4320efe4290257e186250..7c63ec5d4fa9b9007411770347b80491a95d6c08 100644 --- a/arch/powerpc/include/asm/barrier.h +++ b/arch/powerpc/include/asm/barrier.h @@ -39,7 +39,8 @@ #ifdef CONFIG_SMP -#ifdef __SUBARCH_HAS_LWSYNC +/* The sub-arch has lwsync */ +#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) # define SMPWMB LWSYNC #else # define SMPWMB eieio diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index 493e72f64b35feac4a03fe7912aa7c04067e6fe6..5768ec3c17818eb33b7bc1a46bd1f621e2966cd6 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -194,9 +194,6 @@ struct fadump_crash_info_header { struct cpumask cpu_online_mask; }; -/* Crash memory ranges */ -#define INIT_CRASHMEM_RANGES (INIT_MEMBLOCK_REGIONS + 2) - struct fad_crash_memory_ranges { unsigned long long base; unsigned long long size; diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h index 744fd54de374146704587038dea87510610829e8..1bcc84903930ea8ac9b0e152be3576d975ca73bd 100644 --- a/arch/powerpc/include/asm/irq_work.h +++ b/arch/powerpc/include/asm/irq_work.h @@ -5,5 +5,6 @@ static inline bool arch_irq_work_has_interrupt(void) { return true; } +extern void arch_irq_work_raise(void); #endif /* _ASM_POWERPC_IRQ_WORK_H */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 9124b0ede1fc7f531a97d369169706024741ce17..e6bc95da0e1313cd884b29c643ca3997c9d9fd23 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -801,6 +801,9 @@ typedef struct oppanel_line { uint64_t line_len; } oppanel_line_t; +/* Default time to sleep or delay between OPAL_BUSY/OPAL_BUSY_EVENT loops */ +#define OPAL_BUSY_DELAY_MS 10 + /* /sys/firmware/opal */ extern struct kobject *opal_kobj; diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index e682a7143edb767826705243df3613cc85e305ab..e344d98239a76b3b0207d067b65cbcd5b9cb8006 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -5,10 +5,6 @@ #include #include -#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) -#define __SUBARCH_HAS_LWSYNC -#endif - #ifndef __ASSEMBLY__ extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; extern void do_lwsync_fixups(unsigned long value, void *fixup_start, diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index ce068cb2071f7f53d50de82dd2f8f11f3a01ee77..aa3042044118047db1a59c1a367f4c7f0fb1a07c 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -236,6 +236,28 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr) #define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz)) +#define __get_user_or_set_dar(_regs, _dest, _addr) \ + ({ \ + int rc = 0; \ + typeof(_addr) __addr = (_addr); \ + if (__get_user_inatomic(_dest, __addr)) { \ + _regs->dar = (unsigned long)__addr; \ + rc = -EFAULT; \ + } \ + rc; \ + }) + +#define __put_user_or_set_dar(_regs, _src, _addr) \ + ({ \ + int rc = 0; \ + typeof(_addr) __addr = (_addr); \ + if (__put_user_inatomic(_src, __addr)) { \ + _regs->dar = (unsigned long)__addr; \ + rc = -EFAULT; \ + } \ + rc; \ + }) + static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, unsigned int reg, unsigned int nb, unsigned int flags, unsigned int instr, @@ -264,9 +286,10 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, } else { unsigned long pc = regs->nip ^ (swiz & 4); - if (__get_user_inatomic(instr, - (unsigned int __user *)pc)) + if (__get_user_or_set_dar(regs, instr, + (unsigned int __user *)pc)) return -EFAULT; + if (swiz == 0 && (flags & SW)) instr = cpu_to_le32(instr); nb = (instr >> 11) & 0x1f; @@ -310,31 +333,31 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, ((nb0 + 3) / 4) * sizeof(unsigned long)); for (i = 0; i < nb; ++i, ++p) - if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz), - SWIZ_PTR(p))) + if (__get_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; for (i = 0; i < nb0; ++i, ++p) - if (__get_user_inatomic(REG_BYTE(rptr, - i ^ bswiz), - SWIZ_PTR(p))) + if (__get_user_or_set_dar(regs, + REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } else { for (i = 0; i < nb; ++i, ++p) - if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz), - SWIZ_PTR(p))) + if (__put_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; for (i = 0; i < nb0; ++i, ++p) - if (__put_user_inatomic(REG_BYTE(rptr, - i ^ bswiz), - SWIZ_PTR(p))) + if (__put_user_or_set_dar(regs, + REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } @@ -346,29 +369,32 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, * Only POWER6 has these instructions, and it does true little-endian, * so we don't need the address swizzling. */ -static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, - unsigned int flags) +static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr, + unsigned int reg, unsigned int flags) { char *ptr0 = (char *) ¤t->thread.TS_FPR(reg); char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1); - int i, ret, sw = 0; + int i, sw = 0; if (reg & 1) return 0; /* invalid form: FRS/FRT must be even */ if (flags & SW) sw = 7; - ret = 0; + for (i = 0; i < 8; ++i) { if (!(flags & ST)) { - ret |= __get_user(ptr0[i^sw], addr + i); - ret |= __get_user(ptr1[i^sw], addr + i + 8); + if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } else { - ret |= __put_user(ptr0[i^sw], addr + i); - ret |= __put_user(ptr1[i^sw], addr + i + 8); + if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } } - if (ret) - return -EFAULT; + return 1; /* exception handled and fixed up */ } @@ -378,24 +404,27 @@ static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr, { char *ptr0 = (char *)®s->gpr[reg]; char *ptr1 = (char *)®s->gpr[reg+1]; - int i, ret, sw = 0; + int i, sw = 0; if (reg & 1) return 0; /* invalid form: GPR must be even */ if (flags & SW) sw = 7; - ret = 0; + for (i = 0; i < 8; ++i) { if (!(flags & ST)) { - ret |= __get_user(ptr0[i^sw], addr + i); - ret |= __get_user(ptr1[i^sw], addr + i + 8); + if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } else { - ret |= __put_user(ptr0[i^sw], addr + i); - ret |= __put_user(ptr1[i^sw], addr + i + 8); + if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } } - if (ret) - return -EFAULT; + return 1; /* exception handled and fixed up */ } #endif /* CONFIG_PPC64 */ @@ -688,9 +717,14 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg, for (j = 0; j < length; j += elsize) { for (i = 0; i < elsize; ++i) { if (flags & ST) - ret |= __put_user(ptr[i^sw], addr + i); + ret = __put_user_or_set_dar(regs, ptr[i^sw], + addr + i); else - ret |= __get_user(ptr[i^sw], addr + i); + ret = __get_user_or_set_dar(regs, ptr[i^sw], + addr + i); + + if (ret) + return ret; } ptr += elsize; #ifdef __LITTLE_ENDIAN__ @@ -740,7 +774,7 @@ int fix_alignment(struct pt_regs *regs) unsigned int dsisr; unsigned char __user *addr; unsigned long p, swiz; - int ret, i; + int i; union data { u64 ll; double dd; @@ -923,7 +957,7 @@ int fix_alignment(struct pt_regs *regs) if (flags & F) { /* Special case for 16-byte FP loads and stores */ PPC_WARN_ALIGNMENT(fp_pair, regs); - return emulate_fp_pair(addr, reg, flags); + return emulate_fp_pair(regs, addr, reg, flags); } else { #ifdef CONFIG_PPC64 /* Special case for 16-byte loads and stores */ @@ -953,15 +987,12 @@ int fix_alignment(struct pt_regs *regs) } data.ll = 0; - ret = 0; p = (unsigned long)addr; for (i = 0; i < nb; i++) - ret |= __get_user_inatomic(data.v[start + i], - SWIZ_PTR(p++)); - - if (unlikely(ret)) - return -EFAULT; + if (__get_user_or_set_dar(regs, data.v[start + i], + SWIZ_PTR(p++))) + return -EFAULT; } else if (flags & F) { data.ll = current->thread.TS_FPR(reg); @@ -1031,15 +1062,13 @@ int fix_alignment(struct pt_regs *regs) break; } - ret = 0; p = (unsigned long)addr; for (i = 0; i < nb; i++) - ret |= __put_user_inatomic(data.v[start + i], - SWIZ_PTR(p++)); + if (__put_user_or_set_dar(regs, data.v[start + i], + SWIZ_PTR(p++))) + return -EFAULT; - if (unlikely(ret)) - return -EFAULT; } else if (flags & F) current->thread.TS_FPR(reg) = data.ll; else diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index e233c0fec5244619df884e9a5aad8664378ca861..8d64db1c15a64f4bcc0d68ee8c4d106210cee9e0 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -521,6 +521,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) * actually hit this code path. */ + isync slbie r6 slbie r6 /* Workaround POWER5 < DD2.1 issue */ slbmte r7,r0 diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 26d091a1a54cf555627fd95bb135cf98eb3e52b8..c3c835290131539f3257cd97dc924ab5d44d4a85 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -48,8 +49,10 @@ static struct fadump_mem_struct fdm; static const struct fadump_mem_struct *fdm_active; static DEFINE_MUTEX(fadump_mutex); -struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES]; +struct fad_crash_memory_ranges *crash_memory_ranges; +int crash_memory_ranges_size; int crash_mem_ranges; +int max_crash_mem_ranges; /* Scan the Firmware Assisted dump configuration details. */ int __init early_init_dt_scan_fw_dump(unsigned long node, @@ -726,38 +729,88 @@ static int __init process_fadump(const struct fadump_mem_struct *fdm_active) return 0; } -static inline void fadump_add_crash_memory(unsigned long long base, - unsigned long long end) +static void free_crash_memory_ranges(void) +{ + kfree(crash_memory_ranges); + crash_memory_ranges = NULL; + crash_memory_ranges_size = 0; + max_crash_mem_ranges = 0; +} + +/* + * Allocate or reallocate crash memory ranges array in incremental units + * of PAGE_SIZE. + */ +static int allocate_crash_memory_ranges(void) +{ + struct fad_crash_memory_ranges *new_array; + u64 new_size; + + new_size = crash_memory_ranges_size + PAGE_SIZE; + pr_debug("Allocating %llu bytes of memory for crash memory ranges\n", + new_size); + + new_array = krealloc(crash_memory_ranges, new_size, GFP_KERNEL); + if (new_array == NULL) { + pr_err("Insufficient memory for setting up crash memory ranges\n"); + free_crash_memory_ranges(); + return -ENOMEM; + } + + crash_memory_ranges = new_array; + crash_memory_ranges_size = new_size; + max_crash_mem_ranges = (new_size / + sizeof(struct fad_crash_memory_ranges)); + return 0; +} + +static inline int fadump_add_crash_memory(unsigned long long base, + unsigned long long end) { if (base == end) - return; + return 0; + + if (crash_mem_ranges == max_crash_mem_ranges) { + int ret; + + ret = allocate_crash_memory_ranges(); + if (ret) + return ret; + } pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n", crash_mem_ranges, base, end - 1, (end - base)); crash_memory_ranges[crash_mem_ranges].base = base; crash_memory_ranges[crash_mem_ranges].size = end - base; crash_mem_ranges++; + return 0; } -static void fadump_exclude_reserved_area(unsigned long long start, +static int fadump_exclude_reserved_area(unsigned long long start, unsigned long long end) { unsigned long long ra_start, ra_end; + int ret = 0; ra_start = fw_dump.reserve_dump_area_start; ra_end = ra_start + fw_dump.reserve_dump_area_size; if ((ra_start < end) && (ra_end > start)) { if ((start < ra_start) && (end > ra_end)) { - fadump_add_crash_memory(start, ra_start); - fadump_add_crash_memory(ra_end, end); + ret = fadump_add_crash_memory(start, ra_start); + if (ret) + return ret; + + ret = fadump_add_crash_memory(ra_end, end); } else if (start < ra_start) { - fadump_add_crash_memory(start, ra_start); + ret = fadump_add_crash_memory(start, ra_start); } else if (ra_end < end) { - fadump_add_crash_memory(ra_end, end); + ret = fadump_add_crash_memory(ra_end, end); } } else - fadump_add_crash_memory(start, end); + ret = fadump_add_crash_memory(start, end); + + return ret; } static int fadump_init_elfcore_header(char *bufp) @@ -793,10 +846,11 @@ static int fadump_init_elfcore_header(char *bufp) * Traverse through memblock structure and setup crash memory ranges. These * ranges will be used create PT_LOAD program headers in elfcore header. */ -static void fadump_setup_crash_memory_ranges(void) +static int fadump_setup_crash_memory_ranges(void) { struct memblock_region *reg; unsigned long long start, end; + int ret; pr_debug("Setup crash memory ranges.\n"); crash_mem_ranges = 0; @@ -807,7 +861,9 @@ static void fadump_setup_crash_memory_ranges(void) * specified during fadump registration. We need to create a separate * program header for this chunk with the correct offset. */ - fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); + ret = fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); + if (ret) + return ret; for_each_memblock(memory, reg) { start = (unsigned long long)reg->base; @@ -816,8 +872,12 @@ static void fadump_setup_crash_memory_ranges(void) start = fw_dump.boot_memory_size; /* add this range excluding the reserved dump area. */ - fadump_exclude_reserved_area(start, end); + ret = fadump_exclude_reserved_area(start, end); + if (ret) + return ret; } + + return 0; } /* @@ -941,6 +1001,7 @@ static void register_fadump(void) { unsigned long addr; void *vaddr; + int ret; /* * If no memory is reserved then we can not register for firmware- @@ -949,7 +1010,9 @@ static void register_fadump(void) if (!fw_dump.reserve_dump_area_size) return; - fadump_setup_crash_memory_ranges(); + ret = fadump_setup_crash_memory_ranges(); + if (ret) + return ret; addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len); /* Initialize fadump crash info header. */ @@ -1025,6 +1088,10 @@ void fadump_cleanup(void) init_fadump_mem_struct(&fdm, be64_to_cpu(fdm_active->cpu_state_data.destination_address)); fadump_invalidate_dump(&fdm); + } else if (fw_dump.dump_registered) { + /* Un-register Firmware-assisted dump if it was registered. */ + fadump_unregister_dump(&fdm); + free_crash_memory_ranges(); } } diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index fafff8dbd5d990175874d9ca09e40a44085be525..3c957548f33626b2c90d396b779637c5394f55d0 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -722,7 +722,7 @@ start_here: tovirt(r6,r6) lis r5, abatron_pteptrs@h ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(r0) /* Must match your Abatron config file */ + stw r5, 0xf0(0) /* Must match your Abatron config file */ tophys(r5,r5) stw r6, 0(r5) diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 1f7d84e2e8b219e42d5e40c00a90ff5544c02a3a..cc05fe84122485cc5dc41334d84f5e30fed9e5ef 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -174,8 +174,8 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) if (cpu_has_feature(CPU_FTR_DAWR)) { length_max = 512 ; /* 64 doublewords */ /* DAWR region can't cross 512 boundary */ - if ((bp->attr.bp_addr >> 10) != - ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 10)) + if ((bp->attr.bp_addr >> 9) != + ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 9)) return -EINVAL; } if (info->len > diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index 015ae55c18686ffb794938531aa52692e0843b0e..8dff2b3712190c48a282e19e81a0c95919bbd43b 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -186,7 +186,12 @@ void __init reserve_crashkernel(void) (unsigned long)(crashk_res.start >> 20), (unsigned long)(memblock_phys_mem_size() >> 20)); - memblock_reserve(crashk_res.start, crash_size); + if (!memblock_is_region_memory(crashk_res.start, crash_size) || + memblock_reserve(crashk_res.start, crash_size)) { + pr_err("Failed to reserve memory for crashkernel!\n"); + crashk_res.start = crashk_res.end = 0; + return; + } } int overlaps_crashkernel(unsigned long start, unsigned long size) diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 432459c817fa30032b821f70ee07c01e8d6d61d3..28724443d1a610610f2d18f908261f71859063ab 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 93f200f14e19707daed373929f5591b35c75368f..c8a62ee9f92d5bd34cce5adc9cafe0a3b71caec0 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1004,6 +1004,7 @@ static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, /* Create a new breakpoint request if one doesn't exist already */ hw_breakpoint_init(&attr); attr.bp_addr = hw_brk.address; + attr.bp_len = 8; arch_bp_generic_fields(hw_brk.type, &attr.bp_type); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 1362cd62b3fa5c32fdcc27d3ba3e5ee0e21fd974..d4c368b09415be12a3f28d37c301db7ae6b1395f 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -217,14 +217,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) unsigned short maj; unsigned short min; - /* We only show online cpus: disable preempt (overzealous, I - * knew) to prevent cpu going down. */ - preempt_disable(); - if (!cpu_online(cpu_id)) { - preempt_enable(); - return 0; - } - #ifdef CONFIG_SMP pvr = per_cpu(cpu_pvr, cpu_id); #else @@ -329,9 +321,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) #ifdef CONFIG_SMP seq_printf(m, "\n"); #endif - - preempt_enable(); - /* If this is the last cpu, print the summary */ if (cpumask_next(cpu_id, cpu_online_mask) >= nr_cpu_ids) show_cpuinfo_summary(m); diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index cf8c7e4e0b21bb519f0098bd5a72622233dcd358..984a54c85952eaf2d248afc67aebd5bc51cfe76a 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -102,7 +102,7 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, static void do_signal(struct pt_regs *regs) { sigset_t *oldset = sigmask_to_save(); - struct ksignal ksig; + struct ksignal ksig = { .sig = 0 }; int ret; int is32 = is_32bit_task(); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 7505599c2593cc63fd89709fad21e9e5af92c906..a3d0109becd3c89ef9788402b65834a74f89a3c2 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -646,12 +646,20 @@ static int __init get_freq(char *name, int cells, unsigned long *val) static void start_cpu_decrementer(void) { #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) + unsigned int tcr; + /* Clear any pending timer interrupts */ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); - /* Enable decrementer interrupt */ - mtspr(SPRN_TCR, TCR_DIE); -#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */ + tcr = mfspr(SPRN_TCR); + /* + * The watchdog may have already been enabled by u-boot. So leave + * TRC[WP] (Watchdog Period) alone. + */ + tcr &= TCR_WP_MASK; /* Clear all bits except for TCR[WP] */ + tcr |= TCR_DIE; /* Enable decrementer */ + mtspr(SPRN_TCR, tcr); +#endif } void __init generic_calibrate_decr(void) diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c index b982d925c7105f910003ed3e53b5a595558f67ef..c74c9c4134b5a648d3f05dc018759e07d88ef5fc 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -176,12 +176,15 @@ map_again: ret = ppc_md.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags, hpsize, hpsize, MMU_SEGSIZE_256M); - if (ret < 0) { + if (ret == -1) { /* If we couldn't map a primary PTE, try a secondary */ hash = ~hash; vflags ^= HPTE_V_SECONDARY; attempt++; goto map_again; + } else if (ret < 0) { + r = -EIO; + goto out_unlock; } else { trace_kvm_book3s_64_mmu_map(rflags, hpteg, vpn, hpaddr, orig_pte); diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index d40770248b6a10dbb9846b52cbf76de25bfef1d0..191cc3eea0bf664a58a2271812d75ac4fc1479aa 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -449,7 +449,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned long pp, key; unsigned long v, gr; __be64 *hptep; - int index; + long int index; int virtmode = vcpu->arch.shregs.msr & (data ? MSR_DR : MSR_IR); /* Get SLB entry */ diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 54cf9bc94dadfe3a1debf64f03cea511fc0aa97b..3a095670b0c40168d9e809a4dcd7f00c35a0696f 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -101,22 +101,17 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, struct kvm_create_spapr_tce *args) { struct kvmppc_spapr_tce_table *stt = NULL; + struct kvmppc_spapr_tce_table *siter; long npages; int ret = -ENOMEM; int i; - /* Check this LIOBN hasn't been previously allocated */ - list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) { - if (stt->liobn == args->liobn) - return -EBUSY; - } - npages = kvmppc_stt_npages(args->window_size); stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *), GFP_KERNEL); if (!stt) - goto fail; + return ret; stt->liobn = args->liobn; stt->window_size = args->window_size; @@ -128,23 +123,36 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, goto fail; } - kvm_get_kvm(kvm); - mutex_lock(&kvm->lock); - list_add(&stt->list, &kvm->arch.spapr_tce_tables); + + /* Check this LIOBN hasn't been previously allocated */ + ret = 0; + list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) { + if (siter->liobn == args->liobn) { + ret = -EBUSY; + break; + } + } + + if (!ret) + ret = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops, + stt, O_RDWR | O_CLOEXEC); + + if (ret >= 0) { + list_add(&stt->list, &kvm->arch.spapr_tce_tables); + kvm_get_kvm(kvm); + } mutex_unlock(&kvm->lock); - return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops, - stt, O_RDWR | O_CLOEXEC); + if (ret >= 0) + return ret; -fail: - if (stt) { - for (i = 0; i < npages; i++) - if (stt->pages[i]) - __free_page(stt->pages[i]); + fail: + for (i = 0; i < npages; i++) + if (stt->pages[i]) + __free_page(stt->pages[i]); - kfree(stt); - } + kfree(stt); return ret; } diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index cf2eb16846d1179949df7619c224f802ca63b6d6..db549f2ae98fa98057547d7eb0b3bbced9439625 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -625,7 +625,11 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, kvmppc_mmu_unmap_page(vcpu, &pte); } /* The guest's PTE is not mapped yet. Map on the host */ - kvmppc_mmu_map_page(vcpu, &pte, iswrite); + if (kvmppc_mmu_map_page(vcpu, &pte, iswrite) == -EIO) { + /* Exit KVM if mapping failed */ + run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + return RESUME_HOST; + } if (data) vcpu->stat.sp_storage++; else if (vcpu->arch.mmu.is_dcbz32(vcpu) && diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c index ce3c893d509b17b3611e6fe5050a50424ba5d83d..e100aaf97f868c8c2369141a7b9622755db68096 100644 --- a/arch/powerpc/kvm/book3s_pr_papr.c +++ b/arch/powerpc/kvm/book3s_pr_papr.c @@ -50,7 +50,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) pteg_addr = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); - copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)); + ret = H_FUNCTION; + if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg))) + goto done; hpte = pteg; ret = H_PTEG_FULL; @@ -71,7 +73,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6)); hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7)); pteg_addr += i * HPTE_SIZE; - copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE); + ret = H_FUNCTION; + if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE)) + goto done; kvmppc_set_gpr(vcpu, 4, pte_index | i); ret = H_SUCCESS; @@ -93,7 +97,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); - copy_from_user(pte, (void __user *)pteg, sizeof(pte)); + ret = H_FUNCTION; + if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) + goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); @@ -103,7 +109,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) ((flags & H_ANDCOND) && (pte[0] & avpn) != 0)) goto done; - copy_to_user((void __user *)pteg, &v, sizeof(v)); + ret = H_FUNCTION; + if (copy_to_user((void __user *)pteg, &v, sizeof(v))) + goto done; rb = compute_tlbie_rb(pte[0], pte[1], pte_index); vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); @@ -171,7 +179,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) } pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX); - copy_from_user(pte, (void __user *)pteg, sizeof(pte)); + if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) { + ret = H_FUNCTION; + break; + } pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); @@ -184,7 +195,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) tsh |= H_BULK_REMOVE_NOT_FOUND; } else { /* Splat the pteg in (userland) hpt */ - copy_to_user((void __user *)pteg, &v, sizeof(v)); + if (copy_to_user((void __user *)pteg, &v, sizeof(v))) { + ret = H_FUNCTION; + break; + } rb = compute_tlbie_rb(pte[0], pte[1], tsh & H_BULK_REMOVE_PTEX); @@ -211,7 +225,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); - copy_from_user(pte, (void __user *)pteg, sizeof(pte)); + ret = H_FUNCTION; + if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) + goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); @@ -234,7 +250,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); pte[0] = (__force u64)cpu_to_be64(pte[0]); pte[1] = (__force u64)cpu_to_be64(pte[1]); - copy_to_user((void __user *)pteg, pte, sizeof(pte)); + ret = H_FUNCTION; + if (copy_to_user((void __user *)pteg, pte, sizeof(pte))) + goto done; ret = H_SUCCESS; done: diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index 7ce3870d7ddd1054898421647c54819ead09e20e..cd0b7bc34cefa9fdd1e871b06b7b914168fed528 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -52,7 +52,7 @@ static int patch_alt_instruction(unsigned int *src, unsigned int *dest, unsigned int *target = (unsigned int *)branch_target(src); /* Branch within the section doesn't need translating */ - if (target < alt_start || target >= alt_end) { + if (target < alt_start || target > alt_end) { instr = translate_branch(dest, src); if (!instr) return 1; diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index f06b56baf0b324e43a48fd8f5573ada116df506d..9b47840be82ebdebdf41cb9daefdcfb2bf4b16ca 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -294,7 +294,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, * can result in fault, which will cause a deadlock when called with * mmap_sem held */ - if (user_mode(regs)) + if (!is_exec && user_mode(regs)) store_update_sp = store_updates_sp(regs); if (user_mode(regs)) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index ffa07eb5fff0660d77e6e5ea91a1c5ac71c60152..ef77f6e1484e0a6ff56012655c946cb438aa72d0 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -396,8 +396,12 @@ static __u64 power_pmu_bhrb_to(u64 addr) int ret; __u64 target; - if (is_kernel_addr(addr)) - return branch_target((unsigned int *)addr); + if (is_kernel_addr(addr)) { + if (probe_kernel_read(&instr, (void *)addr, sizeof(instr))) + return 0; + + return branch_target(&instr); + } /* Userspace: need copy instruction here then translate it */ pagefault_disable(); @@ -439,6 +443,16 @@ static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) /* invalid entry */ continue; + /* + * BHRB rolling buffer could very much contain the kernel + * addresses at this point. Check the privileges before + * exporting it to userspace (avoid exposure of regions + * where we could have speculative execution) + */ + if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) && + is_kernel_addr(addr)) + continue; + /* Branches are read most recent first (ie. mfbhrb 0 is * the most recent branch). * There are two types of valid entries: @@ -1179,6 +1193,7 @@ static void power_pmu_disable(struct pmu *pmu) */ write_mmcr0(cpuhw, val); mb(); + isync(); /* * Disable instruction sampling if it was enabled @@ -1187,12 +1202,26 @@ static void power_pmu_disable(struct pmu *pmu) mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE); mb(); + isync(); } cpuhw->disabled = 1; cpuhw->n_added = 0; ebb_switch_out(mmcr0); + +#ifdef CONFIG_PPC64 + /* + * These are readable by userspace, may contain kernel + * addresses and are not switched by context switch, so clear + * them now to avoid leaking anything to userspace in general + * including to another process. + */ + if (ppmu->flags & PPMU_ARCH_207S) { + mtspr(SPRN_SDAR, 0); + mtspr(SPRN_SIAR, 0); + } +#endif } local_irq_restore(flags); @@ -1372,7 +1401,7 @@ static int collect_events(struct perf_event *group, int max_count, int n = 0; struct perf_event *event; - if (!is_software_event(group)) { + if (group->pmu->task_ctx_nr == perf_hw_context) { if (n >= max_count) return -1; ctrs[n] = group; @@ -1380,7 +1409,7 @@ static int collect_events(struct perf_event *group, int max_count, events[n++] = group->hw.config; } list_for_each_entry(event, &group->sibling_list, group_entry) { - if (!is_software_event(event) && + if (event->pmu->task_ctx_nr == perf_hw_context && event->state != PERF_EVENT_STATE_OFF) { if (n >= max_count) return -1; diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index be6212ddbf06a8a097ac19d361b2f420da35ef6a..7e42e3ec2142e832785a58ff34e1a163b3863a21 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -174,6 +174,8 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i, if (!dump_skip(cprm, roundup(cprm->written - total + sz, 4) - cprm->written)) goto Eio; + + rc = 0; out: free_page((unsigned long)buf); return rc; diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c index f803f4b8ab6f21cebd6c5de9781ccc72c2a42106..8608e358217f38fd57c02f307b9c0a425580ed22 100644 --- a/arch/powerpc/platforms/chrp/time.c +++ b/arch/powerpc/platforms/chrp/time.c @@ -27,6 +27,8 @@ #include #include +#include + extern spinlock_t rtc_lock; #define NVRAM_AS0 0x74 @@ -62,7 +64,7 @@ long __init chrp_time_init(void) return 0; } -int chrp_cmos_clock_read(int addr) +static int chrp_cmos_clock_read(int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -70,7 +72,7 @@ int chrp_cmos_clock_read(int addr) return (inb(nvram_data)); } -void chrp_cmos_clock_write(unsigned long val, int addr) +static void chrp_cmos_clock_write(unsigned long val, int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index c269caee58f9486f6e260cf67367cb501820642c..f44b382449ca67f0a95568d6c00276f1847c9d2c 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -35,6 +35,8 @@ */ #define HW_BROADWAY_ICR 0x00 #define HW_BROADWAY_IMR 0x04 +#define HW_STARLET_ICR 0x08 +#define HW_STARLET_IMR 0x0c /* @@ -74,6 +76,9 @@ static void hlwd_pic_unmask(struct irq_data *d) void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); + + /* Make sure the ARM (aka. Starlet) doesn't handle this interrupt. */ + clrbits32(io_base + HW_STARLET_IMR, 1 << irq); } diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 3e91ef538114c6adb14401b6e33b5b247f5aa3e4..9adc9eaaf3658ee4d9af162b9cbe9a39bf87603c 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -467,7 +467,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4) boot_infos_t *bi = (boot_infos_t *) r4; unsigned long hdr; unsigned long space; - unsigned long ptr, x; + unsigned long ptr; char *model; unsigned long offset = reloc_offset(); @@ -561,6 +561,8 @@ void __init bootx_init(unsigned long r3, unsigned long r4) * MMU switched OFF, so this should not be useful anymore. */ if (bi->version < 4) { + unsigned long x __maybe_unused; + bootx_printf("Touching pages...\n"); /* diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index b127a29ac526dd0e27e5f5a7b487c0d58c2ae9c1..49148e2e13a880d02455db23ca6f4f4621df894d 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -359,6 +359,7 @@ static int pmac_late_init(void) } machine_late_initcall(powermac, pmac_late_init); +void note_bootable_part(dev_t dev, int part, int goodness); /* * This is __init_refok because we check for "initializing" before * touching any of the __init sensitive things and "initializing" diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c index e462ab947d16aa57ffcf1d55856cef0d46ee132b..6e557771d9aa8603d956152edc5f0cad3b8fe0e6 100644 --- a/arch/powerpc/platforms/powernv/opal-async.c +++ b/arch/powerpc/platforms/powernv/opal-async.c @@ -39,18 +39,18 @@ int __opal_async_get_token(void) int token; spin_lock_irqsave(&opal_async_comp_lock, flags); - token = find_first_bit(opal_async_complete_map, opal_max_async_tokens); + token = find_first_zero_bit(opal_async_token_map, opal_max_async_tokens); if (token >= opal_max_async_tokens) { token = -EBUSY; goto out; } - if (__test_and_set_bit(token, opal_async_token_map)) { + if (!__test_and_clear_bit(token, opal_async_complete_map)) { token = -EBUSY; goto out; } - __clear_bit(token, opal_async_complete_map); + __set_bit(token, opal_async_token_map); out: spin_unlock_irqrestore(&opal_async_comp_lock, flags); diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c index f9896fd5d04afa1acc62f6ca6e82e25edce65d85..28da4f90f83cbac37ede25e7643096d3a064fa21 100644 --- a/arch/powerpc/platforms/powernv/opal-nvram.c +++ b/arch/powerpc/platforms/powernv/opal-nvram.c @@ -11,6 +11,7 @@ #define DEBUG +#include #include #include #include @@ -42,6 +43,10 @@ static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index) return count; } +/* + * This can be called in the panic path with interrupts off, so use + * mdelay in that case. + */ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) { s64 rc = OPAL_BUSY; @@ -55,9 +60,23 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_write_nvram(__pa(buf), count, off); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + if (in_interrupt() || irqs_disabled()) + mdelay(OPAL_BUSY_DELAY_MS); + else + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); + } else if (rc == OPAL_BUSY) { + if (in_interrupt() || irqs_disabled()) + mdelay(OPAL_BUSY_DELAY_MS); + else + msleep(OPAL_BUSY_DELAY_MS); + } } + + if (rc) + return -EIO; + *index += count; return count; } diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index d019b081df9d846177c76b5c923b7e0a41e12fe8..ff3e1fe4936bc3a88a2d591477f97805515ee8a1 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -452,7 +452,7 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) /* Closed or other error drop */ if (rc != OPAL_SUCCESS && rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) { - written = total_len; + written += total_len; break; } if (rc == OPAL_SUCCESS) { diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 3f9546d8a51f907dda294d33c1d507bc01d6aa1b..2512c15db42bc9de73e5dd5d74ca987fc50d0406 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -319,7 +319,7 @@ static unsigned long pnv_get_proc_freq(unsigned int cpu) { unsigned long ret_freq; - ret_freq = cpufreq_quick_get(cpu) * 1000ul; + ret_freq = cpufreq_get(cpu) * 1000ul; /* * If the backend cpufreq driver does not exist, diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index f8c9ff7886e1ce11c086bef7516d01ab59b5e2a6..b86408e91e8b36d979b107cc7f64836ad50922df 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -225,8 +225,10 @@ static int add_dt_node(__be32 parent_phandle, __be32 drc_index) return -ENOENT; dn = dlpar_configure_connector(drc_index, parent_dn); - if (!dn) + if (!dn) { + of_node_put(parent_dn); return -ENOENT; + } rc = dlpar_attach_node(dn); if (rc) diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index d263f7bc80fc5003df54c1886e0403bf12040b9d..a4dcfb24eb265f4e3ecf2640ced01d862ad2f6cb 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -298,7 +298,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) } savep = __va(regs->gpr[3]); - regs->gpr[3] = savep[0]; /* restore original r3 */ + regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */ /* If it isn't an extended log we can use the per cpu 64bit buffer */ h = (struct rtas_error_log *)&savep[1]; @@ -309,7 +309,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) int len, error_log_length; error_log_length = 8 + rtas_error_extended_log_length(h); - len = max_t(int, error_log_length, RTAS_ERROR_LOG_MAX); + len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX); memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX); memcpy(global_mce_data_buf, h, len); errhdr = (struct rtas_error_log *)global_mce_data_buf; diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index e8bb33b2d3cc4080d416d05ac588563ecbf9d013..2f99da0f3d9d7b6e51592cc8af6bc58bbd247a42 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -283,7 +283,9 @@ failed: if (bank->disk->major > 0) unregister_blkdev(bank->disk->major, bank->disk->disk_name); - del_gendisk(bank->disk); + if (bank->disk->flags & GENHD_FL_UP) + del_gendisk(bank->disk); + put_disk(bank->disk); } device->dev.platform_data = NULL; if (bank->io_addr != 0) @@ -308,6 +310,7 @@ axon_ram_remove(struct platform_device *device) device_remove_file(&device->dev, &dev_attr_ecc); free_irq(bank->irq_id, device); del_gendisk(bank->disk); + put_disk(bank->disk); iounmap((void __iomem *) bank->io_addr); kfree(bank); diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 1b9b00f90388528ae7c83ac20e72d86bd06450a2..23d42d796512d3d23161c074a2648cbe154fc362 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -845,12 +845,12 @@ void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq) u32 ipic_get_mcp_status(void) { - return ipic_read(primary_ipic->regs, IPIC_SERMR); + return ipic_read(primary_ipic->regs, IPIC_SERSR); } void ipic_clear_mcp_status(u32 mask) { - ipic_write(primary_ipic->regs, IPIC_SERMR, mask); + ipic_write(primary_ipic->regs, IPIC_SERSR, mask); } /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index bf6f77e274b2b9ed09789c9c39f42a7825d7dd10..a72735c8fa211fdc394c8981cc17c573d3778bf2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -627,7 +627,7 @@ static inline u32 mpic_physmask(u32 cpumask) int i; u32 mask = 0; - for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) + for (i = 0; i < min(32, NR_CPUS) && cpu_possible(i); ++i, cpumask >>= 1) mask |= (cpumask & 1) << get_hard_smp_processor_id(i); return mask; } diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c index 7bdf3cc741e4fb1998f78808bfaff2ffecc99a4d..cfc3b9720763ea25e4aeb0b223635d20611f619c 100644 --- a/arch/powerpc/sysdev/mpic_msgr.c +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -196,7 +196,7 @@ static int mpic_msgr_probe(struct platform_device *dev) /* IO map the message register block. */ of_address_to_resource(np, 0, &rsrc); - msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start); + msgr_block_addr = ioremap(rsrc.start, resource_size(&rsrc)); if (!msgr_block_addr) { dev_err(&dev->dev, "Failed to iomap MPIC message registers"); return -EFAULT; diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 52168bab4c52cf0858b6ea370b8a07d2e6e418f8..82ac578f802c24a91dceedac92d65151fde25a22 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -333,9 +333,6 @@ config COMPAT config SYSVIPC_COMPAT def_bool y if COMPAT && SYSVIPC -config KEYS_COMPAT - def_bool y if COMPAT && KEYS - config SMP def_bool y prompt "Symmetric multi-processing support" diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index c952b981e4f28885223c7f77b51ada2299f03c6a..f7ace92bb1f6df8bd831f4dfe9eeae2aac76ab9d 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -326,7 +326,7 @@ static void hypfs_kill_super(struct super_block *sb) if (sb->s_root) hypfs_delete_tree(sb->s_root); - if (sb_info->update_file) + if (sb_info && sb_info->update_file) hypfs_remove(sb_info->update_file); kfree(sb->s_fs_info); sb->s_fs_info = NULL; diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index cb700d54bd832a91256803b35bbff06adc3a95d3..0a1ca50298e8f6676edda5a61248ccd69ef02d69 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -118,7 +118,7 @@ struct hws_basic_entry { struct hws_diag_entry { unsigned int def:16; /* 0-15 Data Entry Format */ - unsigned int R:14; /* 16-19 and 20-30 reserved */ + unsigned int R:15; /* 16-19 and 20-30 reserved */ unsigned int I:1; /* 31 entry valid or invalid */ u8 data[]; /* Machine-dependent sample data */ } __packed; @@ -134,7 +134,9 @@ struct hws_trailer_entry { unsigned int f:1; /* 0 - Block Full Indicator */ unsigned int a:1; /* 1 - Alert request control */ unsigned int t:1; /* 2 - Timestamp format */ - unsigned long long:61; /* 3 - 63: Reserved */ + unsigned int :29; /* 3 - 31: Reserved */ + unsigned int bsdes:16; /* 32-47: size of basic SDE */ + unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */ }; unsigned long long flags; /* 0 - 63: All indicators */ }; diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 06f3034605a19ceaa5dbd80d150bc1308208871f..33894abf03df619f31df234cbb93c4c0a99e9ca0 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -271,7 +271,6 @@ struct qdio_outbuf_state { void *user; }; -#define QDIO_OUTBUF_STATE_FLAG_NONE 0x00 #define QDIO_OUTBUF_STATE_FLAG_PENDING 0x01 #define CHSC_AC1_INITIATE_INPUTQ 0x80 diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 437e611592790b0ed725998d08281be420fcf954..b5ce954e845c76d83a7b4d5b73aff3506879b2f2 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -110,7 +110,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid) COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid) { - return sys_setgid((gid_t)gid); + return sys_setgid(low2highgid(gid)); } COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid) @@ -120,7 +120,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid) COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid) { - return sys_setuid((uid_t)uid); + return sys_setuid(low2highuid(uid)); } COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid) @@ -173,12 +173,12 @@ COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp, COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid) { - return sys_setfsuid((uid_t)uid); + return sys_setfsuid(low2highuid(uid)); } COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid) { - return sys_setfsgid((gid_t)gid); + return sys_setfsgid(low2highgid(gid)); } static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info) diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index f3762937dd82ee8afcc2c0fddae6397e2be863fa..18ebf7c0b70c8509033432d09818e80d03f95b47 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -1997,7 +1997,7 @@ void show_code(struct pt_regs *regs) { char *mode = user_mode(regs) ? "User" : "Krnl"; unsigned char code[64]; - char buffer[64], *ptr; + char buffer[128], *ptr; mm_segment_t old_fs; unsigned long addr; int start, end, opsize, hops, i; @@ -2060,7 +2060,7 @@ void show_code(struct pt_regs *regs) start += opsize; printk(buffer); ptr = buffer; - ptr += sprintf(ptr, "\n "); + ptr += sprintf(ptr, "\n\t "); hops++; } printk("\n"); diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index f5ec05984364c8f00ad95729db6947b106d6b481..ee2ca1bcfdba10a4ae2d5597df09a7918d803d21 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -808,6 +808,7 @@ static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, /* copy and convert to ebcdic */ memcpy(ipb->hdr.loadparm, buf, lp_len); ASCEBC(ipb->hdr.loadparm, LOADPARM_LEN); + ipb->hdr.flags |= DIAG308_FLAGS_LP_VALID; return len; } diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 35b13ed0af5fa24f2f36fb41040a9f2c08b5c144..3e9baf333b68ebb18a66951890515a6434184d7e 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -28,8 +28,14 @@ SECTIONS { . = 0x00000000; .text : { - _text = .; /* Text and read-only data */ + /* Text and read-only data */ HEAD_TEXT + /* + * E.g. perf doesn't like symbols starting at address zero, + * therefore skip the initial PSW and channel program located + * at address zero and let _text start at 0x200. + */ + _text = 0x200; TEXT_TEXT SCHED_TEXT LOCK_TEXT diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 519bba716cc30c29acbb74f7cfd30db876af170c..783aadec4e406ec0dd64e74188fb8f61d76e6f4c 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -80,7 +80,7 @@ struct qin64 { struct dcss_segment { struct list_head list; char dcss_name[8]; - char res_name[15]; + char res_name[16]; unsigned long start_addr; unsigned long end; atomic_t ref_count; @@ -445,7 +445,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long memcpy(&seg->res_name, seg->dcss_name, 8); EBCASC(seg->res_name, 8); seg->res_name[8] = '\0'; - strncat(seg->res_name, " (DCSS)", 7); + strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name)); seg->res->name = seg->res_name; rc = seg->vm_segtype; if (rc == SEG_TYPE_SC || diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index fbe8f2cf924589c3f0e6e31e1619562e55e92586..eecd61bdc0d9664246798a4292a567437787687a 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -494,6 +494,8 @@ retry: /* No reason to continue if interrupted by SIGKILL. */ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) { fault = VM_FAULT_SIGNAL; + if (flags & FAULT_FLAG_RETRY_NOWAIT) + goto out_up; goto out; } if (unlikely(fault & VM_FAULT_ERROR)) diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index b6b76785f879a3ad9345314dbb9c4ae5ba38e9dd..f5101a890b57abd0cd12de26d26f48803156c77d 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -397,6 +397,8 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) hwirq = 0; list_for_each_entry(msi, &pdev->msi_list, list) { rc = -EIO; + if (hwirq >= msi_vecs) + break; irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ if (irq < 0) goto out_msi; diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c index 658326f44df819eaba9d7d20dbe888d28b796d1f..5e0267624d8dfcf369ea3614b60b58cbf8ab5476 100644 --- a/arch/sh/boards/mach-se/770x/setup.c +++ b/arch/sh/boards/mach-se/770x/setup.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include @@ -114,6 +115,11 @@ static struct platform_device heartbeat_device = { #if defined(CONFIG_CPU_SUBTYPE_SH7710) ||\ defined(CONFIG_CPU_SUBTYPE_SH7712) /* SH771X Ethernet driver */ +static struct sh_eth_plat_data sh_eth_plat = { + .phy = PHY_ID, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + static struct resource sh_eth0_resources[] = { [0] = { .start = SH_ETH0_BASE, @@ -131,7 +137,7 @@ static struct platform_device sh_eth0_device = { .name = "sh771x-ether", .id = 0, .dev = { - .platform_data = PHY_ID, + .platform_data = &sh_eth_plat, }, .num_resources = ARRAY_SIZE(sh_eth0_resources), .resource = sh_eth0_resources, @@ -154,7 +160,7 @@ static struct platform_device sh_eth1_device = { .name = "sh771x-ether", .id = 1, .dev = { - .platform_data = PHY_ID, + .platform_data = &sh_eth_plat, }, .num_resources = ARRAY_SIZE(sh_eth1_resources), .resource = sh_eth1_resources, diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c index 538c10db35379dfd3b4c97fb137453609b0ded7c..8dc315b212c2f10a0e1ab15653a521667e48894a 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c @@ -165,7 +165,6 @@ static struct plat_sci_port scif2_platform_data = { .scscr = SCSCR_TE | SCSCR_RE, .type = PORT_IRDA, .ops = &sh770x_sci_port_ops, - .regshift = 1, }; static struct resource scif2_resources[] = { diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 13047a4facd2eb442866d751dc0c84fa35062063..5a9017ba26aba3c1ad8927e22467d532ec75948d 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -255,7 +255,7 @@ debug_trap: mov.l @r8, r8 jsr @r8 nop - bra __restore_all + bra ret_from_exception nop CFI_ENDPROC diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index ff639342a8bef97fa81b89120deae05740974b28..c5b997757988c097d536cacb000b760941deb29b 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -607,7 +607,8 @@ asmlinkage void do_divide_error(unsigned long r4) break; } - force_sig_info(SIGFPE, &info, current); + info.si_signo = SIGFPE; + force_sig_info(info.si_signo, &info, current); } #endif diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 96ac69c5eba016a7b5c1ef93fd35baccf8e2f52b..e51b50af6373ec1bf87920d9d49e2cba289d83bd 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -542,9 +542,6 @@ config SYSVIPC_COMPAT depends on COMPAT && SYSVIPC default y -config KEYS_COMPAT - def_bool y if COMPAT && KEYS - endmenu source "net/Kconfig" diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 4082749913ce06109a3bd923e0bef4677d0376c9..f5b7db214bd060c71535d5e53b39ad9089e04413 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -70,7 +70,11 @@ ATOMIC_OPS(sub) #define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0) #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +static inline int atomic_xchg(atomic_t *v, int new) +{ + return xchg(&v->counter, new); +} static inline int __atomic_add_unless(atomic_t *v, int a, int u) { diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 71762565513e1a62a5492755077d40b05b141a5d..8bca543977fe09f81d72c6d5ca58cd637df2b1ba 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1693,9 +1693,14 @@ static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size) lp->rcv_nxt = p->seqid; + /* + * If this is a control-only packet, there is nothing + * else to do but advance the rx queue since the packet + * was already processed above. + */ if (!(p->type & LDC_DATA)) { new = rx_advance(lp, new); - goto no_data; + break; } if (p->stype & (LDC_ACK | LDC_NACK)) { err = data_ack_nack(lp, p); diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 646988d4c1a35aca56c0a3f0c56abdf1ca183587..740f43b9b54192a7a202a980a94475bf3445482b 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -201,23 +201,27 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, asmlinkage long sys_getdomainname(char __user *name, int len) { - int nlen, err; - + int nlen, err; + char tmp[__NEW_UTS_LEN + 1]; + if (len < 0) return -EINVAL; - down_read(&uts_sem); - + down_read(&uts_sem); + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) - goto out; + goto out_unlock; + memcpy(tmp, utsname()->domainname, nlen); - err = -EFAULT; - if (!copy_to_user(name, utsname()->domainname, nlen)) - err = 0; + up_read(&uts_sem); -out: + if (copy_to_user(name, tmp, nlen)) + return -EFAULT; + return 0; + +out_unlock: up_read(&uts_sem); return err; } diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 98a5cf313d39a703300446fea7cebf5d7ab2a691..7301fa2091bcae935e99b29f65b0a3f8dd52a220 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -524,23 +524,27 @@ extern void check_pending(int signum); SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len) { - int nlen, err; + int nlen, err; + char tmp[__NEW_UTS_LEN + 1]; if (len < 0) return -EINVAL; - down_read(&uts_sem); - + down_read(&uts_sem); + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) - goto out; + goto out_unlock; + memcpy(tmp, utsname()->domainname, nlen); + + up_read(&uts_sem); - err = -EFAULT; - if (!copy_to_user(name, utsname()->domainname, nlen)) - err = 0; + if (copy_to_user(name, tmp, nlen)) + return -EFAULT; + return 0; -out: +out_unlock: up_read(&uts_sem); return err; } diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 7ad1baa6c914f57b542ed2a4fcf5a5c447a4d5ea..1f4492f6efb09f58f03a6cedc64c5a8109e81fb7 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -2215,9 +2215,16 @@ void __init mem_init(void) { high_memory = __va(last_valid_pfn << PAGE_SHIFT); - register_page_bootmem_info(); free_all_bootmem(); + /* + * Must be done after boot memory is put on freelist, because here we + * might set fields in deferred struct pages that have not yet been + * initialized, and free_all_bootmem() initializes all the reserved + * deferred pages for us. + */ + register_page_bootmem_info(); + /* * Set up the zero page, mark it reserved, so that page count * is not manipulated when freeing the page from user ptes. diff --git a/arch/um/Makefile b/arch/um/Makefile index 78c32029368ac72e3fcb48411eca4b4403d7ef16..d467ae58c9349b1fcbfb931fa862b71e7c750fba 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -117,7 +117,7 @@ archheaders: archprepare: include/generated/user_constants.h LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static -LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib +LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib $(call cc-option, -no-pie) CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ $(call cc-option, -fno-stack-protector,) \ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3de18af37ad137a9fe5913ac6a82021af4e2d8a1..defb688df73286776d1b4c47785bc60f3bd9b2cb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -24,12 +24,6 @@ config X86 select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS select ARCH_HAS_FAST_MULTIPLIER - select ARCH_HAS_GCOV_PROFILE_ALL - select ARCH_HAS_KCOV if X86_64 - select ARCH_HAS_PMEM_API if X86_64 - select ARCH_HAS_MMIO_FLUSH - select ARCH_HAS_SG_CHAIN - select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select HAVE_AOUT if X86_32 @@ -2493,10 +2487,6 @@ config COMPAT_FOR_U64_ALIGNMENT config SYSVIPC_COMPAT def_bool y depends on SYSVIPC - -config KEYS_COMPAT - def_bool y - depends on KEYS endif endmenu diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 366abb63413d02af6e9e5f9019c14e58ae13e44b..585447377463c4fed1811542c24b1d4d9b4e9396 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -9,16 +9,6 @@ # Changed by many, many contributors over the years. # -KASAN_SANITIZE := n -OBJECT_FILES_NON_STANDARD := y - -# Kernel does not boot with kcov instrumentation here. -# One of the problems observed was insertion of __sanitizer_cov_trace_pc() -# callback into middle of per-cpu data enabling code. Thus the callback observed -# inconsistent state and crashed. We are interested mostly in syscall coverage, -# so boot code is not interesting anyway. -KCOV_INSTRUMENT := n - # If you want to preset the SVGA mode, uncomment the next line and # set SVGA_MODE to whatever number you want. # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 1af8b8f74f8d12cdd4a904bb6730769bd5c23c52..1d1cce542850cbf7720e0cec90f52c0aa3f9ce8b 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -4,11 +4,6 @@ # create a compressed vmlinux image from the original vmlinux # -KASAN_SANITIZE := n - -# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. -KCOV_INSTRUMENT := n - targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 2da9cef8ee43a15ea2fead2cc6ea2f19896720fe..1e558d7c76f6e68fc368be869c54f506b5c6d9e8 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -364,7 +364,8 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) goto free_struct; - memcpy(rom->romdata, pci->romimage, pci->romsize); + memcpy(rom->romdata, (void *)(unsigned long)pci->romimage, + pci->romsize); return status; free_struct: @@ -470,7 +471,8 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) goto free_struct; - memcpy(rom->romdata, pci->romimage, pci->romsize); + memcpy(rom->romdata, (void *)(unsigned long)pci->romimage, + pci->romsize); return status; free_struct: diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..b82aca023b700c598e9ea0664b71a09bbd198fe2 --- /dev/null +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -0,0 +1,453 @@ +CONFIG_POSIX_MQUEUE=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_NAMESPACES=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_SMP=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_MCORE2=y +CONFIG_PROCESSOR_SELECT=y +# CONFIG_CPU_SUP_CENTAUR is not set +CONFIG_PREEMPT=y +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_TRANSPARENT_HUGEPAGE=y +# CONFIG_MTRR is not set +CONFIG_HZ_100=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0 reboot=p" +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM_DEBUG=y +CONFIG_SUSPEND_TIME=y +CONFIG_ACPI_PROCFS_POWER=y +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_X86_PM_TIMER is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_X86_ACPI_CPUFREQ=y +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=y +CONFIG_IA32_EMULATION=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=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_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=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_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETLABEL=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_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=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_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +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_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_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_IPV6HEADER=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_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_RFKILL=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEBUG_DEVRES=y +CONFIG_OF=y +CONFIG_OF_SELFTEST=y +# CONFIG_PNP_DEBUG_MESSAGES is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_VIRTIO=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_MIRROR=y +CONFIG_DM_ZERO=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_HASH_PREFETCH_MIN_SIZE=1 +CONFIG_DM_ANDROID_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +# CONFIG_ETHERNET is not set +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_NET_AX8817X is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_MAC80211_HWSIM=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_I8042 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_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HPET=y +# CONFIG_HPET_MMAP_DEFAULT is not set +# CONFIG_DEVPORT is not set +# CONFIG_ACPI_I2C_OPREGION is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_PTP_1588_CLOCK=y +CONFIG_GPIOLIB=y +# CONFIG_HWMON is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_SOFT_WATCHDOG=y +CONFIG_MEDIA_SUPPORT=y +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_VGA_ARB is not set +CONFIG_DRM=y +CONFIG_FB=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_GADGET=y +CONFIG_USB_DUMMY_HCD=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +CONFIG_SW_SYNC_USER=y +CONFIG_ANDROID_VSOC=y +CONFIG_ION=y +# CONFIG_X86_PLATFORM_DEVICES is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_SDCARD_FS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_IO_DELAY_NONE=y +CONFIG_DEBUG_BOOT_PARAMS=y +CONFIG_OPTIMIZE_INLINING=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PATH=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c index 60ada677a92874e7d24fe00f1f309ce9c9a9a8bf..0fe3365debef7f91b51c14a507af7929c1bd2a07 100644 --- a/arch/x86/crypto/cast5_avx_glue.c +++ b/arch/x86/crypto/cast5_avx_glue.c @@ -67,8 +67,6 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, void (*fn)(struct cast5_ctx *ctx, u8 *dst, const u8 *src); int err; - fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way; - err = blkcipher_walk_virt(desc, walk); desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; @@ -80,6 +78,7 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, /* Process multi-block batch */ if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way; do { fn(ctx, wdst, wsrc); diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c index 399a29d067d6367603714633fb8c4de6ab77275a..cb91a64a99e7cdbc0422227383611378fb6b076a 100644 --- a/arch/x86/crypto/salsa20_glue.c +++ b/arch/x86/crypto/salsa20_glue.c @@ -59,13 +59,6 @@ static int encrypt(struct blkcipher_desc *desc, salsa20_ivsetup(ctx, walk.iv); - if (likely(walk.nbytes == nbytes)) - { - salsa20_encrypt_bytes(ctx, walk.src.virt.addr, - walk.dst.virt.addr, nbytes); - return blkcipher_walk_done(desc, &walk, 0); - } - while (walk.nbytes >= 64) { salsa20_encrypt_bytes(ctx, walk.src.virt.addr, walk.dst.virt.addr, diff --git a/arch/x86/crypto/sha-mb/sha1_mb_mgr_flush_avx2.S b/arch/x86/crypto/sha-mb/sha1_mb_mgr_flush_avx2.S index 85c4e1cf717235b8fc1cafcef458c386b84b8f66..e1693457c178627c69216e467fc5a94e1387f377 100644 --- a/arch/x86/crypto/sha-mb/sha1_mb_mgr_flush_avx2.S +++ b/arch/x86/crypto/sha-mb/sha1_mb_mgr_flush_avx2.S @@ -174,8 +174,8 @@ LABEL skip_ %I .endr # Find min length - vmovdqa _lens+0*16(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 + vmovdqu _lens+0*16(state), %xmm0 + vmovdqu _lens+1*16(state), %xmm1 vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} @@ -195,8 +195,8 @@ LABEL skip_ %I vpsubd %xmm2, %xmm0, %xmm0 vpsubd %xmm2, %xmm1, %xmm1 - vmovdqa %xmm0, _lens+0*16(state) - vmovdqa %xmm1, _lens+1*16(state) + vmovdqu %xmm0, _lens+0*16(state) + vmovdqu %xmm1, _lens+1*16(state) # "state" and "args" are the same address, arg1 # len is arg2 @@ -260,8 +260,8 @@ ENTRY(sha1_mb_mgr_get_comp_job_avx2) jc .return_null # Find min length - vmovdqa _lens(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 + vmovdqu _lens(state), %xmm0 + vmovdqu _lens+1*16(state), %xmm1 vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} diff --git a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S index 1c3b7ceb36d24c5f301f0709f0082c47a4af98c1..e7273a606a07ab5b37d3c9da81b98c067146d8a9 100644 --- a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S +++ b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S @@ -55,29 +55,31 @@ #define RAB1bl %bl #define RAB2bl %cl +#define CD0 0x0(%rsp) +#define CD1 0x8(%rsp) +#define CD2 0x10(%rsp) + +# used only before/after all rounds #define RCD0 %r8 #define RCD1 %r9 #define RCD2 %r10 -#define RCD0d %r8d -#define RCD1d %r9d -#define RCD2d %r10d - -#define RX0 %rbp -#define RX1 %r11 -#define RX2 %r12 +# used only during rounds +#define RX0 %r8 +#define RX1 %r9 +#define RX2 %r10 -#define RX0d %ebp -#define RX1d %r11d -#define RX2d %r12d +#define RX0d %r8d +#define RX1d %r9d +#define RX2d %r10d -#define RY0 %r13 -#define RY1 %r14 -#define RY2 %r15 +#define RY0 %r11 +#define RY1 %r12 +#define RY2 %r13 -#define RY0d %r13d -#define RY1d %r14d -#define RY2d %r15d +#define RY0d %r11d +#define RY1d %r12d +#define RY2d %r13d #define RT0 %rdx #define RT1 %rsi @@ -85,6 +87,8 @@ #define RT0d %edx #define RT1d %esi +#define RT1bl %sil + #define do16bit_ror(rot, op1, op2, T0, T1, tmp1, tmp2, ab, dst) \ movzbl ab ## bl, tmp2 ## d; \ movzbl ab ## bh, tmp1 ## d; \ @@ -92,6 +96,11 @@ op1##l T0(CTX, tmp2, 4), dst ## d; \ op2##l T1(CTX, tmp1, 4), dst ## d; +#define swap_ab_with_cd(ab, cd, tmp) \ + movq cd, tmp; \ + movq ab, cd; \ + movq tmp, ab; + /* * Combined G1 & G2 function. Reordered with help of rotates to have moves * at begining. @@ -110,15 +119,15 @@ /* G1,2 && G2,2 */ \ do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 0, x ## 0); \ do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 0, y ## 0); \ - xchgq cd ## 0, ab ## 0; \ + swap_ab_with_cd(ab ## 0, cd ## 0, RT0); \ \ do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 1, x ## 1); \ do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 1, y ## 1); \ - xchgq cd ## 1, ab ## 1; \ + swap_ab_with_cd(ab ## 1, cd ## 1, RT0); \ \ do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 2, x ## 2); \ do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 2, y ## 2); \ - xchgq cd ## 2, ab ## 2; + swap_ab_with_cd(ab ## 2, cd ## 2, RT0); #define enc_round_end(ab, x, y, n) \ addl y ## d, x ## d; \ @@ -168,6 +177,16 @@ decrypt_round3(ba, dc, (n*2)+1); \ decrypt_round3(ba, dc, (n*2)); +#define push_cd() \ + pushq RCD2; \ + pushq RCD1; \ + pushq RCD0; + +#define pop_cd() \ + popq RCD0; \ + popq RCD1; \ + popq RCD2; + #define inpack3(in, n, xy, m) \ movq 4*(n)(in), xy ## 0; \ xorq w+4*m(CTX), xy ## 0; \ @@ -223,11 +242,8 @@ ENTRY(__twofish_enc_blk_3way) * %rdx: src, RIO * %rcx: bool, if true: xor output */ - pushq %r15; - pushq %r14; pushq %r13; pushq %r12; - pushq %rbp; pushq %rbx; pushq %rcx; /* bool xor */ @@ -235,40 +251,36 @@ ENTRY(__twofish_enc_blk_3way) inpack_enc3(); - encrypt_cycle3(RAB, RCD, 0); - encrypt_cycle3(RAB, RCD, 1); - encrypt_cycle3(RAB, RCD, 2); - encrypt_cycle3(RAB, RCD, 3); - encrypt_cycle3(RAB, RCD, 4); - encrypt_cycle3(RAB, RCD, 5); - encrypt_cycle3(RAB, RCD, 6); - encrypt_cycle3(RAB, RCD, 7); + push_cd(); + encrypt_cycle3(RAB, CD, 0); + encrypt_cycle3(RAB, CD, 1); + encrypt_cycle3(RAB, CD, 2); + encrypt_cycle3(RAB, CD, 3); + encrypt_cycle3(RAB, CD, 4); + encrypt_cycle3(RAB, CD, 5); + encrypt_cycle3(RAB, CD, 6); + encrypt_cycle3(RAB, CD, 7); + pop_cd(); popq RIO; /* dst */ - popq %rbp; /* bool xor */ + popq RT1; /* bool xor */ - testb %bpl, %bpl; + testb RT1bl, RT1bl; jnz .L__enc_xor3; outunpack_enc3(mov); popq %rbx; - popq %rbp; popq %r12; popq %r13; - popq %r14; - popq %r15; ret; .L__enc_xor3: outunpack_enc3(xor); popq %rbx; - popq %rbp; popq %r12; popq %r13; - popq %r14; - popq %r15; ret; ENDPROC(__twofish_enc_blk_3way) @@ -278,35 +290,31 @@ ENTRY(twofish_dec_blk_3way) * %rsi: dst * %rdx: src, RIO */ - pushq %r15; - pushq %r14; pushq %r13; pushq %r12; - pushq %rbp; pushq %rbx; pushq %rsi; /* dst */ inpack_dec3(); - decrypt_cycle3(RAB, RCD, 7); - decrypt_cycle3(RAB, RCD, 6); - decrypt_cycle3(RAB, RCD, 5); - decrypt_cycle3(RAB, RCD, 4); - decrypt_cycle3(RAB, RCD, 3); - decrypt_cycle3(RAB, RCD, 2); - decrypt_cycle3(RAB, RCD, 1); - decrypt_cycle3(RAB, RCD, 0); + push_cd(); + decrypt_cycle3(RAB, CD, 7); + decrypt_cycle3(RAB, CD, 6); + decrypt_cycle3(RAB, CD, 5); + decrypt_cycle3(RAB, CD, 4); + decrypt_cycle3(RAB, CD, 3); + decrypt_cycle3(RAB, CD, 2); + decrypt_cycle3(RAB, CD, 1); + decrypt_cycle3(RAB, CD, 0); + pop_cd(); popq RIO; /* dst */ outunpack_dec3(); popq %rbx; - popq %rbp; popq %r12; popq %r13; - popq %r14; - popq %r15; ret; ENDPROC(twofish_dec_blk_3way) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index dbaf844ddcb1864ad8be82798c5445a337c489c6..0ef041090409817503af2476d2618970cb10e91d 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -234,7 +234,15 @@ void register_lapic_address(unsigned long address); extern void setup_boot_APIC_clock(void); extern void setup_secondary_APIC_clock(void); extern int APIC_init_uniprocessor(void); + +#ifdef CONFIG_X86_64 +static inline int apic_force_enable(unsigned long addr) +{ + return -1; +} +#else extern int apic_force_enable(unsigned long addr); +#endif /* * On 32bit this is mach-xxx local diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 306d152336cd9da60d05fe8d53d80e461663c79e..bcae7051aba2170e3089aaf30656d844356e8fd8 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -849,7 +849,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2, static inline int emulate_instruction(struct kvm_vcpu *vcpu, int emulation_type) { - return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0); + return x86_emulate_instruction(vcpu, 0, + emulation_type | EMULTYPE_NO_REEXECUTE, NULL, 0); } void kvm_enable_efer_bits(u64); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 26d5e05a7def9f236a0c56860020bca166efbfe2..f303d65bb20261de314db6727b09f85c3e2c91ac 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -669,7 +669,7 @@ static inline void sync_core(void) { int tmp; -#ifdef CONFIG_M486 +#ifdef CONFIG_X86_32 /* * Do a CPUID if available, otherwise do a jump. The jump * can conveniently enough be the jump around CPUID. diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 391a8711f39ced6e365795e9c88b7337ac53ba21..5c22bd294a6db66e4ef71425500bc513f47ecaa8 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -114,6 +114,7 @@ struct thread_info { #define TIF_SYSCALL_TRACEPOINT 28 /* syscall tracepoint instrumentation */ #define TIF_ADDR32 29 /* 32-bit address space on 64 bits */ #define TIF_X32 30 /* 32-bit native x86-64 binary */ +#define TIF_FSCHECK 31 /* Check FS is USER_DS on return */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -138,6 +139,7 @@ struct thread_info { #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_ADDR32 (1 << TIF_ADDR32) #define _TIF_X32 (1 << TIF_X32) +#define _TIF_FSCHECK (1 << TIF_FSCHECK) /* work to do in syscall_trace_enter() */ #define _TIF_WORK_SYSCALL_ENTRY \ @@ -159,7 +161,7 @@ struct thread_info { /* work to do on any return to user space */ #define _TIF_ALLWORK_MASK \ ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT | \ - _TIF_NOHZ) + _TIF_NOHZ | _TIF_FSCHECK) /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 7e459b7ee7082e073f76a491cdd17deaa09e27ae..ac56615c14f29888a3d3f49b0e7d91b73e9aa958 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -86,7 +86,14 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask) static inline void __native_flush_tlb(void) { + /* + * If current->mm == NULL then we borrow a mm which may change during a + * task switch and therefore we must not be preempted while we write CR3 + * back: + */ + preempt_disable(); native_write_cr3(native_read_cr3()); + preempt_enable(); } static inline void __native_flush_tlb_global_irq_disabled(void) diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index c158198e3cc8849f1db87ba5dcfbe9691bbf5a40..852395f5caad3f9ebcfae45b0fba67bae39abb42 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -29,7 +29,12 @@ #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) -#define set_fs(x) (current_thread_info()->addr_limit = (x)) +static inline void set_fs(mm_segment_t fs) +{ + current_thread_info()->addr_limit = fs; + /* On user-mode return, check fs is correct */ + set_thread_flag(TIF_FSCHECK); +} #define segment_eq(a, b) ((a).seg == (b).seg) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index bcbfade26d8d587835124db66c968a09fd5b7d5b..e9c85e20ef4e9bc383a03f9af5da93f5c7716981 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -299,6 +299,7 @@ enum vmcs_field { #define INTR_TYPE_NMI_INTR (2 << 8) /* NMI */ #define INTR_TYPE_HARD_EXCEPTION (3 << 8) /* processor exception */ #define INTR_TYPE_SOFT_INTR (4 << 8) /* software interrupt */ +#define INTR_TYPE_PRIV_SW_EXCEPTION (5 << 8) /* ICE breakpoint - undocumented */ #define INTR_TYPE_SOFT_EXCEPTION (6 << 8) /* software exception */ /* GUEST_INTERRUPTIBILITY_INFO flags. */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 4170d7da9659c5acc1a999d484d504e40136fc35..8f1e77440b2bd65049b20a7a446213558b644f15 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -16,16 +16,6 @@ CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_early_printk.o = -pg endif -KASAN_SANITIZE_head$(BITS).o := n -KASAN_SANITIZE_dumpstack.o := n -KASAN_SANITIZE_dumpstack_$(BITS).o := n - -# If instrumentation of this dir is enabled, boot hangs during first second. -# Probably could be more selective here, but note that files related to irqs, -# boot, dumpstack/stacktrace, etc are either non-interesting or can lead to -# non-deterministic coverage. -KCOV_INSTRUMENT := n - CFLAGS_irq.o := -I$(src)/../include/asm/trace obj-y := process_$(BITS).o signal.o entry_$(BITS).o diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 690a25967a10418725949ab56b997e89870679a9..f460a63473f0b910150d4ad406f424956c619b4b 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -308,13 +308,12 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e #ifdef CONFIG_X86_IO_APIC #define MP_ISA_BUS 0 +static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity, + u8 trigger, u32 gsi); + static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) { - int ioapic; - int pin; - struct mpc_intsrc mp_irq; - /* * Check bus_irq boundary. */ @@ -323,14 +322,6 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, return; } - /* - * Convert 'gsi' to 'ioapic.pin'. - */ - ioapic = mp_find_ioapic(gsi); - if (ioapic < 0) - return; - pin = mp_find_ioapic_pin(ioapic, gsi); - /* * TBD: This check is for faulty timer entries, where the override * erroneously sets the trigger to level, resulting in a HUGE @@ -339,16 +330,8 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, if ((bus_irq == 0) && (trigger == 3)) trigger = 1; - mp_irq.type = MP_INTSRC; - mp_irq.irqtype = mp_INT; - mp_irq.irqflag = (trigger << 2) | polarity; - mp_irq.srcbus = MP_ISA_BUS; - mp_irq.srcbusirq = bus_irq; /* IRQ */ - mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */ - mp_irq.dstirq = pin; /* INTIN# */ - - mp_save_irq(&mp_irq); - + if (mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi) < 0) + return; /* * Reset default identity mapping if gsi is also an legacy IRQ, * otherwise there will be more than one entry with the same GSI @@ -445,6 +428,34 @@ static struct irq_domain_ops acpi_irqdomain_ops = { .unmap = mp_irqdomain_unmap, }; +static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity, + u8 trigger, u32 gsi) +{ + struct mpc_intsrc mp_irq; + int ioapic, pin; + + /* Convert 'gsi' to 'ioapic.pin'(INTIN#) */ + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) { + pr_warn("Failed to find ioapic for gsi : %u\n", gsi); + return ioapic; + } + + pin = mp_find_ioapic_pin(ioapic, gsi); + + mp_irq.type = MP_INTSRC; + mp_irq.irqtype = mp_INT; + mp_irq.irqflag = (trigger << 2) | polarity; + mp_irq.srcbus = MP_ISA_BUS; + mp_irq.srcbusirq = bus_irq; + mp_irq.dstapic = mpc_ioapic_id(ioapic); + mp_irq.dstirq = pin; + + mp_save_irq(&mp_irq); + + return 0; +} + static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) { @@ -489,7 +500,10 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger, if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK) polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; - mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + if (bus_irq < NR_IRQS_LEGACY) + mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + else + mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi); /* * stash over-ride to indicate we've been here diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile index 60e67f91271c979a5b5076d259b32930869cf677..dcb5b15401ce805f15bb84c111b842696606ea56 100644 --- a/arch/x86/kernel/apic/Makefile +++ b/arch/x86/kernel/apic/Makefile @@ -2,10 +2,6 @@ # Makefile for local APIC drivers and for the IO-APIC code # -# Leads to non-deterministic coverage that is not a function of syscall inputs. -# In particualr, smp_apic_timer_interrupt() is called in random places. -KCOV_INSTRUMENT := n - obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o ipi.o obj-y += hw_nmi.o diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 11fe4c56ae4e40665f4f9fa7759ca3f5eb92c09b..80091ae54c2b0995ea56629a3f7e6969a484fb9b 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -8,10 +8,6 @@ CFLAGS_REMOVE_common.o = -pg CFLAGS_REMOVE_perf_event.o = -pg endif -# If these files are instrumented, boot hangs during the first second. -KCOV_INSTRUMENT_common.o := n -KCOV_INSTRUMENT_perf_event.o := n - # Make sure load_percpu_segment has no stackprotector nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_common.o := $(nostackp) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 9cc6b6f25f424d18426adbab3e31e251e78c13af..2f6882344da6023595bbec16e9fe1b9090fc495e 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -561,6 +561,9 @@ static const struct _tlb_table intel_tlb_table[] = { { 0x5d, TLB_DATA_4K_4M, 256, " TLB_DATA 4 KByte and 4 MByte pages" }, { 0x61, TLB_INST_4K, 48, " TLB_INST 4 KByte pages, full associative" }, { 0x63, TLB_DATA_1G, 4, " TLB_DATA 1 GByte pages, 4-way set associative" }, + { 0x6b, TLB_DATA_4K, 256, " TLB_DATA 4 KByte pages, 8-way associative" }, + { 0x6c, TLB_DATA_2M_4M, 128, " TLB_DATA 2 MByte or 4 MByte pages, 8-way associative" }, + { 0x6d, TLB_DATA_1G, 16, " TLB_DATA 1 GByte pages, fully associative" }, { 0x76, TLB_INST_2M_4M, 8, " TLB_INST 2-MByte or 4-MByte pages, fully associative" }, { 0xb0, TLB_INST_4K, 128, " TLB_INST 4 KByte pages, 4-way set associative" }, { 0xb1, TLB_INST_2M_4M, 4, " TLB_INST 2M pages, 4-way, 8 entries or 4M pages, 4-way entries" }, diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index bf44e45a2a7637f61bb55cd8794a0f90c18f9533..291cb502d14151e8166ab0fd9231f0013cf67e53 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -56,6 +56,9 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex); rcu_read_lock_sched_held() || \ lockdep_is_held(&mce_chrdev_read_mutex)) +/* sysfs synchronization */ +static DEFINE_MUTEX(mce_sysfs_mutex); + #define CREATE_TRACE_POINTS #include @@ -2183,6 +2186,7 @@ static ssize_t set_ignore_ce(struct device *s, if (kstrtou64(buf, 0, &new) < 0) return -EINVAL; + mutex_lock(&mce_sysfs_mutex); if (mca_cfg.ignore_ce ^ !!new) { if (new) { /* disable ce features */ @@ -2195,6 +2199,8 @@ static ssize_t set_ignore_ce(struct device *s, on_each_cpu(mce_enable_ce, (void *)1, 1); } } + mutex_unlock(&mce_sysfs_mutex); + return size; } @@ -2207,6 +2213,7 @@ static ssize_t set_cmci_disabled(struct device *s, if (kstrtou64(buf, 0, &new) < 0) return -EINVAL; + mutex_lock(&mce_sysfs_mutex); if (mca_cfg.cmci_disabled ^ !!new) { if (new) { /* disable cmci */ @@ -2218,6 +2225,8 @@ static ssize_t set_cmci_disabled(struct device *s, on_each_cpu(mce_enable_ce, NULL, 1); } } + mutex_unlock(&mce_sysfs_mutex); + return size; } @@ -2225,8 +2234,16 @@ static ssize_t store_int_with_restart(struct device *s, struct device_attribute *attr, const char *buf, size_t size) { - ssize_t ret = device_store_int(s, attr, buf, size); + unsigned long old_check_interval = check_interval; + ssize_t ret = device_store_ulong(s, attr, buf, size); + + if (check_interval == old_check_interval) + return ret; + + mutex_lock(&mce_sysfs_mutex); mce_restart(); + mutex_unlock(&mce_sysfs_mutex); + return ret; } diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index c6826d1e8082584268d1b5e8f3abeb176ee61187..73293d879d4e412139539357806a0afed55c73a2 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -87,6 +87,9 @@ MODULE_DESCRIPTION("Microcode Update Driver"); MODULE_AUTHOR("Tigran Aivazian "); MODULE_LICENSE("GPL"); +/* last level cache size per core */ +static int llc_size_per_core; + static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) { struct cpuinfo_x86 *c = &cpu_data(cpu_num); @@ -267,6 +270,29 @@ static int get_ucode_fw(void *to, const void *from, size_t n) return 0; } +static bool is_blacklisted(unsigned int cpu) +{ + struct cpuinfo_x86 *c = &cpu_data(cpu); + + /* + * Late loading on model 79 with microcode revision less than 0x0b000021 + * and LLC size per core bigger than 2.5MB may result in a system hang. + * This behavior is documented in item BDF90, #334165 (Intel Xeon + * Processor E7-8800/4800 v4 Product Family). + */ + if (c->x86 == 6 && + c->x86_model == 79 && + c->x86_mask == 0x01 && + llc_size_per_core > 2621440 && + c->microcode < 0x0b000021) { + pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); + pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); + return true; + } + + return false; +} + static enum ucode_state request_microcode_fw(int cpu, struct device *device, bool refresh_fw) { @@ -275,6 +301,9 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device, const struct firmware *firmware; enum ucode_state ret; + if (is_blacklisted(cpu)) + return UCODE_NFOUND; + sprintf(name, "intel-ucode/%02x-%02x-%02x", c->x86, c->x86_model, c->x86_mask); @@ -299,6 +328,9 @@ static int get_ucode_user(void *to, const void *from, size_t n) static enum ucode_state request_microcode_user(int cpu, const void __user *buf, size_t size) { + if (is_blacklisted(cpu)) + return UCODE_NFOUND; + return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user); } @@ -318,6 +350,15 @@ static struct microcode_ops microcode_intel_ops = { .microcode_fini_cpu = microcode_fini_cpu, }; +static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c) +{ + u64 llc_size = c->x86_cache_size * 1024; + + do_div(llc_size, c->x86_max_cores); + + return (int)llc_size; +} + struct microcode_ops * __init init_intel_microcode(void) { struct cpuinfo_x86 *c = &cpu_data(0); @@ -328,6 +369,8 @@ struct microcode_ops * __init init_intel_microcode(void) return NULL; } + llc_size_per_core = calc_llc_size_per_core(c); + return µcode_intel_ops; } diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index e98f68cfea022a0695bdb0bb8c9150f455b4593e..cae9a3b6446b910324f93f2ed659650c42e353f4 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -175,7 +175,7 @@ void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *e u64 prev_count, new_count, delta; int shift; - if (event->hw.idx >= UNCORE_PMC_IDX_FIXED) + if (event->hw.idx == UNCORE_PMC_IDX_FIXED) shift = 64 - uncore_fixed_ctr_bits(box); else shift = 64 - uncore_perf_ctr_bits(box); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c index 2749965afed0b037ff8dc05cd62b976b7c5ecc17..83cadc2605a78564a29afac2527d1316b40c8c70 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c @@ -240,7 +240,7 @@ static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct p { struct hw_perf_event *hwc = &event->hw; - if (hwc->idx >= UNCORE_PMC_IDX_FIXED) + if (hwc->idx == UNCORE_PMC_IDX_FIXED) wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0); else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0) wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 3d3503351242b7c6d8dcc0d32350e36e63da1939..8f4b94272472191b41e0a6f7f6c013f62e36a56c 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -224,7 +224,7 @@ static int ioapic_xlate(struct irq_domain *domain, return 0; } -const struct irq_domain_ops ioapic_irq_domain_ops = { +static const struct irq_domain_ops ioapic_irq_domain_ops = { .map = mp_irqdomain_map, .unmap = mp_irqdomain_unmap, .xlate = ioapic_xlate, diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 8d6e954db2a7b8dd592b9bad99b7b92366db4e3b..9c9f4c0b01062ea99abd80970fa348d8ee054750 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -388,11 +388,22 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, xsave_hdr = &target->thread.fpu.state->xsave.xsave_hdr; xsave_hdr->xstate_bv &= pcntxt_mask; + + /* xcomp_bv must be 0 when using uncompacted format */ + if (!ret && xsave_hdr->xcomp_bv) + ret = -EINVAL; + /* * These bits must be zero. */ memset(xsave_hdr->reserved, 0, 48); + /* + * In case of failure, mark all states as init: + */ + if (ret) + fpu_finit(&target->thread.fpu); + return ret; } diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index e7cc5370cd2fcade87dc1cecae2ab85184f62d27..6c7e7986939a76c90b0b3aa6391726e52d9b9e80 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c @@ -405,6 +405,7 @@ struct legacy_pic default_legacy_pic = { }; struct legacy_pic *legacy_pic = &default_legacy_pic; +EXPORT_SYMBOL(legacy_pic); static int __init i8259A_init_ops(void) { diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index b6547a441badda8fe19b569e087ca382e27ea503..323d122267b281b79179cfab7539242b6c49a959 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -196,6 +197,8 @@ retry: return (opcode != 0x62 && opcode != 0x67); case 0x70: return 0; /* can't boost conditional jump */ + case 0x90: + return opcode != 0x9a; /* can't boost call far */ case 0xc0: /* can't boost software-interruptions */ return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf; @@ -362,7 +365,6 @@ int __copy_instruction(u8 *dest, u8 *src) newdisp = (u8 *) src + (s64) insn.displacement.value - (u8 *) dest; if ((s64) (s32) newdisp != newdisp) { pr_err("Kprobes error: new displacement does not fit into s32 (%llx)\n", newdisp); - pr_err("\tSrc: %p, Dest: %p, old disp: %x\n", src, dest, insn.displacement.value); return 0; } disp = (u8 *) dest + insn_offset_displacement(&insn); @@ -372,10 +374,20 @@ int __copy_instruction(u8 *dest, u8 *src) return length; } +/* Recover page to RW mode before releasing it */ +void free_insn_page(void *page) +{ + set_memory_nx((unsigned long)page & PAGE_MASK, 1); + set_memory_rw((unsigned long)page & PAGE_MASK, 1); + vfree(page); +} + static int arch_copy_kprobe(struct kprobe *p) { int ret; + set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1); + /* Copy an instruction with recovering if other optprobe modifies it.*/ ret = __copy_instruction(p->ainsn.insn, p->addr); if (!ret) @@ -390,6 +402,8 @@ static int arch_copy_kprobe(struct kprobe *p) else p->ainsn.boostable = -1; + set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1); + /* Check whether the instruction modifies Interrupt Flag or not */ p->ainsn.if_modifier = is_IF_modifier(p->ainsn.insn); @@ -553,8 +567,7 @@ static int reenter_kprobe(struct kprobe *p, struct pt_regs *regs, * Raise a BUG or we'll continue in an endless reentering loop * and eventually a stack overflow. */ - printk(KERN_WARNING "Unrecoverable kprobe detected at %p.\n", - p->addr); + pr_err("Unrecoverable kprobe detected.\n"); dump_kprobe(p); BUG(); default: diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index cdb672c3049b953d4962b396f84fbe947b0a9730..aec5dfa8b7e115a0b5c2487b4e22453a599d29f2 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -344,6 +344,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op) } buf = (u8 *)op->optinsn.insn; + set_memory_rw((unsigned long)buf & PAGE_MASK, 1); /* Copy instructions into the out-of-line buffer */ ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr); @@ -366,6 +367,8 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op) synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size, (u8 *)op->kp.addr + op->optinsn.size); + set_memory_ro((unsigned long)buf & PAGE_MASK, 1); + flush_icache_range((unsigned long) buf, (unsigned long) buf + TMPL_END_IDX + op->optinsn.size + RELATIVEJUMP_SIZE); diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 72e8e310258d610c8a05f89920ddf101deb92a05..348e454ce6f863351dac6d5cbf1de1cf2a417af0 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -70,12 +70,17 @@ static void load_segments(void) static void machine_kexec_free_page_tables(struct kimage *image) { free_page((unsigned long)image->arch.pgd); + image->arch.pgd = NULL; #ifdef CONFIG_X86_PAE free_page((unsigned long)image->arch.pmd0); + image->arch.pmd0 = NULL; free_page((unsigned long)image->arch.pmd1); + image->arch.pmd1 = NULL; #endif free_page((unsigned long)image->arch.pte0); + image->arch.pte0 = NULL; free_page((unsigned long)image->arch.pte1); + image->arch.pte1 = NULL; } static int machine_kexec_alloc_page_tables(struct kimage *image) @@ -92,7 +97,6 @@ static int machine_kexec_alloc_page_tables(struct kimage *image) !image->arch.pmd0 || !image->arch.pmd1 || #endif !image->arch.pte0 || !image->arch.pte1) { - machine_kexec_free_page_tables(image); return -ENOMEM; } return 0; diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 485981059a40e703e7be8debd49a14e45dde0e54..7c16b11d39ed71b872bb18629a9cd445af870338 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -34,8 +34,11 @@ static struct kexec_file_ops *kexec_file_loaders[] = { static void free_transition_pgtable(struct kimage *image) { free_page((unsigned long)image->arch.pud); + image->arch.pud = NULL; free_page((unsigned long)image->arch.pmd); + image->arch.pmd = NULL; free_page((unsigned long)image->arch.pte); + image->arch.pte = NULL; } static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) @@ -76,7 +79,6 @@ static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC)); return 0; err: - free_transition_pgtable(image); return result; } @@ -516,6 +518,7 @@ int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, goto overflow; break; case R_X86_64_PC32: + case R_X86_64_PLT32: value -= (u64)address; *(u32 *)location = value; break; diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index d1ac80b72c72184a0b999c2b299b5e265d26de7a..0bc26d71a9dcc91a4959cfd93972f14ca20538b2 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -177,19 +177,28 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, case R_X86_64_NONE: break; case R_X86_64_64: + if (*(u64 *)loc != 0) + goto invalid_relocation; *(u64 *)loc = val; break; case R_X86_64_32: + if (*(u32 *)loc != 0) + goto invalid_relocation; *(u32 *)loc = val; if (val != *(u32 *)loc) goto overflow; break; case R_X86_64_32S: + if (*(s32 *)loc != 0) + goto invalid_relocation; *(s32 *)loc = val; if ((s64)val != *(s32 *)loc) goto overflow; break; case R_X86_64_PC32: + case R_X86_64_PLT32: + if (*(u32 *)loc != 0) + goto invalid_relocation; val -= (u64)loc; *(u32 *)loc = val; #if 0 @@ -205,6 +214,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, } return 0; +invalid_relocation: + pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n", + (int)ELF64_R_TYPE(rel[i].r_info), loc, val); + return -ENOEXEC; + overflow: pr_err("overflow in relocation type %d val %Lx\n", (int)ELF64_R_TYPE(rel[i].r_info), val); diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index f547f866e86c43b3154755f9584ec0d1bb2cc95a..ba48e77c8e9e442ed2f01940047551b58256a0f6 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -438,6 +438,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) return prev_p; } +EXPORT_SYMBOL_GPL(start_thread); void set_personality_64bit(void) { diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 0a62df4abcf77edb2aa3b606edf47f43ea6ba41b..edd1a76425b0aaaa1e0a2cce8f44cc4192aa914c 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -740,6 +741,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { user_exit(); + addr_limit_user_check(); + #ifdef CONFIG_X86_MCE /* notify userspace of pending MCEs */ if (thread_info_flags & _TIF_MCE_NOTIFY) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 668d8f2a8781ea11fab5110315a946171b0e274d..a3edf722a7c93f0abc0ccd26f2d0a638eab2099e 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1290,6 +1290,7 @@ static void remove_siblinginfo(int cpu) cpumask_clear(cpu_core_mask(cpu)); c->phys_proc_id = 0; c->cpu_core_id = 0; + c->booted_cores = 0; cpumask_clear_cpu(cpu, cpu_sibling_setup_mask); } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 21187ebee7d0906e5b8586fa9bad883e4c8082da..8fdcdbf5f30957950ac30f45956893522b4af374 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -356,6 +356,8 @@ static int __init tsc_setup(char *str) tsc_clocksource_reliable = 1; if (!strncmp(str, "noirqtime", 9)) no_sched_irq_time = 1; + if (!strcmp(str, "unstable")) + mark_tsc_unstable("boot parameter"); return 1; } @@ -397,7 +399,7 @@ static unsigned long calc_hpet_ref(u64 deltatsc, u64 hpet1, u64 hpet2) hpet2 -= hpet1; tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); do_div(tmp, 1000000); - do_div(deltatsc, tmp); + deltatsc = div64_u64(deltatsc, tmp); return (unsigned long) deltatsc; } diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 6aa0f4d9eea6816bbf0c78514e0b76d8f4dc7def..0e37e369b3a0cd74ff7890a7dadcf2bea83ab341 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -21,6 +21,7 @@ #include #include #include +#include /* CPU reference clock frequency: in KHz */ #define FREQ_83 83200 diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index cdc6cf90307800abb83f1b4b516ba389212c3dd0..460e72155f51b060a569a3c243e3dd49c4f17d8d 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -394,7 +394,9 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size) drop_fpu(tsk); if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) || - __copy_from_user(&env, buf, sizeof(env))) { + __copy_from_user(&env, buf, sizeof(env)) || + (state_size > offsetof(struct xsave_struct, xsave_hdr) && + fpu->state->xsave.xsave_hdr.xcomp_bv)) { fpu_finit(fpu); err = -1; } else { diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 852572c971c4a60ca6a1cb7433f8e84ac7cde89d..08751c554d358d2dc47f178915d8220c3a628ce6 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -4385,6 +4385,8 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) bool op_prefix = false; bool has_seg_override = false; struct opcode opcode; + u16 dummy; + struct desc_struct desc; ctxt->memop.type = OP_NONE; ctxt->memopp = NULL; @@ -4403,6 +4405,11 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) switch (mode) { case X86EMUL_MODE_REAL: case X86EMUL_MODE_VM86: + def_op_bytes = def_ad_bytes = 2; + ctxt->ops->get_segment(ctxt, &dummy, &desc, NULL, VCPU_SREG_CS); + if (desc.d) + def_op_bytes = def_ad_bytes = 4; + break; case X86EMUL_MODE_PROT16: def_op_bytes = def_ad_bytes = 2; break; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 9dc0aa0dae96b6f4a75b8c8d09d4db0b56929997..2e0c64a08549caebd9d4a8d28a092dc42c1b7260 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1467,6 +1467,7 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, */ if (var->unusable) var->db = 0; + /* This is symmetric with svm_set_segment() */ var->dpl = to_svm(vcpu)->vmcb->save.cpl; break; } @@ -1611,18 +1612,14 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, s->base = var->base; s->limit = var->limit; s->selector = var->selector; - if (var->unusable) - s->attrib = 0; - else { - s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); - s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; - s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; - s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT; - s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; - s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; - s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; - s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; - } + s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); + s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; + s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; + s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT; + s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; + s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; + s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; + s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; /* * This is always accurate, except if SYSRET returned to a segment @@ -1631,7 +1628,8 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, * would entail passing the CPL to userspace and back. */ if (seg == VCPU_SREG_SS) - svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; + /* This is symmetric with svm_get_segment() */ + svm->vmcb->save.cpl = (var->dpl & 3); mark_dirty(svm->vmcb, VMCB_SEG); } @@ -1785,6 +1783,8 @@ static int ud_interception(struct vcpu_svm *svm) int er; er = emulate_instruction(&svm->vcpu, EMULTYPE_TRAP_UD); + if (er == EMULATE_USER_EXIT) + return 0; if (er != EMULATE_DONE) kvm_queue_exception(&svm->vcpu, UD_VECTOR); return 1; @@ -3187,6 +3187,13 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) u32 ecx = msr->index; u64 data = msr->data; switch (ecx) { + case MSR_IA32_CR_PAT: + if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data)) + return 1; + vcpu->arch.pat = data; + svm->vmcb->save.g_pat = data; + mark_dirty(svm->vmcb, VMCB_NPT); + break; case MSR_IA32_TSC: kvm_write_tsc(vcpu, msr); break; @@ -3936,6 +3943,25 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%[svm]) \n\t" "mov %%r14, %c[r14](%[svm]) \n\t" "mov %%r15, %c[r15](%[svm]) \n\t" +#endif + /* + * Clear host registers marked as clobbered to prevent + * speculative use. + */ + "xor %%" _ASM_BX ", %%" _ASM_BX " \n\t" + "xor %%" _ASM_CX ", %%" _ASM_CX " \n\t" + "xor %%" _ASM_DX ", %%" _ASM_DX " \n\t" + "xor %%" _ASM_SI ", %%" _ASM_SI " \n\t" + "xor %%" _ASM_DI ", %%" _ASM_DI " \n\t" +#ifdef CONFIG_X86_64 + "xor %%r8, %%r8 \n\t" + "xor %%r9, %%r9 \n\t" + "xor %%r10, %%r10 \n\t" + "xor %%r11, %%r11 \n\t" + "xor %%r12, %%r12 \n\t" + "xor %%r13, %%r13 \n\t" + "xor %%r14, %%r14 \n\t" + "xor %%r15, %%r15 \n\t" #endif "pop %%" _ASM_BP : diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 99c004ddefd8ea49db9ac9ba2ce203aebb38178e..cd51f320a4600c54223f263bb314ee227ba5f60a 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -883,6 +883,13 @@ static inline bool is_machine_check(u32 intr_info) (INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK); } +/* Undocumented: icebp/int1 */ +static inline bool is_icebp(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) + == (INTR_TYPE_PRIV_SW_EXCEPTION | INTR_INFO_VALID_MASK); +} + static inline bool cpu_has_vmx_msr_bitmap(void) { return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS; @@ -2057,6 +2064,8 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, return; } + WARN_ON_ONCE(vmx->emulation_required); + if (kvm_exception_is_soft(nr)) { vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, vmx->vcpu.arch.event_exit_inst_len); @@ -4569,7 +4578,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) vmcs_writel(GUEST_SYSENTER_ESP, 0); vmcs_writel(GUEST_SYSENTER_EIP, 0); - vmcs_writel(GUEST_RFLAGS, 0x02); + kvm_set_rflags(vcpu, X86_EFLAGS_FIXED); kvm_rip_write(vcpu, 0xfff0); vmcs_writel(GUEST_GDTR_BASE, 0); @@ -4899,6 +4908,8 @@ static int handle_exception(struct kvm_vcpu *vcpu) if (is_invalid_opcode(intr_info)) { er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD); + if (er == EMULATE_USER_EXIT) + return 0; if (er != EMULATE_DONE) kvm_queue_exception(vcpu, UD_VECTOR); return 1; @@ -4949,7 +4960,7 @@ static int handle_exception(struct kvm_vcpu *vcpu) (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) { vcpu->arch.dr6 &= ~15; vcpu->arch.dr6 |= dr6 | DR6_RTM; - if (!(dr6 & ~DR6_RESERVED)) /* icebp */ + if (is_icebp(intr_info)) skip_emulated_instruction(vcpu); kvm_queue_exception(vcpu, DB_VECTOR); @@ -5705,7 +5716,7 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) if (test_bit(KVM_REQ_EVENT, &vcpu->requests)) return 1; - err = emulate_instruction(vcpu, EMULTYPE_NO_REEXECUTE); + err = emulate_instruction(vcpu, 0); if (err == EMULATE_USER_EXIT) { ++vcpu->stat.mmio_exits; @@ -5713,12 +5724,12 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) goto out; } - if (err != EMULATE_DONE) { - vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; - vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; - vcpu->run->internal.ndata = 0; - return 0; - } + if (err != EMULATE_DONE) + goto emulation_error; + + if (vmx->emulation_required && !vmx->rmode.vm86_active && + vcpu->arch.exception.pending) + goto emulation_error; if (vcpu->arch.halt_request) { vcpu->arch.halt_request = 0; @@ -5734,6 +5745,12 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) out: return ret; + +emulation_error: + vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; + vcpu->run->internal.ndata = 0; + return 0; } static int __grow_ple_window(int val) @@ -6926,11 +6943,13 @@ static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu, { unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); int cr = exit_qualification & 15; - int reg = (exit_qualification >> 8) & 15; - unsigned long val = kvm_register_readl(vcpu, reg); + int reg; + unsigned long val; switch ((exit_qualification >> 4) & 3) { case 0: /* mov to cr */ + reg = (exit_qualification >> 8) & 15; + val = kvm_register_readl(vcpu, reg); switch (cr) { case 0: if (vmcs12->cr0_guest_host_mask & @@ -6985,6 +7004,7 @@ static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu, * lmsw can change bits 1..3 of cr0, and only set bit 0 of * cr0. Other attempted changes are ignored, with no exit. */ + val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f; if (vmcs12->cr0_guest_host_mask & 0xe & (val ^ vmcs12->cr0_read_shadow)) return 1; @@ -7651,6 +7671,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) /* Save guest registers, load host registers, keep flags */ "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t" "pop %0 \n\t" + "setbe %c[fail](%0)\n\t" "mov %%" _ASM_AX ", %c[rax](%0) \n\t" "mov %%" _ASM_BX ", %c[rbx](%0) \n\t" __ASM_SIZE(pop) " %c[rcx](%0) \n\t" @@ -7667,12 +7688,23 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%0) \n\t" "mov %%r14, %c[r14](%0) \n\t" "mov %%r15, %c[r15](%0) \n\t" + "xor %%r8d, %%r8d \n\t" + "xor %%r9d, %%r9d \n\t" + "xor %%r10d, %%r10d \n\t" + "xor %%r11d, %%r11d \n\t" + "xor %%r12d, %%r12d \n\t" + "xor %%r13d, %%r13d \n\t" + "xor %%r14d, %%r14d \n\t" + "xor %%r15d, %%r15d \n\t" #endif "mov %%cr2, %%" _ASM_AX " \n\t" "mov %%" _ASM_AX ", %c[cr2](%0) \n\t" + "xor %%eax, %%eax \n\t" + "xor %%ebx, %%ebx \n\t" + "xor %%esi, %%esi \n\t" + "xor %%edi, %%edi \n\t" "pop %%" _ASM_BP "; pop %%" _ASM_DX " \n\t" - "setbe %c[fail](%0) \n\t" ".pushsection .rodata \n\t" ".global vmx_return \n\t" "vmx_return: " _ASM_PTR " 2b \n\t" @@ -8275,6 +8307,11 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, page_to_phys(vmx->nested.virtual_apic_page)); vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold); + } else { +#ifdef CONFIG_X86_64 + exec_control |= CPU_BASED_CR8_LOAD_EXITING | + CPU_BASED_CR8_STORE_EXITING; +#endif } /* @@ -8899,7 +8936,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, * (KVM doesn't change it)- no reason to call set_cr4_guest_host_mask(); */ vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); - kvm_set_cr4(vcpu, vmcs12->host_cr4); + vmx_set_cr4(vcpu, vmcs12->host_cr4); nested_ept_uninit_mmu_context(vcpu); @@ -8924,6 +8961,8 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip); vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base); vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base); + vmcs_write32(GUEST_IDTR_LIMIT, 0xFFFF); + vmcs_write32(GUEST_GDTR_LIMIT, 0xFFFF); /* If not VM_EXIT_CLEAR_BNDCFGS, the L2 value propagates to L1. */ if (vmcs12->vm_exit_controls & VM_EXIT_CLEAR_BNDCFGS) @@ -9077,8 +9116,10 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, */ static void vmx_leave_nested(struct kvm_vcpu *vcpu) { - if (is_guest_mode(vcpu)) + if (is_guest_mode(vcpu)) { + to_vmx(vcpu)->nested.nested_run_pending = 0; nested_vmx_vmexit(vcpu, -1, 0, 0); + } free_nested(to_vmx(vcpu)); } @@ -9271,12 +9312,7 @@ static int __init vmx_init(void) memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE); memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE); - /* - * Allow direct access to the PC debug port (it is often used for I/O - * delays, but the vmexits simply slow things down). - */ memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE); - clear_bit(0x80, vmx_io_bitmap_a); memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3411283e0b5e7ae6193a8829440427a082a38ddf..2a084b0168f8877342bc4cc52dd88be658aed7e2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4025,13 +4025,14 @@ long kvm_arch_vm_ioctl(struct file *filp, break; } case KVM_XEN_HVM_CONFIG: { + struct kvm_xen_hvm_config xhc; r = -EFAULT; - if (copy_from_user(&kvm->arch.xen_hvm_config, argp, - sizeof(struct kvm_xen_hvm_config))) + if (copy_from_user(&xhc, argp, sizeof(xhc))) goto out; r = -EINVAL; - if (kvm->arch.xen_hvm_config.flags) + if (xhc.flags) goto out; + memcpy(&kvm->arch.xen_hvm_config, &xhc, sizeof(xhc)); r = 0; break; } @@ -5109,7 +5110,7 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu) vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; vcpu->run->internal.ndata = 0; - r = EMULATE_FAIL; + r = EMULATE_USER_EXIT; } kvm_queue_exception(vcpu, UD_VECTOR); @@ -5372,6 +5373,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, emulation_type)) return EMULATE_DONE; + if (ctxt->have_exception && inject_emulated_exception(vcpu)) + return EMULATE_DONE; if (emulation_type & EMULTYPE_SKIP) return EMULATE_FAIL; return handle_emulation_failure(vcpu); @@ -6642,7 +6645,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) #endif kvm_rip_write(vcpu, regs->rip); - kvm_set_rflags(vcpu, regs->rflags); + kvm_set_rflags(vcpu, regs->rflags | X86_EFLAGS_FIXED); vcpu->arch.exception.pending = false; @@ -7754,6 +7757,13 @@ static int apf_put_user(struct kvm_vcpu *vcpu, u32 val) sizeof(val)); } +static int apf_get_user(struct kvm_vcpu *vcpu, u32 *val) +{ + + return kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apf.data, val, + sizeof(u32)); +} + void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) { @@ -7780,21 +7790,32 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) { struct x86_exception fault; + u32 val; - trace_kvm_async_pf_ready(work->arch.token, work->gva); if (work->wakeup_all) work->arch.token = ~0; /* broadcast wakeup */ else kvm_del_async_pf_gfn(vcpu, work->arch.gfn); + trace_kvm_async_pf_ready(work->arch.token, work->gva); - if ((vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) && - !apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) { - fault.vector = PF_VECTOR; - fault.error_code_valid = true; - fault.error_code = 0; - fault.nested_page_fault = false; - fault.address = work->arch.token; - kvm_inject_page_fault(vcpu, &fault); + if (vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED && + !apf_get_user(vcpu, &val)) { + if (val == KVM_PV_REASON_PAGE_NOT_PRESENT && + vcpu->arch.exception.pending && + vcpu->arch.exception.nr == PF_VECTOR && + !apf_put_user(vcpu, 0)) { + vcpu->arch.exception.pending = false; + vcpu->arch.exception.nr = 0; + vcpu->arch.exception.has_error_code = false; + vcpu->arch.exception.error_code = 0; + } else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) { + fault.vector = PF_VECTOR; + fault.error_code_valid = true; + fault.error_code = 0; + fault.nested_page_fault = false; + fault.address = work->arch.token; + kvm_inject_page_fault(vcpu, &fault); + } } vcpu->arch.apf.halted = false; vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index d6377b7ea7bca16f19b75cfb52615539474d4766..db92793b7e23edaf7a252fe3d72daf4f893d5c31 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -2,9 +2,6 @@ # Makefile for x86 specific library files. # -# Produces uninteresting flaky coverage. -KCOV_INSTRUMENT_delay.o := n - inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt quiet_cmd_inat_tables = GEN $@ diff --git a/arch/x86/lib/cmdline.c b/arch/x86/lib/cmdline.c index 422db000d72767adf718dc75db682e5df576e877..49548bed2301fcb9101ffea64cabdcee26e7f808 100644 --- a/arch/x86/lib/cmdline.c +++ b/arch/x86/lib/cmdline.c @@ -21,12 +21,14 @@ static inline int myisspace(u8 c) * @option: option string to look for * * Returns the position of that @option (starts counting with 1) - * or 0 on not found. + * or 0 on not found. @option will only be found if it is found + * as an entire word in @cmdline. For instance, if @option="car" + * then a cmdline which contains "cart" will not match. */ int cmdline_find_option_bool(const char *cmdline, const char *option) { char c; - int len, pos = 0, wstart = 0; + int pos = 0, wstart = 0; const char *opptr = NULL; enum { st_wordstart = 0, /* Start of word/after whitespace */ @@ -37,11 +39,14 @@ int cmdline_find_option_bool(const char *cmdline, const char *option) if (!cmdline) return -1; /* No command line */ - len = min_t(int, strlen(cmdline), COMMAND_LINE_SIZE); - if (!len) + if (!strlen(cmdline)) return 0; - while (len--) { + /* + * This 'pos' check ensures we do not overrun + * a non-NULL-terminated 'cmdline' + */ + while (pos < COMMAND_LINE_SIZE) { c = *(char *)cmdline++; pos++; @@ -58,17 +63,26 @@ int cmdline_find_option_bool(const char *cmdline, const char *option) /* fall through */ case st_wordcmp: - if (!*opptr) + if (!*opptr) { + /* + * We matched all the way to the end of the + * option we were looking for. If the + * command-line has a space _or_ ends, then + * we matched! + */ if (!c || myisspace(c)) return wstart; else state = st_wordskip; - else if (!c) + } else if (!c) { + /* + * Hit the NULL terminator on the end of + * cmdline. + */ return 0; - else if (c != *opptr++) + } else if (c != *opptr++) { state = st_wordskip; - else if (!len) /* last word and is matching */ - return wstart; + } break; case st_wordskip: diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 1a2be7c6895d811be12083b5dab49f92cfb8791f..3ce0dcc56ce5f07566402a12c5a935bacf56df30 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -814,7 +814,7 @@ EndTable GrpTable: Grp3_1 0: TEST Eb,Ib -1: +1: TEST Eb,Ib 2: NOT Eb 3: NEG Eb 4: MUL AL,Eb diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 043a3bd397d491ebcc8170ae338ba0e46b37b087..4a665a14d66c8b80a2798be9e6e0c5ba4de8ff2e 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -1,6 +1,3 @@ -# Kernel does not boot with instrumentation of tlb.c. -KCOV_INSTRUMENT_tlb.o := n - obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ pat.o pgtable.o physaddr.o gup.o setup_nx.o diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 6fa245ae52c549ccc6c85720177fe5a237037ba9..899b2f94f9c247acf6aae9cff0c4e61374e029b0 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -271,8 +271,6 @@ static noinline int vmalloc_fault(unsigned long address) if (!(address >= VMALLOC_START && address < VMALLOC_END)) return -1; - WARN_ON_ONCE(in_nmi()); - /* * Synchronize this task's top level page-table * with the 'reference' page table. diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index af78e50ca6cee7e4b7293075171986ab6f7166d5..c76ea35fa19faf577fe128d51495bede34f23d68 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -296,11 +296,11 @@ void iounmap(volatile void __iomem *addr) (void __force *)addr < phys_to_virt(ISA_END_ADDRESS)) return; + mmiotrace_iounmap(addr); + addr = (volatile void __iomem *) (PAGE_MASK & (unsigned long __force)addr); - mmiotrace_iounmap(addr); - /* Use the vm area unlocked, assuming the caller ensures there isn't another iounmap for the same address in parallel. Reuse of the virtual address is prevented by diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c index ddb2244b06a1d618679d83a9133f72e8d884b3a2..76604c8a2a487885d0ee40f9c5db7acae97cfa08 100644 --- a/arch/x86/mm/kmmio.c +++ b/arch/x86/mm/kmmio.c @@ -434,17 +434,18 @@ int register_kmmio_probe(struct kmmio_probe *p) unsigned long flags; int ret = 0; unsigned long size = 0; + unsigned long addr = p->addr & PAGE_MASK; const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK); unsigned int l; pte_t *pte; spin_lock_irqsave(&kmmio_lock, flags); - if (get_kmmio_probe(p->addr)) { + if (get_kmmio_probe(addr)) { ret = -EEXIST; goto out; } - pte = lookup_address(p->addr, &l); + pte = lookup_address(addr, &l); if (!pte) { ret = -EINVAL; goto out; @@ -453,7 +454,7 @@ int register_kmmio_probe(struct kmmio_probe *p) kmmio_count++; list_add_rcu(&p->list, &kmmio_probes); while (size < size_lim) { - if (add_kmmio_fault_page(p->addr + size)) + if (add_kmmio_fault_page(addr + size)) pr_err("Unable to set page fault.\n"); size += page_level_size(l); } @@ -527,19 +528,20 @@ void unregister_kmmio_probe(struct kmmio_probe *p) { unsigned long flags; unsigned long size = 0; + unsigned long addr = p->addr & PAGE_MASK; const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK); struct kmmio_fault_page *release_list = NULL; struct kmmio_delayed_release *drelease; unsigned int l; pte_t *pte; - pte = lookup_address(p->addr, &l); + pte = lookup_address(addr, &l); if (!pte) return; spin_lock_irqsave(&kmmio_lock, flags); while (size < size_lim) { - release_kmmio_fault_page(p->addr + size, &release_list); + release_kmmio_fault_page(addr + size, &release_list); size += page_level_size(l); } list_del_rcu(&p->list); diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c index a8f90ce3dedff5e0ddae9f618893da8afcf2e07d..dc6d99017f3f0af49f958a7d2b3c13ced1cbe687 100644 --- a/arch/x86/mm/numa_emulation.c +++ b/arch/x86/mm/numa_emulation.c @@ -60,7 +60,7 @@ static int __init emu_setup_memblk(struct numa_meminfo *ei, eb->nid = nid; if (emu_nid_to_phys[nid] == NUMA_NO_NODE) - emu_nid_to_phys[nid] = nid; + emu_nid_to_phys[nid] = pb->nid; pb->start += size; if (pb->start >= pb->end) { diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 1d2e6392f5faaf6f450cdfa598b9b2a734064962..f24bd724953638b50dd38d8f5a724beb91cb531f 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -471,7 +471,7 @@ static int nmi_setup(void) goto fail; for_each_possible_cpu(cpu) { - if (!cpu) + if (!IS_ENABLED(CONFIG_SMP) || !cpu) continue; memcpy(per_cpu(cpu_msrs, cpu).counters, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index d90528ea541206b57f3048e191d4340ee070b40b..12c051d19e4bf084cc42497d49cc32718b3ddee3 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -212,8 +212,8 @@ static void arch_perfmon_setup_counters(void) eax.full = cpuid_eax(0xa); /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */ - if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 && - __this_cpu_read(cpu_info.x86_model) == 15) { + if (eax.split.version_id == 0 && boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model == 15) { eax.split.version_id = 2; eax.split.num_counters = 2; eax.split.bit_width = 40; diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c index bb461cfd01abc78cdc45c6e69f013128e04ccdb4..526536c81ddc41d395fd971d909a3b687e46d989 100644 --- a/arch/x86/pci/broadcom_bus.c +++ b/arch/x86/pci/broadcom_bus.c @@ -97,7 +97,7 @@ static int __init broadcom_postcore_init(void) * We should get host bridge information from ACPI unless the BIOS * doesn't support it. */ - if (acpi_os_get_root_pointer()) + if (!acpi_disabled && acpi_os_get_root_pointer()) return 0; #endif diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c index 291226b952a997f55d3a0be723f15cb9b9b1ab92..77ac4e4deb168f790d96d8646824a298050f5cc2 100644 --- a/arch/x86/power/hibernate_32.c +++ b/arch/x86/power/hibernate_32.c @@ -142,7 +142,7 @@ static inline void resume_init_first_level_page_table(pgd_t *pg_dir) #endif } -int swsusp_arch_resume(void) +asmlinkage int swsusp_arch_resume(void) { int error; diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c index 009947d419a61ae2fc41f58ad9d85ece1555fec2..0e0c773edffc2cbc1cff70ed3f1990b352f397cf 100644 --- a/arch/x86/power/hibernate_64.c +++ b/arch/x86/power/hibernate_64.c @@ -78,7 +78,7 @@ static int set_up_temporary_mappings(void) return 0; } -int swsusp_arch_resume(void) +asmlinkage int swsusp_arch_resume(void) { int error; diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 83bab78bbfa16ff2f07d460718213179d9fdd68e..7d3952eafec9770b8218f8a38ace6239c9dcf6df 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -11,9 +11,6 @@ KASAN_SANITIZE := n # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. KCOV_INSTRUMENT := n -# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. -KCOV_INSTRUMENT := n - always := realmode.bin realmode.relocs wakeup-objs := wakeup_asm.o wakemain.o video-mode.o diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 73eb7fd4aec48d02e367b87ec1326da6c4022bde..5b6c8486a0bece83fe9af6248537675d41f9a3ac 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -769,9 +769,12 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, break; case R_X86_64_PC32: + case R_X86_64_PLT32: /* * PC relative relocations don't need to be adjusted unless * referencing a percpu symbol. + * + * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32. */ if (is_percpu_sym(sym, symname)) add_reloc(&relocs32neg, offset); diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 9793322751e02f63ddba0d1b8fef5f21b0a4d502..5360c6591b8ef546aa2220926b21a4eb17a8c51d 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c @@ -46,8 +46,9 @@ static notrace cycle_t vread_hpet(void) notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) { long ret; - asm("syscall" : "=a" (ret) : - "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory"); + asm ("syscall" : "=a" (ret), "=m" (*ts) : + "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : + "memory", "rcx", "r11"); return ret; } @@ -55,8 +56,9 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) { long ret; - asm("syscall" : "=a" (ret) : - "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory"); + asm ("syscall" : "=a" (ret), "=m" (*tv), "=m" (*tz) : + "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : + "memory", "rcx", "r11"); return ret; } @@ -136,13 +138,13 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) { long ret; - asm( + asm ( "mov %%ebx, %%edx \n" - "mov %2, %%ebx \n" + "mov %[clock], %%ebx \n" "call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" - : "=a" (ret) - : "0" (__NR_clock_gettime), "g" (clock), "c" (ts) + : "=a" (ret), "=m" (*ts) + : "0" (__NR_clock_gettime), [clock] "g" (clock), "c" (ts) : "memory", "edx"); return ret; } @@ -151,13 +153,13 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) { long ret; - asm( + asm ( "mov %%ebx, %%edx \n" - "mov %2, %%ebx \n" + "mov %[tv], %%ebx \n" "call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" - : "=a" (ret) - : "0" (__NR_gettimeofday), "g" (tv), "c" (tz) + : "=a" (ret), "=m" (*tv), "=m" (*tz) + : "0" (__NR_gettimeofday), [tv] "g" (tv), "c" (tz) : "memory", "edx"); return ret; } diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 039d4e14194d26c952fbfc520f48ecac37121d3c..196f9302cfcf76c5c1f2c587213315c94ce2d9a8 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1246,8 +1246,6 @@ void xen_flush_tlb_all(void) struct mmuext_op *op; struct multicall_space mcs; - trace_xen_mmu_flush_tlb_all(0); - preempt_disable(); mcs = xen_mc_entry(sizeof(*op)); @@ -1265,8 +1263,6 @@ static void xen_flush_tlb(void) struct mmuext_op *op; struct multicall_space mcs; - trace_xen_mmu_flush_tlb(0); - preempt_disable(); mcs = xen_mc_entry(sizeof(*op)); diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h index b39531babec03e778e53c481d8b7b5374c67449a..72bfc1cbc2b546578d902866d76256fffa7451fe 100644 --- a/arch/xtensa/include/asm/futex.h +++ b/arch/xtensa/include/asm/futex.h @@ -109,7 +109,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { int ret = 0; - u32 prev; if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; @@ -120,26 +119,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, __asm__ __volatile__ ( " # futex_atomic_cmpxchg_inatomic\n" - "1: l32i %1, %3, 0\n" - " mov %0, %5\n" - " wsr %1, scompare1\n" - "2: s32c1i %0, %3, 0\n" - "3:\n" + " wsr %5, scompare1\n" + "1: s32c1i %1, %4, 0\n" + " s32i %1, %6, 0\n" + "2:\n" " .section .fixup,\"ax\"\n" " .align 4\n" - "4: .long 3b\n" - "5: l32r %1, 4b\n" - " movi %0, %6\n" + "3: .long 2b\n" + "4: l32r %1, 3b\n" + " movi %0, %7\n" " jx %1\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .long 1b,5b,2b,5b\n" + " .long 1b,4b\n" " .previous\n" - : "+r" (ret), "=&r" (prev), "+m" (*uaddr) - : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT) + : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval) + : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT) : "memory"); - *uval = prev; return ret; } diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index 9d2f45f010ef7e9448e3837e873b617f0a493b23..148985f3cc5b5cdad3c5ad4b5c9ad71ddf804834 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -280,7 +280,7 @@ do_unaligned_user (struct pt_regs *regs) info.si_errno = 0; info.si_code = BUS_ADRALN; info.si_addr = (void *) regs->excvaddr; - force_sig_info(SIGSEGV, &info, current); + force_sig_info(SIGBUS, &info, current); } #endif diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 5cbd5d9ea61dd52969d9c55313dbf703f3c4d24f..d9f4b3caaa41baeb67089b9901bd545a92b3671d 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -165,6 +165,9 @@ bool bio_integrity_enabled(struct bio *bio) if (!bio_is_rw(bio)) return false; + if (!bio_sectors(bio)) + return false; + /* Already protected? */ if (bio_integrity(bio)) return false; diff --git a/block/bio.c b/block/bio.c index 92304d50114e76dc4bf8f18d5148c2d32db5c20a..91be29db270cb6a1ae56572046bc331f0da668df 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1339,6 +1339,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q, offset = uaddr & ~PAGE_MASK; for (j = cur_page; j < page_limit; j++) { unsigned int bytes = PAGE_SIZE - offset; + unsigned short prev_bi_vcnt = bio->bi_vcnt; if (len <= 0) break; @@ -1353,6 +1354,13 @@ static struct bio *__bio_map_user_iov(struct request_queue *q, bytes) break; + /* + * check if vector was merged with previous + * drop page reference if needed + */ + if (bio->bi_vcnt == prev_bi_vcnt) + put_page(pages[j]); + len -= bytes; offset = 0; } diff --git a/block/blk-core.c b/block/blk-core.c index 27831507f34c81886b193ada167956880e26abbb..710f99a5063a8a029fdc1d8f37b477ea52e1b73d 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -196,7 +196,7 @@ EXPORT_SYMBOL(blk_delay_queue); **/ void blk_start_queue(struct request_queue *q) { - WARN_ON(!irqs_disabled()); + WARN_ON(!in_interrupt() && !irqs_disabled()); queue_flag_clear(QUEUE_FLAG_STOPPED, q); __blk_run_queue(q); @@ -3374,76 +3374,43 @@ int __init blk_dev_init(void) * TODO : If necessary, we can make the histograms per-cpu and aggregate * them when printing them out. */ -void -blk_zero_latency_hist(struct io_latency_state *s) -{ - memset(s->latency_y_axis_read, 0, - sizeof(s->latency_y_axis_read)); - memset(s->latency_y_axis_write, 0, - sizeof(s->latency_y_axis_write)); - s->latency_reads_elems = 0; - s->latency_writes_elems = 0; -} -EXPORT_SYMBOL(blk_zero_latency_hist); - ssize_t -blk_latency_hist_show(struct io_latency_state *s, char *buf) +blk_latency_hist_show(char* name, struct io_latency_state *s, char *buf, + int buf_size) { int i; int bytes_written = 0; u_int64_t num_elem, elem; int pct; - - num_elem = s->latency_reads_elems; - if (num_elem > 0) { - bytes_written += scnprintf(buf + bytes_written, - PAGE_SIZE - bytes_written, - "IO svc_time Read Latency Histogram (n = %llu):\n", - num_elem); - for (i = 0; - i < ARRAY_SIZE(latency_x_axis_us); - i++) { - elem = s->latency_y_axis_read[i]; - pct = div64_u64(elem * 100, num_elem); - bytes_written += scnprintf(buf + bytes_written, - PAGE_SIZE - bytes_written, - "\t< %5lluus%15llu%15d%%\n", - latency_x_axis_us[i], - elem, pct); - } - /* Last element in y-axis table is overflow */ - elem = s->latency_y_axis_read[i]; - pct = div64_u64(elem * 100, num_elem); - bytes_written += scnprintf(buf + bytes_written, - PAGE_SIZE - bytes_written, - "\t> %5dms%15llu%15d%%\n", 10, - elem, pct); - } - num_elem = s->latency_writes_elems; - if (num_elem > 0) { - bytes_written += scnprintf(buf + bytes_written, - PAGE_SIZE - bytes_written, - "IO svc_time Write Latency Histogram (n = %llu):\n", - num_elem); - for (i = 0; - i < ARRAY_SIZE(latency_x_axis_us); - i++) { - elem = s->latency_y_axis_write[i]; - pct = div64_u64(elem * 100, num_elem); - bytes_written += scnprintf(buf + bytes_written, - PAGE_SIZE - bytes_written, - "\t< %5lluus%15llu%15d%%\n", - latency_x_axis_us[i], - elem, pct); - } - /* Last element in y-axis table is overflow */ - elem = s->latency_y_axis_write[i]; - pct = div64_u64(elem * 100, num_elem); - bytes_written += scnprintf(buf + bytes_written, - PAGE_SIZE - bytes_written, - "\t> %5dms%15llu%15d%%\n", 10, - elem, pct); + u_int64_t average; + + num_elem = s->latency_elems; + if (num_elem > 0) { + average = div64_u64(s->latency_sum, s->latency_elems); + bytes_written += scnprintf(buf + bytes_written, + buf_size - bytes_written, + "IO svc_time %s Latency Histogram (n = %llu," + " average = %llu):\n", name, num_elem, average); + for (i = 0; + i < ARRAY_SIZE(latency_x_axis_us); + i++) { + elem = s->latency_y_axis[i]; + pct = div64_u64(elem * 100, num_elem); + bytes_written += scnprintf(buf + bytes_written, + PAGE_SIZE - bytes_written, + "\t< %6lluus%15llu%15d%%\n", + latency_x_axis_us[i], + elem, pct); + } + /* Last element in y-axis table is overflow */ + elem = s->latency_y_axis[i]; + pct = div64_u64(elem * 100, num_elem); + bytes_written += scnprintf(buf + bytes_written, + PAGE_SIZE - bytes_written, + "\t>=%6lluus%15llu%15d%%\n", + latency_x_axis_us[i - 1], elem, pct); } + return bytes_written; } EXPORT_SYMBOL(blk_latency_hist_show); diff --git a/block/blk-flush.c b/block/blk-flush.c index 10679fe62c8c30047ff7749da13e66bafa9eb1d3..d9a005037179d2ef328894fb3322a7b7e0155da2 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -112,6 +112,7 @@ #include "blk.h" #include "blk-mq.h" +#include "blk-mq-tag.h" /* FLUSH/FUA sequences */ enum { @@ -283,7 +284,12 @@ static void flush_end_io(struct request *flush_rq, int error) struct blk_flush_queue *fq = blk_get_flush_queue(q, flush_rq->mq_ctx); if (q->mq_ops) { + struct blk_mq_hw_ctx *hctx; + + /* release the tag's ownership to the req cloned from */ spin_lock_irqsave(&fq->mq_flush_lock, flags); + hctx = q->mq_ops->map_queue(q, flush_rq->mq_ctx->cpu); + blk_mq_tag_set_rq(hctx, flush_rq->tag, fq->orig_rq); flush_rq->tag = -1; } @@ -366,11 +372,18 @@ static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq) /* * Borrow tag from the first request since they can't - * be in flight at the same time. + * be in flight at the same time. And acquire the tag's + * ownership for flush req. */ if (q->mq_ops) { + struct blk_mq_hw_ctx *hctx; + flush_rq->mq_ctx = first_rq->mq_ctx; flush_rq->tag = first_rq->tag; + fq->orig_rq = first_rq; + + hctx = q->mq_ops->map_queue(q, first_rq->mq_ctx->cpu); + blk_mq_tag_set_rq(hctx, first_rq->tag, flush_rq); } flush_rq->cmd_type = REQ_TYPE_FS; diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 702ae29b8d90ff820aa3bc47a3f0c0cd535d1d55..4fbc8d563777fc5128e1c9b03d4551f0fa1387da 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -403,7 +403,7 @@ static void bt_for_each(struct blk_mq_hw_ctx *hctx, for (bit = find_first_bit(&bm->word, bm->depth); bit < bm->depth; bit = find_next_bit(&bm->word, bm->depth, bit + 1)) { - rq = blk_mq_tag_to_rq(hctx->tags, off + bit); + rq = hctx->tags->rqs[off + bit]; if (rq->q == hctx->queue) fn(hctx, rq, data, reserved); } diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h index 6206ed17ef766714b655a715ffbc05fd34b0463a..14c6e4c925564c829d6dcde73a84060146139c36 100644 --- a/block/blk-mq-tag.h +++ b/block/blk-mq-tag.h @@ -85,4 +85,16 @@ static inline void blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx) __blk_mq_tag_idle(hctx); } +/* + * This helper should only be used for flush request to share tag + * with the request cloned from, and both the two requests can't be + * in flight at the same time. The caller has to make sure the tag + * can't be freed. + */ +static inline void blk_mq_tag_set_rq(struct blk_mq_hw_ctx *hctx, + unsigned int tag, struct request *rq) +{ + hctx->tags->rqs[tag] = rq; +} + #endif diff --git a/block/blk-mq.c b/block/blk-mq.c index 444e84bea39d43e9bc364b4a1ed789d0f256f2c1..647ec3538d273fc4c2d61312bb998d643d924387 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -498,23 +498,9 @@ void blk_mq_kick_requeue_list(struct request_queue *q) } EXPORT_SYMBOL(blk_mq_kick_requeue_list); -static inline bool is_flush_request(struct request *rq, - struct blk_flush_queue *fq, unsigned int tag) -{ - return ((rq->cmd_flags & REQ_FLUSH_SEQ) && - fq->flush_rq->tag == tag); -} - struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag) { - struct request *rq = tags->rqs[tag]; - /* mq_ctx of flush rq is always cloned from the corresponding req */ - struct blk_flush_queue *fq = blk_get_flush_queue(rq->q, rq->mq_ctx); - - if (!is_flush_request(rq, fq, tag)) - return rq; - - return fq->flush_rq; + return tags->rqs[tag]; } EXPORT_SYMBOL(blk_mq_tag_to_rq); diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 5b9c6d5c3636ad6412c7b898c44e4709b35597d1..fd51c8be247d476b0f7bdf8f97df968571c8d7d6 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -648,6 +648,17 @@ static void throtl_dequeue_tg(struct throtl_grp *tg) static void throtl_schedule_pending_timer(struct throtl_service_queue *sq, unsigned long expires) { + unsigned long max_expire = jiffies + 8 * throtl_slice; + + /* + * Since we are adjusting the throttle limit dynamically, the sleep + * time calculated according to previous limit might be invalid. It's + * possible the cgroup sleep time is very long and no other cgroups + * have IO running so notify the limit changes. Make sure the cgroup + * doesn't sleep too long to avoid the missed notification. + */ + if (time_after(expires, max_expire)) + expires = max_expire; mod_timer(&sq->pending_timer, expires); throtl_log(sq, "schedule timer. delay=%lu jiffies=%lu", expires - jiffies, jiffies); diff --git a/block/blk.h b/block/blk.h index 39471974401c549e3988ffcd7b6f5059a803a21b..a9cd7d987d54fda7939c1d21b0403469ab09682a 100644 --- a/block/blk.h +++ b/block/blk.h @@ -22,6 +22,12 @@ struct blk_flush_queue { struct list_head flush_queue[2]; struct list_head flush_data_in_flight; struct request *flush_rq; + + /* + * flush_rq shares tag with this rq, both can't be active + * at the same time + */ + struct request *orig_rq; spinlock_t mq_flush_lock; }; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index ad7c85eb5c47215bbc73348fd81a706aaf0ea16a..2f077c3c5bcb154a7b6566a85f79a80e9c075fcb 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -2828,7 +2828,6 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq) if (time_before(jiffies, rq->fifo_time)) rq = NULL; - cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq); return rq; } @@ -3202,6 +3201,9 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq) { unsigned int max_dispatch; + if (cfq_cfqq_must_dispatch(cfqq)) + return true; + /* * Drain async requests before we start sync IO */ @@ -3293,15 +3295,20 @@ static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq) BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list)); + rq = cfq_check_fifo(cfqq); + if (rq) + cfq_mark_cfqq_must_dispatch(cfqq); + if (!cfq_may_dispatch(cfqd, cfqq)) return false; /* * follow expired path, else get first next available */ - rq = cfq_check_fifo(cfqq); if (!rq) rq = cfqq->next_rq; + else + cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq); /* * insert request into driver dispatch list @@ -3810,7 +3817,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, * if the new request is sync, but the currently running queue is * not, let the sync request have priority. */ - if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq)) + if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq) && !cfq_cfqq_must_dispatch(cfqq)) return true; if (new_cfqq->cfqg != cfqq->cfqg) diff --git a/block/partition-generic.c b/block/partition-generic.c index 47284e7126503ced01b47adc6bada024bf258e09..9f7d967516a63c46ccffc2b08c3998956ecf366e 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -320,8 +320,10 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, if (info) { struct partition_meta_info *pinfo = alloc_part_info(disk); - if (!pinfo) + if (!pinfo) { + err = -ENOMEM; goto out_free_stats; + } memcpy(pinfo, info, sizeof(*info)); p->info = pinfo; } diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 56d08fd75b1a9511152eb120b6439f4afe01a00a..8de885e1e0c6e27a11462ccfb95754835a0ab610 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -293,7 +293,7 @@ static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, if (!gpt) return NULL; - count = le32_to_cpu(gpt->num_partition_entries) * + count = (size_t)le32_to_cpu(gpt->num_partition_entries) * le32_to_cpu(gpt->sizeof_partition_entry); if (!count) return NULL; @@ -352,7 +352,7 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, gpt_header **gpt, gpt_entry **ptes) { u32 crc, origcrc; - u64 lastlba; + u64 lastlba, pt_size; if (!ptes) return 0; @@ -434,13 +434,20 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, goto fail; } + /* Sanity check partition table size */ + pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) * + le32_to_cpu((*gpt)->sizeof_partition_entry); + if (pt_size > KMALLOC_MAX_SIZE) { + pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n", + (unsigned long long)pt_size, KMALLOC_MAX_SIZE); + goto fail; + } + if (!(*ptes = alloc_read_gpt_entries(state, *gpt))) goto fail; /* Check the GUID Partition Entry Array CRC */ - crc = efi_crc32((const unsigned char *) (*ptes), - le32_to_cpu((*gpt)->num_partition_entries) * - le32_to_cpu((*gpt)->sizeof_partition_entry)); + crc = efi_crc32((const unsigned char *) (*ptes), pt_size); if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { pr_debug("GUID Partitition Entry Array CRC check failed.\n"); diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c index 5610cd537da78812e2633d76ca90e5c3fb66e7cc..7d8d50c11ce779b55d55984523cf1c2ae35cc5e1 100644 --- a/block/partitions/msdos.c +++ b/block/partitions/msdos.c @@ -300,7 +300,9 @@ static void parse_bsd(struct parsed_partitions *state, continue; bsd_start = le32_to_cpu(p->p_offset); bsd_size = le32_to_cpu(p->p_size); - if (memcmp(flavour, "bsd\0", 4) == 0) + /* FreeBSD has relative offset if C partition offset is zero */ + if (memcmp(flavour, "bsd\0", 4) == 0 && + le32_to_cpu(l->d_partitions[2].p_offset) == 0) bsd_start += offset; if (offset == bsd_start && size == bsd_size) /* full parent partition, we have it already */ diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 new file mode 100644 index 0000000000000000000000000000000000000000..753a7155ed9ccd50f157a9c7096e91e403c6bd7c --- /dev/null +++ b/build.config.cuttlefish.x86_64 @@ -0,0 +1,14 @@ +ARCH=x86_64 +BRANCH=android-3.18 +CROSS_COMPILE=x86_64-linux-androidkernel- +DEFCONFIG=x86_64_cuttlefish_defconfig +EXTRA_CMDS='' +KERNEL_DIR=common +POST_DEFCONFIG_CMDS="check_defconfig" +LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin +FILES=" +arch/x86/boot/bzImage +vmlinux +System.map +" +STOP_SHIP_TRACEPRINTK=1 diff --git a/crypto/Kconfig b/crypto/Kconfig index 8e8fda3dc0a0bd75f657cafc433f690ad891a5ee..bb61d20878cde682746a9fe3cc25c578c8ebfa30 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -590,6 +590,15 @@ config CRYPTO_SHA256_SPARC64 SHA-256 secure hash standard (DFIPS 180-2) implemented using sparc64 crypto instructions, when available. +config CRYPTO_SHA2_ARM_CE + tristate "SHA-224/256 digest algorithm (ARM v8 Crypto Extensions)" + depends on ARM && KERNEL_MODE_NEON + select CRYPTO_SHA256 + select CRYPTO_HASH + help + SHA-256 secure hash standard (DFIPS 180-2) implemented + using special ARMv8 Crypto Extensions. + config CRYPTO_SHA512 tristate "SHA384 and SHA512 digest algorithms" select CRYPTO_HASH @@ -773,6 +782,55 @@ config CRYPTO_AES_SPARC64 for some popular block cipher mode is supported too, including ECB and CBC. +config CRYPTO_AES_ARM + tristate "AES cipher algorithms (ARM-asm)" + depends on ARM + select CRYPTO_ALGAPI + select CRYPTO_AES + help + Use optimized AES assembler routines for ARM platforms. + + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. + + Rijndael appears to be consistently a very good performer in + both hardware and software across a wide range of computing + environments regardless of its use in feedback or non-feedback + modes. Its key setup time is excellent, and its key agility is + good. Rijndael's very low memory requirements make it very well + suited for restricted-space environments, in which it also + demonstrates excellent performance. Rijndael's operations are + among the easiest to defend against power and timing attacks. + + The AES specifies three key sizes: 128, 192 and 256 bits + + See for more information. + +config CRYPTO_AES_ARM_BS + tristate "Bit sliced AES using NEON instructions" + depends on ARM && KERNEL_MODE_NEON + select CRYPTO_ALGAPI + select CRYPTO_AES_ARM + select CRYPTO_ABLK_HELPER + help + Use a faster and more secure NEON based implementation of AES in CBC, + CTR and XTS modes + + Bit sliced AES gives around 45% speedup on Cortex-A15 for CTR mode + and for XTS mode encryption, CBC and XTS mode decryption speedup is + around 25%. (CBC encryption speed is not affected by this driver.) + This implementation does not rely on any lookup tables so it is + believed to be invulnerable to cache timing attacks. + +config CRYPTO_AES_ARM_CE + tristate "Accelerated AES using ARMv8 Crypto Extensions" + depends on ARM && KERNEL_MODE_NEON + select CRYPTO_ALGAPI + select CRYPTO_ABLK_HELPER + help + Use an implementation of AES in CBC, CTR and XTS modes that uses + ARMv8 Crypto Extensions + config CRYPTO_ANUBIS tristate "Anubis cipher algorithm" select CRYPTO_ALGAPI @@ -1188,6 +1246,27 @@ config CRYPTO_SERPENT_AVX2_X86_64 See also: +config CRYPTO_SPECK + tristate "Speck cipher algorithm" + select CRYPTO_ALGAPI + help + Speck is a lightweight block cipher that is tuned for optimal + performance in software (rather than hardware). + + Speck may not be as secure as AES, and should only be used on systems + where AES is not fast enough. + + See also: + + If unsure, say N. + +config CRYPTO_SPECK_NEON + tristate "NEON accelerated Speck cipher algorithms" + depends on ARM && KERNEL_MODE_NEON + select CRYPTO_BLKCIPHER + select CRYPTO_GF128MUL + select CRYPTO_SPECK + config CRYPTO_TEA tristate "TEA, XTEA and XETA cipher algorithms" select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index ea11cf871ebcdad3e3e6e40c41abe3caa9ae9662..c1de48157dc471058a33c0e20617efeb3fcb6091 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o obj-$(CONFIG_CRYPTO_SEED) += seed.o +obj-$(CONFIG_CRYPTO_SPECK) += speck.o obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 520729d898fe156fdf0bb846d29632c496955c43..cad66af5a1ae26896e79a96af60bb784a4bf2436 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -72,11 +72,9 @@ static inline u8 *ablkcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk, - unsigned int bsize) +static inline void ablkcipher_done_slow(struct ablkcipher_walk *walk, + unsigned int n) { - unsigned int n = bsize; - for (;;) { unsigned int len_this_page = scatterwalk_pagelen(&walk->out); @@ -88,17 +86,13 @@ static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk, n -= len_this_page; scatterwalk_start(&walk->out, scatterwalk_sg_next(walk->out.sg)); } - - return bsize; } -static inline unsigned int ablkcipher_done_fast(struct ablkcipher_walk *walk, - unsigned int n) +static inline void ablkcipher_done_fast(struct ablkcipher_walk *walk, + unsigned int n) { scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); - - return n; } static int ablkcipher_walk_next(struct ablkcipher_request *req, @@ -108,39 +102,40 @@ int ablkcipher_walk_done(struct ablkcipher_request *req, struct ablkcipher_walk *walk, int err) { struct crypto_tfm *tfm = req->base.tfm; - unsigned int nbytes = 0; + unsigned int n; /* bytes processed */ + bool more; - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; + if (unlikely(err < 0)) + goto finish; - if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) - n = ablkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = ablkcipher_done_slow(walk, n); + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total != 0); - nbytes = walk->total - n; - err = 0; + if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) { + ablkcipher_done_fast(walk, n); + } else { + if (WARN_ON(err)) { + /* unexpected case; didn't process all bytes */ + err = -EINVAL; + goto finish; + } + ablkcipher_done_slow(walk, n); } - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; + scatterwalk_done(&walk->in, 0, more); + scatterwalk_done(&walk->out, 1, more); - if (nbytes) { + if (more) { crypto_yield(req->base.flags); return ablkcipher_walk_next(req, walk); } - + err = 0; +finish: + walk->nbytes = 0; if (walk->iv != req->info) memcpy(req->info, walk->iv, tfm->crt_ablkcipher.ivsize); kfree(walk->iv_buffer); - return err; } EXPORT_SYMBOL_GPL(ablkcipher_walk_done); @@ -387,6 +382,7 @@ static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) strncpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type)); strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "", sizeof(rblkcipher.geniv)); + rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0'; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize; @@ -468,6 +464,7 @@ static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg) strncpy(rblkcipher.type, "givcipher", sizeof(rblkcipher.type)); strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "", sizeof(rblkcipher.geniv)); + rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0'; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize; diff --git a/crypto/ahash.c b/crypto/ahash.c index a11220e78152afb61781f0a420e28e7e5fd2a426..6ae2b2fd72bac79f7e29fbd3ed8d2d2a54c47d2e 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -90,13 +90,14 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) if (nbytes && walk->offset & alignmask && !err) { walk->offset = ALIGN(walk->offset, alignmask + 1); - walk->data += walk->offset; - nbytes = min(nbytes, ((unsigned int)(PAGE_SIZE)) - walk->offset); walk->entrylen -= nbytes; - return nbytes; + if (nbytes) { + walk->data += walk->offset; + return nbytes; + } } if (walk->flags & CRYPTO_ALG_ASYNC) @@ -636,5 +637,16 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(ahash_attr_alg); +bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg) +{ + struct crypto_alg *alg = &halg->base; + + if (alg->cra_type != &crypto_ahash_type) + return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg)); + + return __crypto_ahash_alg(alg)->setkey != NULL; +} +EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); diff --git a/crypto/algapi.c b/crypto/algapi.c index 314cc745f2f805de8cb218625e9b69410b2d6c32..bfa509412edf3389ebcd6418cb0c67af903d77a5 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -159,6 +159,18 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, spawn->alg = NULL; spawns = &inst->alg.cra_users; + + /* + * We may encounter an unregistered instance here, since + * an instance's spawns are set up prior to the instance + * being registered. An unregistered instance will have + * NULL ->cra_users.next, since ->cra_users isn't + * properly initialized until registration. But an + * unregistered instance cannot have any users, so treat + * it the same as ->cra_users being empty. + */ + if (spawns->next == NULL) + break; } } while ((spawns = crypto_more_spawns(alg, &stack, &top, &secondary_spawns))); diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index cbbccfdae1600eb837feb2c40c0471c1b7b798eb..110970be07165c1c5d3c0feb87b83e7271c5b09c 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -92,8 +92,10 @@ static int skcipher_alloc_sgl(struct sock *sk) sg_init_table(sgl->sg, MAX_SGL_ENTS + 1); sgl->cur = 0; - if (sg) + if (sg) { scatterwalk_sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg); + sg_unmark_end(sg + (MAX_SGL_ENTS - 1)); + } list_add_tail(&sgl->list, &ctx->tsgl); } @@ -446,7 +448,6 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, char __user *from = iov->iov_base; while (seglen) { - used = ctx->used; if (!used) { err = skcipher_wait_for_data(sk, flags); @@ -467,8 +468,9 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, err = -EINVAL; if (!used) goto free; + sgl = list_first_entry(&ctx->tsgl, - struct skcipher_sg_list, list); + struct skcipher_sg_list, list); sg = sgl->sg; while (!sg->length) diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index a668d90302d38c541fb5a78aa5442019cc739b21..4c4f4c936063950a16186ee8929d1fc469a8835f 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -381,6 +381,8 @@ int x509_extract_key_data(void *context, size_t hdrlen, ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA; /* Discard the BIT STRING metadata */ + if (vlen < 1 || *(const u8 *)value != 0) + return -EBADMSG; ctx->key = value + 1; ctx->key_size = vlen - 1; return 0; diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c index d05327caf69dbc18532478b122ea9834e67f1fd9..c09a51dbe59eb500a8690d2b9334acf769cbf20b 100644 --- a/crypto/async_tx/async_pq.c +++ b/crypto/async_tx/async_pq.c @@ -62,9 +62,6 @@ do_async_gen_syndrome(struct dma_chan *chan, dma_addr_t dma_dest[2]; int src_off = 0; - if (submit->flags & ASYNC_TX_FENCE) - dma_flags |= DMA_PREP_FENCE; - while (src_cnt > 0) { submit->flags = flags_orig; pq_src_cnt = min(src_cnt, dma_maxpq(dma, dma_flags)); @@ -83,6 +80,8 @@ do_async_gen_syndrome(struct dma_chan *chan, if (cb_fn_orig) dma_flags |= DMA_PREP_INTERRUPT; } + if (submit->flags & ASYNC_TX_FENCE) + dma_flags |= DMA_PREP_FENCE; /* Drivers force forward progress in case they can not provide * a descriptor diff --git a/crypto/authenc.c b/crypto/authenc.c index 78fb16cab13f9660553a0705941608ec3a59d88a..eb029ea72f98efcd7d20ab4e7cf31d1a23102d85 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -112,6 +112,7 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 024bff2344fcff9d0ae3af5c04b4a75280dd2d4a..c248a966aa5bb7bd0ec8f654c28c18b51dab5204 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -86,6 +86,7 @@ static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 * CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index f25799f351f722b8ea48280458ebe18161b617e8..5ba9916a33c8a6d719f67707c1fb70baf8dc2c20 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -70,19 +70,18 @@ static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk, - unsigned int bsize) +static inline void blkcipher_done_slow(struct blkcipher_walk *walk, + unsigned int bsize) { u8 *addr; addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); addr = blkcipher_get_spot(addr, bsize); scatterwalk_copychunks(addr, &walk->out, bsize, 1); - return bsize; } -static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, - unsigned int n) +static inline void blkcipher_done_fast(struct blkcipher_walk *walk, + unsigned int n) { if (walk->flags & BLKCIPHER_WALK_COPY) { blkcipher_map_dst(walk); @@ -96,49 +95,48 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); - - return n; } int blkcipher_walk_done(struct blkcipher_desc *desc, struct blkcipher_walk *walk, int err) { - unsigned int nbytes = 0; + unsigned int n; /* bytes processed */ + bool more; - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; + if (unlikely(err < 0)) + goto finish; - if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) - n = blkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = blkcipher_done_slow(walk, n); + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total != 0); - nbytes = walk->total - n; - err = 0; + if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) { + blkcipher_done_fast(walk, n); + } else { + if (WARN_ON(err)) { + /* unexpected case; didn't process all bytes */ + err = -EINVAL; + goto finish; + } + blkcipher_done_slow(walk, n); } - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; + scatterwalk_done(&walk->in, 0, more); + scatterwalk_done(&walk->out, 1, more); - if (nbytes) { + if (more) { crypto_yield(desc->flags); return blkcipher_walk_next(desc, walk); } - + err = 0; +finish: + walk->nbytes = 0; if (walk->iv != desc->info) memcpy(desc->info, walk->iv, walk->ivsize); if (walk->buffer != walk->page) kfree(walk->buffer); if (walk->page) free_page((unsigned long)walk->page); - return err; } EXPORT_SYMBOL_GPL(blkcipher_walk_done); @@ -516,6 +514,7 @@ static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) strncpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type)); strncpy(rblkcipher.geniv, alg->cra_blkcipher.geniv ?: "", sizeof(rblkcipher.geniv)); + rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0'; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = alg->cra_blkcipher.min_keysize; diff --git a/crypto/cryptd.c b/crypto/cryptd.c index fb0d140065e23c7bb7f2bfca5463243b9f9d10c9..828ead458c09ef62a407fdbf26477e78d6f7e090 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -618,7 +618,8 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, inst->alg.finup = cryptd_hash_finup_enqueue; inst->alg.export = cryptd_hash_export; inst->alg.import = cryptd_hash_import; - inst->alg.setkey = cryptd_hash_setkey; + if (crypto_shash_alg_has_setkey(salg)) + inst->alg.setkey = cryptd_hash_setkey; inst->alg.digest = cryptd_hash_digest_enqueue; err = ahash_register_instance(tmpl, inst); diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c index 02a1c10fa9099162746878f9fce6b1ad215ffc10..8cd2bc32c7fb59333f477d2278f130d99e25b5e6 100644 --- a/crypto/mcryptd.c +++ b/crypto/mcryptd.c @@ -80,6 +80,7 @@ static int mcryptd_init_queue(struct mcryptd_queue *queue, pr_debug("cpu_queue #%d %p\n", cpu, queue->cpu_queue); crypto_init_queue(&cpu_queue->queue, max_cpu_qlen); INIT_WORK(&cpu_queue->work, mcryptd_queue_worker); + spin_lock_init(&cpu_queue->q_lock); } return 0; } @@ -103,15 +104,16 @@ static int mcryptd_enqueue_request(struct mcryptd_queue *queue, int cpu, err; struct mcryptd_cpu_queue *cpu_queue; - cpu = get_cpu(); - cpu_queue = this_cpu_ptr(queue->cpu_queue); - rctx->tag.cpu = cpu; + cpu_queue = raw_cpu_ptr(queue->cpu_queue); + spin_lock(&cpu_queue->q_lock); + cpu = smp_processor_id(); + rctx->tag.cpu = smp_processor_id(); err = crypto_enqueue_request(&cpu_queue->queue, request); pr_debug("enqueue request: cpu %d cpu_queue %p request %p\n", cpu, cpu_queue, request); + spin_unlock(&cpu_queue->q_lock); queue_work_on(cpu, kcrypto_wq, &cpu_queue->work); - put_cpu(); return err; } @@ -164,16 +166,11 @@ static void mcryptd_queue_worker(struct work_struct *work) cpu_queue = container_of(work, struct mcryptd_cpu_queue, work); i = 0; while (i < MCRYPTD_BATCH || single_task_running()) { - /* - * preempt_disable/enable is used to prevent - * being preempted by mcryptd_enqueue_request() - */ - local_bh_disable(); - preempt_disable(); + + spin_lock_bh(&cpu_queue->q_lock); backlog = crypto_get_backlog(&cpu_queue->queue); req = crypto_dequeue_request(&cpu_queue->queue); - preempt_enable(); - local_bh_enable(); + spin_unlock_bh(&cpu_queue->q_lock); if (!req) { mcryptd_opportunistic_flush(); @@ -188,7 +185,7 @@ static void mcryptd_queue_worker(struct work_struct *work) ++i; } if (cpu_queue->queue.qlen) - queue_work(kcrypto_wq, &cpu_queue->work); + queue_work_on(smp_processor_id(), kcrypto_wq, &cpu_queue->work); } void mcryptd_flusher(struct work_struct *__work) diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index f550b5d9463074b16670129341de59e069f8509c..d7da0eea5622af96f63300ad45c35450951551e1 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -188,13 +188,6 @@ static int encrypt(struct blkcipher_desc *desc, salsa20_ivsetup(ctx, walk.iv); - if (likely(walk.nbytes == nbytes)) - { - salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, - walk.src.virt.addr, nbytes); - return blkcipher_walk_done(desc, &walk, 0); - } - while (walk.nbytes >= 64) { salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, walk.src.virt.addr, diff --git a/crypto/shash.c b/crypto/shash.c index 4ac57f5694fc817e106ef460cd2bb33bed28e8e3..73c065321867193fff1145f75cd39b55a99e9b6e 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -275,12 +275,14 @@ static int shash_async_finup(struct ahash_request *req) int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) { - struct scatterlist *sg = req->src; - unsigned int offset = sg->offset; unsigned int nbytes = req->nbytes; + struct scatterlist *sg; + unsigned int offset; int err; - if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { + if (nbytes && + (sg = req->src, offset = sg->offset, + nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) { void *data; data = kmap_atomic(sg_page(sg)); diff --git a/crypto/speck.c b/crypto/speck.c new file mode 100644 index 0000000000000000000000000000000000000000..58aa9f7f91f791e58ccc7e2e1ed54de5134ccce2 --- /dev/null +++ b/crypto/speck.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Speck: a lightweight block cipher + * + * Copyright (c) 2018 Google, Inc + * + * Speck has 10 variants, including 5 block sizes. For now we only implement + * the variants Speck128/128, Speck128/192, Speck128/256, Speck64/96, and + * Speck64/128. Speck${B}/${K} denotes the variant with a block size of B bits + * and a key size of K bits. The Speck128 variants are believed to be the most + * secure variants, and they use the same block size and key sizes as AES. The + * Speck64 variants are less secure, but on 32-bit processors are usually + * faster. The remaining variants (Speck32, Speck48, and Speck96) are even less + * secure and/or not as well suited for implementation on either 32-bit or + * 64-bit processors, so are omitted. + * + * Reference: "The Simon and Speck Families of Lightweight Block Ciphers" + * https://eprint.iacr.org/2013/404.pdf + * + * In a correspondence, the Speck designers have also clarified that the words + * should be interpreted in little-endian format, and the words should be + * ordered such that the first word of each block is 'y' rather than 'x', and + * the first key word (rather than the last) becomes the first round key. + */ + +#include +#include +#include +#include +#include +#include + +/* Speck128 */ + +static __always_inline void speck128_round(u64 *x, u64 *y, u64 k) +{ + *x = ror64(*x, 8); + *x += *y; + *x ^= k; + *y = rol64(*y, 3); + *y ^= *x; +} + +static __always_inline void speck128_unround(u64 *x, u64 *y, u64 k) +{ + *y ^= *x; + *y = ror64(*y, 3); + *x ^= k; + *x -= *y; + *x = rol64(*x, 8); +} + +void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx, + u8 *out, const u8 *in) +{ + u64 y = get_unaligned_le64(in); + u64 x = get_unaligned_le64(in + 8); + int i; + + for (i = 0; i < ctx->nrounds; i++) + speck128_round(&x, &y, ctx->round_keys[i]); + + put_unaligned_le64(y, out); + put_unaligned_le64(x, out + 8); +} +EXPORT_SYMBOL_GPL(crypto_speck128_encrypt); + +static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + crypto_speck128_encrypt(crypto_tfm_ctx(tfm), out, in); +} + +void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx, + u8 *out, const u8 *in) +{ + u64 y = get_unaligned_le64(in); + u64 x = get_unaligned_le64(in + 8); + int i; + + for (i = ctx->nrounds - 1; i >= 0; i--) + speck128_unround(&x, &y, ctx->round_keys[i]); + + put_unaligned_le64(y, out); + put_unaligned_le64(x, out + 8); +} +EXPORT_SYMBOL_GPL(crypto_speck128_decrypt); + +static void speck128_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + crypto_speck128_decrypt(crypto_tfm_ctx(tfm), out, in); +} + +int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key, + unsigned int keylen) +{ + u64 l[3]; + u64 k; + int i; + + switch (keylen) { + case SPECK128_128_KEY_SIZE: + k = get_unaligned_le64(key); + l[0] = get_unaligned_le64(key + 8); + ctx->nrounds = SPECK128_128_NROUNDS; + for (i = 0; i < ctx->nrounds; i++) { + ctx->round_keys[i] = k; + speck128_round(&l[0], &k, i); + } + break; + case SPECK128_192_KEY_SIZE: + k = get_unaligned_le64(key); + l[0] = get_unaligned_le64(key + 8); + l[1] = get_unaligned_le64(key + 16); + ctx->nrounds = SPECK128_192_NROUNDS; + for (i = 0; i < ctx->nrounds; i++) { + ctx->round_keys[i] = k; + speck128_round(&l[i % 2], &k, i); + } + break; + case SPECK128_256_KEY_SIZE: + k = get_unaligned_le64(key); + l[0] = get_unaligned_le64(key + 8); + l[1] = get_unaligned_le64(key + 16); + l[2] = get_unaligned_le64(key + 24); + ctx->nrounds = SPECK128_256_NROUNDS; + for (i = 0; i < ctx->nrounds; i++) { + ctx->round_keys[i] = k; + speck128_round(&l[i % 3], &k, i); + } + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_speck128_setkey); + +static int speck128_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + return crypto_speck128_setkey(crypto_tfm_ctx(tfm), key, keylen); +} + +/* Speck64 */ + +static __always_inline void speck64_round(u32 *x, u32 *y, u32 k) +{ + *x = ror32(*x, 8); + *x += *y; + *x ^= k; + *y = rol32(*y, 3); + *y ^= *x; +} + +static __always_inline void speck64_unround(u32 *x, u32 *y, u32 k) +{ + *y ^= *x; + *y = ror32(*y, 3); + *x ^= k; + *x -= *y; + *x = rol32(*x, 8); +} + +void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx, + u8 *out, const u8 *in) +{ + u32 y = get_unaligned_le32(in); + u32 x = get_unaligned_le32(in + 4); + int i; + + for (i = 0; i < ctx->nrounds; i++) + speck64_round(&x, &y, ctx->round_keys[i]); + + put_unaligned_le32(y, out); + put_unaligned_le32(x, out + 4); +} +EXPORT_SYMBOL_GPL(crypto_speck64_encrypt); + +static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + crypto_speck64_encrypt(crypto_tfm_ctx(tfm), out, in); +} + +void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx, + u8 *out, const u8 *in) +{ + u32 y = get_unaligned_le32(in); + u32 x = get_unaligned_le32(in + 4); + int i; + + for (i = ctx->nrounds - 1; i >= 0; i--) + speck64_unround(&x, &y, ctx->round_keys[i]); + + put_unaligned_le32(y, out); + put_unaligned_le32(x, out + 4); +} +EXPORT_SYMBOL_GPL(crypto_speck64_decrypt); + +static void speck64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + crypto_speck64_decrypt(crypto_tfm_ctx(tfm), out, in); +} + +int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key, + unsigned int keylen) +{ + u32 l[3]; + u32 k; + int i; + + switch (keylen) { + case SPECK64_96_KEY_SIZE: + k = get_unaligned_le32(key); + l[0] = get_unaligned_le32(key + 4); + l[1] = get_unaligned_le32(key + 8); + ctx->nrounds = SPECK64_96_NROUNDS; + for (i = 0; i < ctx->nrounds; i++) { + ctx->round_keys[i] = k; + speck64_round(&l[i % 2], &k, i); + } + break; + case SPECK64_128_KEY_SIZE: + k = get_unaligned_le32(key); + l[0] = get_unaligned_le32(key + 4); + l[1] = get_unaligned_le32(key + 8); + l[2] = get_unaligned_le32(key + 12); + ctx->nrounds = SPECK64_128_NROUNDS; + for (i = 0; i < ctx->nrounds; i++) { + ctx->round_keys[i] = k; + speck64_round(&l[i % 3], &k, i); + } + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_speck64_setkey); + +static int speck64_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + return crypto_speck64_setkey(crypto_tfm_ctx(tfm), key, keylen); +} + +/* Algorithm definitions */ + +static struct crypto_alg speck_algs[] = { + { + .cra_name = "speck128", + .cra_driver_name = "speck128-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = SPECK128_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct speck128_tfm_ctx), + .cra_module = THIS_MODULE, + .cra_u = { + .cipher = { + .cia_min_keysize = SPECK128_128_KEY_SIZE, + .cia_max_keysize = SPECK128_256_KEY_SIZE, + .cia_setkey = speck128_setkey, + .cia_encrypt = speck128_encrypt, + .cia_decrypt = speck128_decrypt + } + } + }, { + .cra_name = "speck64", + .cra_driver_name = "speck64-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = SPECK64_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct speck64_tfm_ctx), + .cra_module = THIS_MODULE, + .cra_u = { + .cipher = { + .cia_min_keysize = SPECK64_96_KEY_SIZE, + .cia_max_keysize = SPECK64_128_KEY_SIZE, + .cia_setkey = speck64_setkey, + .cia_encrypt = speck64_encrypt, + .cia_decrypt = speck64_decrypt + } + } + } +}; + +static int __init speck_module_init(void) +{ + return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +static void __exit speck_module_exit(void) +{ + crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +module_init(speck_module_init); +module_exit(speck_module_exit); + +MODULE_DESCRIPTION("Speck block cipher (generic)"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biggers "); +MODULE_ALIAS_CRYPTO("speck128"); +MODULE_ALIAS_CRYPTO("speck128-generic"); +MODULE_ALIAS_CRYPTO("speck64"); +MODULE_ALIAS_CRYPTO("speck64-generic"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 29a0cbdd0d19b1ddca6ee34c402ac7263d1647d4..91aa9f33ad01e9ebf83d8fff9db67360e9b3a52e 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2912,6 +2912,36 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "ecb(speck128)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = speck128_enc_tv_template, + .count = ARRAY_SIZE(speck128_enc_tv_template) + }, + .dec = { + .vecs = speck128_dec_tv_template, + .count = ARRAY_SIZE(speck128_dec_tv_template) + } + } + } + }, { + .alg = "ecb(speck64)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = speck64_enc_tv_template, + .count = ARRAY_SIZE(speck64_enc_tv_template) + }, + .dec = { + .vecs = speck64_dec_tv_template, + .count = ARRAY_SIZE(speck64_dec_tv_template) + } + } + } }, { .alg = "ecb(tea)", .test = alg_test_skcipher, @@ -3572,6 +3602,36 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "xts(speck128)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = speck128_xts_enc_tv_template, + .count = ARRAY_SIZE(speck128_xts_enc_tv_template) + }, + .dec = { + .vecs = speck128_xts_dec_tv_template, + .count = ARRAY_SIZE(speck128_xts_dec_tv_template) + } + } + } + }, { + .alg = "xts(speck64)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = speck64_xts_enc_tv_template, + .count = ARRAY_SIZE(speck64_xts_enc_tv_template) + }, + .dec = { + .vecs = speck64_xts_dec_tv_template, + .count = ARRAY_SIZE(speck64_xts_dec_tv_template) + } + } + } }, { .alg = "xts(twofish)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 1dc754e0d7437745301ffb7eab1f6b476f2f59a4..c31b8654e7746cdb94cd434b9393f36b1dc08714 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -12060,6 +12060,1492 @@ static struct cipher_testvec serpent_xts_dec_tv_template[] = { }, }; +/* + * Speck test vectors taken from the original paper: + * "The Simon and Speck Families of Lightweight Block Ciphers" + * https://eprint.iacr.org/2013/404.pdf + * + * Note that the paper does not make byte and word order clear. But it was + * confirmed with the authors that the intended orders are little endian byte + * order and (y, x) word order. Equivalently, the printed test vectors, when + * looking at only the bytes (ignoring the whitespace that divides them into + * words), are backwards: the left-most byte is actually the one with the + * highest memory address, while the right-most byte is actually the one with + * the lowest memory address. + */ + +static struct cipher_testvec speck128_enc_tv_template[] = { + { /* Speck128/128 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .klen = 16, + .input = "\x20\x6d\x61\x64\x65\x20\x69\x74" + "\x20\x65\x71\x75\x69\x76\x61\x6c", + .ilen = 16, + .result = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78" + "\x65\x32\x78\x79\x51\x98\x5d\xa6", + .rlen = 16, + }, { /* Speck128/192 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17", + .klen = 24, + .input = "\x65\x6e\x74\x20\x74\x6f\x20\x43" + "\x68\x69\x65\x66\x20\x48\x61\x72", + .ilen = 16, + .result = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9" + "\x66\x55\x13\x13\x3a\xcf\xe4\x1b", + .rlen = 16, + }, { /* Speck128/256 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + .klen = 32, + .input = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20" + "\x49\x6e\x20\x74\x68\x6f\x73\x65", + .ilen = 16, + .result = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e" + "\x3e\xf5\xc0\x05\x04\x01\x09\x41", + .rlen = 16, + }, +}; + +static struct cipher_testvec speck128_dec_tv_template[] = { + { /* Speck128/128 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .klen = 16, + .input = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78" + "\x65\x32\x78\x79\x51\x98\x5d\xa6", + .ilen = 16, + .result = "\x20\x6d\x61\x64\x65\x20\x69\x74" + "\x20\x65\x71\x75\x69\x76\x61\x6c", + .rlen = 16, + }, { /* Speck128/192 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17", + .klen = 24, + .input = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9" + "\x66\x55\x13\x13\x3a\xcf\xe4\x1b", + .ilen = 16, + .result = "\x65\x6e\x74\x20\x74\x6f\x20\x43" + "\x68\x69\x65\x66\x20\x48\x61\x72", + .rlen = 16, + }, { /* Speck128/256 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + .klen = 32, + .input = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e" + "\x3e\xf5\xc0\x05\x04\x01\x09\x41", + .ilen = 16, + .result = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20" + "\x49\x6e\x20\x74\x68\x6f\x73\x65", + .rlen = 16, + }, +}; + +/* + * Speck128-XTS test vectors, taken from the AES-XTS test vectors with the + * result recomputed with Speck128 as the cipher + */ + +static struct cipher_testvec speck128_xts_enc_tv_template[] = { + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ilen = 32, + .result = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62" + "\x3b\x99\x4a\x64\x74\x77\xac\xed" + "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42" + "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54", + .rlen = 32, + }, { + .key = "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\xfb\x53\x81\x75\x6f\x9f\x34\xad" + "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a" + "\xd4\x84\xa4\x53\xd5\x88\x73\x1b" + "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6", + .rlen = 32, + }, { + .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" + "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\x21\x52\x84\x15\xd1\xf7\x21\x55" + "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d" + "\xda\x63\xb2\xf1\x82\xb0\x89\x59" + "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92", + .rlen = 32, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82" + "\x53\xd0\xed\x2d\x30\xc1\x20\xef" + "\x70\x67\x5e\xff\x09\x70\xbb\xc1" + "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48" + "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7" + "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9" + "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44" + "\x19\xc5\x58\x84\x63\xb9\x12\x68" + "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c" + "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd" + "\x74\x79\x2e\xb4\x44\xd7\x69\xc4" + "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d" + "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb" + "\x6d\x13\x65\xa0\xf9\x31\x12\xe2" + "\x26\xd1\xec\x2b\x0a\x8b\x59\x99" + "\xa7\x49\xa0\x0e\x09\x33\x85\x50" + "\xc3\x23\xca\x7a\xdd\x13\x45\x5f" + "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f" + "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6" + "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f" + "\x79\x91\x8d\x36\x13\x7b\xd0\x4a" + "\x6c\x39\xfb\x53\xb8\x6f\x02\x51" + "\xa5\x20\xac\x24\x1c\x73\x59\x73" + "\x58\x61\x3a\x87\x58\xb3\x20\x56" + "\x39\x06\x2b\x4d\xd3\x20\x2b\x89" + "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd" + "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91" + "\x09\x35\x71\x50\x65\xac\x92\xe3" + "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92" + "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9" + "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d" + "\x77\x04\x80\xa9\xbf\x38\xb5\xbd" + "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8" + "\x2a\x26\xcc\x49\x14\x6d\x55\x01" + "\x06\x94\xd8\xb2\x2d\x53\x83\x1b" + "\x8f\xd4\xdd\x57\x12\x7e\x18\xba" + "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d" + "\x24\xa9\x60\xa4\x97\x85\x86\x2a" + "\x01\x00\x09\xf1\xcb\x4a\x24\x1c" + "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4" + "\x97\x1c\x10\xc6\x4d\x66\x4f\x98" + "\x87\x30\xac\xd5\xea\x73\x49\x10" + "\x80\xea\xe5\x5f\x4d\x5f\x03\x33" + "\x66\x02\x35\x3d\x60\x06\x36\x4f" + "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8" + "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28" + "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93" + "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30" + "\xcc\x75\xcf\x16\x26\xa9\x26\x3b" + "\xe7\x68\x2f\x15\x21\x5b\xe4\x00" + "\xbd\x48\x50\xcd\x75\x70\xc4\x62" + "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b" + "\x51\x66\x02\x69\x04\x97\x36\xd4" + "\x75\xae\x0b\xa3\x42\xf8\xca\x79" + "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2" + "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd" + "\xea\x15\x5a\xa0\x85\x7e\x81\x0d" + "\x03\xe7\x05\x39\xf5\x05\x26\xee" + "\xec\xaa\x1f\x3d\xc9\x98\x76\x01" + "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4" + "\x50\x65\x50\x6d\x04\x1f\xdf\x5a" + "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca" + "\x47\x26\xef\x39\xb8\xb4\xf2\xd1" + "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf", + .rlen = 512, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95" + "\x02\x88\x41\x97\x16\x93\x99\x37" + "\x51\x05\x82\x09\x74\x94\x45\x92", + .klen = 64, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1" + "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb" + "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73" + "\x92\x99\xde\xd3\x76\xed\xcd\x63" + "\x64\x3a\x22\x57\xc1\x43\x49\xd4" + "\x79\x36\x31\x19\x62\xae\x10\x7e" + "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa" + "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0" + "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00" + "\xfc\x81\x99\x8a\x14\x62\xf5\x7e" + "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec" + "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6" + "\x62\x62\x37\xfe\x0a\x4c\x4a\x37" + "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e" + "\x85\x3c\x4f\x26\x64\x85\xbc\x68" + "\xb0\xe0\x86\x5e\x26\x41\xce\x11" + "\x50\xda\x97\x14\xe9\x9e\xc7\x6d" + "\x3b\xdc\x43\xde\x2b\x27\x69\x7d" + "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31" + "\x14\x4d\xf0\x74\x37\xfd\x07\x25" + "\x96\x55\xe5\xfc\x9e\x27\x2a\x74" + "\x1b\x83\x4d\x15\x83\xac\x57\xa0" + "\xac\xa5\xd0\x38\xef\x19\x56\x53" + "\x25\x4b\xfc\xce\x04\x23\xe5\x6b" + "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5" + "\xed\x22\x34\x1c\x5d\xed\x17\x06" + "\x36\xa3\xe6\x77\xb9\x97\x46\xb8" + "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc" + "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82" + "\x35\x91\x3d\x1b\xe4\x97\x9f\x92" + "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1" + "\x8d\x39\xfc\x42\xfb\x38\x80\xb9" + "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1" + "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7" + "\xa1\xbf\xf7\xda\x95\x93\x4b\x78" + "\x19\xf5\x94\xf9\xd2\x00\x33\x37" + "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee" + "\x42\xb2\x9e\x2c\x5f\x48\x23\x26" + "\x15\x25\x17\x03\x3d\xfe\x2c\xfc" + "\xeb\xba\xda\xe0\x00\x05\xb6\xa6" + "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf" + "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a" + "\x49\xa1\xc3\xfa\x10\x52\xb9\x14" + "\xad\xb7\x73\xf8\x78\x12\xc8\x59" + "\x17\x80\x4c\x57\x39\xf1\x6d\x80" + "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21" + "\xec\xce\xb7\xc8\x02\x8a\xed\x53" + "\x2c\x25\x68\x2e\x1f\x85\x5e\x67" + "\xd1\x07\x7a\x3a\x89\x08\xe0\x34" + "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40" + "\x31\x15\x72\xa0\xf0\x73\xd9\x3b" + "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2" + "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8" + "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6" + "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58" + "\xcc\x1f\x48\x49\x65\x47\x75\xe9" + "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07" + "\xf2\xec\x76\xd8\x8f\x09\xf3\x16" + "\xa1\x51\x89\x3b\xeb\x96\x42\xac" + "\x65\xe0\x67\x63\x29\xdc\xb4\x7d" + "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb" + "\x66\x8d\x13\xca\xe0\x59\x2a\x00" + "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5" + "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c", + .rlen = 512, + .also_non_np = 1, + .np = 3, + .tap = { 512 - 20, 4, 16 }, + } +}; + +static struct cipher_testvec speck128_xts_dec_tv_template[] = { + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62" + "\x3b\x99\x4a\x64\x74\x77\xac\xed" + "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42" + "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54", + .ilen = 32, + .result = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .rlen = 32, + }, { + .key = "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\xfb\x53\x81\x75\x6f\x9f\x34\xad" + "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a" + "\xd4\x84\xa4\x53\xd5\x88\x73\x1b" + "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6", + .ilen = 32, + .result = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .rlen = 32, + }, { + .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" + "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x21\x52\x84\x15\xd1\xf7\x21\x55" + "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d" + "\xda\x63\xb2\xf1\x82\xb0\x89\x59" + "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92", + .ilen = 32, + .result = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .rlen = 32, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82" + "\x53\xd0\xed\x2d\x30\xc1\x20\xef" + "\x70\x67\x5e\xff\x09\x70\xbb\xc1" + "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48" + "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7" + "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9" + "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44" + "\x19\xc5\x58\x84\x63\xb9\x12\x68" + "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c" + "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd" + "\x74\x79\x2e\xb4\x44\xd7\x69\xc4" + "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d" + "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb" + "\x6d\x13\x65\xa0\xf9\x31\x12\xe2" + "\x26\xd1\xec\x2b\x0a\x8b\x59\x99" + "\xa7\x49\xa0\x0e\x09\x33\x85\x50" + "\xc3\x23\xca\x7a\xdd\x13\x45\x5f" + "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f" + "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6" + "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f" + "\x79\x91\x8d\x36\x13\x7b\xd0\x4a" + "\x6c\x39\xfb\x53\xb8\x6f\x02\x51" + "\xa5\x20\xac\x24\x1c\x73\x59\x73" + "\x58\x61\x3a\x87\x58\xb3\x20\x56" + "\x39\x06\x2b\x4d\xd3\x20\x2b\x89" + "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd" + "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91" + "\x09\x35\x71\x50\x65\xac\x92\xe3" + "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92" + "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9" + "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d" + "\x77\x04\x80\xa9\xbf\x38\xb5\xbd" + "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8" + "\x2a\x26\xcc\x49\x14\x6d\x55\x01" + "\x06\x94\xd8\xb2\x2d\x53\x83\x1b" + "\x8f\xd4\xdd\x57\x12\x7e\x18\xba" + "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d" + "\x24\xa9\x60\xa4\x97\x85\x86\x2a" + "\x01\x00\x09\xf1\xcb\x4a\x24\x1c" + "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4" + "\x97\x1c\x10\xc6\x4d\x66\x4f\x98" + "\x87\x30\xac\xd5\xea\x73\x49\x10" + "\x80\xea\xe5\x5f\x4d\x5f\x03\x33" + "\x66\x02\x35\x3d\x60\x06\x36\x4f" + "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8" + "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28" + "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93" + "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30" + "\xcc\x75\xcf\x16\x26\xa9\x26\x3b" + "\xe7\x68\x2f\x15\x21\x5b\xe4\x00" + "\xbd\x48\x50\xcd\x75\x70\xc4\x62" + "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b" + "\x51\x66\x02\x69\x04\x97\x36\xd4" + "\x75\xae\x0b\xa3\x42\xf8\xca\x79" + "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2" + "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd" + "\xea\x15\x5a\xa0\x85\x7e\x81\x0d" + "\x03\xe7\x05\x39\xf5\x05\x26\xee" + "\xec\xaa\x1f\x3d\xc9\x98\x76\x01" + "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4" + "\x50\x65\x50\x6d\x04\x1f\xdf\x5a" + "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca" + "\x47\x26\xef\x39\xb8\xb4\xf2\xd1" + "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf", + .ilen = 512, + .result = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .rlen = 512, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95" + "\x02\x88\x41\x97\x16\x93\x99\x37" + "\x51\x05\x82\x09\x74\x94\x45\x92", + .klen = 64, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1" + "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb" + "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73" + "\x92\x99\xde\xd3\x76\xed\xcd\x63" + "\x64\x3a\x22\x57\xc1\x43\x49\xd4" + "\x79\x36\x31\x19\x62\xae\x10\x7e" + "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa" + "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0" + "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00" + "\xfc\x81\x99\x8a\x14\x62\xf5\x7e" + "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec" + "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6" + "\x62\x62\x37\xfe\x0a\x4c\x4a\x37" + "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e" + "\x85\x3c\x4f\x26\x64\x85\xbc\x68" + "\xb0\xe0\x86\x5e\x26\x41\xce\x11" + "\x50\xda\x97\x14\xe9\x9e\xc7\x6d" + "\x3b\xdc\x43\xde\x2b\x27\x69\x7d" + "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31" + "\x14\x4d\xf0\x74\x37\xfd\x07\x25" + "\x96\x55\xe5\xfc\x9e\x27\x2a\x74" + "\x1b\x83\x4d\x15\x83\xac\x57\xa0" + "\xac\xa5\xd0\x38\xef\x19\x56\x53" + "\x25\x4b\xfc\xce\x04\x23\xe5\x6b" + "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5" + "\xed\x22\x34\x1c\x5d\xed\x17\x06" + "\x36\xa3\xe6\x77\xb9\x97\x46\xb8" + "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc" + "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82" + "\x35\x91\x3d\x1b\xe4\x97\x9f\x92" + "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1" + "\x8d\x39\xfc\x42\xfb\x38\x80\xb9" + "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1" + "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7" + "\xa1\xbf\xf7\xda\x95\x93\x4b\x78" + "\x19\xf5\x94\xf9\xd2\x00\x33\x37" + "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee" + "\x42\xb2\x9e\x2c\x5f\x48\x23\x26" + "\x15\x25\x17\x03\x3d\xfe\x2c\xfc" + "\xeb\xba\xda\xe0\x00\x05\xb6\xa6" + "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf" + "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a" + "\x49\xa1\xc3\xfa\x10\x52\xb9\x14" + "\xad\xb7\x73\xf8\x78\x12\xc8\x59" + "\x17\x80\x4c\x57\x39\xf1\x6d\x80" + "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21" + "\xec\xce\xb7\xc8\x02\x8a\xed\x53" + "\x2c\x25\x68\x2e\x1f\x85\x5e\x67" + "\xd1\x07\x7a\x3a\x89\x08\xe0\x34" + "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40" + "\x31\x15\x72\xa0\xf0\x73\xd9\x3b" + "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2" + "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8" + "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6" + "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58" + "\xcc\x1f\x48\x49\x65\x47\x75\xe9" + "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07" + "\xf2\xec\x76\xd8\x8f\x09\xf3\x16" + "\xa1\x51\x89\x3b\xeb\x96\x42\xac" + "\x65\xe0\x67\x63\x29\xdc\xb4\x7d" + "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb" + "\x66\x8d\x13\xca\xe0\x59\x2a\x00" + "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5" + "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c", + .ilen = 512, + .result = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .rlen = 512, + .also_non_np = 1, + .np = 3, + .tap = { 512 - 20, 4, 16 }, + } +}; + +static struct cipher_testvec speck64_enc_tv_template[] = { + { /* Speck64/96 */ + .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b" + "\x10\x11\x12\x13", + .klen = 12, + .input = "\x65\x61\x6e\x73\x20\x46\x61\x74", + .ilen = 8, + .result = "\x6c\x94\x75\x41\xec\x52\x79\x9f", + .rlen = 8, + }, { /* Speck64/128 */ + .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b" + "\x10\x11\x12\x13\x18\x19\x1a\x1b", + .klen = 16, + .input = "\x2d\x43\x75\x74\x74\x65\x72\x3b", + .ilen = 8, + .result = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c", + .rlen = 8, + }, +}; + +static struct cipher_testvec speck64_dec_tv_template[] = { + { /* Speck64/96 */ + .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b" + "\x10\x11\x12\x13", + .klen = 12, + .input = "\x6c\x94\x75\x41\xec\x52\x79\x9f", + .ilen = 8, + .result = "\x65\x61\x6e\x73\x20\x46\x61\x74", + .rlen = 8, + }, { /* Speck64/128 */ + .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b" + "\x10\x11\x12\x13\x18\x19\x1a\x1b", + .klen = 16, + .input = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c", + .ilen = 8, + .result = "\x2d\x43\x75\x74\x74\x65\x72\x3b", + .rlen = 8, + }, +}; + +/* + * Speck64-XTS test vectors, taken from the AES-XTS test vectors with the result + * recomputed with Speck64 as the cipher, and key lengths adjusted + */ + +static struct cipher_testvec speck64_xts_enc_tv_template[] = { + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 24, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ilen = 32, + .result = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6" + "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2" + "\x80\xf5\x72\xe7\xcd\xf0\x99\x22" + "\x35\xa7\x2f\x06\xef\xdc\x51\xaa", + .rlen = 32, + }, { + .key = "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 24, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\x12\x56\x73\xcd\x15\x87\xa8\x59" + "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f" + "\xb3\x12\x69\x7e\x36\xeb\x52\xff" + "\x62\xdd\xba\x90\xb3\xe1\xee\x99", + .rlen = 32, + }, { + .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" + "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 24, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c" + "\x27\x36\xc0\xbf\x5d\xea\x36\x37" + "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b" + "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34", + .rlen = 32, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x31\x41\x59\x26\x53\x58\x97\x93", + .klen = 24, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e" + "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09" + "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3" + "\x11\xc7\x39\x96\xd0\x95\xf4\x56" + "\xf4\xdd\x03\x38\x01\x44\x2c\xcf" + "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66" + "\xfe\x3d\xc6\xfb\x01\x23\x51\x43" + "\xd5\xd2\x13\x86\x94\x34\xe9\x62" + "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef" + "\x76\x35\x04\x3f\xdb\x23\x9d\x0b" + "\x85\x42\xb9\x02\xd6\xcc\xdb\x96" + "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d" + "\xae\xd2\x04\xd5\xda\xc1\x7e\x24" + "\x8c\x73\xbe\x48\x7e\xcf\x65\x28" + "\x29\xe5\xbe\x54\x30\xcb\x46\x95" + "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe" + "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69" + "\xa1\x09\x95\x71\x26\xe9\xc4\xdf" + "\xe6\x31\xc3\x46\xda\xaf\x0b\x41" + "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3" + "\x82\xc0\x37\x27\xfc\x91\xa7\x05" + "\xfb\xc5\xdc\x2b\x74\x96\x48\x43" + "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f" + "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a" + "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c" + "\x07\xff\xf3\x72\x74\x48\xb5\x40" + "\x50\xb5\xdd\x90\x43\x31\x18\x15" + "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a" + "\x29\x93\x90\x8b\xda\x07\xf0\x35" + "\x6d\x90\x88\x09\x4e\x83\xf5\x5b" + "\x94\x12\xbb\x33\x27\x1d\x3f\x23" + "\x51\xa8\x7c\x07\xa2\xae\x77\xa6" + "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f" + "\x66\xdd\xcd\x75\x24\x8b\x33\xf7" + "\x20\xdb\x83\x9b\x4f\x11\x63\x6e" + "\xcf\x37\xef\xc9\x11\x01\x5c\x45" + "\x32\x99\x7c\x3c\x9e\x42\x89\xe3" + "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05" + "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc" + "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d" + "\xa0\xa8\x89\x3b\x73\x39\xa5\x94" + "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89" + "\x10\xff\xaf\xef\xca\xdd\x4f\x80" + "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7" + "\x33\xca\x00\x8b\x8b\x3f\xea\xec" + "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f" + "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5" + "\x64\xa3\xf1\x1a\x76\x28\xcc\x35" + "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b" + "\xc7\x1b\x53\x17\x02\xea\xd1\xad" + "\x13\x51\x73\xc0\xa0\xb2\x05\x32" + "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19" + "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d" + "\x59\xda\xee\x1a\x22\x18\xda\x0d" + "\x88\x0f\x55\x8b\x72\x62\xfd\xc1" + "\x69\x13\xcd\x0d\x5f\xc1\x09\x52" + "\xee\xd6\xe3\x84\x4d\xee\xf6\x88" + "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f" + "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54" + "\x7d\x69\x8d\x00\x62\x77\x0d\x14" + "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3" + "\x50\xf7\x5f\xf4\xc2\xca\x41\x97" + "\x37\xbe\x75\x74\xcd\xf0\x75\x6e" + "\x25\x23\x94\xbd\xda\x8d\xb0\xd4", + .rlen = 512, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27", + .klen = 32, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\x55\xed\x71\xd3\x02\x8e\x15\x3b" + "\xc6\x71\x29\x2d\x3e\x89\x9f\x59" + "\x68\x6a\xcc\x8a\x56\x97\xf3\x95" + "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c" + "\x78\x16\xea\x80\xdb\x33\x75\x94" + "\xf9\x29\xc4\x2b\x76\x75\x97\xc7" + "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b" + "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee" + "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a" + "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c" + "\xf5\xec\x32\x74\xa3\xb8\x03\x88" + "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f" + "\x84\x5e\x46\xed\x20\x89\xb6\x44" + "\x8d\xd0\xed\x54\x47\x16\xbe\x95" + "\x8a\xb3\x6b\x72\xc4\x32\x52\x13" + "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6" + "\x44\x18\xdd\x8c\x6e\xca\x6e\x45" + "\x8f\x1e\x10\x07\x57\x25\x98\x7b" + "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8" + "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb" + "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff" + "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e" + "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d" + "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65" + "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a" + "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a" + "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78" + "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3" + "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e" + "\x35\x10\x30\x82\x0d\xe7\xc5\x9b" + "\xde\x44\x18\xbd\x9f\xd1\x45\xa9" + "\x7b\x7a\x4a\xad\x35\x65\x27\xca" + "\xb2\xc3\xd4\x9b\x71\x86\x70\xee" + "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf" + "\xfc\x42\xc8\x31\x59\xbe\x16\x60" + "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14" + "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef" + "\x52\x7f\x29\x51\x94\x20\x67\x3c" + "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63" + "\xe7\xff\x73\x25\xd1\xdd\x96\x8a" + "\x98\x52\x6d\xf3\xac\x3e\xf2\x18" + "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed" + "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e" + "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad" + "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa" + "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81" + "\x65\x53\x0f\x41\x11\xbd\x98\x99" + "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d" + "\x84\x98\xf9\x34\xed\x33\x2a\x1f" + "\x82\xed\xc1\x73\x98\xd3\x02\xdc" + "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76" + "\x63\x51\x34\x9d\x96\x12\xae\xce" + "\x83\xc9\x76\x5e\xa4\x1b\x53\x37" + "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d" + "\x54\x27\x74\xbb\x10\x86\x57\x46" + "\x68\xe1\xed\x14\xe7\x9d\xfc\x84" + "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf" + "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d" + "\x7b\x4f\x38\x55\x36\x71\x64\xc1" + "\xfc\x5c\x75\x52\x33\x02\x18\xf8" + "\x17\xe1\x2b\xc2\x43\x39\xbd\x76" + "\x9b\x63\x76\x32\x2f\x19\x72\x10" + "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5" + "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c", + .rlen = 512, + .also_non_np = 1, + .np = 3, + .tap = { 512 - 20, 4, 16 }, + } +}; + +static struct cipher_testvec speck64_xts_dec_tv_template[] = { + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 24, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6" + "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2" + "\x80\xf5\x72\xe7\xcd\xf0\x99\x22" + "\x35\xa7\x2f\x06\xef\xdc\x51\xaa", + .ilen = 32, + .result = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .rlen = 32, + }, { + .key = "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 24, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x12\x56\x73\xcd\x15\x87\xa8\x59" + "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f" + "\xb3\x12\x69\x7e\x36\xeb\x52\xff" + "\x62\xdd\xba\x90\xb3\xe1\xee\x99", + .ilen = 32, + .result = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .rlen = 32, + }, { + .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" + "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 24, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c" + "\x27\x36\xc0\xbf\x5d\xea\x36\x37" + "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b" + "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34", + .ilen = 32, + .result = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .rlen = 32, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x31\x41\x59\x26\x53\x58\x97\x93", + .klen = 24, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e" + "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09" + "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3" + "\x11\xc7\x39\x96\xd0\x95\xf4\x56" + "\xf4\xdd\x03\x38\x01\x44\x2c\xcf" + "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66" + "\xfe\x3d\xc6\xfb\x01\x23\x51\x43" + "\xd5\xd2\x13\x86\x94\x34\xe9\x62" + "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef" + "\x76\x35\x04\x3f\xdb\x23\x9d\x0b" + "\x85\x42\xb9\x02\xd6\xcc\xdb\x96" + "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d" + "\xae\xd2\x04\xd5\xda\xc1\x7e\x24" + "\x8c\x73\xbe\x48\x7e\xcf\x65\x28" + "\x29\xe5\xbe\x54\x30\xcb\x46\x95" + "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe" + "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69" + "\xa1\x09\x95\x71\x26\xe9\xc4\xdf" + "\xe6\x31\xc3\x46\xda\xaf\x0b\x41" + "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3" + "\x82\xc0\x37\x27\xfc\x91\xa7\x05" + "\xfb\xc5\xdc\x2b\x74\x96\x48\x43" + "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f" + "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a" + "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c" + "\x07\xff\xf3\x72\x74\x48\xb5\x40" + "\x50\xb5\xdd\x90\x43\x31\x18\x15" + "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a" + "\x29\x93\x90\x8b\xda\x07\xf0\x35" + "\x6d\x90\x88\x09\x4e\x83\xf5\x5b" + "\x94\x12\xbb\x33\x27\x1d\x3f\x23" + "\x51\xa8\x7c\x07\xa2\xae\x77\xa6" + "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f" + "\x66\xdd\xcd\x75\x24\x8b\x33\xf7" + "\x20\xdb\x83\x9b\x4f\x11\x63\x6e" + "\xcf\x37\xef\xc9\x11\x01\x5c\x45" + "\x32\x99\x7c\x3c\x9e\x42\x89\xe3" + "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05" + "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc" + "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d" + "\xa0\xa8\x89\x3b\x73\x39\xa5\x94" + "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89" + "\x10\xff\xaf\xef\xca\xdd\x4f\x80" + "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7" + "\x33\xca\x00\x8b\x8b\x3f\xea\xec" + "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f" + "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5" + "\x64\xa3\xf1\x1a\x76\x28\xcc\x35" + "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b" + "\xc7\x1b\x53\x17\x02\xea\xd1\xad" + "\x13\x51\x73\xc0\xa0\xb2\x05\x32" + "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19" + "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d" + "\x59\xda\xee\x1a\x22\x18\xda\x0d" + "\x88\x0f\x55\x8b\x72\x62\xfd\xc1" + "\x69\x13\xcd\x0d\x5f\xc1\x09\x52" + "\xee\xd6\xe3\x84\x4d\xee\xf6\x88" + "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f" + "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54" + "\x7d\x69\x8d\x00\x62\x77\x0d\x14" + "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3" + "\x50\xf7\x5f\xf4\xc2\xca\x41\x97" + "\x37\xbe\x75\x74\xcd\xf0\x75\x6e" + "\x25\x23\x94\xbd\xda\x8d\xb0\xd4", + .ilen = 512, + .result = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .rlen = 512, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27", + .klen = 32, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x55\xed\x71\xd3\x02\x8e\x15\x3b" + "\xc6\x71\x29\x2d\x3e\x89\x9f\x59" + "\x68\x6a\xcc\x8a\x56\x97\xf3\x95" + "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c" + "\x78\x16\xea\x80\xdb\x33\x75\x94" + "\xf9\x29\xc4\x2b\x76\x75\x97\xc7" + "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b" + "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee" + "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a" + "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c" + "\xf5\xec\x32\x74\xa3\xb8\x03\x88" + "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f" + "\x84\x5e\x46\xed\x20\x89\xb6\x44" + "\x8d\xd0\xed\x54\x47\x16\xbe\x95" + "\x8a\xb3\x6b\x72\xc4\x32\x52\x13" + "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6" + "\x44\x18\xdd\x8c\x6e\xca\x6e\x45" + "\x8f\x1e\x10\x07\x57\x25\x98\x7b" + "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8" + "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb" + "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff" + "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e" + "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d" + "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65" + "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a" + "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a" + "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78" + "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3" + "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e" + "\x35\x10\x30\x82\x0d\xe7\xc5\x9b" + "\xde\x44\x18\xbd\x9f\xd1\x45\xa9" + "\x7b\x7a\x4a\xad\x35\x65\x27\xca" + "\xb2\xc3\xd4\x9b\x71\x86\x70\xee" + "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf" + "\xfc\x42\xc8\x31\x59\xbe\x16\x60" + "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14" + "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef" + "\x52\x7f\x29\x51\x94\x20\x67\x3c" + "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63" + "\xe7\xff\x73\x25\xd1\xdd\x96\x8a" + "\x98\x52\x6d\xf3\xac\x3e\xf2\x18" + "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed" + "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e" + "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad" + "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa" + "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81" + "\x65\x53\x0f\x41\x11\xbd\x98\x99" + "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d" + "\x84\x98\xf9\x34\xed\x33\x2a\x1f" + "\x82\xed\xc1\x73\x98\xd3\x02\xdc" + "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76" + "\x63\x51\x34\x9d\x96\x12\xae\xce" + "\x83\xc9\x76\x5e\xa4\x1b\x53\x37" + "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d" + "\x54\x27\x74\xbb\x10\x86\x57\x46" + "\x68\xe1\xed\x14\xe7\x9d\xfc\x84" + "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf" + "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d" + "\x7b\x4f\x38\x55\x36\x71\x64\xc1" + "\xfc\x5c\x75\x52\x33\x02\x18\xf8" + "\x17\xe1\x2b\xc2\x43\x39\xbd\x76" + "\x9b\x63\x76\x32\x2f\x19\x72\x10" + "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5" + "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c", + .ilen = 512, + .result = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .rlen = 512, + .also_non_np = 1, + .np = 3, + .tap = { 512 - 20, 4, 16 }, + } +}; + /* Cast6 test vectors from RFC 2612 */ #define CAST6_ENC_TEST_VECTORS 4 #define CAST6_DEC_TEST_VECTORS 4 diff --git a/crypto/vmac.c b/crypto/vmac.c index df76a816cfb22f68ac173d3ef01e2e2f9e166c72..bb2fc787d61568d3c0a871f1fc2e04cfc0732437 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c @@ -1,6 +1,10 @@ /* - * Modified to interface to the Linux kernel + * VMAC: Message Authentication Code using Universal Hashing + * + * Reference: https://tools.ietf.org/html/draft-krovetz-vmac-01 + * * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2018, Google Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,14 +20,15 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. */ -/* -------------------------------------------------------------------------- - * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. - * This implementation is herby placed in the public domain. - * The authors offers no warranty. Use at your own risk. - * Please send bug reports to the authors. - * Last modified: 17 APR 08, 1700 PDT - * ----------------------------------------------------------------------- */ +/* + * Derived from: + * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. + * This implementation is herby placed in the public domain. + * The authors offers no warranty. Use at your own risk. + * Last modified: 17 APR 08, 1700 PDT + */ +#include #include #include #include @@ -31,9 +36,35 @@ #include #include #include -#include #include +/* + * User definable settings. + */ +#define VMAC_TAG_LEN 64 +#define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */ +#define VMAC_KEY_LEN (VMAC_KEY_SIZE/8) +#define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/ + +/* per-transform (per-key) context */ +struct vmac_tfm_ctx { + struct crypto_cipher *cipher; + u64 nhkey[(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; + u64 polykey[2*VMAC_TAG_LEN/64]; + u64 l3key[2*VMAC_TAG_LEN/64]; +}; + +/* per-request context */ +struct vmac_desc_ctx { + union { + u8 partial[VMAC_NHBYTES]; /* partial block */ + __le64 partial_words[VMAC_NHBYTES / 8]; + }; + unsigned int partial_size; /* size of the partial block */ + bool first_block_processed; + u64 polytmp[2*VMAC_TAG_LEN/64]; /* running total of L2-hash */ +}; + /* * Constants and masks */ @@ -318,13 +349,6 @@ static void poly_step_func(u64 *ahi, u64 *alo, } while (0) #endif -static void vhash_abort(struct vmac_ctx *ctx) -{ - ctx->polytmp[0] = ctx->polykey[0] ; - ctx->polytmp[1] = ctx->polykey[1] ; - ctx->first_block_processed = 0; -} - static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) { u64 rh, rl, t, z = 0; @@ -364,280 +388,209 @@ static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) return rl; } -static void vhash_update(const unsigned char *m, - unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */ - struct vmac_ctx *ctx) +/* L1 and L2-hash one or more VMAC_NHBYTES-byte blocks */ +static void vhash_blocks(const struct vmac_tfm_ctx *tctx, + struct vmac_desc_ctx *dctx, + const __le64 *mptr, unsigned int blocks) { - u64 rh, rl, *mptr; - const u64 *kptr = (u64 *)ctx->nhkey; - int i; - u64 ch, cl; - u64 pkh = ctx->polykey[0]; - u64 pkl = ctx->polykey[1]; - - if (!mbytes) - return; - - BUG_ON(mbytes % VMAC_NHBYTES); - - mptr = (u64 *)m; - i = mbytes / VMAC_NHBYTES; /* Must be non-zero */ - - ch = ctx->polytmp[0]; - cl = ctx->polytmp[1]; - - if (!ctx->first_block_processed) { - ctx->first_block_processed = 1; + const u64 *kptr = tctx->nhkey; + const u64 pkh = tctx->polykey[0]; + const u64 pkl = tctx->polykey[1]; + u64 ch = dctx->polytmp[0]; + u64 cl = dctx->polytmp[1]; + u64 rh, rl; + + if (!dctx->first_block_processed) { + dctx->first_block_processed = true; nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); rh &= m62; ADD128(ch, cl, rh, rl); mptr += (VMAC_NHBYTES/sizeof(u64)); - i--; + blocks--; } - while (i--) { + while (blocks--) { nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); rh &= m62; poly_step(ch, cl, pkh, pkl, rh, rl); mptr += (VMAC_NHBYTES/sizeof(u64)); } - ctx->polytmp[0] = ch; - ctx->polytmp[1] = cl; + dctx->polytmp[0] = ch; + dctx->polytmp[1] = cl; } -static u64 vhash(unsigned char m[], unsigned int mbytes, - u64 *tagl, struct vmac_ctx *ctx) +static int vmac_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) { - u64 rh, rl, *mptr; - const u64 *kptr = (u64 *)ctx->nhkey; - int i, remaining; - u64 ch, cl; - u64 pkh = ctx->polykey[0]; - u64 pkl = ctx->polykey[1]; - - mptr = (u64 *)m; - i = mbytes / VMAC_NHBYTES; - remaining = mbytes % VMAC_NHBYTES; - - if (ctx->first_block_processed) { - ch = ctx->polytmp[0]; - cl = ctx->polytmp[1]; - } else if (i) { - nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, ch, cl); - ch &= m62; - ADD128(ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - i--; - } else if (remaining) { - nh_16(mptr, kptr, 2*((remaining+15)/16), ch, cl); - ch &= m62; - ADD128(ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - goto do_l3; - } else {/* Empty String */ - ch = pkh; cl = pkl; - goto do_l3; - } - - while (i--) { - nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); - rh &= m62; - poly_step(ch, cl, pkh, pkl, rh, rl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - } - if (remaining) { - nh_16(mptr, kptr, 2*((remaining+15)/16), rh, rl); - rh &= m62; - poly_step(ch, cl, pkh, pkl, rh, rl); - } - -do_l3: - vhash_abort(ctx); - remaining *= 8; - return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1], remaining); -} + struct vmac_tfm_ctx *tctx = crypto_shash_ctx(tfm); + __be64 out[2]; + u8 in[16] = { 0 }; + unsigned int i; + int err; -static u64 vmac(unsigned char m[], unsigned int mbytes, - const unsigned char n[16], u64 *tagl, - struct vmac_ctx_t *ctx) -{ - u64 *in_n, *out_p; - u64 p, h; - int i; - - in_n = ctx->__vmac_ctx.cached_nonce; - out_p = ctx->__vmac_ctx.cached_aes; - - i = n[15] & 1; - if ((*(u64 *)(n+8) != in_n[1]) || (*(u64 *)(n) != in_n[0])) { - in_n[0] = *(u64 *)(n); - in_n[1] = *(u64 *)(n+8); - ((unsigned char *)in_n)[15] &= 0xFE; - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out_p, (unsigned char *)in_n); - - ((unsigned char *)in_n)[15] |= (unsigned char)(1-i); + if (keylen != VMAC_KEY_LEN) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; } - p = be64_to_cpup(out_p + i); - h = vhash(m, mbytes, (u64 *)0, &ctx->__vmac_ctx); - return le64_to_cpu(p + h); -} -static int vmac_set_key(unsigned char user_key[], struct vmac_ctx_t *ctx) -{ - u64 in[2] = {0}, out[2]; - unsigned i; - int err = 0; - - err = crypto_cipher_setkey(ctx->child, user_key, VMAC_KEY_LEN); + err = crypto_cipher_setkey(tctx->cipher, key, keylen); if (err) return err; /* Fill nh key */ - ((unsigned char *)in)[0] = 0x80; - for (i = 0; i < sizeof(ctx->__vmac_ctx.nhkey)/8; i += 2) { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.nhkey[i] = be64_to_cpup(out); - ctx->__vmac_ctx.nhkey[i+1] = be64_to_cpup(out+1); - ((unsigned char *)in)[15] += 1; + in[0] = 0x80; + for (i = 0; i < ARRAY_SIZE(tctx->nhkey); i += 2) { + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->nhkey[i] = be64_to_cpu(out[0]); + tctx->nhkey[i+1] = be64_to_cpu(out[1]); + in[15]++; } /* Fill poly key */ - ((unsigned char *)in)[0] = 0xC0; - in[1] = 0; - for (i = 0; i < sizeof(ctx->__vmac_ctx.polykey)/8; i += 2) { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.polytmp[i] = - ctx->__vmac_ctx.polykey[i] = - be64_to_cpup(out) & mpoly; - ctx->__vmac_ctx.polytmp[i+1] = - ctx->__vmac_ctx.polykey[i+1] = - be64_to_cpup(out+1) & mpoly; - ((unsigned char *)in)[15] += 1; + in[0] = 0xC0; + in[15] = 0; + for (i = 0; i < ARRAY_SIZE(tctx->polykey); i += 2) { + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->polykey[i] = be64_to_cpu(out[0]) & mpoly; + tctx->polykey[i+1] = be64_to_cpu(out[1]) & mpoly; + in[15]++; } /* Fill ip key */ - ((unsigned char *)in)[0] = 0xE0; - in[1] = 0; - for (i = 0; i < sizeof(ctx->__vmac_ctx.l3key)/8; i += 2) { + in[0] = 0xE0; + in[15] = 0; + for (i = 0; i < ARRAY_SIZE(tctx->l3key); i += 2) { do { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.l3key[i] = be64_to_cpup(out); - ctx->__vmac_ctx.l3key[i+1] = be64_to_cpup(out+1); - ((unsigned char *)in)[15] += 1; - } while (ctx->__vmac_ctx.l3key[i] >= p64 - || ctx->__vmac_ctx.l3key[i+1] >= p64); + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->l3key[i] = be64_to_cpu(out[0]); + tctx->l3key[i+1] = be64_to_cpu(out[1]); + in[15]++; + } while (tctx->l3key[i] >= p64 || tctx->l3key[i+1] >= p64); } - /* Invalidate nonce/aes cache and reset other elements */ - ctx->__vmac_ctx.cached_nonce[0] = (u64)-1; /* Ensure illegal nonce */ - ctx->__vmac_ctx.cached_nonce[1] = (u64)0; /* Ensure illegal nonce */ - ctx->__vmac_ctx.first_block_processed = 0; - - return err; + return 0; } -static int vmac_setkey(struct crypto_shash *parent, - const u8 *key, unsigned int keylen) +static int vmac_init(struct shash_desc *desc) { - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); - if (keylen != VMAC_KEY_LEN) { - crypto_shash_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - return vmac_set_key((u8 *)key, ctx); -} - -static int vmac_init(struct shash_desc *pdesc) -{ + dctx->partial_size = 0; + dctx->first_block_processed = false; + memcpy(dctx->polytmp, tctx->polykey, sizeof(dctx->polytmp)); return 0; } -static int vmac_update(struct shash_desc *pdesc, const u8 *p, - unsigned int len) +static int vmac_update(struct shash_desc *desc, const u8 *p, unsigned int len) { - struct crypto_shash *parent = pdesc->tfm; - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); - int expand; - int min; - - expand = VMAC_NHBYTES - ctx->partial_size > 0 ? - VMAC_NHBYTES - ctx->partial_size : 0; - - min = len < expand ? len : expand; - - memcpy(ctx->partial + ctx->partial_size, p, min); - ctx->partial_size += min; - - if (len < expand) - return 0; - - vhash_update(ctx->partial, VMAC_NHBYTES, &ctx->__vmac_ctx); - ctx->partial_size = 0; - - len -= expand; - p += expand; + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); + unsigned int n; + + if (dctx->partial_size) { + n = min(len, VMAC_NHBYTES - dctx->partial_size); + memcpy(&dctx->partial[dctx->partial_size], p, n); + dctx->partial_size += n; + p += n; + len -= n; + if (dctx->partial_size == VMAC_NHBYTES) { + vhash_blocks(tctx, dctx, dctx->partial_words, 1); + dctx->partial_size = 0; + } + } - if (len % VMAC_NHBYTES) { - memcpy(ctx->partial, p + len - (len % VMAC_NHBYTES), - len % VMAC_NHBYTES); - ctx->partial_size = len % VMAC_NHBYTES; + if (len >= VMAC_NHBYTES) { + n = round_down(len, VMAC_NHBYTES); + /* TODO: 'p' may be misaligned here */ + vhash_blocks(tctx, dctx, (const __le64 *)p, n / VMAC_NHBYTES); + p += n; + len -= n; } - vhash_update(p, len - len % VMAC_NHBYTES, &ctx->__vmac_ctx); + if (len) { + memcpy(dctx->partial, p, len); + dctx->partial_size = len; + } return 0; } -static int vmac_final(struct shash_desc *pdesc, u8 *out) +static u64 vhash_final(const struct vmac_tfm_ctx *tctx, + struct vmac_desc_ctx *dctx) { - struct crypto_shash *parent = pdesc->tfm; - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); - vmac_t mac; - u8 nonce[16] = {}; - - /* vmac() ends up accessing outside the array bounds that - * we specify. In appears to access up to the next 2-word - * boundary. We'll just be uber cautious and zero the - * unwritten bytes in the buffer. - */ - if (ctx->partial_size) { - memset(ctx->partial + ctx->partial_size, 0, - VMAC_NHBYTES - ctx->partial_size); + unsigned int partial = dctx->partial_size; + u64 ch = dctx->polytmp[0]; + u64 cl = dctx->polytmp[1]; + + /* L1 and L2-hash the final block if needed */ + if (partial) { + /* Zero-pad to next 128-bit boundary */ + unsigned int n = round_up(partial, 16); + u64 rh, rl; + + memset(&dctx->partial[partial], 0, n - partial); + nh_16(dctx->partial_words, tctx->nhkey, n / 8, rh, rl); + rh &= m62; + if (dctx->first_block_processed) + poly_step(ch, cl, tctx->polykey[0], tctx->polykey[1], + rh, rl); + else + ADD128(ch, cl, rh, rl); } - mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx); - memcpy(out, &mac, sizeof(vmac_t)); - memzero_explicit(&mac, sizeof(vmac_t)); - memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); - ctx->partial_size = 0; + + /* L3-hash the 128-bit output of L2-hash */ + return l3hash(ch, cl, tctx->l3key[0], tctx->l3key[1], partial * 8); +} + +static int vmac_final(struct shash_desc *desc, u8 *out) +{ + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); + static const u8 nonce[16] = {}; /* TODO: this is insecure */ + union { + u8 bytes[16]; + __be64 pads[2]; + } block; + int index; + u64 hash, pad; + + /* Finish calculating the VHASH of the message */ + hash = vhash_final(tctx, dctx); + + /* Generate pseudorandom pad by encrypting the nonce */ + memcpy(&block, nonce, 16); + index = block.bytes[15] & 1; + block.bytes[15] &= ~1; + crypto_cipher_encrypt_one(tctx->cipher, block.bytes, block.bytes); + pad = be64_to_cpu(block.pads[index]); + + /* The VMAC is the sum of VHASH and the pseudorandom pad */ + put_unaligned_le64(hash + pad, out); return 0; } static int vmac_init_tfm(struct crypto_tfm *tfm) { - struct crypto_cipher *cipher; - struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); struct crypto_spawn *spawn = crypto_instance_ctx(inst); - struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); + struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; cipher = crypto_spawn_cipher(spawn); if (IS_ERR(cipher)) return PTR_ERR(cipher); - ctx->child = cipher; + tctx->cipher = cipher; return 0; } static void vmac_exit_tfm(struct crypto_tfm *tfm) { - struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); - crypto_free_cipher(ctx->child); + struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(tctx->cipher); } static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) @@ -655,6 +608,10 @@ static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) if (IS_ERR(alg)) return PTR_ERR(alg); + err = -EINVAL; + if (alg->cra_blocksize != 16) + goto out_put_alg; + inst = shash_alloc_instance("vmac", alg); err = PTR_ERR(inst); if (IS_ERR(inst)) @@ -670,11 +627,12 @@ static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_blocksize = alg->cra_blocksize; inst->alg.base.cra_alignmask = alg->cra_alignmask; - inst->alg.digestsize = sizeof(vmac_t); - inst->alg.base.cra_ctxsize = sizeof(struct vmac_ctx_t); + inst->alg.base.cra_ctxsize = sizeof(struct vmac_tfm_ctx); inst->alg.base.cra_init = vmac_init_tfm; inst->alg.base.cra_exit = vmac_exit_tfm; + inst->alg.descsize = sizeof(struct vmac_desc_ctx); + inst->alg.digestsize = VMAC_TAG_LEN / 8; inst->alg.init = vmac_init; inst->alg.update = vmac_update; inst->alg.final = vmac_final; diff --git a/drivers/Makefile b/drivers/Makefile index f5306e9584c07cb073760dd1beec8a23133b3e90..1f3f921c315ce185643dd0448907d0f9653bc741 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_UWB) += uwb/ obj-$(CONFIG_USB_PHY) += usb/ obj-$(CONFIG_USB) += usb/ +obj-$(CONFIG_USB_SUPPORT) += usb/ obj-$(CONFIG_PCI) += usb/ obj-$(CONFIG_USB_GADGET) += usb/ obj-$(CONFIG_SERIO) += input/serio/ diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index f148a0580e0404b64b9fe1a104e05c0c1aaa498b..970f9543e65de3332595b6a85e00c36563c2339f 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -117,6 +117,7 @@ static void round_robin_cpu(unsigned int tsk_index) cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus); if (cpumask_empty(tmp)) { mutex_unlock(&round_robin_lock); + free_cpumask_var(tmp); return; } for_each_cpu(cpu, tmp) { @@ -134,6 +135,8 @@ static void round_robin_cpu(unsigned int tsk_index) mutex_unlock(&round_robin_lock); set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu)); + + free_cpumask_var(tmp); } static void exit_round_robin(unsigned int tsk_index) diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index c7bffff9ed32c97e4c35f8ef5fa0c1372c82687a..f535685336717c4ade5df116754b74cd73240cf9 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -204,6 +204,7 @@ u32 acpi_ev_fixed_event_detect(void) u32 fixed_status; u32 fixed_enable; u32 i; + acpi_status status; ACPI_FUNCTION_NAME(ev_fixed_event_detect); @@ -211,8 +212,12 @@ u32 acpi_ev_fixed_event_detect(void) * Read the fixed feature status and enable registers, as all the cases * depend on their values. Ignore errors here. */ - (void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); - (void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); + status |= + acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); + if (ACPI_FAILURE(status)) { + return (int_status); + } ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, "Fixed Event Block: Enable %08X Status %08X\n", diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index bb8cbf5961bf46de0cf241e18bd76cf18c6f8b6e..d375968c807217c62bae2dbf6acd110f1e4cc333 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -180,6 +180,12 @@ acpi_status acpi_enable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_enable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -237,6 +243,12 @@ acpi_status acpi_disable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_disable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -290,6 +302,12 @@ acpi_status acpi_clear_event(u32 event) ACPI_FUNCTION_TRACE(acpi_clear_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index e634a05974db6a52d4e6bfc2e25996703074c4a8..1358c701883beefed3a3c7028f22c080b8c3b5cd 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -308,6 +308,14 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ status = AE_OK; + } else if (ACPI_FAILURE(status)) { + + /* If return_object exists, delete it */ + + if (info->return_object) { + acpi_ut_remove_reference(info->return_object); + info->return_object = NULL; + } } ACPI_DEBUG_PRINT((ACPI_DB_NAMES, diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index a6885077d59ee7373c7ff8c6fcc1fb327a455eb3..e49a7fa4789eeda32fde43ae3b608311bcccf75c 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -118,6 +118,9 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) (u32)(walk_state->aml_offset + sizeof(struct acpi_table_header))); + ACPI_ERROR((AE_INFO, + "Aborting disassembly, AML byte code is corrupt")); + /* Dump the context surrounding the invalid opcode */ acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. @@ -126,6 +129,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) sizeof(struct acpi_table_header) - 16)); acpi_os_printf(" */\n"); + + /* + * Just abort the disassembly, cannot continue because the + * parser is essentially lost. The disassembler can then + * randomly fail because an ill-constructed parse tree + * can result. + */ + return_ACPI_STATUS(AE_AML_BAD_OPCODE); #endif } @@ -290,6 +301,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, if (status == AE_CTRL_PARSE_CONTINUE) { return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Create Op structure and append to parent's argument list */ diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index ed65e9c4b5b0415c1dcc77690a4add725a49a0bd..ba4930c0e98c9ca51a249574c5e4a371448a6e9c 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -1023,7 +1023,7 @@ skip: /* The record may be cleared by others, try read next record */ if (len == -ENOENT) goto skip; - else if (len < sizeof(*rcd)) { + else if (len < 0 || len < sizeof(*rcd)) { rc = -EIO; goto out; } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index cd4de7e038ea5e0460a896232a99c89554436b52..3e72f9b4209778550240f8a7b2a4824b808b4003 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -476,9 +476,11 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, } control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL - | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | OSC_PCI_EXPRESS_PME_CONTROL; + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; + if (pci_aer_available()) { if (aer_acpi_firmware_first()) dev_info(&device->dev, diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index d9f71581b79b2ede3d90398a6265f6378fa748ac..bdc3063f694d930dd69d1a7601962a8ceebcc875 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -231,11 +231,16 @@ static int __acpi_processor_start(struct acpi_device *device) static int acpi_processor_start(struct device *dev) { struct acpi_device *device = ACPI_COMPANION(dev); + int ret; if (!device) return -ENODEV; - return __acpi_processor_start(device); + /* Protect against concurrent CPU hotplug operations */ + get_online_cpus(); + ret = __acpi_processor_start(device); + put_online_cpus(); + return ret; } static int acpi_processor_stop(struct device *dev) diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index cfc8aba72f86d02eb0c9ae53576382b6ef76f287..59130ce3601eda87d856db3b73d1ec5c66d247f0 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -165,7 +165,7 @@ int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) { int ret; - if (ignore_ppc) { + if (ignore_ppc || !pr->performance) { /* * Only when it is notification event, the _OST object * will be evaluated. Otherwise it is skipped. diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 84243c32e29c515381634b6e7b2cc6f4d219635b..a92ea0a1c7e416a4544265bac81cbf6597d2ac8c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -66,8 +66,8 @@ struct acpi_processor_throttling_arg { #define THROTTLING_POSTCHANGE (2) static int acpi_processor_get_throttling(struct acpi_processor *pr); -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force); +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct); static int acpi_processor_update_tsd_coord(void) { @@ -886,7 +886,8 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid throttling state, reset\n")); state = 0; - ret = acpi_processor_set_throttling(pr, state, true); + ret = __acpi_processor_set_throttling(pr, state, true, + true); if (ret) return ret; } @@ -896,36 +897,31 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) return 0; } -static int acpi_processor_get_throttling(struct acpi_processor *pr) +static long __acpi_processor_get_throttling(void *data) { - cpumask_var_t saved_mask; - int ret; + struct acpi_processor *pr = data; + + return pr->throttling.acpi_processor_get_throttling(pr); +} +static int acpi_processor_get_throttling(struct acpi_processor *pr) +{ if (!pr) return -EINVAL; if (!pr->flags.throttling) return -ENODEV; - if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) - return -ENOMEM; - /* - * Migrate task to the cpu pointed by pr. + * This is either called from the CPU hotplug callback of + * processor_driver or via the ACPI probe function. In the latter + * case the CPU is not guaranteed to be online. Both call sites are + * protected against CPU hotplug. */ - cpumask_copy(saved_mask, ¤t->cpus_allowed); - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { - /* Can't migrate to the target pr->id CPU. Exit */ - free_cpumask_var(saved_mask); + if (!cpu_online(pr->id)) return -ENODEV; - } - ret = pr->throttling.acpi_processor_get_throttling(pr); - /* restore the previous state */ - set_cpus_allowed_ptr(current, saved_mask); - free_cpumask_var(saved_mask); - return ret; + return work_on_cpu(pr->id, __acpi_processor_get_throttling, pr); } static int acpi_processor_get_fadt_info(struct acpi_processor *pr) @@ -1075,8 +1071,15 @@ static long acpi_processor_throttling_fn(void *data) arg->target_state, arg->force); } -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force) +static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct) +{ + if (direct) + return fn(arg); + return work_on_cpu(cpu, fn, arg); +} + +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct) { int ret = 0; unsigned int i; @@ -1125,7 +1128,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, arg.pr = pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg, + direct); } else { /* * When the T-state coordination is SW_ALL or HW_ALL, @@ -1158,8 +1162,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, arg.pr = match_pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, - &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, + &arg, direct); } } /* @@ -1177,6 +1181,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, return ret; } +int acpi_processor_set_throttling(struct acpi_processor *pr, int state, + bool force) +{ + return __acpi_processor_set_throttling(pr, state, force, false); +} + int acpi_processor_get_throttling_info(struct acpi_processor *pr) { int result = 0; diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index bf034f8b7c1acde77f90ded7f39f70dbd636b7db..030ab2f543df58534956d770d97fd6ce012dde1f 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -309,8 +309,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device) device->driver_data = hc; acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); - printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", - hc->ec, hc->offset, hc->query_bit); + dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n", + hc->offset, hc->query_bit); return 0; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index cd4cccbfd2abf6642eb7532c3412317bb279522f..aaf30674d223eb57e1b249978d28b0e026afb319 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -245,6 +245,7 @@ config SATA_SX4 config ATA_BMDMA bool "ATA BMDMA support" + depends on HAS_DMA default y help This option adds support for SFF ATA controllers with BMDMA @@ -290,6 +291,7 @@ config SATA_DWC_VDEBUG config SATA_HIGHBANK tristate "Calxeda Highbank SATA support" + depends on HAS_DMA depends on ARCH_HIGHBANK || COMPILE_TEST help This option enables support for the Calxeda Highbank SoC's @@ -299,6 +301,7 @@ config SATA_HIGHBANK config SATA_MV tristate "Marvell SATA support" + depends on HAS_DMA depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \ ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST select GENERIC_PHY diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 794448ce2fc00c508479fbb5a751c92bbb7eff11..5469a81aa6d3aa028ef1a2abb92f30dd4de5ee56 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2052,6 +2052,8 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) deto = 20; } + /* Make dito, mdat, deto bits to 0s */ + devslp &= ~GENMASK_ULL(24, 2); devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) | (mdat << PORT_DEVSLP_MDAT_OFFSET) | (deto << PORT_DEVSLP_DETO_OFFSET) | diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 0b03f90566924182e4c0411a798c66837d4530ac..94249ceb99f0a34c19bdc9cbb79090bae4320557 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -419,8 +419,9 @@ int ahci_platform_init_host(struct platform_device *pdev, irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(dev, "no irq\n"); - return -EINVAL; + if (irq != -EPROBE_DEFER) + dev_err(dev, "no irq\n"); + return irq; } /* prepare host */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7f15707b485032b4b903abedee2b416e55832982..cd589d012ef13da2b9b41b6124a9f6f8d089b6e3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4188,6 +4188,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */ { "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ, }, + /* Some Sandisk SSDs lock up hard with NCQ enabled. Reported on + SD7SN6S256G and SD8SN8U256G */ + { "SanDisk SD[78]SN*G", NULL, ATA_HORKAGE_NONCQ, }, + /* devices which puke on READ_NATIVE_MAX */ { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, }, { "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA }, @@ -4225,6 +4229,25 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, + /* Crucial BX100 SSD 500GB has broken LPM support */ + { "CT500BX100SSD1", NULL, ATA_HORKAGE_NOLPM }, + + /* 512GB MX100 with MU01 firmware has both queued TRIM and LPM issues */ + { "Crucial_CT512MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + /* 512GB MX100 with newer firmware has only LPM issues */ + { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + + /* 480GB+ M500 SSDs have both queued TRIM and LPM issues */ + { "Crucial_CT480M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + { "Crucial_CT960M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + /* devices that don't properly handle queued TRIM commands */ { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, @@ -4236,7 +4259,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, - { "Samsung SSD 8*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + { "Samsung SSD 840*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Samsung SSD 850*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "FCCT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, @@ -5109,8 +5134,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) * We guarantee to LLDs that they will have at least one * non-zero sg if the command is a data command. */ - if (WARN_ON_ONCE(ata_is_data(prot) && - (!qc->sg || !qc->n_elem || !qc->nbytes))) + if (ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes)) goto sys_err; if (ata_is_dma(prot) || (ata_is_pio(prot) && diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0550c76f4e6c9025bc91af48dc996198f487ba1c..bdf540f8ca8a3b04db43e2584af9a669839376bf 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -174,8 +174,8 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) { } #endif /* CONFIG_PM */ -static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt, - va_list args) +static __printf(2, 0) void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, + const char *fmt, va_list args) { ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len, ATA_EH_DESC_LEN - ehi->desc_len, @@ -2173,12 +2173,16 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (qc->err_mask & ~AC_ERR_OTHER) qc->err_mask &= ~AC_ERR_OTHER; - /* SENSE_VALID trumps dev/unknown error and revalidation */ + /* + * SENSE_VALID trumps dev/unknown error and revalidation. Upper + * layers will determine whether the command is worth retrying + * based on the sense data and device class/type. Otherwise, + * determine directly if the command is worth retrying using its + * error mask and flags. + */ if (qc->flags & ATA_QCFLAG_SENSE_VALID) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); - - /* determine whether the command is worth retrying */ - if (ata_eh_worth_retry(qc)) + else if (ata_eh_worth_retry(qc)) qc->flags |= ATA_QCFLAG_RETRY; /* accumulate error info */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8efa864c02e5d452c20f000f5c58e73be996bb97..3ef02110a8c1304647afd9dadaa8e633ae06f5e5 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3429,7 +3429,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, if (likely((scsi_op != ATA_16) || !atapi_passthru16)) { /* relay SCSI command to ATAPI device */ int len = COMMAND_SIZE(scsi_op); - if (unlikely(len > scmd->cmd_len || len > dev->cdb_len)) + if (unlikely(len > scmd->cmd_len || + len > dev->cdb_len || + scmd->cmd_len > ATAPI_CDB_LEN)) goto bad_cdb_len; xlat_func = atapi_xlat; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 12d337754e4a5b0e6f13fbbf433ad35fe12db801..58b0a58a7f1d898e542eb3eefac231a4ea7fb46b 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1480,7 +1480,6 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; default: - WARN_ON_ONCE(1); return AC_ERR_SYSTEM; } diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index fd29b72240826a51d6a57cffa6e04043774f1d76..43d4fbb377da07c1ba22dad5a1dbb24d4d3418a1 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -223,7 +223,6 @@ static DECLARE_TRANSPORT_CLASS(ata_port_class, static void ata_tport_release(struct device *dev) { - put_device(dev->parent); } /** @@ -283,7 +282,7 @@ int ata_tport_add(struct device *parent, device_initialize(dev); dev->type = &ata_port_type; - dev->parent = get_device(parent); + dev->parent = parent; dev->release = ata_tport_release; dev_set_name(dev, "ata%d", ap->print_id); transport_setup_device(dev); @@ -347,7 +346,6 @@ static DECLARE_TRANSPORT_CLASS(ata_link_class, static void ata_tlink_release(struct device *dev) { - put_device(dev->parent); } /** @@ -409,7 +407,7 @@ int ata_tlink_add(struct ata_link *link) int error; device_initialize(dev); - dev->parent = get_device(&ap->tdev); + dev->parent = &ap->tdev; dev->release = ata_tlink_release; if (ata_is_host_link(link)) dev_set_name(dev, "link%d", ap->print_id); @@ -587,7 +585,6 @@ static DECLARE_TRANSPORT_CLASS(ata_dev_class, static void ata_tdev_release(struct device *dev) { - put_device(dev->parent); } /** @@ -660,7 +657,7 @@ static int ata_tdev_add(struct ata_device *ata_dev) int error; device_initialize(dev); - dev->parent = get_device(&link->tdev); + dev->parent = &link->tdev; dev->release = ata_tdev_release; if (ata_is_host_link(link)) dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno); diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index f3a65a3140d3c7e51bef6dce19f676de768abfdf..0ad96c647541a94bb6e1c68d79d7a661a9bdd703 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -34,7 +34,7 @@ struct zpodd { static int eject_tray(struct ata_device *dev) { struct ata_taskfile tf; - const char cdb[] = { GPCMD_START_STOP_UNIT, + static const char cdb[ATAPI_CDB_LEN] = { GPCMD_START_STOP_UNIT, 0, 0, 0, 0x02, /* LoEj */ 0, 0, 0, 0, 0, 0, 0, @@ -55,7 +55,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) unsigned int ret; struct rm_feature_desc *desc = (void *)(buf + 8); struct ata_taskfile tf; - char cdb[] = { GPCMD_GET_CONFIGURATION, + static const char cdb[] = { GPCMD_GET_CONFIGURATION, 2, /* only 1 feature descriptor requested */ 0, 3, /* 3, removable medium feature */ 0, 0, 0,/* reserved */ diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 1dc0519333f291ab859b58739e762b2aa5ae5834..27a9fa2718f7d491332fc90d7c76ef988fbceb69 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -2828,7 +2828,7 @@ out: return err; out_free_irq: - free_irq(dev->irq, dev); + free_irq(irq, dev); out_free: kfree(dev); out_release: diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 969c3c29000c3622094068d940b854d251393673..9b8130946a35b87d84e21f1666ce7e25885aed9d 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1148,8 +1148,8 @@ static void eprom_get_byte(struct zatm_dev *zatm_dev, unsigned char *byte, } -static unsigned char eprom_try_esi(struct atm_dev *dev, unsigned short cmd, - int offset, int swap) +static int eprom_try_esi(struct atm_dev *dev, unsigned short cmd, int offset, + int swap) { unsigned char buf[ZEPROM_SIZE]; struct zatm_dev *zatm_dev; diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 987ba4488d328f9d7a0fb4f456d9ead526b85cc9..ed9f560142ed68885a8ae37f19bc42d81270fe11 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -4,7 +4,8 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o devres.o \ attribute_container.o transport_class.o \ - topology.o container.o property.o + topology.o container.o property.o \ + cacheinfo.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-$(CONFIG_DMA_CMA) += dma-contiguous.o obj-y += power/ diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c new file mode 100644 index 0000000000000000000000000000000000000000..0428bd732c56205aad809c45b854fd8d25f6bb6d --- /dev/null +++ b/drivers/base/cacheinfo.c @@ -0,0 +1,560 @@ +/* + * cacheinfo support - processor cache information via sysfs + * + * Based on arch/x86/kernel/cpu/intel_cacheinfo.c + * Author: Sudeep Holla + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* pointer to per cpu cacheinfo */ +static DEFINE_PER_CPU(struct cpu_cacheinfo, ci_cpu_cacheinfo); +#define ci_cacheinfo(cpu) (&per_cpu(ci_cpu_cacheinfo, cpu)) +#define cache_leaves(cpu) (ci_cacheinfo(cpu)->num_leaves) +#define per_cpu_cacheinfo(cpu) (ci_cacheinfo(cpu)->info_list) + +struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu) +{ + return ci_cacheinfo(cpu); +} + +#ifdef CONFIG_OF +static int cache_setup_of_node(unsigned int cpu) +{ + struct device_node *np; + struct cacheinfo *this_leaf; + struct device *cpu_dev = get_cpu_device(cpu); + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + unsigned int index = 0; + + /* skip if of_node is already populated */ + if (this_cpu_ci->info_list->of_node) + return 0; + + if (!cpu_dev) { + pr_err("No cpu device for CPU %d\n", cpu); + return -ENODEV; + } + np = cpu_dev->of_node; + if (!np) { + pr_err("Failed to find cpu%d device node\n", cpu); + return -ENOENT; + } + + while (index < cache_leaves(cpu)) { + this_leaf = this_cpu_ci->info_list + index; + if (this_leaf->level != 1) + np = of_find_next_cache_node(np); + else + np = of_node_get(np);/* cpu node itself */ + if (!np) + break; + this_leaf->of_node = np; + index++; + } + + if (index != cache_leaves(cpu)) /* not all OF nodes populated */ + return -ENOENT; + + return 0; +} + +static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, + struct cacheinfo *sib_leaf) +{ + return sib_leaf->of_node == this_leaf->of_node; +} +#else +static inline int cache_setup_of_node(unsigned int cpu) { return 0; } +static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, + struct cacheinfo *sib_leaf) +{ + /* + * For non-DT systems, assume unique level 1 cache, system-wide + * shared caches for all other levels. This will be used only if + * arch specific code has not populated shared_cpu_map + */ + return !(this_leaf->level == 1); +} +#endif + +static int cache_shared_cpu_map_setup(unsigned int cpu) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf, *sib_leaf; + unsigned int index; + int ret; + + ret = cache_setup_of_node(cpu); + if (ret) + return ret; + + for (index = 0; index < cache_leaves(cpu); index++) { + unsigned int i; + + this_leaf = this_cpu_ci->info_list + index; + /* skip if shared_cpu_map is already populated */ + if (!cpumask_empty(&this_leaf->shared_cpu_map)) + continue; + + cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); + for_each_online_cpu(i) { + struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i); + + if (i == cpu || !sib_cpu_ci->info_list) + continue;/* skip if itself or no cacheinfo */ + sib_leaf = sib_cpu_ci->info_list + index; + if (cache_leaves_are_shared(this_leaf, sib_leaf)) { + cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); + cpumask_set_cpu(i, &this_leaf->shared_cpu_map); + } + } + } + + return 0; +} + +static void cache_shared_cpu_map_remove(unsigned int cpu) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf, *sib_leaf; + unsigned int sibling, index; + + for (index = 0; index < cache_leaves(cpu); index++) { + this_leaf = this_cpu_ci->info_list + index; + for_each_cpu(sibling, &this_leaf->shared_cpu_map) { + struct cpu_cacheinfo *sib_cpu_ci; + + if (sibling == cpu) /* skip itself */ + continue; + + sib_cpu_ci = get_cpu_cacheinfo(sibling); + if (!sib_cpu_ci->info_list) + continue; + + sib_leaf = sib_cpu_ci->info_list + index; + cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); + cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map); + } + of_node_put(this_leaf->of_node); + } +} + +static void free_cache_attributes(unsigned int cpu) +{ + if (!per_cpu_cacheinfo(cpu)) + return; + + cache_shared_cpu_map_remove(cpu); + + kfree(per_cpu_cacheinfo(cpu)); + per_cpu_cacheinfo(cpu) = NULL; +} + +int __weak init_cache_level(unsigned int cpu) +{ + return -ENOENT; +} + +int __weak populate_cache_leaves(unsigned int cpu) +{ + return -ENOENT; +} + +static int detect_cache_attributes(unsigned int cpu) +{ + int ret; + + if (init_cache_level(cpu) || !cache_leaves(cpu)) + return -ENOENT; + + per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), + sizeof(struct cacheinfo), GFP_KERNEL); + if (per_cpu_cacheinfo(cpu) == NULL) + return -ENOMEM; + + ret = populate_cache_leaves(cpu); + if (ret) + goto free_ci; + /* + * For systems using DT for cache hierarchy, of_node and shared_cpu_map + * will be set up here only if they are not populated already + */ + ret = cache_shared_cpu_map_setup(cpu); + if (ret) { + pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n", + cpu); + goto free_ci; + } + return 0; + +free_ci: + free_cache_attributes(cpu); + return ret; +} + +/* pointer to cpuX/cache device */ +static DEFINE_PER_CPU(struct device *, ci_cache_dev); +#define per_cpu_cache_dev(cpu) (per_cpu(ci_cache_dev, cpu)) + +static cpumask_t cache_dev_map; + +/* pointer to array of devices for cpuX/cache/indexY */ +static DEFINE_PER_CPU(struct device **, ci_index_dev); +#define per_cpu_index_dev(cpu) (per_cpu(ci_index_dev, cpu)) +#define per_cache_index_dev(cpu, idx) ((per_cpu_index_dev(cpu))[idx]) + +#define show_one(file_name, object) \ +static ssize_t file_name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); \ + return sprintf(buf, "%u\n", this_leaf->object); \ +} + +show_one(level, level); +show_one(coherency_line_size, coherency_line_size); +show_one(number_of_sets, number_of_sets); +show_one(physical_line_partition, physical_line_partition); +show_one(ways_of_associativity, ways_of_associativity); + +static ssize_t size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + + return sprintf(buf, "%uK\n", this_leaf->size >> 10); +} + +static ssize_t shared_cpumap_show_func(struct device *dev, bool list, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + const struct cpumask *mask = &this_leaf->shared_cpu_map; + int len; + + len = list ? + cpulist_scnprintf(buf, PAGE_SIZE-2, mask) : + cpumask_scnprintf(buf, PAGE_SIZE-2, mask); + buf[len++] = '\n'; + buf[len] = '\0'; + return len; +} + +static ssize_t shared_cpu_map_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return shared_cpumap_show_func(dev, false, buf); +} + +static ssize_t shared_cpu_list_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return shared_cpumap_show_func(dev, true, buf); +} + +static ssize_t type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + + switch (this_leaf->type) { + case CACHE_TYPE_DATA: + return sprintf(buf, "Data\n"); + case CACHE_TYPE_INST: + return sprintf(buf, "Instruction\n"); + case CACHE_TYPE_UNIFIED: + return sprintf(buf, "Unified\n"); + default: + return -EINVAL; + } +} + +static ssize_t allocation_policy_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + unsigned int ci_attr = this_leaf->attributes; + int n = 0; + + if ((ci_attr & CACHE_READ_ALLOCATE) && (ci_attr & CACHE_WRITE_ALLOCATE)) + n = sprintf(buf, "ReadWriteAllocate\n"); + else if (ci_attr & CACHE_READ_ALLOCATE) + n = sprintf(buf, "ReadAllocate\n"); + else if (ci_attr & CACHE_WRITE_ALLOCATE) + n = sprintf(buf, "WriteAllocate\n"); + return n; +} + +static ssize_t write_policy_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + unsigned int ci_attr = this_leaf->attributes; + int n = 0; + + if (ci_attr & CACHE_WRITE_THROUGH) + n = sprintf(buf, "WriteThrough\n"); + else if (ci_attr & CACHE_WRITE_BACK) + n = sprintf(buf, "WriteBack\n"); + return n; +} + +static DEVICE_ATTR_RO(level); +static DEVICE_ATTR_RO(type); +static DEVICE_ATTR_RO(coherency_line_size); +static DEVICE_ATTR_RO(ways_of_associativity); +static DEVICE_ATTR_RO(number_of_sets); +static DEVICE_ATTR_RO(size); +static DEVICE_ATTR_RO(allocation_policy); +static DEVICE_ATTR_RO(write_policy); +static DEVICE_ATTR_RO(shared_cpu_map); +static DEVICE_ATTR_RO(shared_cpu_list); +static DEVICE_ATTR_RO(physical_line_partition); + +static struct attribute *cache_default_attrs[] = { + &dev_attr_type.attr, + &dev_attr_level.attr, + &dev_attr_shared_cpu_map.attr, + &dev_attr_shared_cpu_list.attr, + &dev_attr_coherency_line_size.attr, + &dev_attr_ways_of_associativity.attr, + &dev_attr_number_of_sets.attr, + &dev_attr_size.attr, + &dev_attr_allocation_policy.attr, + &dev_attr_write_policy.attr, + &dev_attr_physical_line_partition.attr, + NULL +}; + +static umode_t +cache_default_attrs_is_visible(struct kobject *kobj, + struct attribute *attr, int unused) +{ + struct device *dev = kobj_to_dev(kobj); + struct cacheinfo *this_leaf = dev_get_drvdata(dev); + const struct cpumask *mask = &this_leaf->shared_cpu_map; + umode_t mode = attr->mode; + + if ((attr == &dev_attr_type.attr) && this_leaf->type) + return mode; + if ((attr == &dev_attr_level.attr) && this_leaf->level) + return mode; + if ((attr == &dev_attr_shared_cpu_map.attr) && !cpumask_empty(mask)) + return mode; + if ((attr == &dev_attr_shared_cpu_list.attr) && !cpumask_empty(mask)) + return mode; + if ((attr == &dev_attr_coherency_line_size.attr) && + this_leaf->coherency_line_size) + return mode; + if ((attr == &dev_attr_ways_of_associativity.attr) && + this_leaf->size) /* allow 0 = full associativity */ + return mode; + if ((attr == &dev_attr_number_of_sets.attr) && + this_leaf->number_of_sets) + return mode; + if ((attr == &dev_attr_size.attr) && this_leaf->size) + return mode; + if ((attr == &dev_attr_write_policy.attr) && + (this_leaf->attributes & CACHE_WRITE_POLICY_MASK)) + return mode; + if ((attr == &dev_attr_allocation_policy.attr) && + (this_leaf->attributes & CACHE_ALLOCATE_POLICY_MASK)) + return mode; + if ((attr == &dev_attr_physical_line_partition.attr) && + this_leaf->physical_line_partition) + return mode; + + return 0; +} + +static const struct attribute_group cache_default_group = { + .attrs = cache_default_attrs, + .is_visible = cache_default_attrs_is_visible, +}; + +static const struct attribute_group *cache_default_groups[] = { + &cache_default_group, + NULL, +}; + +static const struct attribute_group *cache_private_groups[] = { + &cache_default_group, + NULL, /* Place holder for private group */ + NULL, +}; + +const struct attribute_group * +__weak cache_get_priv_group(struct cacheinfo *this_leaf) +{ + return NULL; +} + +static const struct attribute_group ** +cache_get_attribute_groups(struct cacheinfo *this_leaf) +{ + const struct attribute_group *priv_group = + cache_get_priv_group(this_leaf); + + if (!priv_group) + return cache_default_groups; + + if (!cache_private_groups[1]) + cache_private_groups[1] = priv_group; + + return cache_private_groups; +} + +/* Add/Remove cache interface for CPU device */ +static void cpu_cache_sysfs_exit(unsigned int cpu) +{ + int i; + struct device *ci_dev; + + if (per_cpu_index_dev(cpu)) { + for (i = 0; i < cache_leaves(cpu); i++) { + ci_dev = per_cache_index_dev(cpu, i); + if (!ci_dev) + continue; + device_unregister(ci_dev); + } + kfree(per_cpu_index_dev(cpu)); + per_cpu_index_dev(cpu) = NULL; + } + device_unregister(per_cpu_cache_dev(cpu)); + per_cpu_cache_dev(cpu) = NULL; +} + +static int cpu_cache_sysfs_init(unsigned int cpu) +{ + struct device *dev = get_cpu_device(cpu); + + if (per_cpu_cacheinfo(cpu) == NULL) + return -ENOENT; + + per_cpu_cache_dev(cpu) = cpu_device_create(dev, NULL, NULL, "cache"); + if (IS_ERR(per_cpu_cache_dev(cpu))) + return PTR_ERR(per_cpu_cache_dev(cpu)); + + /* Allocate all required memory */ + per_cpu_index_dev(cpu) = kcalloc(cache_leaves(cpu), + sizeof(struct device *), GFP_KERNEL); + if (unlikely(per_cpu_index_dev(cpu) == NULL)) + goto err_out; + + return 0; + +err_out: + cpu_cache_sysfs_exit(cpu); + return -ENOMEM; +} + +static int cache_add_dev(unsigned int cpu) +{ + unsigned int i; + int rc; + struct device *ci_dev, *parent; + struct cacheinfo *this_leaf; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + const struct attribute_group **cache_groups; + + rc = cpu_cache_sysfs_init(cpu); + if (unlikely(rc < 0)) + return rc; + + parent = per_cpu_cache_dev(cpu); + for (i = 0; i < cache_leaves(cpu); i++) { + this_leaf = this_cpu_ci->info_list + i; + if (this_leaf->disable_sysfs) + continue; + cache_groups = cache_get_attribute_groups(this_leaf); + ci_dev = cpu_device_create(parent, this_leaf, cache_groups, + "index%1u", i); + if (IS_ERR(ci_dev)) { + rc = PTR_ERR(ci_dev); + goto err; + } + per_cache_index_dev(cpu, i) = ci_dev; + } + cpumask_set_cpu(cpu, &cache_dev_map); + + return 0; +err: + cpu_cache_sysfs_exit(cpu); + return rc; +} + +static void cache_remove_dev(unsigned int cpu) +{ + if (!cpumask_test_cpu(cpu, &cache_dev_map)) + return; + cpumask_clear_cpu(cpu, &cache_dev_map); + + cpu_cache_sysfs_exit(cpu); +} + +static int cacheinfo_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + int rc = 0; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_ONLINE: + rc = detect_cache_attributes(cpu); + if (!rc) + rc = cache_add_dev(cpu); + break; + case CPU_DEAD: + cache_remove_dev(cpu); + free_cache_attributes(cpu); + break; + } + return notifier_from_errno(rc); +} + +static int __init cacheinfo_sysfs_init(void) +{ + int cpu, rc = 0; + + cpu_notifier_register_begin(); + + for_each_online_cpu(cpu) { + rc = detect_cache_attributes(cpu); + if (rc) + goto out; + rc = cache_add_dev(cpu); + if (rc) { + free_cache_attributes(cpu); + pr_err("error populating cacheinfo..cpu%d\n", cpu); + goto out; + } + } + __hotcpu_notifier(cacheinfo_cpu_callback, 0); + +out: + cpu_notifier_register_done(); + return rc; +} + +device_initcall(cacheinfo_sysfs_init); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 802b0faf25e896e5a8e223ba3a2f6d6dd491f86b..4fc7f22b4d9d8e26f039ef2118de13ba3efd3c2d 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -666,6 +666,60 @@ struct device *get_cpu_device(unsigned cpu) } EXPORT_SYMBOL_GPL(get_cpu_device); +static void device_create_release(struct device *dev) +{ + kfree(dev); +} + +static struct device * +__cpu_device_create(struct device *parent, void *drvdata, + const struct attribute_group **groups, + const char *fmt, va_list args) +{ + struct device *dev = NULL; + int retval = -ENODEV; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto error; + } + + device_initialize(dev); + dev->parent = parent; + dev->groups = groups; + dev->release = device_create_release; + dev_set_drvdata(dev, drvdata); + + retval = kobject_set_name_vargs(&dev->kobj, fmt, args); + if (retval) + goto error; + + retval = device_add(dev); + if (retval) + goto error; + + return dev; + +error: + put_device(dev); + return ERR_PTR(retval); +} + +struct device *cpu_device_create(struct device *parent, void *drvdata, + const struct attribute_group **groups, + const char *fmt, ...) +{ + va_list vargs; + struct device *dev; + + va_start(vargs, fmt); + dev = __cpu_device_create(parent, drvdata, groups, fmt, vargs); + va_end(vargs); + return dev; +} +EXPORT_SYMBOL_GPL(cpu_device_create); + #ifdef CONFIG_GENERIC_CPU_AUTOPROBE static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); #endif diff --git a/drivers/base/dd.c b/drivers/base/dd.c index af92c61b6a4e35312351bd68f1e5271a2b6a425f..76c39fdb293b0092cf2da9f9740add219252abe0 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -384,6 +384,7 @@ int driver_probe_done(void) return -EBUSY; return 0; } +EXPORT_SYMBOL_GPL(driver_probe_done); /** * wait_for_device_probe diff --git a/drivers/base/isa.c b/drivers/base/isa.c index 91dba65d72645509b74e289a04402af7696009b4..901d8185309e9b2c7cd3754fbf6b944422417627 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -39,7 +39,7 @@ static int isa_bus_probe(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->probe) + if (isa_driver && isa_driver->probe) return isa_driver->probe(dev, to_isa_dev(dev)->id); return 0; @@ -49,7 +49,7 @@ static int isa_bus_remove(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->remove) + if (isa_driver && isa_driver->remove) return isa_driver->remove(dev, to_isa_dev(dev)->id); return 0; @@ -59,7 +59,7 @@ static void isa_bus_shutdown(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->shutdown) + if (isa_driver && isa_driver->shutdown) isa_driver->shutdown(dev, to_isa_dev(dev)->id); } @@ -67,7 +67,7 @@ static int isa_bus_suspend(struct device *dev, pm_message_t state) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->suspend) + if (isa_driver && isa_driver->suspend) return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); return 0; @@ -77,7 +77,7 @@ static int isa_bus_resume(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->resume) + if (isa_driver && isa_driver->resume) return isa_driver->resume(dev, to_isa_dev(dev)->id); return 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index d620d687c6f89c13e727d391237003119430a2ad..ead6ea0b1a714a72c03eada62dded4c902d28c6d 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -729,7 +729,8 @@ static ssize_t driver_override_store(struct device *dev, struct platform_device *pdev = to_platform_device(dev); char *driver_override, *old, *cp; - if (count > PATH_MAX) + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) return -EINVAL; driver_override = kstrndup(buf, count, GFP_KERNEL); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3d20a9dffdfbae924ee88ed054ad64763c8edac9..4b6af6c3186b747014a0dcfd04d62aec1af3fe0f 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1359,8 +1359,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) dpm_wait_for_children(dev, async); - if (async_error) + if (async_error) { + dev->power.direct_complete = false; goto Complete; + } /* * If a device configured to wake up the system from sleep states @@ -1375,6 +1377,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_get_active_wakeup_sources(suspend_abort, MAX_SUSPEND_ABORT_LEN); log_suspend_abort_reason(suspend_abort); + dev->power.direct_complete = false; async_error = -EBUSY; goto Complete; } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 56d46ffb08e1512eba11e2b1628baeb3a420d63e..f824836d2e7ae63f7bcd797343861fa35aa65789 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3459,6 +3459,9 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int (struct floppy_struct **)&outparam); if (ret) return ret; + memcpy(&inparam.g, outparam, + offsetof(struct floppy_struct, name)); + outparam = &inparam.g; break; case FDMSGON: UDP->flags |= FTD_MSG; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 94385b969f6752729f16dde617d971d1cf8eebe7..15157a3eabb4bf45c85c6fde1b6e496ad8d0794b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -628,6 +628,36 @@ out: } +static inline int is_loop_device(struct file *file) +{ + struct inode *i = file->f_mapping->host; + + return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; +} + +static int loop_validate_file(struct file *file, struct block_device *bdev) +{ + struct inode *inode = file->f_mapping->host; + struct file *f = file; + + /* Avoid recursion */ + while (is_loop_device(f)) { + struct loop_device *l; + + if (f->f_mapping->host->i_bdev == bdev) + return -EBADF; + + l = f->f_mapping->host->i_bdev->bd_disk->private_data; + if (l->lo_state == Lo_unbound) { + return -EINVAL; + } + f = l->lo_backing_file; + } + if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) + return -EINVAL; + return 0; +} + /* * loop_change_fd switched the backing store of a loopback device to * a new file. This is useful for operating system installers to free up @@ -657,14 +687,15 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, if (!file) goto out; + error = loop_validate_file(file, bdev); + if (error) + goto out_putf; + inode = file->f_mapping->host; old_file = lo->lo_backing_file; error = -EINVAL; - if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) - goto out_putf; - /* size of the new backing store needs to be the same */ if (get_loop_size(lo, file) != get_loop_size(lo, old_file)) goto out_putf; @@ -685,13 +716,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, return error; } -static inline int is_loop_device(struct file *file) -{ - struct inode *i = file->f_mapping->host; - - return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; -} - /* loop sysfs attributes */ static ssize_t loop_attr_show(struct device *dev, char *page, @@ -779,16 +803,17 @@ static struct attribute_group loop_attribute_group = { .attrs= loop_attrs, }; -static int loop_sysfs_init(struct loop_device *lo) +static void loop_sysfs_init(struct loop_device *lo) { - return sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj, - &loop_attribute_group); + lo->sysfs_inited = !sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj, + &loop_attribute_group); } static void loop_sysfs_exit(struct loop_device *lo) { - sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj, - &loop_attribute_group); + if (lo->sysfs_inited) + sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj, + &loop_attribute_group); } static void loop_config_discard(struct loop_device *lo) @@ -823,7 +848,7 @@ static void loop_config_discard(struct loop_device *lo) static int loop_set_fd(struct loop_device *lo, fmode_t mode, struct block_device *bdev, unsigned int arg) { - struct file *file, *f; + struct file *file; struct inode *inode; struct address_space *mapping; unsigned lo_blocksize; @@ -843,29 +868,13 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, if (lo->lo_state != Lo_unbound) goto out_putf; - /* Avoid recursion */ - f = file; - while (is_loop_device(f)) { - struct loop_device *l; - - if (f->f_mapping->host->i_bdev == bdev) - goto out_putf; - - l = f->f_mapping->host->i_bdev->bd_disk->private_data; - if (l->lo_state == Lo_unbound) { - error = -EINVAL; - goto out_putf; - } - f = l->lo_backing_file; - } + error = loop_validate_file(file, bdev); + if (error) + goto out_putf; mapping = file->f_mapping; inode = mapping->host; - error = -EINVAL; - if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) - goto out_putf; - if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) || !file->f_op->write) lo_flags |= LO_FLAGS_READ_ONLY; diff --git a/drivers/block/loop.h b/drivers/block/loop.h index 90df5d6485b696bf897dbdf204fa4fea3c414b63..fb113dd45e9766e61b62b1e5c5c3df076580ac1d 100644 --- a/drivers/block/loop.h +++ b/drivers/block/loop.h @@ -60,6 +60,7 @@ struct loop_device { wait_queue_head_t lo_event; /* wait queue for incoming requests */ wait_queue_head_t lo_req_wait; + bool sysfs_inited; struct request_queue *lo_queue; struct gendisk *lo_disk; diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 3b7c9f1be484eb13b483ddc0e5f5f4794a9fe98b..9c981f600d240d84e65fdb0564e1f036f4cef343 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -229,6 +229,8 @@ static int pcd_block_open(struct block_device *bdev, fmode_t mode) struct pcd_unit *cd = bdev->bd_disk->private_data; int ret; + check_disk_change(bdev); + mutex_lock(&pcd_mutex); ret = cdrom_open(&cd->info, bdev, mode); mutex_unlock(&pcd_mutex); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 09e628dafd9d829eadd9abb68c6956d182a582f8..46098d236476ee693dcebe7b36cf92190e3127b3 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2798,7 +2798,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) pd->pkt_dev = MKDEV(pktdev_major, idx); ret = pkt_new_dev(pd, dev); if (ret) - goto out_new_dev; + goto out_mem2; /* inherit events of the host device */ disk->events = pd->bdev->bd_disk->events; @@ -2816,8 +2816,6 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) mutex_unlock(&ctl_mutex); return 0; -out_new_dev: - blk_cleanup_queue(disk->queue); out_mem2: put_disk(disk); out_mem: diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 2f735872673766cc895ae3b479fddb94bf162414..9e97f3415b365b96cff4416e5375ea98a5daa6a0 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2700,7 +2700,7 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request) * from the parent. */ page_count = (u32)calc_pages_for(0, length); - pages = ceph_alloc_page_vector(page_count, GFP_KERNEL); + pages = ceph_alloc_page_vector(page_count, GFP_NOIO); if (IS_ERR(pages)) { result = PTR_ERR(pages); pages = NULL; @@ -2827,7 +2827,7 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request) */ size = sizeof (__le64) + sizeof (__le32) + sizeof (__le32); page_count = (u32)calc_pages_for(0, size); - pages = ceph_alloc_page_vector(page_count, GFP_KERNEL); + pages = ceph_alloc_page_vector(page_count, GFP_NOIO); if (IS_ERR(pages)) return PTR_ERR(pages); diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 1e46eb2305c04a8e63e378befb95a905fdf01850..f928e698f6594293885b93047c648e3f2103bf25 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -2214,6 +2214,9 @@ static void skd_send_fitmsg(struct skd_device *skdev, */ qcmd |= FIT_QCMD_MSGSIZE_64; + /* Make sure skd_msg_buf is written before the doorbell is triggered. */ + smp_wmb(); + SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); } @@ -2260,6 +2263,9 @@ static void skd_send_special_fitmsg(struct skd_device *skdev, qcmd = skspcl->mb_dma_address; qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128; + /* Make sure skd_msg_buf is written before the doorbell is triggered. */ + smp_wmb(); + SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); } @@ -4679,15 +4685,16 @@ static void skd_free_disk(struct skd_device *skdev) { struct gendisk *disk = skdev->disk; - if (disk != NULL) { - struct request_queue *q = disk->queue; + if (disk && (disk->flags & GENHD_FL_UP)) + del_gendisk(disk); - if (disk->flags & GENHD_FL_UP) - del_gendisk(disk); - if (q) - blk_cleanup_queue(q); - put_disk(disk); + if (skdev->queue) { + blk_cleanup_queue(skdev->queue); + skdev->queue = NULL; + disk->queue = NULL; } + + put_disk(disk); skdev->disk = NULL; } diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index d3d0070146796d84bc74b7cb9c250ad32ad1c105..895eedfc2e1730978995865870b53ddc88b075f5 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -85,6 +85,7 @@ config BT_HCIUART_LL config BT_HCIUART_3WIRE bool "Three-wire UART (H5) protocol support" depends on BT_HCIUART + depends on BT_HCIUART_SERDEV help The HCI Three-wire UART Transport Layer makes it possible to user the Bluetooth HCI over a serial port interface. The HCI diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 8485481d0c891532e0cbf344fe39a712ba19dc05..1fb3c61cea75d65fb31cb28a43cd2f58a98356ee 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, 2013-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2010, 2013-2017 The Linux Foundation. All rights reserved. * * 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 diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c index 4d523cfe51cee0416ec04517e8faf3c2c7722a61..31342fccd29084fd6c2e1a2938a469c92894e30c 100644 --- a/drivers/bus/arm-ccn.c +++ b/drivers/bus/arm-ccn.c @@ -1157,6 +1157,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) /* Perf driver registration */ ccn->dt.pmu = (struct pmu) { + .module = THIS_MODULE, .attr_groups = arm_ccn_pmu_attr_groups, .task_ctx_nr = perf_invalid_context, .event_init = arm_ccn_pmu_event_init, diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index d29f5ffdb0f4adbc0db8029b99a99488197023d4..d729c1cc7542b7ae3450da13c00dba8a2c90ef80 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -523,7 +523,7 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) if (mbus->hw_io_coherency) w->mbus_attr |= ATTR_HW_COHERENCY; w->base = base & DDR_BASE_CS_LOW_MASK; - w->size = (size | ~DDR_SIZE_MASK) + 1; + w->size = (u64)(size | ~DDR_SIZE_MASK) + 1; } } mvebu_mbus_dram_info.num_cs = cs; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 5d28a45d2960c6a40945b134c755ff03a1117c76..81fb29741dc1cec3a0ca620ca3704c5f2fa253bb 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1153,9 +1153,6 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, cd_dbg(CD_OPEN, "entering cdrom_open\n"); - /* open is event synchronization point, check events first */ - check_disk_change(bdev); - /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ cdi->use_count++; @@ -2357,7 +2354,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi, if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) return media_changed(cdi, 1); - if ((unsigned int)arg >= cdi->capacity) + if (arg >= cdi->capacity) return -EINVAL; info = kmalloc(sizeof(*info), GFP_KERNEL); @@ -2528,7 +2525,7 @@ static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi, if (!CDROM_CAN(CDC_SELECT_DISC) || (arg == CDSL_CURRENT || arg == CDSL_NONE)) return cdi->ops->drive_status(cdi, CDSL_CURRENT); - if (((int)arg >= cdi->capacity)) + if (arg >= cdi->capacity) return -EINVAL; return cdrom_slot_status(cdi, arg); } diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 584bc3126403d58955a915db2117fcd1d16de5a2..e2808fefbb78b28bf64889d1af10556bf2c5c08c 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -497,6 +497,9 @@ static struct cdrom_device_ops gdrom_ops = { static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) { int ret; + + check_disk_change(bdev); + mutex_lock(&gdrom_mutex); ret = cdrom_open(gd.cd_info, bdev, mode); mutex_unlock(&gdrom_mutex); diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index c33e3473b01136bc1e3a1b6af87d92a0d9d3b537..1d0e53d8ad1ba03474842b52d8127dbe0c3a2634 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -72,6 +72,7 @@ #define FASTRPC_CTXID_MASK (0xFF0) #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0) +#define FASTRPC_STATIC_HANDLE_KERNEL (1) static void file_free_work_handler(struct work_struct *w); @@ -155,9 +156,11 @@ struct smq_invoke_ctx { int tgid; remote_arg_t *lpra; remote_arg64_t *rpra; + remote_arg64_t *lrpra; /* Local copy of rpra for put_args */ int *fds; struct fastrpc_mmap **maps; struct fastrpc_buf *buf; + struct fastrpc_buf *lbuf; size_t used; struct fastrpc_file *fl; uint32_t sc; @@ -286,7 +289,7 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { }, { .name = "mdsprpc-smd", - .subsys = "mdsp", + .subsys = "modem", .channel = SMD_APPS_MODEM, .edge = "mdsp", }, @@ -403,6 +406,10 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { + if (map->refs + 1 == INT_MAX) { + spin_unlock(&me->hlock); + return -ETOOMANYREFS; + } map->refs++; match = map; break; @@ -415,6 +422,10 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { + if (map->refs + 1 == INT_MAX) { + spin_unlock(&fl->hlock); + return -ETOOMANYREFS; + } map->refs++; match = map; break; @@ -961,6 +972,7 @@ static void context_free(struct smq_invoke_ctx *ctx) for (i = 0; i < nbufs; ++i) fastrpc_mmap_free(ctx->maps[i]); fastrpc_buf_free(ctx->buf, 1); + fastrpc_buf_free(ctx->lbuf, 1); ctx->magic = 0; ctx->ctxid = 0; @@ -1073,7 +1085,7 @@ static void fastrpc_file_list_dtor(struct fastrpc_apps *me) static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) { - remote_arg64_t *rpra; + remote_arg64_t *rpra, *lrpra; remote_arg_t *lpra = ctx->lpra; struct smq_invoke_buf *list; struct smq_phy_page *pages, *ipage; @@ -1082,10 +1094,11 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) int outbufs = REMOTE_SCALARS_OUTBUFS(sc); int bufs = inbufs + outbufs; uintptr_t args; - size_t rlen = 0, copylen = 0, metalen = 0; + size_t rlen = 0, copylen = 0, metalen = 0, lrpralen = 0; int i, inh, oix; int err = 0; int mflags = 0; + DEFINE_DMA_ATTRS(ctx_attrs); /* calculate size of the metadata */ rpra = NULL; @@ -1102,7 +1115,22 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) ipage += 1; } metalen = copylen = (size_t)&ipage[0]; - /* calculate len requreed for copying */ + + /* allocate new local rpra buffer */ + lrpralen = (u64)(uintptr_t)&list[0]; + if (lrpralen) { + err = fastrpc_buf_alloc(ctx->fl, lrpralen, + ctx_attrs, 0, 0, &ctx->lbuf); + if (err) + goto bail; + } + if (ctx->lbuf->virt) + memset(ctx->lbuf->virt, 0, lrpralen); + + lrpra = ctx->lbuf->virt; + ctx->lrpra = lrpra; + + /* calculate len required for copying */ for (oix = 0; oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; uintptr_t mstart, mend; @@ -1128,8 +1156,6 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) /* allocate new buffer */ if (copylen) { - DEFINE_DMA_ATTRS(ctx_attrs); - err = fastrpc_buf_alloc(ctx->fl, copylen, ctx_attrs, 0, 0, &ctx->buf); if (err) @@ -1153,12 +1179,13 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) ipage++; } /* map ion buffers */ - for (i = 0; i < inbufs + outbufs; ++i) { + for (i = 0; rpra && lrpra && i < inbufs + outbufs; ++i) { struct fastrpc_mmap *map = ctx->maps[i]; uint64_t buf = ptr_to_uint64(lpra[i].buf.pv); size_t len = lpra[i].buf.len; - rpra[i].buf.pv = 0; - rpra[i].buf.len = len; + + rpra[i].buf.pv = lrpra[i].buf.pv = 0; + rpra[i].buf.len = lrpra[i].buf.len = len; if (!len) continue; if (map) { @@ -1183,11 +1210,11 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) pages[idx].addr = map->phys + offset; pages[idx].size = num << PAGE_SHIFT; } - rpra[i].buf.pv = buf; + rpra[i].buf.pv = lrpra[i].buf.pv = buf; } /* copy non ion buffers */ rlen = copylen - metalen; - for (oix = 0; oix < inbufs + outbufs; ++oix) { + for (oix = 0; rpra && lrpra && oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; struct fastrpc_mmap *map = ctx->maps[i]; size_t mlen; @@ -1206,7 +1233,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) VERIFY(err, rlen >= mlen); if (err) goto bail; - rpra[i].buf.pv = (args - ctx->overps[oix]->offset); + rpra[i].buf.pv = lrpra[i].buf.pv = + (args - ctx->overps[oix]->offset); pages[list[i].pgidx].addr = ctx->buf->phys - ctx->overps[oix]->offset + (copylen - rlen); @@ -1229,7 +1257,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) struct fastrpc_mmap *map = ctx->maps[i]; if (map && map->uncached) continue; - if (rpra[i].buf.len && ctx->overps[oix]->mstart) { + if (rpra && lrpra && rpra[i].buf.len && + ctx->overps[oix]->mstart) { if (map && map->handle) msm_ion_do_cache_op(ctx->fl->apps->client, map->handle, @@ -1243,10 +1272,12 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) } } inh = inbufs + outbufs; - for (i = 0; i < REMOTE_SCALARS_INHANDLES(sc); i++) { - rpra[inh + i].buf.pv = ptr_to_uint64(ctx->lpra[inh + i].buf.pv); - rpra[inh + i].buf.len = ctx->lpra[inh + i].buf.len; - rpra[inh + i].h = ctx->lpra[inh + i].h; + for (i = 0; rpra && lrpra && i < REMOTE_SCALARS_INHANDLES(sc); i++) { + rpra[inh + i].buf.pv = lrpra[inh + i].buf.pv = + ptr_to_uint64(ctx->lpra[inh + i].buf.pv); + rpra[inh + i].buf.len = lrpra[inh + i].buf.len = + ctx->lpra[inh + i].buf.len; + rpra[inh + i].h = lrpra[inh + i].h = ctx->lpra[inh + i].h; } bail: @@ -1257,7 +1288,7 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, remote_arg_t *upra) { uint32_t sc = ctx->sc; - remote_arg64_t *rpra = ctx->rpra; + remote_arg64_t *rpra = ctx->lrpra; int i, inbufs, outbufs, outh, size; int err = 0; @@ -1337,7 +1368,7 @@ static void inv_args(struct smq_invoke_ctx *ctx) { int i, inbufs, outbufs; uint32_t sc = ctx->sc; - remote_arg64_t *rpra = ctx->rpra; + remote_arg64_t *rpra = ctx->lrpra; int inv = 0; inbufs = REMOTE_SCALARS_INBUFS(sc); @@ -1482,6 +1513,15 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, int interrupted = 0; int err = 0; + if (!kernel) { + VERIFY(err, invoke->handle != FASTRPC_STATIC_HANDLE_KERNEL); + if (err) { + pr_err("adsprpc: ERROR: %s: user application %s trying to send a kernel RPC message to channel %d\n", + __func__, current->comm, cid); + goto bail; + } + } + VERIFY(err, fl->sctx != NULL); if (err) goto bail; @@ -1560,7 +1600,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, ra[0].buf.pv = (void *)&tgid; ra[0].buf.len = sizeof(tgid); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0); ioctl.inv.pra = ra; ioctl.fds = NULL; @@ -1583,8 +1623,9 @@ static int fastrpc_init_process(struct fastrpc_file *fl, inbuf.pgid = current->tgid; inbuf.namelen = strlen(current->comm) + 1; inbuf.filelen = init->filelen; - if (!access_ok(VERIFY_READ, (void const __user *)init->file, - init->filelen)) + VERIFY(err, access_ok(0, (void __user *)init->file, + init->filelen)); + if (err) goto bail; if (init->filelen) { VERIFY(err, !fastrpc_mmap_create(fl, init->filefd, @@ -1631,7 +1672,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, ra[3].buf.len = 1 * sizeof(*pages); fds[3] = 0; - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(6, 4, 0); ioctl.inv.pra = ra; ioctl.fds = fds; @@ -1663,7 +1704,7 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) tgid = fl->tgid; ra[0].buf.pv = (void *)&tgid; ra[0].buf.len = sizeof(tgid); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0); ioctl.inv.pra = ra; ioctl.fds = NULL; @@ -1707,7 +1748,7 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags, ra[2].buf.pv = (void *)&routargs; ra[2].buf.len = sizeof(routargs); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; if (fl->apps->compat) ioctl.inv.sc = REMOTE_SCALARS_MAKE(4, 2, 1); else @@ -1748,7 +1789,7 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, uint64_t phys, ra[0].buf.pv = (void *)&routargs; ra[0].buf.len = sizeof(routargs); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(7, 0, 1); ioctl.inv.pra = ra; ioctl.fds = NULL; @@ -1792,7 +1833,7 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, uintptr_t raddr, ra[0].buf.pv = (void *)&inargs; ra[0].buf.len = sizeof(inargs); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; if (fl->apps->compat) ioctl.inv.sc = REMOTE_SCALARS_MAKE(5, 1, 0); else @@ -1853,6 +1894,31 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, static void fastrpc_mmap_add(struct fastrpc_mmap *map); +static inline void get_fastrpc_ioctl_mmap_64( + struct fastrpc_ioctl_mmap_64 *mmap64, + struct fastrpc_ioctl_mmap *immap) +{ + immap->fd = mmap64->fd; + immap->flags = mmap64->flags; + immap->vaddrin = (uintptr_t)mmap64->vaddrin; + immap->size = mmap64->size; +} + +static inline void put_fastrpc_ioctl_mmap_64( + struct fastrpc_ioctl_mmap_64 *mmap64, + struct fastrpc_ioctl_mmap *immap) +{ + mmap64->vaddrout = (uint64_t)immap->vaddrout; +} + +static inline void get_fastrpc_ioctl_munmap_64( + struct fastrpc_ioctl_munmap_64 *munmap64, + struct fastrpc_ioctl_munmap *imunmap) +{ + imunmap->vaddrout = (uintptr_t)munmap64->vaddrout; + imunmap->size = munmap64->size; +} + static int fastrpc_internal_munmap(struct fastrpc_file *fl, struct fastrpc_ioctl_munmap *ud) { @@ -1993,8 +2059,10 @@ static int fastrpc_file_free(struct fastrpc_file *fl) hlist_del_init(&fl->hn); spin_unlock(&fl->apps->hlock); - if (!fl->sctx) - goto bail; + if (!fl->sctx) { + kfree(fl); + return 0; + } (void)fastrpc_release_current_dsp_process(fl); if (!IS_ERR_OR_NULL(fl->init_mem)) @@ -2007,8 +2075,6 @@ static int fastrpc_file_free(struct fastrpc_file *fl) if (fl->ssrcount == fl->apps->channel[cid].ssrcount) kref_put_mutex(&fl->apps->channel[cid].kref, fastrpc_channel_close, &fl->apps->smd_mutex); - -bail: mutex_destroy(&fl->map_mutex); fastrpc_remote_buf_list_free(fl); kfree(fl); @@ -2290,11 +2356,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->init_mem = NULL; VERIFY(err, !fastrpc_session_alloc(&me->channel[cid], &session)); - if (err) { - kfree(fl); - fl = NULL; + if (err) goto bail; - } fl->sctx = &me->channel[cid].session[session]; fl->ssrcount = me->channel[cid].ssrcount; @@ -2385,10 +2448,16 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, union { struct fastrpc_ioctl_invoke_fd invokefd; struct fastrpc_ioctl_mmap mmap; + struct fastrpc_ioctl_mmap_64 mmap64; struct fastrpc_ioctl_munmap munmap; + struct fastrpc_ioctl_munmap_64 munmap64; struct fastrpc_ioctl_init init; struct fastrpc_ioctl_control cp; } p; + union { + struct fastrpc_ioctl_mmap mmap; + struct fastrpc_ioctl_munmap munmap; + } i; void *param = (char *)ioctl_param; struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data; int size = 0, err = 0; @@ -2430,6 +2499,31 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, if (err) goto bail; break; + case FASTRPC_IOCTL_MMAP_64: + K_COPY_FROM_USER(err, 0, &p.mmap64, param, + sizeof(p.mmap64)); + if (err) + goto bail; + get_fastrpc_ioctl_mmap_64(&p.mmap64, &i.mmap); + VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &i.mmap))); + if (err) + goto bail; + put_fastrpc_ioctl_mmap_64(&p.mmap64, &i.mmap); + K_COPY_TO_USER(err, 0, param, &p.mmap64, sizeof(p.mmap64)); + if (err) + goto bail; + break; + case FASTRPC_IOCTL_MUNMAP_64: + K_COPY_FROM_USER(err, 0, &p.munmap64, param, + sizeof(p.munmap64)); + if (err) + goto bail; + get_fastrpc_ioctl_munmap_64(&p.munmap64, &i.munmap); + VERIFY(err, 0 == (err = fastrpc_internal_munmap(fl, + &i.munmap))); + if (err) + goto bail; + break; case FASTRPC_IOCTL_SETMODE: switch ((uint32_t)ioctl_param) { case FASTRPC_MODE_PARALLEL: @@ -2471,10 +2565,6 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, sizeof(p.init))); if (err) goto bail; - VERIFY(err, p.init.filelen >= 0 && - p.init.memlen >= 0); - if (err) - goto bail; VERIFY(err, 0 == fastrpc_init_process(fl, &p.init)); if (err) goto bail; diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c index c52f091287e309a73184be1110ff93a8be2fac95..be100985fa765e1a0159f02417a3080933172ee1 100644 --- a/drivers/char/adsprpc_compat.c +++ b/drivers/char/adsprpc_compat.c @@ -30,6 +30,10 @@ _IOWR('R', 4, struct compat_fastrpc_ioctl_invoke_fd) #define COMPAT_FASTRPC_IOCTL_INIT \ _IOWR('R', 6, struct compat_fastrpc_ioctl_init) +#define COMPAT_FASTRPC_IOCTL_MMAP_64 \ + _IOWR('R', 14, struct compat_fastrpc_ioctl_mmap_64) +#define COMPAT_FASTRPC_IOCTL_MUNMAP_64 \ + _IOWR('R', 15, struct compat_fastrpc_ioctl_munmap_64) #define COMPAT_FASTRPC_IOCTL_CONTROL \ _IOWR('R', 12, struct compat_fastrpc_ioctl_control) @@ -62,11 +66,24 @@ struct compat_fastrpc_ioctl_mmap { compat_uptr_t vaddrout; /* dsps virtual address */ }; +struct compat_fastrpc_ioctl_mmap_64 { + compat_int_t fd; /* ion fd */ + compat_uint_t flags; /* flags for dsp to map with */ + compat_u64 vaddrin; /* optional virtual address */ + compat_size_t size; /* size */ + compat_u64 vaddrout; /* dsps virtual address */ +}; + struct compat_fastrpc_ioctl_munmap { compat_uptr_t vaddrout; /* address to unmap */ compat_size_t size; /* size */ }; +struct compat_fastrpc_ioctl_munmap_64 { + compat_u64 vaddrout; /* address to unmap */ + compat_size_t size; /* size */ +}; + struct compat_fastrpc_ioctl_init { compat_uint_t flags; /* one of FASTRPC_INIT_* macros */ compat_uptr_t file; /* pointer to elf file */ @@ -206,6 +223,28 @@ static int compat_get_fastrpc_ioctl_mmap( return err; } +static int compat_get_fastrpc_ioctl_mmap_64( + struct compat_fastrpc_ioctl_mmap_64 __user *map32, + struct fastrpc_ioctl_mmap __user *map) +{ + compat_uint_t u; + compat_int_t i; + compat_size_t s; + compat_u64 p; + int err; + + err = get_user(i, &map32->fd); + err |= put_user(i, &map->fd); + err |= get_user(u, &map32->flags); + err |= put_user(u, &map->flags); + err |= get_user(p, &map32->vaddrin); + err |= put_user(p, &map->vaddrin); + err |= get_user(s, &map32->size); + err |= put_user(s, &map->size); + + return err; +} + static int compat_put_fastrpc_ioctl_mmap( struct compat_fastrpc_ioctl_mmap __user *map32, struct fastrpc_ioctl_mmap __user *map) @@ -219,6 +258,19 @@ static int compat_put_fastrpc_ioctl_mmap( return err; } +static int compat_put_fastrpc_ioctl_mmap_64( + struct compat_fastrpc_ioctl_mmap_64 __user *map32, + struct fastrpc_ioctl_mmap __user *map) +{ + compat_u64 p; + int err; + + err = get_user(p, &map->vaddrout); + err |= put_user(p, &map32->vaddrout); + + return err; +} + static int compat_get_fastrpc_ioctl_munmap( struct compat_fastrpc_ioctl_munmap __user *unmap32, struct fastrpc_ioctl_munmap __user *unmap) @@ -235,6 +287,22 @@ static int compat_get_fastrpc_ioctl_munmap( return err; } +static int compat_get_fastrpc_ioctl_munmap_64( + struct compat_fastrpc_ioctl_munmap_64 __user *unmap32, + struct fastrpc_ioctl_munmap __user *unmap) +{ + compat_u64 p; + compat_size_t s; + int err; + + err = get_user(p, &unmap32->vaddrout); + err |= put_user(p, &unmap->vaddrout); + err |= get_user(s, &unmap32->size); + err |= put_user(s, &unmap->size); + + return err; +} + static int compat_get_fastrpc_ioctl_control( struct compat_fastrpc_ioctl_control __user *ctrl32, struct fastrpc_ioctl_control __user *ctrl) @@ -324,6 +392,27 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, VERIFY(err, 0 == compat_put_fastrpc_ioctl_mmap(map32, map)); return err; } + case COMPAT_FASTRPC_IOCTL_MMAP_64: + { + struct compat_fastrpc_ioctl_mmap_64 __user *map32; + struct fastrpc_ioctl_mmap __user *map; + long ret; + + map32 = compat_ptr(arg); + VERIFY(err, NULL != (map = compat_alloc_user_space( + sizeof(*map)))); + if (err) + return -EFAULT; + VERIFY(err, 0 == compat_get_fastrpc_ioctl_mmap_64(map32, map)); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MMAP_64, + (unsigned long)map); + if (ret) + return ret; + VERIFY(err, 0 == compat_put_fastrpc_ioctl_mmap_64(map32, map)); + return err; + } case COMPAT_FASTRPC_IOCTL_MUNMAP: { struct compat_fastrpc_ioctl_munmap __user *unmap32; @@ -341,6 +430,23 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, return filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MUNMAP, (unsigned long)unmap); } + case COMPAT_FASTRPC_IOCTL_MUNMAP_64: + { + struct compat_fastrpc_ioctl_munmap_64 __user *unmap32; + struct fastrpc_ioctl_munmap __user *unmap; + + unmap32 = compat_ptr(arg); + VERIFY(err, NULL != (unmap = compat_alloc_user_space( + sizeof(*unmap)))); + if (err) + return -EFAULT; + VERIFY(err, 0 == compat_get_fastrpc_ioctl_munmap_64(unmap32, + unmap)); + if (err) + return err; + return filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MUNMAP_64, + (unsigned long)unmap); + } case COMPAT_FASTRPC_IOCTL_INIT: { struct compat_fastrpc_ioctl_init __user *init32; diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index 0c9e00a6f35d0c1852d0183839db684692c02f5a..709863d856980215f138f3fa7fe207a716877549 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -19,6 +19,8 @@ #define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke) #define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap) #define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap) +#define FASTRPC_IOCTL_MMAP_64 _IOWR('R', 14, struct fastrpc_ioctl_mmap_64) +#define FASTRPC_IOCTL_MUNMAP_64 _IOWR('R', 15, struct fastrpc_ioctl_munmap_64) #define FASTRPC_IOCTL_INVOKE_FD _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd) #define FASTRPC_IOCTL_SETMODE _IOWR('R', 5, uint32_t) #define FASTRPC_IOCTL_INIT _IOWR('R', 6, struct fastrpc_ioctl_init) @@ -143,6 +145,10 @@ struct fastrpc_ioctl_munmap { size_t size; /* size */ }; +struct fastrpc_ioctl_munmap_64 { + uint64_t vaddrout; /* address to unmap */ + size_t size; /* size */ +}; struct fastrpc_ioctl_mmap { int fd; /* ion fd */ @@ -152,6 +158,14 @@ struct fastrpc_ioctl_mmap { uintptr_t vaddrout; /* dsps virtual address */ }; +struct fastrpc_ioctl_mmap_64 { + int fd; /* ion fd */ + uint32_t flags; /* flags for dsp to map with */ + uint64_t vaddrin; /* optional virtual address */ + size_t size; /* size */ + uint64_t vaddrout; /* dsps virtual address */ +}; + #define FASTRPC_CONTROL_LATENCY (1) struct fastrpc_ctrl_latency { uint32_t enable; /* !latency control enable */ diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index a56ee9bedd112ddeea5551ba922a7d767ab7cd3b..a5a0e135cfecc119d5661f9e016a901b0f5446d9 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -196,7 +196,7 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, int ty return 0; } -int uninorth_remove_memory(struct agp_memory *mem, off_t pg_start, int type) +static int uninorth_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { size_t i; u32 *gp; @@ -467,7 +467,7 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge) return 0; } -void null_cache_flush(void) +static void null_cache_flush(void) { mb(); } diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 6e24f475d65dbfda496338bfa86c139a86fc19b5..9c9c09b3025677a6eb9f5fe94d8997cc71468f6a 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -695,32 +695,47 @@ int diag_dci_query_event_mask(struct diag_dci_client_tbl *entry, return ((*event_mask_ptr & byte_mask) == byte_mask) ? 1 : 0; } -static int diag_dci_filter_commands(struct diag_pkt_header_t *header) +static int diag_dci_filter_commands(struct diag_pkt_header_t *header, + int header_len) { if (!header) return -ENOMEM; - switch (header->cmd_code) { - case 0x7d: /* Msg Mask Configuration */ - case 0x73: /* Log Mask Configuration */ - case 0x81: /* Event Mask Configuration */ - case 0x82: /* Event Mask Change */ - case 0x60: /* Event Mask Toggle */ - return 1; - } + if (header_len <= 0) + return -EIO; - if (header->cmd_code == 0x4b && header->subsys_id == 0x12) { - switch (header->subsys_cmd_code) { - case 0x60: /* Extended Event Mask Config */ - case 0x61: /* Extended Msg Mask Config */ - case 0x62: /* Extended Log Mask Config */ - case 0x20C: /* Set current Preset ID */ - case 0x20D: /* Get current Preset ID */ - case 0x218: /* HDLC Disabled Command */ + if (header_len) { + switch (header->cmd_code) { + case 0x7d: /* Msg Mask Configuration */ + case 0x73: /* Log Mask Configuration */ + case 0x81: /* Event Mask Configuration */ + case 0x82: /* Event Mask Change */ + case 0x60: /* Event Mask Toggle */ + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: command not supported: %d\n", + header->cmd_code); return 1; } } + if (header_len >= (3*sizeof(uint8_t))) { + if (header->cmd_code == 0x4b && header->subsys_id == 0x12) { + switch (header->subsys_cmd_code) { + case 0x60: /* Extended Event Mask Config */ + case 0x61: /* Extended Msg Mask Config */ + case 0x62: /* Extended Log Mask Config */ + case 0x20C: /* Set current Preset ID */ + case 0x20D: /* Get current Preset ID */ + case 0x218: /* HDLC Disabled Command */ + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: command not supported %d %d %d\n", + header->cmd_code, header->subsys_id, + header->subsys_cmd_code); + return 1; + } + } + } + return 0; } @@ -951,8 +966,9 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, unsigned char *temp = buf; int save_req_uid = 0; struct diag_dci_pkt_rsp_header_t pkt_rsp_header; + int header_len = sizeof(struct diag_dci_pkt_rsp_header_t); - if (!buf) { + if (!buf || len <= 0) { pr_err("diag: Invalid pointer in %s\n", __func__); return; } @@ -966,6 +982,8 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, dci_cmd_code); return; } + if (len < (cmd_code_len + sizeof(int))) + return; temp += cmd_code_len; tag = *(int *)temp; temp += sizeof(int); @@ -974,10 +992,16 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, * The size of the response is (total length) - (length of the command * code, the tag (int) */ - rsp_len = len - (cmd_code_len + sizeof(int)); - if ((rsp_len == 0) || (rsp_len > (len - 5))) { - pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d", - __func__, len, rsp_len); + if (len >= cmd_code_len + sizeof(int)) { + rsp_len = len - (cmd_code_len + sizeof(int)); + if ((rsp_len == 0) || (rsp_len > (len - 5))) { + pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d\n", + __func__, len, rsp_len); + return; + } + } else { + pr_err("diag:%s: Invalid length(%d) for calculating rsp_len\n", + __func__, len); return; } @@ -1011,23 +1035,24 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, mutex_lock(&rsp_buf->data_mutex); /* * Check if we can fit the data in the rsp buffer. The total length of - * the rsp is the rsp length (write_len) + DCI_PKT_RSP_TYPE header (int) - * + field for length (int) + delete_flag (uint8_t) + * the rsp is the rsp length (write_len) + dci response packet header + * length (sizeof(struct diag_dci_pkt_rsp_header_t)) */ - if ((rsp_buf->data_len + 9 + rsp_len) > rsp_buf->capacity) { + if ((rsp_buf->data_len + header_len + rsp_len) > rsp_buf->capacity) { pr_alert("diag: create capacity for pkt rsp\n"); - rsp_buf->capacity += 9 + rsp_len; - temp_buf = krealloc(rsp_buf->data, rsp_buf->capacity, - GFP_KERNEL); + temp_buf = vzalloc(rsp_buf->capacity + header_len + rsp_len); if (!temp_buf) { pr_err("diag: DCI realloc failed\n"); mutex_unlock(&rsp_buf->data_mutex); mutex_unlock(&entry->buffers[data_source].buf_mutex); mutex_unlock(&driver->dci_mutex); return; - } else { - rsp_buf->data = temp_buf; } + rsp_buf->capacity += header_len + rsp_len; + if (rsp_buf->capacity > rsp_buf->data_len) + memcpy(temp_buf, rsp_buf->data, rsp_buf->data_len); + vfree(rsp_buf->data); + rsp_buf->data = temp_buf; } /* Fill in packet response header information */ @@ -1036,9 +1061,8 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, pkt_rsp_header.length = rsp_len + sizeof(int); pkt_rsp_header.delete_flag = delete_flag; pkt_rsp_header.uid = save_req_uid; - memcpy(rsp_buf->data + rsp_buf->data_len, &pkt_rsp_header, - sizeof(struct diag_dci_pkt_rsp_header_t)); - rsp_buf->data_len += sizeof(struct diag_dci_pkt_rsp_header_t); + memcpy(rsp_buf->data + rsp_buf->data_len, &pkt_rsp_header, header_len); + rsp_buf->data_len += header_len; memcpy(rsp_buf->data + rsp_buf->data_len, temp, rsp_len); rsp_buf->data_len += rsp_len; rsp_buf->data_source = data_source; @@ -1437,6 +1461,7 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc) DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: dci client with pid = %d Exited..\n", entry->tgid); + put_pid(pid_struct); mutex_unlock(&driver->dci_mutex); return; } @@ -1451,9 +1476,12 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc) if (stat) pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n", info.si_int, stat); - } else + } else { pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n", info.si_int, stat); + } + put_task_struct(dci_task); + put_pid(pid_struct); } } } @@ -1684,22 +1712,26 @@ int diag_dci_send_handshake_pkt(int index) static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header, unsigned char *req_buf, int req_len, - int tag) + int tag, int pkt_header_len) { - uint8_t cmd_code, subsys_id, i, goto_download = 0; + uint8_t cmd_code = 0, subsys_id = 0, i, goto_download = 0; uint8_t header_len = sizeof(struct diag_dci_pkt_header_t); - uint16_t ss_cmd_code; + uint16_t ss_cmd_code = 0; uint32_t write_len = 0; unsigned char *dest_buf = driver->apps_dci_buf; unsigned char *payload_ptr = driver->apps_dci_buf + header_len; struct diag_dci_pkt_header_t dci_header; - if (!pkt_header || !req_buf || req_len <= 0 || tag < 0) + if (!pkt_header || !req_buf || req_len <= 0 || tag < 0 || + pkt_header_len <= 0) return -EIO; - cmd_code = pkt_header->cmd_code; - subsys_id = pkt_header->subsys_id; - ss_cmd_code = pkt_header->subsys_cmd_code; + if (pkt_header_len >= (sizeof(uint8_t))) + cmd_code = pkt_header->cmd_code; + if (pkt_header_len >= (2 * sizeof(uint8_t))) + subsys_id = pkt_header->subsys_id; + if (pkt_header_len >= (3 * sizeof(uint8_t))) + ss_cmd_code = pkt_header->subsys_cmd_code; if (cmd_code == DIAG_CMD_DOWNLOAD) { *payload_ptr = DIAG_CMD_DOWNLOAD; @@ -1819,7 +1851,7 @@ fill_buffer: static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) { int ret = DIAG_DCI_TABLE_ERR; - int common_cmd = 0; + int common_cmd = 0, header_len = 0; struct diag_pkt_header_t *header = NULL; unsigned char *temp = buf; unsigned char *req_buf = NULL; @@ -1835,7 +1867,8 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) if (!buf) return -EIO; - if (len <= sizeof(struct dci_pkt_req_t) || len > DCI_REQ_BUF_SIZE) { + if (len < sizeof(struct dci_pkt_req_t) || + len > DCI_REQ_BUF_SIZE) { pr_err("diag: dci: Invalid length %d len in %s", len, __func__); return -EIO; } @@ -1845,14 +1878,6 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) read_len += sizeof(struct dci_pkt_req_t); req_len -= sizeof(struct dci_pkt_req_t); req_buf = temp; /* Start of the Request */ - header = (struct diag_pkt_header_t *)temp; - temp += sizeof(struct diag_pkt_header_t); - read_len += sizeof(struct diag_pkt_header_t); - if (read_len >= DCI_REQ_BUF_SIZE) { - pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__, - read_len); - return -EIO; - } mutex_lock(&driver->dci_mutex); dci_entry = diag_dci_get_client_entry(req_hdr.client_id); @@ -1863,11 +1888,40 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) return DIAG_DCI_NO_REG; } + header = (void *)temp; + header_len = len - sizeof(struct dci_pkt_req_t); + if (header_len <= 0) { + mutex_unlock(&driver->dci_mutex); + return -EIO; + } + if (header_len >= sizeof(uint8_t)) { + header->cmd_code = (uint16_t)(*(uint8_t *)temp); + read_len += sizeof(uint8_t); + } + if (header_len >= (2 * sizeof(uint8_t))) { + temp += sizeof(uint8_t); + header->subsys_id = (uint16_t)(*(uint8_t *)temp); + read_len += sizeof(uint8_t); + } + if (header_len == (3 * sizeof(uint8_t))) { + temp += sizeof(uint8_t); + header->subsys_cmd_code = (uint16_t)(*(uint8_t *)temp); + read_len += sizeof(uint8_t); + } else if (header_len >= + (2 * sizeof(uint8_t)) + sizeof(uint16_t)) { + temp += sizeof(uint8_t); + header->subsys_cmd_code = (uint16_t)(*(uint16_t *)temp); + read_len += sizeof(uint16_t); + } + if (read_len > DCI_REQ_BUF_SIZE) { + pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__, + read_len); + mutex_unlock(&driver->dci_mutex); + return -EIO; + } + /* Check if the command is allowed on DCI */ - if (diag_dci_filter_commands(header)) { - pr_debug("diag: command not supported %d %d %d", - header->cmd_code, header->subsys_id, - header->subsys_cmd_code); + if (diag_dci_filter_commands(header, header_len)) { mutex_unlock(&driver->dci_mutex); return DIAG_DCI_SEND_DATA_FAIL; } @@ -1921,14 +1975,23 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) /* Check if it is a dedicated Apps command */ ret = diag_dci_process_apps_pkt(header, req_buf, req_len, - req_entry->tag); + req_entry->tag, header_len); if ((ret == DIAG_DCI_NO_ERROR && !common_cmd) || ret < 0) return ret; - reg_entry.cmd_code = header->cmd_code; - reg_entry.subsys_id = header->subsys_id; - reg_entry.cmd_code_hi = header->subsys_cmd_code; - reg_entry.cmd_code_lo = header->subsys_cmd_code; + reg_entry.cmd_code = 0; + reg_entry.subsys_id = 0; + reg_entry.cmd_code_hi = 0; + reg_entry.cmd_code_lo = 0; + + if (header_len >= (sizeof(uint8_t))) + reg_entry.cmd_code = header->cmd_code; + if (header_len >= (2 * sizeof(uint8_t))) + reg_entry.subsys_id = header->subsys_id; + if (header_len >= (3 * sizeof(uint8_t))) { + reg_entry.cmd_code_hi = header->subsys_cmd_code; + reg_entry.cmd_code_lo = header->subsys_cmd_code; + } mutex_lock(&driver->cmd_reg_mutex); temp_entry = diag_cmd_search(®_entry, ALL_PROC); @@ -1958,9 +2021,9 @@ int diag_process_dci_transaction(unsigned char *buf, int len) uint8_t *event_mask_ptr; struct diag_dci_client_tbl *dci_entry = NULL; - if (!temp) { - pr_err("diag: Invalid buffer in %s\n", __func__); - return -ENOMEM; + if (!temp || len < sizeof(int)) { + pr_err("diag: Invalid input in %s\n", __func__); + return -EINVAL; } /* This is Pkt request/response transaction */ @@ -2015,7 +2078,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) count = 0; /* iterator for extracting log codes */ while (count < num_codes) { - if (read_len >= USER_SPACE_DATA) { + if (read_len + sizeof(uint16_t) > len) { pr_err("diag: dci: Invalid length for log type in %s", __func__); mutex_unlock(&driver->dci_mutex); @@ -2128,7 +2191,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) pr_debug("diag: head of dci event mask %pK\n", event_mask_ptr); count = 0; /* iterator for extracting log codes */ while (count < num_codes) { - if (read_len >= USER_SPACE_DATA) { + if (read_len + sizeof(int) > len) { pr_err("diag: dci: Invalid length for event type in %s", __func__); mutex_unlock(&driver->dci_mutex); @@ -2196,8 +2259,8 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid) pid_struct = find_get_pid(entry->tgid); if (!pid_struct) { DIAG_LOG(DIAG_DEBUG_DCI, - "diag: valid pid doesn't exist for pid = %d\n", - entry->tgid); + "diag: Exited pid (%d) doesn't match dci client of pid (%d)\n", + tgid, entry->tgid); continue; } task_s = get_pid_task(pid_struct, PIDTYPE_PID); @@ -2205,11 +2268,18 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid) DIAG_LOG(DIAG_DEBUG_DCI, "diag: valid task doesn't exist for pid = %d\n", entry->tgid); + put_pid(pid_struct); continue; } - if (task_s == entry->client) - if (entry->client->tgid == tgid) + if (task_s == entry->client) { + if (entry->client->tgid == tgid) { + put_task_struct(task_s); + put_pid(pid_struct); return entry; + } + } + put_task_struct(task_s); + put_pid(pid_struct); } return NULL; } @@ -2835,6 +2905,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) mutex_lock(&driver->dci_mutex); + get_task_struct(current); new_entry->client = current; new_entry->tgid = current->tgid; new_entry->client_info.notification_list = @@ -2981,6 +3052,9 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) if (!list_empty(&entry->track)) list_del(&entry->track); driver->num_dci_client--; + + put_task_struct(entry->client); + entry->client = NULL; /* * Clear the client's log and event masks, update the cumulative * masks and send the masks to peripherals diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h index a9e2d35cc50af32023b3fe7da9054a911e06d33b..fa19219e5d6e57ecfbc7ee87d29d1184ba1fa689 100644 --- a/drivers/char/diag/diag_dci.h +++ b/drivers/char/diag/diag_dci.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -25,7 +25,7 @@ #define DISABLE_LOG_MASK 0 #define MAX_EVENT_SIZE 512 #define DCI_CLIENT_INDEX_INVALID -1 -#define DCI_LOG_CON_MIN_LEN 14 +#define DCI_LOG_CON_MIN_LEN 16 #define DCI_EVENT_CON_MIN_LEN 16 #define DCI_BUF_PRIMARY 1 diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 4b24df4b6e4c82164d1589113ed1942b9a66fe2e..bd3107b3eaf2b46ea0fc1fd94729ff7c2ebe1864 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * 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,9 +27,6 @@ #define DIAG_SET_FEATURE_MASK(x) (feature_bytes[(x)/8] |= (1 << (x & 0x7))) -#define diag_check_update(x) \ - (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x)))) \ - struct diag_mask_info msg_mask; struct diag_mask_info msg_bt_mask; struct diag_mask_info log_mask; @@ -64,6 +61,20 @@ static const struct diag_ssid_range_t msg_mask_tbl[] = { { .ssid_first = MSG_SSID_25, .ssid_last = MSG_SSID_25_LAST } }; +static int diag_check_update(int md_peripheral, int pid) +{ + int ret; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); + ret = (!info || (info && + (info->peripheral_mask & MD_PERIPHERAL_MASK(md_peripheral)))); + mutex_unlock(&driver->md_session_lock); + + return ret; +} + static int diag_apps_responds(void) { /* @@ -142,6 +153,9 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) mutex_lock(&mask_info->lock); for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + if (!mask->ptr) + continue; + if (equip_id != i && equip_id != ALL_EQUIP_ID) continue; @@ -293,11 +307,12 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) int temp_len = 0; uint8_t *buf = NULL; uint8_t *temp = NULL; + uint8_t msg_mask_tbl_count_local = 0; uint32_t mask_size = 0; struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_ctrl_msg_mask header; - uint8_t msg_mask_tbl_count_local; + struct diag_md_session_t *md_session_info = NULL; if (peripheral >= NUM_PERIPHERALS) return; @@ -309,10 +324,11 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } - if (driver->md_session_mask != 0 && - (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))) + if ((driver->md_session_mask != 0) && + (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))) { + md_session_info = driver->md_session_map[peripheral]; mask_info = driver->md_session_map[peripheral]->msg_mask; - else + } else mask_info = &msg_mask; if (!mask_info) @@ -325,7 +341,10 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } buf = mask_info->update_buf; - msg_mask_tbl_count_local = driver->msg_mask_tbl_count; + if (md_session_info) + msg_mask_tbl_count_local = md_session_info->msg_mask_tbl_count; + else + msg_mask_tbl_count_local = driver->msg_mask_tbl_count; mutex_unlock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); switch (mask_info->status) { @@ -344,6 +363,8 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) } for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) { + if (!mask->ptr) + continue; mutex_lock(&driver->msg_mask_lock); if (((mask->ssid_first > first) || (mask->ssid_last_tools < last)) && first != ALL_SSID) { @@ -496,6 +517,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, { int i; int write_len = 0; + uint8_t msg_mask_tbl_count = 0; struct diag_msg_mask_t *mask_ptr = NULL; struct diag_msg_ssid_query_t rsp; struct diag_ssid_range_t ssid_range; @@ -525,15 +547,17 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, return 0; } mutex_lock(&driver->msg_mask_lock); + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE; rsp.status = MSG_STATUS_SUCCESS; rsp.padding = 0; - rsp.count = driver->msg_mask_tbl_count; + rsp.count = msg_mask_tbl_count; memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); mask_ptr = (struct diag_msg_mask_t *)mask_info->ptr; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask_ptr++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask_ptr++) { if (write_len + sizeof(ssid_range) > dest_len) { pr_err("diag: In %s, Truncating response due to size limitations of rsp buffer\n", __func__); @@ -560,7 +584,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, struct diag_build_mask_req_t *req = NULL; struct diag_msg_build_mask_t rsp; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + if (!src_buf || !dest_buf || dest_len <= 0 || + src_len < sizeof(struct diag_build_mask_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d\n", __func__, src_buf, src_len, dest_buf, dest_len); return -EINVAL; @@ -579,6 +604,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, rsp.padding = 0; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { + if (!build_mask->ptr) + continue; if (build_mask->ssid_first != req->ssid_first) continue; num_entries = req->ssid_last - req->ssid_first + 1; @@ -610,6 +637,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, int i; int write_len = 0; uint32_t mask_size = 0; + uint8_t msg_mask_tbl_count = 0; struct diag_msg_mask_t *mask = NULL; struct diag_build_mask_req_t *req = NULL; struct diag_msg_build_mask_t rsp; @@ -620,8 +648,8 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || + !mask_info || (src_len < sizeof(struct diag_build_mask_req_t))) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -640,6 +668,8 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, } mutex_lock(&driver->msg_mask_lock); + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; req = (struct diag_build_mask_req_t *)src_buf; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_MSG_MASK; @@ -655,7 +685,9 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; if ((req->ssid_first < mask->ssid_first) || (req->ssid_first > mask->ssid_last_tools)) { continue; @@ -692,13 +724,14 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, struct diag_msg_mask_t *mask_next = NULL; uint32_t *temp = NULL; struct diag_md_session_t *info = NULL; + uint8_t msg_mask_tbl_count = 0; mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + (src_len < sizeof(struct diag_msg_build_mask_t))) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -724,8 +757,12 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { - if (i < (driver->msg_mask_tbl_count - 1)) { + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; + if (i < (msg_mask_tbl_count - 1)) { mask_next = mask; mask_next++; } else @@ -778,7 +815,9 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, break; } mask_size = mask_size * sizeof(uint32_t); - memcpy(mask->ptr + offset, src_buf + header_len, mask_size); + if (mask_size && src_len >= header_len + mask_size) + memcpy(mask->ptr + offset, src_buf + header_len, + mask_size); mutex_unlock(&mask->lock); mask_info->status = DIAG_CTRL_MASK_VALID; break; @@ -786,7 +825,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(MSG_MASKS_TYPE); /* @@ -805,10 +844,11 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, goto end; if (mask_size + write_len > dest_len) mask_size = dest_len - write_len; - memcpy(dest_buf + write_len, src_buf + header_len, mask_size); + if (mask_size && src_len >= header_len + mask_size) + memcpy(dest_buf + write_len, src_buf + header_len, mask_size); write_len += mask_size; for (i = 0; i < NUM_PERIPHERALS; i++) { - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; diag_send_msg_mask_update(i, req->ssid_first, req->ssid_last); } @@ -827,13 +867,14 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, struct diag_msg_mask_t *mask = NULL; struct diag_mask_info *mask_info = NULL; struct diag_md_session_t *info = NULL; + uint8_t msg_mask_tbl_count = 0; mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + (src_len < sizeof(struct diag_msg_config_rsp_t))) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -861,9 +902,11 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (mask && mask->ptr) { mutex_lock(&mask->lock); memset(mask->ptr, req->rt_mask, @@ -874,7 +917,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(MSG_MASKS_TYPE); /* @@ -890,7 +933,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, write_len += header_len; for (i = 0; i < NUM_PERIPHERALS; i++) { - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; diag_send_msg_mask_update(i, ALL_SSID, ALL_SSID); } @@ -948,8 +991,8 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); mask_info = (!info) ? &event_mask : info->event_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + src_len < sizeof(struct diag_event_mask_config_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -972,11 +1015,12 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, } mutex_lock(&mask_info->lock); - memcpy(mask_info->ptr, src_buf + header_len, mask_len); + if (src_len >= header_len + mask_len) + memcpy(mask_info->ptr, src_buf + header_len, mask_len); mask_info->status = DIAG_CTRL_MASK_VALID; mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(EVENT_MASKS_TYPE); /* @@ -993,7 +1037,7 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, write_len += mask_len; for (i = 0; i < NUM_PERIPHERALS; i++) { - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; diag_send_event_mask_update(i); } @@ -1014,8 +1058,8 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); mask_info = (!info) ? &event_mask : info->event_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || src_len <= sizeof(uint8_t) || + dest_len <= 0 || !mask_info) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1040,7 +1084,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, } mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(EVENT_MASKS_TYPE); /* @@ -1050,7 +1094,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, header.cmd_code = DIAG_CMD_EVENT_TOGGLE; header.padding = 0; for (i = 0; i < NUM_PERIPHERALS; i++) { - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; diag_send_event_mask_update(i); } @@ -1080,8 +1124,8 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &log_mask : info->log_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + src_len < sizeof(struct diag_log_config_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1224,8 +1268,8 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &log_mask : info->log_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + src_len < sizeof(struct diag_log_config_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1299,7 +1343,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, mask->range_tools = mask_size; } req->num_items = mask->num_items_tools; - if (mask_size > 0) + if (mask_size > 0 && src_len >= read_len + mask_size) memcpy(mask->ptr, src_buf + read_len, mask_size); DIAG_LOG(DIAG_DEBUG_MASKS, "copying log mask, e %d num %d range %d size %d\n", @@ -1311,7 +1355,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, } mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(LOG_MASKS_TYPE); /* @@ -1340,7 +1384,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, write_len += payload_len; for (i = 0; i < NUM_PERIPHERALS; i++) { - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; diag_send_log_mask_update(i, req->equip_id); } @@ -1392,7 +1436,7 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, } mask_info->status = DIAG_CTRL_MASK_ALL_DISABLED; mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(LOG_MASKS_TYPE); /* @@ -1408,7 +1452,7 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, memcpy(dest_buf, &header, sizeof(struct diag_log_config_rsp_t)); write_len += sizeof(struct diag_log_config_rsp_t); for (i = 0; i < NUM_PERIPHERALS; i++) { - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; diag_send_log_mask_update(i, ALL_EQUIP_ID); } @@ -1451,7 +1495,8 @@ static int diag_create_msg_mask_table(void) mutex_lock(&msg_mask.lock); mutex_lock(&driver->msg_mask_lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; (i < driver->msg_mask_tbl_count) && mask; + i++, mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(mask, &range); @@ -1476,7 +1521,8 @@ static int diag_create_build_time_mask(void) mutex_lock(&driver->msg_mask_lock); driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; - for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; (i < driver->bt_msg_mask_tbl_count) && build_mask; + i++, build_mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(build_mask, &range); @@ -1599,7 +1645,7 @@ static int diag_create_log_mask_table(void) mutex_lock(&log_mask.lock); mask = (struct diag_log_mask_t *)(log_mask.ptr); - for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + for (i = 0; (i < MAX_EQUIP_ID) && mask; i++, mask++) { mask->equip_id = i; mask->num_items = LOG_GET_ITEM_NUM(log_code_last_tbl[i]); mask->num_items_tools = mask->num_items; @@ -1639,11 +1685,11 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len, mask_info->update_buf = kzalloc(update_buf_len, GFP_KERNEL); if (!mask_info->update_buf) { kfree(mask_info->ptr); + mask_info->ptr = NULL; return -ENOMEM; } kmemleak_not_leak(mask_info->update_buf); } - mutex_init(&mask_info->lock); return 0; } @@ -1667,9 +1713,10 @@ int diag_log_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) struct diag_log_mask_t *src_mask = NULL; struct diag_log_mask_t *dest_mask = NULL; - if (!src) + if (!src || !dest) return -EINVAL; + mutex_init(&dest->lock); err = __diag_mask_init(dest, LOG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -1732,9 +1779,11 @@ static int diag_msg_mask_init(void) int err = 0; int i; + mutex_init(&msg_mask.lock); err = __diag_mask_init(&msg_mask, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; + err = diag_create_msg_mask_table(); if (err) { pr_err("diag: Unable to create msg masks, err: %d\n", err); @@ -1749,7 +1798,8 @@ static int diag_msg_mask_init(void) return 0; } -int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) +int diag_msg_mask_copy(struct diag_md_session_t *new_session, + struct diag_mask_info *dest, struct diag_mask_info *src) { int i; int err = 0; @@ -1760,17 +1810,25 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) if (!src || !dest) return -EINVAL; - err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); - if (err) - return err; + mutex_init(&dest->lock); mutex_lock(&dest->lock); mutex_lock(&driver->msg_mask_lock); + new_session->msg_mask_tbl_count = + driver->msg_mask_tbl_count; + err = __diag_mask_init(dest, + (new_session->msg_mask_tbl_count * + sizeof(struct diag_msg_mask_t)), APPS_BUF_SIZE); + if (err) { + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&dest->lock); + return err; + } src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; dest->mask_len = src->mask_len; dest->status = src->status; - for (i = 0; i < driver->msg_mask_tbl_count; i++) { + for (i = 0; i < new_session->msg_mask_tbl_count; i++) { range.ssid_first = src_mask->ssid_first; range.ssid_last = src_mask->ssid_last; err = diag_create_msg_mask_table_entry(dest_mask, &range); @@ -1786,10 +1844,12 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) return err; } -void diag_msg_mask_free(struct diag_mask_info *mask_info) +void diag_msg_mask_free(struct diag_mask_info *mask_info, + struct diag_md_session_t *session_info) { int i; struct diag_msg_mask_t *mask = NULL; + uint8_t msg_mask_tbl_count = 0; if (!mask_info || !mask_info->ptr) return; @@ -1803,7 +1863,10 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) mutex_unlock(&mask_info->lock); return; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (session_info) ? + session_info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; } @@ -1834,6 +1897,7 @@ static int diag_build_time_mask_init(void) int err = 0; /* There is no need for update buffer for Build Time masks */ + mutex_init(&msg_bt_mask.lock); err = __diag_mask_init(&msg_bt_mask, MSG_MASK_SIZE, 0); if (err) return err; @@ -1867,6 +1931,7 @@ static int diag_log_mask_init(void) int err = 0; int i; + mutex_init(&log_mask.lock); err = __diag_mask_init(&log_mask, LOG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -1901,6 +1966,7 @@ static int diag_event_mask_init(void) int err = 0; int i; + mutex_init(&event_mask.lock); err = __diag_mask_init(&event_mask, EVENT_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -1922,6 +1988,7 @@ int diag_event_mask_copy(struct diag_mask_info *dest, if (!src || !dest) return -EINVAL; + mutex_init(&dest->lock); err = __diag_mask_init(dest, EVENT_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -1961,6 +2028,7 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; unsigned char *ptr = NULL; + uint8_t msg_mask_tbl_count = 0; if (!buf || count == 0) return -EINVAL; @@ -1974,14 +2042,6 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, __func__, mask_info->ptr, mask_info->update_buf); return -EINVAL; } - mutex_lock(&driver->diag_maskclear_mutex); - if (driver->mask_clear) { - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag:%s: count = %zu\n", __func__, count); - mutex_unlock(&driver->diag_maskclear_mutex); - return -EIO; - } - mutex_unlock(&driver->diag_maskclear_mutex); mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); @@ -1993,7 +2053,11 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, mutex_unlock(&mask_info->lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; ptr = mask_info->update_buf; len = 0; mutex_lock(&mask->lock); @@ -2068,6 +2132,8 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, return -EINVAL; } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + if (!mask->ptr) + continue; ptr = mask_info->update_buf; len = 0; mutex_lock(&mask->lock); diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h index 6edeee954d74baedccd5b7dc877bd61522dbdb7e..a736ff269e8d5c3bc12616ff0a490b2e2fd6942f 100644 --- a/drivers/char/diag/diag_masks.h +++ b/drivers/char/diag/diag_masks.h @@ -160,12 +160,13 @@ int diag_masks_init(void); void diag_masks_exit(void); int diag_log_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src); -int diag_msg_mask_copy(struct diag_mask_info *dest, - struct diag_mask_info *src); +int diag_msg_mask_copy(struct diag_md_session_t *new_session, + struct diag_mask_info *dest, struct diag_mask_info *src); int diag_event_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src); void diag_log_mask_free(struct diag_mask_info *mask_info); -void diag_msg_mask_free(struct diag_mask_info *mask_info); +void diag_msg_mask_free(struct diag_mask_info *mask_info, + struct diag_md_session_t *session_info); void diag_event_mask_free(struct diag_mask_info *mask_info); int diag_process_apps_masks(unsigned char *buf, int len, int pid); void diag_send_updates_peripheral(uint8_t peripheral); diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index 51b937f768681e3987c522e876865c91adbc8af5..80b550bad74278bf5e610d019fccb47ab7b51f4a 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, 2016, 2018 The Linux Foundation. +/* Copyright (c) 2014-2016, 2018-2019 The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -37,6 +37,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MUX_APPS, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -46,6 +47,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MDM_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -54,6 +56,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MDM2_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -62,6 +65,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_QSC_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, } @@ -85,6 +89,8 @@ void diag_md_open_all() for (i = 0; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; if (ch->ops && ch->ops->open) ch->ops->open(ch->ctx, DIAG_MEMORY_DEVICE_MODE); } @@ -101,6 +107,8 @@ void diag_md_close_all() for (i = 0; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; if (ch->ops && ch->ops->close) ch->ops->close(ch->ctx, DIAG_MEMORY_DEVICE_MODE); @@ -158,6 +166,8 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) mutex_unlock(&driver->md_session_lock); ch = &diag_md[id]; + if (!ch || !ch->md_info_inited) + return -EINVAL; spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -199,7 +209,10 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) continue; found = 1; - driver->data_ready[i] |= USER_SPACE_DATA_TYPE; + if (!(driver->data_ready[i] & USER_SPACE_DATA_TYPE)) { + driver->data_ready[i] |= USER_SPACE_DATA_TYPE; + atomic_inc(&driver->data_ready_notif[i]); + } pr_debug("diag: wake up logging process\n"); wake_up_interruptible(&driver->wait_q); } @@ -228,6 +241,8 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; for (j = 0; j < ch->num_tbl_entries && !err; j++) { entry = &ch->tbl[j]; if (entry->len <= 0) @@ -325,6 +340,8 @@ int diag_md_close_peripheral(int id, uint8_t peripheral) return -EINVAL; ch = &diag_md[id]; + if (!ch || !ch->md_info_inited) + return -EINVAL; spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -345,12 +362,12 @@ int diag_md_close_peripheral(int id, uint8_t peripheral) return 0; } -int diag_md_init() +int diag_md_init(void) { int i, j; struct diag_md_info *ch = NULL; - for (i = 0; i < NUM_DIAG_MD_DEV; i++) { + for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) { ch = &diag_md[i]; ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize; ch->tbl = kzalloc(ch->num_tbl_entries * @@ -365,6 +382,7 @@ int diag_md_init() ch->tbl[j].ctx = 0; } spin_lock_init(&(ch->lock)); + ch->md_info_inited = 1; } return 0; @@ -374,12 +392,54 @@ fail: return -ENOMEM; } -void diag_md_exit() +int diag_md_mdm_init(void) +{ + int i, j; + struct diag_md_info *ch = NULL; + + for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) { + ch = &diag_md[i]; + ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize; + ch->tbl = kcalloc(ch->num_tbl_entries, sizeof(*ch->tbl), + GFP_KERNEL); + if (!ch->tbl) + goto fail; + + for (j = 0; j < ch->num_tbl_entries; j++) { + ch->tbl[j].buf = NULL; + ch->tbl[j].len = 0; + ch->tbl[j].ctx = 0; + } + spin_lock_init(&(ch->lock)); + ch->md_info_inited = 1; + } + + return 0; + +fail: + diag_md_mdm_exit(); + return -ENOMEM; +} + +void diag_md_exit(void) { int i; struct diag_md_info *ch = NULL; - for (i = 0; i < NUM_DIAG_MD_DEV; i++) { + for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) { + ch = &diag_md[i]; + kfree(ch->tbl); + ch->num_tbl_entries = 0; + ch->ops = NULL; + } +} + +void diag_md_mdm_exit(void) +{ + int i; + struct diag_md_info *ch = NULL; + + for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; kfree(ch->tbl); ch->num_tbl_entries = 0; diff --git a/drivers/char/diag/diag_memorydevice.h b/drivers/char/diag/diag_memorydevice.h index 35a1ee35a956c6b2fcbb9113a432366fe9e3223a..4d65dedfdb5814bb95b27ba20f2026b4e7be33c5 100644 --- a/drivers/char/diag/diag_memorydevice.h +++ b/drivers/char/diag/diag_memorydevice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -38,6 +38,7 @@ struct diag_md_info { int ctx; int mempool; int num_tbl_entries; + int md_info_inited; spinlock_t lock; struct diag_buf_tbl_t *tbl; struct diag_mux_ops *ops; @@ -46,7 +47,9 @@ struct diag_md_info { extern struct diag_md_info diag_md[NUM_DIAG_MD_DEV]; int diag_md_init(void); +int diag_md_mdm_init(void); void diag_md_exit(void); +void diag_md_mdm_exit(void); void diag_md_open_all(void); void diag_md_close_all(void); int diag_md_register(int id, int ctx, struct diag_mux_ops *ops); diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 6586f5e0cf867ba930439990a83ba22b7fb00d0d..1f562f8d129acc60ea4c7b36b41ab31acfe35b7d 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -192,6 +192,8 @@ int diag_mux_switch_logging(int *req_mode, int *peripheral_mask) new_mask = ~(*peripheral_mask) & diag_mux->mux_mask; if (new_mask != DIAG_CON_NONE) *req_mode = DIAG_MULTI_MODE; + if (new_mask == DIAG_CON_ALL) + *req_mode = DIAG_MEMORY_DEVICE_MODE; break; case DIAG_MEMORY_DEVICE_MODE: new_mask = (*peripheral_mask) | diag_mux->mux_mask; diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index 87d021f6a95642fb0d43ceb02f7c1e2942bb505a..4dcc0a5727d01938c0fdf9ade9a1d0ccfa2d6f48 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -139,8 +139,11 @@ static void diag_usb_buf_tbl_remove(struct diag_usb_info *usb_info, * Remove reference from the table if it is the * only instance of the buffer */ - if (atomic_read(&entry->ref_count) == 0) + if (atomic_read(&entry->ref_count) == 0) { list_del(&entry->track); + kfree(entry); + entry = NULL; + } break; } } @@ -216,13 +219,6 @@ static void usb_connect_work_fn(struct work_struct *work) */ static void usb_disconnect(struct diag_usb_info *ch) { - if (!ch) - return; - - if (!atomic_read(&ch->connected) && - driver->usb_connected && diag_mask_param()) - diag_clear_masks(0); - if (ch && ch->ops && ch->ops->close) ch->ops->close(ch->ctxt, DIAG_USB_MODE); } @@ -231,6 +227,14 @@ static void usb_disconnect_work_fn(struct work_struct *work) { struct diag_usb_info *ch = container_of(work, struct diag_usb_info, disconnect_work); + + if (!ch) + return; + + if (!atomic_read(&ch->connected) && + driver->usb_connected && diag_mask_param()) + diag_clear_masks(0); + usb_disconnect(ch); } @@ -330,6 +334,7 @@ static void diag_usb_write_done(struct diag_usb_info *ch, buf = entry->buf; len = entry->len; kfree(entry); + entry = NULL; diag_ws_on_copy_complete(DIAG_WS_MUX); if (ch->ops && ch->ops->write_done) diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index f265cc7f01b823e8ba7cd30827bf900d9f08cd70..ee61fc2ee01fec2ae0febfa1d6ed7fa063d371c7 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * 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 @@ -26,6 +26,8 @@ #include #include "diagfwd_bridge.h" +#define THRESHOLD_CLIENT_LIMIT 50 + /* Size of the USB buffers used for read and write*/ #define USB_MAX_OUT_BUF 4096 #define APPS_BUF_SIZE 4096 @@ -34,7 +36,7 @@ #define DIAG_MAX_REQ_SIZE (16 * 1024) #define DIAG_MAX_RSP_SIZE (16 * 1024) -#define APF_DIAG_PADDING 0 +#define APF_DIAG_PADDING 256 /* * In the worst case, the HDLC buffer can be atmost twice the size of the * original packet. Add 3 bytes for 16 bit CRC (2 bytes) and a delimiter @@ -402,10 +404,16 @@ struct diag_logging_mode_param_t { uint8_t mode_param; } __packed; +struct diag_con_all_param_t { + uint32_t diag_con_all; + uint32_t num_peripherals; +}; + struct diag_md_session_t { int pid; int peripheral_mask; uint8_t hdlc_disabled; + uint8_t msg_mask_tbl_count; struct timer_list hdlc_reset_timer; struct diag_mask_info *msg_mask; struct diag_mask_info *log_mask; @@ -463,14 +471,13 @@ struct diagchar_dev { struct class *diagchar_class; struct device *diag_dev; int ref_count; - int mask_clear; - struct mutex diag_maskclear_mutex; struct mutex diag_notifier_mutex; struct mutex diagchar_mutex; struct mutex diag_file_mutex; wait_queue_head_t wait_q; struct diag_client_map *client_map; int *data_ready; + atomic_t data_ready_notif[THRESHOLD_CLIENT_LIMIT]; int num_clients; int polling_reg_flag; int use_device_tree; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index f5bbb03930e4b908c70b49693a87fc8e40274885..b594a4e1f411f1208d73ccef9c14f7e7d8884781 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * 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 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_DIAG_OVER_USB @@ -139,7 +140,6 @@ module_param(poolsize_qsc_usb, uint, 0); /* This is the max number of user-space clients supported at initialization*/ static unsigned int max_clients = 15; -static unsigned int threshold_client_limit = 50; module_param(max_clients, uint, 0); /* Timer variables */ @@ -339,7 +339,7 @@ static int diagchar_open(struct inode *inode, struct file *file) if (i < driver->num_clients) { diag_add_client(i, file); } else { - if (i < threshold_client_limit) { + if (i < THRESHOLD_CLIENT_LIMIT) { driver->num_clients++; temp = krealloc(driver->client_map , (driver->num_clients) * sizeof(struct @@ -369,11 +369,17 @@ static int diagchar_open(struct inode *inode, struct file *file) } } driver->data_ready[i] = 0x0; + atomic_set(&driver->data_ready_notif[i], 0); driver->data_ready[i] |= MSG_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= EVENT_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= LOG_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= DCI_LOG_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= DCI_EVENT_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); if (driver->ref_count == 0) diag_mempool_init(); @@ -411,7 +417,6 @@ int diag_mask_param(void) { return diag_mask_clear_param; } - void diag_clear_masks(int pid) { int ret; @@ -452,12 +457,7 @@ static void diag_close_logging_process(const int pid) if (diag_mask_clear_param) diag_clear_masks(pid); - mutex_lock(&driver->diag_maskclear_mutex); - driver->mask_clear = 1; - mutex_unlock(&driver->diag_maskclear_mutex); - mutex_lock(&driver->diagchar_mutex); - session_peripheral_mask = session_info->peripheral_mask; for (i = 0; i < NUM_MD_SESSIONS; i++) if (MD_PERIPHERAL_MASK(i) & session_peripheral_mask) diag_mux_close_peripheral(DIAG_LOCAL_PROC, i); @@ -535,12 +535,10 @@ static int diag_remove_client_entry(struct file *file) static int diagchar_close(struct inode *inode, struct file *file) { int ret; - DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag: process exit %s\n", - current->comm); + DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag: %s process exit with pid = %d\n", + current->comm, current->tgid); ret = diag_remove_client_entry(file); - mutex_lock(&driver->diag_maskclear_mutex); - driver->mask_clear = 0; - mutex_unlock(&driver->diag_maskclear_mutex); + return ret; } @@ -953,6 +951,7 @@ static int diag_remote_init(void) poolsize_mdm_dci_write); diagmem_setsize(POOL_TYPE_QSC_MUX, itemsize_qsc_usb, poolsize_qsc_usb); + diag_md_mdm_init(); driver->hdlc_encode_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE, GFP_KERNEL); if (!driver->hdlc_encode_buf) return -ENOMEM; @@ -1143,15 +1142,19 @@ static int diag_process_userspace_remote(int proc, void *buf, int len) } #endif -static int mask_request_validate(unsigned char mask_buf[]) +static int mask_request_validate(unsigned char mask_buf[], int len) { uint8_t packet_id; uint8_t subsys_id; uint16_t ss_cmd; + if (len <= 0) + return 0; packet_id = mask_buf[0]; if (packet_id == DIAG_CMD_DIAG_SUBSYS_DELAY) { + if (len < 2*sizeof(uint8_t) + sizeof(uint16_t)) + return 0; subsys_id = mask_buf[1]; ss_cmd = *(uint16_t *)(mask_buf + 2); switch (subsys_id) { @@ -1167,6 +1170,8 @@ static int mask_request_validate(unsigned char mask_buf[]) return 0; } } else if (packet_id == 0x4B) { + if (len < 2*sizeof(uint8_t) + sizeof(uint16_t)) + return 0; subsys_id = mask_buf[1]; ss_cmd = *(uint16_t *)(mask_buf + 2); /* Packets with SSID which are allowed */ @@ -1255,7 +1260,8 @@ static void diag_md_session_exit(void) diag_log_mask_free(session_info->log_mask); kfree(session_info->log_mask); session_info->log_mask = NULL; - diag_msg_mask_free(session_info->msg_mask); + diag_msg_mask_free(session_info->msg_mask, + session_info); kfree(session_info->msg_mask); session_info->msg_mask = NULL; diag_event_mask_free(session_info->event_mask); @@ -1328,7 +1334,9 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) "return value of event copy. err %d\n", err); goto fail_peripheral; } - err = diag_msg_mask_copy(new_session->msg_mask, &msg_mask); + new_session->msg_mask_tbl_count = 0; + err = diag_msg_mask_copy(new_session, new_session->msg_mask, + &msg_mask); if (err) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "return value of msg copy. err %d\n", err); @@ -1364,7 +1372,8 @@ fail_peripheral: diag_event_mask_free(new_session->event_mask); kfree(new_session->event_mask); new_session->event_mask = NULL; - diag_msg_mask_free(new_session->msg_mask); + diag_msg_mask_free(new_session->msg_mask, + new_session); kfree(new_session->msg_mask); new_session->msg_mask = NULL; kfree(new_session); @@ -1392,7 +1401,8 @@ static void diag_md_session_close(int pid) diag_log_mask_free(session_info->log_mask); kfree(session_info->log_mask); session_info->log_mask = NULL; - diag_msg_mask_free(session_info->msg_mask); + diag_msg_mask_free(session_info->msg_mask, + session_info); kfree(session_info->msg_mask); session_info->msg_mask = NULL; diag_event_mask_free(session_info->event_mask); @@ -1611,6 +1621,51 @@ static uint32_t diag_translate_mask(uint32_t peripheral_mask) return ret; } +static void diag_switch_logging_clear_mask( + struct diag_logging_mode_param_t *param, int pid) +{ + int new_mode; + struct diag_md_session_t *session_info = NULL; + + mutex_lock(&driver->md_session_lock); + session_info = diag_md_session_get_pid(pid); + if (!session_info) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, "Invalid pid: %d\n", pid); + mutex_unlock(&driver->md_session_lock); + return; + } + mutex_unlock(&driver->md_session_lock); + + if (!param) + return; + + if (!param->peripheral_mask) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "asking for mode switch with no peripheral mask set\n"); + return; + } + + switch (param->req_mode) { + case CALLBACK_MODE: + case UART_MODE: + case SOCKET_MODE: + case MEMORY_DEVICE_MODE: + new_mode = DIAG_MEMORY_DEVICE_MODE; + break; + case USB_MODE: + new_mode = DIAG_USB_MODE; + break; + default: + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "Request to switch to invalid mode: %d\n", + param->req_mode); + return; + } + if ((new_mode == DIAG_USB_MODE) && diag_mask_clear_param) + diag_clear_masks(pid); + +} + static int diag_switch_logging(struct diag_logging_mode_param_t *param) { int new_mode; @@ -1786,8 +1841,10 @@ static int diag_ioctl_lsm_deinit(void) mutex_unlock(&driver->diagchar_mutex); return -EINVAL; } - - driver->data_ready[i] |= DEINIT_TYPE; + if (!(driver->data_ready[i] & DEINIT_TYPE)) { + driver->data_ready[i] |= DEINIT_TYPE; + atomic_inc(&driver->data_ready_notif[i]); + } mutex_unlock(&driver->diagchar_mutex); wake_up_interruptible(&driver->wait_q); @@ -2101,6 +2158,7 @@ long diagchar_compat_ioctl(struct file *filp, uint16_t remote_dev; struct diag_dci_client_tbl *dci_client = NULL; struct diag_logging_mode_param_t mode_param; + struct diag_con_all_param_t con_param; switch (iocmd) { case DIAG_IOCTL_COMMAND_REG: @@ -2180,6 +2238,7 @@ long diagchar_compat_ioctl(struct file *filp, if (copy_from_user((void *)&mode_param, (void __user *)ioarg, sizeof(mode_param))) return -EFAULT; + diag_switch_logging_clear_mask(&mode_param, current->tgid); mutex_lock(&driver->diagchar_mutex); result = diag_switch_logging(&mode_param); mutex_unlock(&driver->diagchar_mutex); @@ -2212,6 +2271,15 @@ long diagchar_compat_ioctl(struct file *filp, case DIAG_IOCTL_HDLC_TOGGLE: result = diag_ioctl_hdlc_toggle(ioarg); break; + case DIAG_IOCTL_QUERY_CON_ALL: + con_param.diag_con_all = DIAG_CON_ALL; + con_param.num_peripherals = NUM_PERIPHERALS; + if (copy_to_user((void __user *)ioarg, &con_param, + sizeof(struct diag_con_all_param_t))) + result = -EFAULT; + else + result = 0; + break; } return result; } @@ -2226,6 +2294,7 @@ long diagchar_ioctl(struct file *filp, uint16_t remote_dev; struct diag_dci_client_tbl *dci_client = NULL; struct diag_logging_mode_param_t mode_param; + struct diag_con_all_param_t con_param; switch (iocmd) { case DIAG_IOCTL_COMMAND_REG: @@ -2305,6 +2374,7 @@ long diagchar_ioctl(struct file *filp, if (copy_from_user((void *)&mode_param, (void __user *)ioarg, sizeof(mode_param))) return -EFAULT; + diag_switch_logging_clear_mask(&mode_param, current->tgid); mutex_lock(&driver->diagchar_mutex); result = diag_switch_logging(&mode_param); mutex_unlock(&driver->diagchar_mutex); @@ -2337,6 +2407,15 @@ long diagchar_ioctl(struct file *filp, case DIAG_IOCTL_HDLC_TOGGLE: result = diag_ioctl_hdlc_toggle(ioarg); break; + case DIAG_IOCTL_QUERY_CON_ALL: + con_param.diag_con_all = DIAG_CON_ALL; + con_param.num_peripherals = NUM_PERIPHERALS; + if (copy_to_user((void __user *)ioarg, &con_param, + sizeof(struct diag_con_all_param_t))) + result = -EFAULT; + else + result = 0; + break; } return result; } @@ -2635,7 +2714,8 @@ static int diag_user_process_raw_data(const char __user *buf, int len) } /* Check for proc_type */ - remote_proc = diag_get_remote(*(int *)user_space_data); + if (len >= sizeof(int)) + remote_proc = diag_get_remote(*(int *)user_space_data); if (remote_proc) { token_offset = sizeof(int); if (len <= MIN_SIZ_ALLOW) { @@ -2649,7 +2729,7 @@ static int diag_user_process_raw_data(const char __user *buf, int len) } if (driver->mask_check) { if (!mask_request_validate(user_space_data + - token_offset)) { + token_offset, len)) { pr_alert("diag: mask request Invalid\n"); diagmem_free(driver, user_space_data, mempool); user_space_data = NULL; @@ -2726,7 +2806,7 @@ static int diag_user_process_userspace_data(const char __user *buf, int len) /* Check masks for On-Device logging */ if (driver->mask_check) { if (!mask_request_validate(driver->user_space_data_buf + - token_offset)) { + token_offset, len)) { pr_alert("diag: mask request Invalid\n"); return -EFAULT; } @@ -2862,16 +2942,6 @@ static int diag_user_process_apps_data(const char __user *buf, int len, return 0; } -static int check_data_ready(int index) -{ - int data_type = 0; - - mutex_lock(&driver->diagchar_mutex); - data_type = driver->data_ready[index]; - mutex_unlock(&driver->diagchar_mutex); - return data_type; -} - static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -2883,6 +2953,8 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, int exit_stat = 0; int write_len = 0; struct diag_md_session_t *session_info = NULL; + struct pid *pid_struct = NULL; + struct task_struct *task_s = NULL; mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) @@ -2898,7 +2970,8 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, pr_err("diag: bad address from user side\n"); return -EFAULT; } - wait_event_interruptible(driver->wait_q, (check_data_ready(index)) > 0); + wait_event_interruptible(driver->wait_q, + atomic_read(&driver->data_ready_notif[index]) > 0); mutex_lock(&driver->diagchar_mutex); @@ -2909,6 +2982,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, /*Copy the type of data being passed*/ data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE; driver->data_ready[index] ^= USER_SPACE_DATA_TYPE; + atomic_dec(&driver->data_ready_notif[index]); COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int)); /* place holder for number of data field */ ret += sizeof(int); @@ -2922,11 +2996,13 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, /* In case, the thread wakes up and the logging mode is not memory device any more, the condition needs to be cleared */ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE; + atomic_dec(&driver->data_ready_notif[index]); } if (driver->data_ready[index] & HDLC_SUPPORT_TYPE) { data_type = driver->data_ready[index] & HDLC_SUPPORT_TYPE; driver->data_ready[index] ^= HDLC_SUPPORT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int)); mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); @@ -2948,6 +3024,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, data_type = driver->data_ready[index] & DEINIT_TYPE; COPY_USER_SPACE_OR_EXIT(buf, data_type, 4); driver->data_ready[index] ^= DEINIT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); mutex_unlock(&driver->diagchar_mutex); diag_remove_client_entry(file); return ret; @@ -2969,6 +3046,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (write_len > 0) ret += write_len; driver->data_ready[index] ^= MSG_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -3002,6 +3080,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, } mutex_unlock(&driver->md_session_lock); driver->data_ready[index] ^= EVENT_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -3021,6 +3100,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (write_len > 0) ret += write_len; driver->data_ready[index] ^= LOG_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -3032,6 +3112,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, *(driver->apps_req_buf), driver->apps_req_buf_len); driver->data_ready[index] ^= PKT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); driver->in_busy_pktdata = 0; goto exit; } @@ -3043,6 +3124,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->dci_pkt_buf), driver->dci_pkt_length); driver->data_ready[index] ^= DCI_PKT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); driver->in_busy_dcipktdata = 0; goto exit; } @@ -3055,6 +3137,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, COPY_USER_SPACE_OR_EXIT(buf + 8, (dci_ops_tbl[DCI_LOCAL_PROC]. event_mask_composite), DCI_EVENT_MASK_SIZE); driver->data_ready[index] ^= DCI_EVENT_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -3066,6 +3149,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, COPY_USER_SPACE_OR_EXIT(buf+8, (dci_ops_tbl[DCI_LOCAL_PROC]. log_mask_composite), DCI_LOG_MASK_SIZE); driver->data_ready[index] ^= DCI_LOG_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -3078,17 +3162,40 @@ exit: list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); - if (entry->client->tgid != current->tgid) + pid_struct = find_get_pid(entry->tgid); + if (!pid_struct) + continue; + task_s = get_pid_task(pid_struct, PIDTYPE_PID); + if (!task_s) { + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: valid task doesn't exist for pid = %d\n", + entry->tgid); + put_pid(pid_struct); continue; - if (!entry->in_service) + } + if (task_s == entry->client) { + if (entry->client->tgid != current->tgid) { + put_task_struct(task_s); + put_pid(pid_struct); + continue; + } + } + if (!entry->in_service) { + put_task_struct(task_s); + put_pid(pid_struct); continue; + } if (copy_to_user(buf + ret, &data_type, sizeof(int))) { + put_task_struct(task_s); + put_pid(pid_struct); mutex_unlock(&driver->dci_mutex); goto end; } ret += sizeof(int); if (copy_to_user(buf + ret, &entry->client_info.token, sizeof(int))) { + put_task_struct(task_s); + put_pid(pid_struct); mutex_unlock(&driver->dci_mutex); goto end; } @@ -3097,11 +3204,16 @@ exit: exit_stat = diag_copy_dci(buf, count, entry, &ret); mutex_lock(&driver->diagchar_mutex); driver->data_ready[index] ^= DCI_DATA_TYPE; + atomic_dec(&driver->data_ready_notif[index]); mutex_unlock(&driver->diagchar_mutex); if (exit_stat == 1) { + put_task_struct(task_s); + put_pid(pid_struct); mutex_unlock(&driver->dci_mutex); goto end; } + put_task_struct(task_s); + put_pid(pid_struct); } mutex_unlock(&driver->dci_mutex); goto end; @@ -3565,7 +3677,6 @@ static int __init diagchar_init(void) non_hdlc_data.len = 0; mutex_init(&driver->hdlc_disable_mutex); mutex_init(&driver->diagchar_mutex); - mutex_init(&driver->diag_maskclear_mutex); mutex_init(&driver->diag_notifier_mutex); mutex_init(&driver->diag_file_mutex); mutex_init(&driver->delayed_rsp_mutex); diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 37f4c3c00282fbb5114278eee5c8862e4b33d181..4ddc475f319193690368e37627b45a92b1ca8cb7 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * 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 @@ -227,6 +227,7 @@ void chk_logging_wakeup(void) * situation. */ driver->data_ready[i] |= USER_SPACE_DATA_TYPE; + atomic_inc(&driver->data_ready_notif[i]); pr_debug("diag: Force wakeup of logging process\n"); wake_up_interruptible(&driver->wait_q); break; @@ -456,8 +457,11 @@ void diag_update_userspace_clients(unsigned int type) mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) - if (driver->client_map[i].pid != 0) + if (driver->client_map[i].pid != 0 && + !(driver->data_ready[i] & type)) { driver->data_ready[i] |= type; + atomic_inc(&driver->data_ready_notif[i]); + } wake_up_interruptible(&driver->wait_q); mutex_unlock(&driver->diagchar_mutex); } @@ -474,7 +478,11 @@ void diag_update_md_clients(unsigned int type) if (driver->client_map[j].pid != 0 && driver->client_map[j].pid == driver->md_session_map[i]->pid) { - driver->data_ready[j] |= type; + if (!(driver->data_ready[i] & type)) { + driver->data_ready[j] |= type; + atomic_inc( + &driver->data_ready_notif[j]); + } break; } } @@ -490,7 +498,10 @@ void diag_update_sleeping_process(int process_id, int data_type) mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == process_id) { - driver->data_ready[i] |= data_type; + if (!(driver->data_ready[i] & data_type)) { + driver->data_ready[i] |= data_type; + atomic_inc(&driver->data_ready_notif[i]); + } break; } wake_up_interruptible(&driver->wait_q); @@ -624,7 +635,8 @@ int diag_process_time_sync_query_cmd(unsigned char *src_buf, int src_len, struct diag_cmd_time_sync_query_req_t *req = NULL; struct diag_cmd_time_sync_query_rsp_t rsp; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || + src_len < sizeof(struct diag_cmd_time_sync_query_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d", __func__, src_buf, src_len, dest_buf, dest_len); return -EINVAL; @@ -651,7 +663,8 @@ int diag_process_time_sync_switch_cmd(unsigned char *src_buf, int src_len, int msg_size = sizeof(struct diag_ctrl_msg_time_sync); int err = 0, write_len = 0; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || + src_len < sizeof(struct diag_cmd_time_sync_switch_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d", __func__, src_buf, src_len, dest_buf, dest_len); return -EINVAL; @@ -891,7 +904,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) struct diag_cmd_reg_t *reg_item = NULL; struct diag_md_session_t *info = NULL; - if (!buf) + if (!buf || len <= 0) return -EIO; /* Check if the command is a supported mask command */ @@ -902,18 +915,31 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) } temp = buf; - entry.cmd_code = (uint16_t)(*(uint8_t *)temp); - temp += sizeof(uint8_t); - entry.subsys_id = (uint16_t)(*(uint8_t *)temp); - temp += sizeof(uint8_t); - entry.cmd_code_hi = (uint16_t)(*(uint16_t *)temp); - entry.cmd_code_lo = (uint16_t)(*(uint16_t *)temp); - temp += sizeof(uint16_t); - - pr_debug("diag: In %s, received cmd %02x %02x %02x\n", - __func__, entry.cmd_code, entry.subsys_id, entry.cmd_code_hi); - - if (*buf == DIAG_CMD_LOG_ON_DMND && driver->log_on_demand_support && + if (len >= sizeof(uint8_t)) { + entry.cmd_code = (uint16_t)(*(uint8_t *)temp); + pr_debug("diag: received cmd_code %02x\n", entry.cmd_code); + } + if (len >= (2 * sizeof(uint8_t))) { + temp += sizeof(uint8_t); + entry.subsys_id = (uint16_t)(*(uint8_t *)temp); + pr_debug("diag: received subsys_id %02x\n", entry.subsys_id); + } + if (len == (3 * sizeof(uint8_t))) { + temp += sizeof(uint8_t); + entry.cmd_code_hi = (uint16_t)(*(uint8_t *)temp); + entry.cmd_code_lo = (uint16_t)(*(uint8_t *)temp); + pr_debug("diag: received cmd_code_hi %02x\n", + entry.cmd_code_hi); + } else if (len >= (2 * sizeof(uint8_t)) + sizeof(uint16_t)) { + temp += sizeof(uint8_t); + entry.cmd_code_hi = (uint16_t)(*(uint16_t *)temp); + entry.cmd_code_lo = (uint16_t)(*(uint16_t *)temp); + pr_debug("diag: received cmd_code_hi %02x\n", + entry.cmd_code_hi); + } + + if ((len >= sizeof(uint8_t)) && *buf == DIAG_CMD_LOG_ON_DMND && + driver->log_on_demand_support && driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask) { write_len = diag_cmd_log_on_demand(buf, len, driver->apps_rsp_buf, @@ -938,8 +964,11 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) } else { mutex_unlock(&driver->md_session_lock); if (MD_PERIPHERAL_MASK(reg_item->proc) & - driver->logging_mask) + driver->logging_mask) { + mutex_unlock(&driver->cmd_reg_mutex); diag_send_error_rsp(buf, len); + return write_len; + } else write_len = diag_send_data(reg_item, buf, len); } @@ -950,14 +979,16 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) #if defined(CONFIG_DIAG_OVER_USB) /* Check for the command/respond msg for the maximum packet length */ - if ((*buf == 0x4b) && (*(buf+1) == 0x12) && + if ((len >= (4 * sizeof(uint8_t))) && + (*buf == 0x4b) && (*(buf+1) == 0x12) && (*(uint16_t *)(buf+2) == 0x0055)) { for (i = 0; i < 4; i++) *(driver->apps_rsp_buf+i) = *(buf+i); *(uint32_t *)(driver->apps_rsp_buf+4) = DIAG_MAX_REQ_SIZE; diag_send_rsp(driver->apps_rsp_buf, 8); return 0; - } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) && + } else if ((len >= ((2 * sizeof(uint8_t)) + sizeof(uint16_t))) && + (*buf == 0x4b) && (*(buf+1) == 0x12) && (*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) { len = diag_process_stm_cmd(buf, driver->apps_rsp_buf); if (len > 0) { @@ -967,7 +998,8 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) return len; } /* Check for time sync query command */ - else if ((*buf == DIAG_CMD_DIAG_SUBSYS) && + else if ((len >= ((2 * sizeof(uint8_t)) + sizeof(uint16_t))) && + (*buf == DIAG_CMD_DIAG_SUBSYS) && (*(buf+1) == DIAG_SS_DIAG) && (*(uint16_t *)(buf+2) == DIAG_GET_TIME_API)) { write_len = diag_process_time_sync_query_cmd(buf, len, @@ -978,7 +1010,8 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) return 0; } /* Check for time sync switch command */ - else if ((*buf == DIAG_CMD_DIAG_SUBSYS) && + else if ((len >= ((2 * sizeof(uint8_t)) + sizeof(uint16_t))) && + (*buf == DIAG_CMD_DIAG_SUBSYS) && (*(buf+1) == DIAG_SS_DIAG) && (*(uint16_t *)(buf+2) == DIAG_SET_TIME_API)) { write_len = diag_process_time_sync_switch_cmd(buf, len, @@ -989,7 +1022,8 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) return 0; } /* Check for download command */ - else if ((chk_apps_master()) && (*buf == 0x3A)) { + else if ((len >= sizeof(uint8_t)) && (chk_apps_master()) && + (*buf == 0x3A)) { /* send response back */ driver->apps_rsp_buf[0] = *buf; diag_send_rsp(driver->apps_rsp_buf, 1); @@ -1002,8 +1036,8 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) return 0; } /* Check for polling for Apps only DIAG */ - else if ((*buf == 0x4b) && (*(buf+1) == 0x32) && - (*(buf+2) == 0x03)) { + else if ((len >= (3 * sizeof(uint8_t))) && + (*buf == 0x4b) && (*(buf+1) == 0x32) && (*(buf+2) == 0x03)) { /* If no one has registered for polling */ if (chk_polling_response()) { /* Respond to polling for Apps only DIAG */ @@ -1017,7 +1051,8 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) } } /* Return the Delayed Response Wrap Status */ - else if ((*buf == 0x4b) && (*(buf+1) == 0x32) && + else if ((len >= (4 * sizeof(uint8_t))) && + (*buf == 0x4b) && (*(buf+1) == 0x32) && (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) { memcpy(driver->apps_rsp_buf, buf, 4); driver->apps_rsp_buf[4] = wrap_enabled; @@ -1025,7 +1060,8 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) return 0; } /* Wrap the Delayed Rsp ID */ - else if ((*buf == 0x4b) && (*(buf+1) == 0x32) && + else if ((len >= (4 * sizeof(uint8_t))) && + (*buf == 0x4b) && (*(buf+1) == 0x32) && (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) { wrap_enabled = true; memcpy(driver->apps_rsp_buf, buf, 4); @@ -1034,10 +1070,11 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) return 0; } /* Mobile ID Rsp */ - else if ((*buf == DIAG_CMD_DIAG_SUBSYS) && - (*(buf+1) == DIAG_SS_PARAMS) && - (*(buf+2) == DIAG_EXT_MOBILE_ID) && (*(buf+3) == 0x0)) { - write_len = diag_cmd_get_mobile_id(buf, len, + else if ((len >= (4 * sizeof(uint8_t))) && + (*buf == DIAG_CMD_DIAG_SUBSYS) && + (*(buf+1) == DIAG_SS_PARAMS) && + (*(buf+2) == DIAG_EXT_MOBILE_ID) && (*(buf+3) == 0x0)) { + write_len = diag_cmd_get_mobile_id(buf, len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) { @@ -1057,7 +1094,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) !(driver->diagfwd_cntl[PERIPHERAL_MODEM]->ch_open) && !(driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask)) { /* respond to 0x0 command */ - if (*buf == 0x00) { + if ((len >= sizeof(uint8_t)) && *buf == 0x00) { for (i = 0; i < 55; i++) driver->apps_rsp_buf[i] = 0; @@ -1065,7 +1102,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) return 0; } /* respond to 0x7c command */ - else if (*buf == 0x7c) { + else if ((len >= sizeof(uint8_t)) && *buf == 0x7c) { driver->apps_rsp_buf[0] = 0x7c; for (i = 1; i < 8; i++) driver->apps_rsp_buf[i] = 0; @@ -1298,7 +1335,6 @@ static uint8_t hdlc_reset; static void hdlc_reset_timer_start(int pid) { struct diag_md_session_t *info = NULL; - mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); if (!hdlc_timer_in_progress) { @@ -1671,6 +1707,10 @@ int diagfwd_init(void) , GFP_KERNEL)) == NULL) goto err; kmemleak_not_leak(driver->data_ready); + + for (i = 0; i < THRESHOLD_CLIENT_LIMIT; i++) + atomic_set(&driver->data_ready_notif[i], 0); + if (driver->apps_req_buf == NULL) { driver->apps_req_buf = kzalloc(DIAG_MAX_REQ_SIZE, GFP_KERNEL); if (!driver->apps_req_buf) diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index e2b2343d988d5c1b3ef01b5d07bdc6be49a85242..ea2e6a98178110855ffc544d3184662dff85e3f6 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -478,7 +478,12 @@ static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask, } if (range->ssid_last >= mask->ssid_last) { temp_range = range->ssid_last - mask->ssid_first + 1; - mask->ssid_last = range->ssid_last; + if (temp_range > MAX_SSID_PER_RANGE) { + temp_range = MAX_SSID_PER_RANGE; + mask->ssid_last = mask->ssid_first + temp_range - 1; + } else + mask->ssid_last = range->ssid_last; + mask->ssid_last_tools = mask->ssid_last; mask->range = temp_range; } @@ -519,7 +524,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, mask_ptr = (struct diag_msg_mask_t *)msg_mask.ptr; found = 0; for (j = 0; j < driver->msg_mask_tbl_count; j++, mask_ptr++) { - if (!mask_ptr || !ssid_range) { + if (!mask_ptr->ptr || !ssid_range) { found = 1; break; } @@ -591,7 +596,7 @@ static void diag_build_time_mask_update(uint8_t *buf, num_items = range->ssid_last - range->ssid_first + 1; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { - if (!build_mask) { + if (!build_mask->ptr) { found = 1; break; } diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 3541b34e56adc4c32ff6f33748cf4e16491e548c..b8af791ac4d638955e3fd92643128ebb94f1086a 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -730,10 +730,12 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info) if (!fwd_info->inited) return; - if (fwd_info->buf_1) - atomic_set(&fwd_info->buf_1->in_busy, 0); - if (fwd_info->buf_2) - atomic_set(&fwd_info->buf_2->in_busy, 0); + if (driver->logging_mode != DIAG_USB_MODE) { + if (fwd_info->buf_1) + atomic_set(&fwd_info->buf_1->in_busy, 0); + if (fwd_info->buf_2) + atomic_set(&fwd_info->buf_2->in_busy, 0); + } if (fwd_info->p_ops && fwd_info->p_ops->open) fwd_info->p_ops->open(fwd_info->ctxt); diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 61e71616689b7c3bd5441230b5af30df79df837c..84b5c746124ccda08c3526fcf7a30d9d7be15853 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -522,11 +522,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); + bt->timeout = bt->BT_CAP_req2rsp; + /* Read BT capabilities if it hasn't been done yet */ if (!bt->BT_CAP_outreqs) BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, SI_SM_CALL_WITHOUT_DELAY); - bt->timeout = bt->BT_CAP_req2rsp; BT_SI_SM_RETURN(SI_SM_IDLE); case BT_STATE_XACTION_START: diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index f816211f062f7a2386b215a0e6155bed19b271b5..63164ff66bb4b57cd8479a857b9705febf36227f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4010,7 +4010,8 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, } static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, - struct list_head *timeouts, long timeout_period, + struct list_head *timeouts, + unsigned long timeout_period, int slot, unsigned long *flags, unsigned int *waiting_msgs) { @@ -4023,8 +4024,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, if (!ent->inuse) return; - ent->timeout -= timeout_period; - if (ent->timeout > 0) { + if (timeout_period < ent->timeout) { + ent->timeout -= timeout_period; (*waiting_msgs)++; return; } @@ -4091,7 +4092,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, } } -static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, long timeout_period) +static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, + unsigned long timeout_period) { struct list_head timeouts; struct ipmi_recv_msg *msg, *msg2; diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index f335fcee09af2bdc0c3233b96e8ec6d6ca787e04..0109d3fb5fbce3b33e22af0e1056d2b09f96b800 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -509,7 +509,7 @@ static void panic_halt_ipmi_heartbeat(void) msg.cmd = IPMI_WDOG_RESET_TIMER; msg.data = NULL; msg.data_len = 0; - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = ipmi_request_supply_msgs(watchdog_user, (struct ipmi_addr *) &addr, 0, @@ -519,7 +519,7 @@ static void panic_halt_ipmi_heartbeat(void) &panic_halt_heartbeat_recv_msg, 1); if (rv) - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); } static struct ipmi_smi_msg panic_halt_smi_msg = { @@ -543,12 +543,12 @@ static void panic_halt_ipmi_set_timeout(void) /* Wait for the messages to be free. */ while (atomic_read(&panic_done_count) != 0) ipmi_poll_interface(watchdog_user); - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = i_ipmi_set_timeout(&panic_halt_smi_msg, &panic_halt_recv_msg, &send_heartbeat_now); if (rv) { - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); printk(KERN_WARNING PFX "Unable to extend the watchdog timeout."); } else { diff --git a/drivers/char/random.c b/drivers/char/random.c index d55156fc064df472fa51c6f2cb22381dd03c17bb..28970b8e45647979239798dd66995e838f5931ca 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -704,7 +704,7 @@ retry: static void credit_entropy_bits_safe(struct entropy_store *r, int nbits) { - const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); + const int nbits_max = r->poolinfo->poolwords * 32; /* Cap the value to avoid overflows */ nbits = min(nbits, nbits_max); @@ -863,12 +863,16 @@ static void add_interrupt_bench(cycles_t start) static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs) { __u32 *ptr = (__u32 *) regs; + unsigned int idx; if (regs == NULL) return 0; - if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32)) - f->reg_idx = 0; - return *(ptr + f->reg_idx++); + idx = READ_ONCE(f->reg_idx); + if (idx >= sizeof(struct pt_regs) / sizeof(__u32)) + idx = 0; + ptr += idx++; + WRITE_ONCE(f->reg_idx, idx); + return *ptr; } void add_interrupt_randomness(int irq, int irq_flags) @@ -1413,14 +1417,22 @@ static int write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { size_t bytes; - __u32 buf[16]; + __u32 t, buf[16]; const char __user *p = buffer; while (count > 0) { + int b, i = 0; + bytes = min(count, sizeof(buf)); if (copy_from_user(&buf, p, bytes)) return -EFAULT; + for (b = bytes ; b > 0 ; b -= sizeof(__u32), i++) { + if (!arch_get_random_int(&t)) + break; + buf[i] ^= t; + } + count -= bytes; p += bytes; diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 472af4bb1b6128d3f7a0176fcb51720115f11aec..ce41780a4213cb6562edb4f4b14da197a43df620 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -436,7 +436,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; - int expected, status; + int status; + u32 expected; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -451,7 +452,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) } expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if ((size_t) expected > count) { + if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) { size = -EIO; goto out; } diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 23c7b137a7fdb47584b98429bc54f8e5c732d5dd..39635429ea3fc2b7c932bd5fd653d21c627aeae7 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -267,7 +267,11 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) struct device *dev = chip->dev; struct i2c_client *client = to_i2c_client(dev); s32 rc; - int expected, status, burst_count, retries, size = 0; + int status; + int burst_count; + int retries; + int size = 0; + u32 expected; if (count < TPM_HEADER_SIZE) { i2c_nuvoton_ready(chip); /* return to idle */ @@ -309,7 +313,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) * to machine native */ expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { + if (expected > count || expected < size) { dev_err(dev, "%s() expected > count\n", __func__); size = -EIO; continue; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 5480deb4b89589879920313c6012aa322c7c90ec..a6f1ba7f511f887d11d8cef64918399966086949 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1398,7 +1398,6 @@ static int add_port(struct ports_device *portdev, u32 id) { char debugfs_name[16]; struct port *port; - struct port_buffer *buf; dev_t devt; unsigned int nr_added_bufs; int err; @@ -1509,8 +1508,6 @@ static int add_port(struct ports_device *portdev, u32 id) return 0; free_inbufs: - while ((buf = virtqueue_detach_unused_buf(port->in_vq))) - free_buf(buf, true); free_device: device_destroy(pdrvdata.class, port->dev->devt); free_cdev: @@ -1535,34 +1532,14 @@ static void remove_port(struct kref *kref) static void remove_port_data(struct port *port) { - struct port_buffer *buf; - spin_lock_irq(&port->inbuf_lock); /* Remove unused data this port might have received. */ discard_port_data(port); spin_unlock_irq(&port->inbuf_lock); - /* Remove buffers we queued up for the Host to send us data in. */ - do { - spin_lock_irq(&port->inbuf_lock); - buf = virtqueue_detach_unused_buf(port->in_vq); - spin_unlock_irq(&port->inbuf_lock); - if (buf) - free_buf(buf, true); - } while (buf); - spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); - - /* Free pending buffers from the out-queue. */ - do { - spin_lock_irq(&port->outvq_lock); - buf = virtqueue_detach_unused_buf(port->out_vq); - spin_unlock_irq(&port->outvq_lock); - if (buf) - free_buf(buf, true); - } while (buf); } /* @@ -1783,13 +1760,24 @@ static void control_work_handler(struct work_struct *work) spin_unlock(&portdev->c_ivq_lock); } +static void flush_bufs(struct virtqueue *vq, bool can_sleep) +{ + struct port_buffer *buf; + unsigned int len; + + while ((buf = virtqueue_get_buf(vq, &len))) + free_buf(buf, can_sleep); +} + static void out_intr(struct virtqueue *vq) { struct port *port; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } wake_up_interruptible(&port->waitqueue); } @@ -1800,8 +1788,10 @@ static void in_intr(struct virtqueue *vq) unsigned long flags; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } spin_lock_irqsave(&port->inbuf_lock, flags); port->inbuf = get_inbuf(port); @@ -1976,6 +1966,15 @@ static const struct file_operations portdev_fops = { static void remove_vqs(struct ports_device *portdev) { + struct virtqueue *vq; + + virtio_device_for_each_vq(portdev->vdev, vq) { + struct port_buffer *buf; + + flush_bufs(vq, true); + while ((buf = virtqueue_detach_unused_buf(vq))) + free_buf(buf, true); + } portdev->vdev->config->del_vqs(portdev->vdev); kfree(portdev->in_vqs); kfree(portdev->out_vqs); diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 44ea107cfc6729818ea8a02dfd250f7e6a557967..8c8c2443f601529b699e2c0e885421efbe35bd0e 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -72,7 +72,7 @@ static const char * const si5351_input_names[] = { "xtal", "clkin" }; static const char * const si5351_pll_names[] = { - "plla", "pllb", "vxco" + "si5351_plla", "si5351_pllb", "si5351_vxco" }; static const char * const si5351_msynth_names[] = { "ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7" diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile index def38f0735c1f06170e6566d515df5c335cb9d57..8c5c68afef61869bb1093ce6f519ed5753372bb9 100644 --- a/drivers/clk/msm/Makefile +++ b/drivers/clk/msm/Makefile @@ -76,3 +76,7 @@ obj-$(CONFIG_ARCH_SDM450) += clock-rcgwr.o obj-y += gdsc.o obj-y += mdss/ + +ifdef CONFIG_ARCH_MDM9607 +KBUILD_CFLAGS += -fno-cse-follow-jumps +endif diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c index 05e69c18ca5caf1d27d1c0e47087d0c342a1727a..948adeca8a12abac8ac81b8a31b738360eee70dd 100644 --- a/drivers/clk/msm/clock-gcc-8953.c +++ b/drivers/clk/msm/clock-gcc-8953.c @@ -1178,9 +1178,6 @@ static struct rcg_clk camss_gp1_clk_src = { static struct clk_freq_tbl ftbl_mclk0_clk_src[] = { F( 12000000, gpll6_main_div2, 1, 2, 90), -#ifdef CONFIG_MACH_XIAOMI_MIDO - F( 19200000, xo, 1, 0, 0), -#endif F( 24000000, gpll6_main_div2, 1, 2, 45), F( 33330000, gpll0_main_div2, 12, 0, 0), F( 36610000, gpll6, 1, 2, 59), @@ -2792,6 +2789,7 @@ static struct branch_clk gcc_oxili_timer_clk = { .base = &virt_bases[GFX_BASE], .c = { .dbg_name = "gcc_oxili_timer_clk", + .parent = &xo_clk_src.c, .ops = &clk_ops_branch, CLK_INIT(gcc_oxili_timer_clk.c), }, diff --git a/drivers/clk/msm/clock-gcc-mdm9607.c b/drivers/clk/msm/clock-gcc-mdm9607.c index 826fea0fdb271cd01fe37d7a0c15855c4c0dccd7..1157d44b47f5b7bcc981a248bea6fda23e7fcc61 100644 --- a/drivers/clk/msm/clock-gcc-mdm9607.c +++ b/drivers/clk/msm/clock-gcc-mdm9607.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. * 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. @@ -1826,6 +1826,10 @@ static int msm_gcc_probe(struct platform_device *pdev) return PTR_ERR(vdd_stromer_pll.regulator[0]); } + /* Use use_max_uv for vdd_dig and vdd_stromer_pll */ + vdd_dig.use_max_uV = true; + vdd_stromer_pll.use_max_uV = true; + /*Vote for GPLL0 to turn on. Needed by acpuclock. */ regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE)); regval |= BIT(0); diff --git a/drivers/clk/msm/clock-rpm-8909.c b/drivers/clk/msm/clock-rpm-8909.c index f2705927bab9452e57705c9f080c67bfb5cbefd1..53c882bfd651f46c39814e0066a5d10e9718c5cb 100644 --- a/drivers/clk/msm/clock-rpm-8909.c +++ b/drivers/clk/msm/clock-rpm-8909.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -50,7 +50,9 @@ /* XO clock */ #define BB_CLK1_ID 1 #define BB_CLK2_ID 2 +#define BB_CLK3_ID 3 #define RF_CLK2_ID 5 +#define RF_CLK1_ID 4 static void __iomem *virt_base; @@ -68,11 +70,15 @@ DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID); /* SMD_XO_BUFFER */ DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID); DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk2, bb_clk2_a, BB_CLK2_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk3, bb_clk3_a, BB_CLK3_ID); DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_a, RF_CLK2_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk1, rf_clk1_a, RF_CLK1_ID); DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID); DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk2_pin, bb_clk2_a_pin, BB_CLK2_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk3_pin, bb_clk3_a_pin, BB_CLK3_ID); DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk2_pin, rf_clk2_a_pin, RF_CLK2_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk1_pin, rf_clk1_a_pin, RF_CLK1_ID); /* Voter clocks */ static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX); @@ -171,15 +177,71 @@ static struct clk_lookup msm_clocks_rpm[] = { CLK_LIST(rpm_debug_mux), }; +/* Lookup Table for MSM8909w-PM660 MTP */ +static struct clk_lookup msm_clocks_rpm_8909_pm660[] = { + CLK_LIST(xo_clk_src), + CLK_LIST(xo_a_clk_src), + CLK_LIST(xo_otg_clk), + CLK_LIST(xo_lpm_clk), + CLK_LIST(xo_pil_mss_clk), + CLK_LIST(xo_pil_pronto_clk), + CLK_LIST(xo_wlan_clk), + + CLK_LIST(snoc_msmbus_clk), + CLK_LIST(snoc_msmbus_a_clk), + CLK_LIST(snoc_mm_msmbus_clk), + CLK_LIST(snoc_mm_msmbus_a_clk), + CLK_LIST(pcnoc_msmbus_clk), + CLK_LIST(pcnoc_msmbus_a_clk), + CLK_LIST(bimc_msmbus_clk), + CLK_LIST(bimc_msmbus_a_clk), + CLK_LIST(pcnoc_keepalive_a_clk), + + CLK_LIST(pcnoc_usb_a_clk), + CLK_LIST(snoc_usb_a_clk), + CLK_LIST(bimc_usb_a_clk), + + /* CoreSight clocks */ + CLK_LIST(qdss_clk), + CLK_LIST(qdss_a_clk), + + CLK_LIST(snoc_clk), + CLK_LIST(pcnoc_clk), + CLK_LIST(bimc_clk), + CLK_LIST(snoc_a_clk), + CLK_LIST(pcnoc_a_clk), + CLK_LIST(bimc_a_clk), + CLK_LIST(qpic_clk), + CLK_LIST(qpic_a_clk), + + CLK_LIST(bb_clk1), + CLK_LIST(bb_clk2), + CLK_LIST(bb_clk3), + CLK_LIST(rf_clk1), + CLK_LIST(rf_clk2), + + CLK_LIST(bb_clk1_pin), + CLK_LIST(bb_clk2_pin), + CLK_LIST(bb_clk3_pin), + CLK_LIST(rf_clk2_pin), + CLK_LIST(rf_clk1_pin), + + /* RPM debug Mux*/ + CLK_LIST(rpm_debug_mux), +}; + static int msm_rpmcc_8909_probe(struct platform_device *pdev) { struct resource *res; - int ret; + int ret, is_8909_pm660 = 0; ret = enable_rpm_scaling(); if (ret) return ret; + is_8909_pm660 = of_device_is_compatible(pdev->dev.of_node, + "qcom,rpmcc-8909-pm660"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base"); if (!res) { dev_err(&pdev->dev, "Unable to get register base\n"); @@ -192,8 +254,14 @@ static int msm_rpmcc_8909_probe(struct platform_device *pdev) return -ENOMEM; } - ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_rpm, - ARRAY_SIZE(msm_clocks_rpm)); + if (is_8909_pm660) + ret = of_msm_clock_register(pdev->dev.of_node, + msm_clocks_rpm_8909_pm660, + ARRAY_SIZE(msm_clocks_rpm_8909_pm660)); + else + ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_rpm, + ARRAY_SIZE(msm_clocks_rpm)); + if (ret) { dev_err(&pdev->dev, "Unable to register RPM clocks\n"); return ret; @@ -214,6 +282,7 @@ static int msm_rpmcc_8909_probe(struct platform_device *pdev) static struct of_device_id msm_clk_rpm_match_table[] = { { .compatible = "qcom,rpmcc-8909" }, + { .compatible = "qcom,rpmcc-8909-pm660" }, {} }; diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c index 8bccf4ecdab641bf0a24d2db15ccf419023d7357..9ff4ea63932d507c9a5b7289e34eddf125193652 100644 --- a/drivers/clk/mvebu/armada-38x.c +++ b/drivers/clk/mvebu/armada-38x.c @@ -46,10 +46,11 @@ static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) } static const u32 armada_38x_cpu_frequencies[] __initconst = { - 0, 0, 0, 0, - 1066 * 1000 * 1000, 0, 0, 0, + 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0, + 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0, 1332 * 1000 * 1000, 0, 0, 0, - 1600 * 1000 * 1000, + 1600 * 1000 * 1000, 0, 0, 0, + 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000, }; static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) @@ -75,11 +76,11 @@ static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { }; static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { - {0, 1}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, @@ -90,7 +91,7 @@ static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {7, 15}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 6e6cca3920829b5a7dc0685a071389a2d201d780..55cab0d1a929db6987a76dfe9a9d27ae87da7ea4 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -740,7 +740,7 @@ static struct samsung_pll_rate_table exynos3250_epll_rates[] = { PLL_36XX_RATE(144000000, 96, 2, 3, 0), PLL_36XX_RATE( 96000000, 128, 2, 4, 0), PLL_36XX_RATE( 84000000, 112, 2, 4, 0), - PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), + PLL_36XX_RATE( 80000003, 106, 2, 4, 43691), PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), @@ -776,7 +776,7 @@ static struct samsung_pll_rate_table exynos3250_vpll_rates[] = { PLL_36XX_RATE(148352005, 98, 2, 3, 59070), PLL_36XX_RATE(108000000, 144, 2, 4, 0), PLL_36XX_RATE( 74250000, 99, 2, 4, 0), - PLL_36XX_RATE( 74176002, 98, 3, 4, 59070), + PLL_36XX_RATE( 74176002, 98, 2, 4, 59070), PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), PLL_36XX_RATE( 54000000, 144, 2, 5, 0), { /* sentinel */ } diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 70ec3d2608a17e2f282e65dc198cd6af9c3fbbb9..b42fbbe911cc745c790ec2cfd78b41b60008d1a2 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -700,13 +700,13 @@ static struct samsung_pll_rate_table epll_24mhz_tbl[] __initdata = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ PLL_36XX_RATE(192000000, 64, 2, 2, 0), - PLL_36XX_RATE(180633600, 90, 3, 2, 20762), + PLL_36XX_RATE(180633605, 90, 3, 2, 20762), PLL_36XX_RATE(180000000, 90, 3, 2, 0), PLL_36XX_RATE(73728000, 98, 2, 4, 19923), - PLL_36XX_RATE(67737600, 90, 2, 4, 20762), + PLL_36XX_RATE(67737602, 90, 2, 4, 20762), PLL_36XX_RATE(49152000, 98, 3, 4, 19923), - PLL_36XX_RATE(45158400, 90, 3, 4, 20762), - PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + PLL_36XX_RATE(45158401, 90, 3, 4, 20762), + PLL_36XX_RATE(32768001, 131, 3, 5, 4719), { }, }; diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index 2527e39aadcfbfafab2a0b5c97d4aab2e4809458..e4330b78eaad29d628f29c7b4c132e369927b9b4 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -102,7 +102,7 @@ static struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initdata = { PLL_36XX_RATE(480000000, 160, 2, 2, 0), PLL_36XX_RATE(432000000, 144, 2, 2, 0), PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(394073130, 459, 7, 2, 49282), + PLL_36XX_RATE(394073128, 459, 7, 2, 49282), PLL_36XX_RATE(333000000, 111, 2, 2, 0), PLL_36XX_RATE(300000000, 100, 2, 2, 0), PLL_36XX_RATE(266000000, 266, 3, 3, 0), diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index 5d2f03461bc5d2fe6cf4acd6ef11b379ef25e0bd..607924766a894d8a9056e42dce9e83daafdf92c3 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -170,7 +170,7 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(226000000, 105, 1, 1), PLL_35XX_RATE(210000000, 132, 2, 1), /* 2410 common */ - PLL_35XX_RATE(203000000, 161, 3, 1), + PLL_35XX_RATE(202800000, 161, 3, 1), PLL_35XX_RATE(192000000, 88, 1, 1), PLL_35XX_RATE(186000000, 85, 1, 1), PLL_35XX_RATE(180000000, 82, 1, 1), @@ -180,18 +180,18 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(147000000, 90, 2, 1), PLL_35XX_RATE(135000000, 82, 2, 1), PLL_35XX_RATE(124000000, 116, 1, 2), - PLL_35XX_RATE(118000000, 150, 2, 2), + PLL_35XX_RATE(118500000, 150, 2, 2), PLL_35XX_RATE(113000000, 105, 1, 2), - PLL_35XX_RATE(101000000, 127, 2, 2), + PLL_35XX_RATE(101250000, 127, 2, 2), PLL_35XX_RATE(90000000, 112, 2, 2), - PLL_35XX_RATE(85000000, 105, 2, 2), + PLL_35XX_RATE(84750000, 105, 2, 2), PLL_35XX_RATE(79000000, 71, 1, 2), - PLL_35XX_RATE(68000000, 82, 2, 2), - PLL_35XX_RATE(56000000, 142, 2, 3), + PLL_35XX_RATE(67500000, 82, 2, 2), + PLL_35XX_RATE(56250000, 142, 2, 3), PLL_35XX_RATE(48000000, 120, 2, 3), - PLL_35XX_RATE(51000000, 161, 3, 3), + PLL_35XX_RATE(50700000, 161, 3, 3), PLL_35XX_RATE(45000000, 82, 1, 3), - PLL_35XX_RATE(34000000, 82, 2, 3), + PLL_35XX_RATE(33750000, 82, 2, 3), { /* sentinel */ }, }; diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 5bbacd01094f3770fcd3161e733070ea3412b97c..92f2121837c3a9f3749c1eae7547b967843a161b 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1063,7 +1063,7 @@ static void __init tegra30_super_clk_init(void) * U71 divider of cclk_lp. */ clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3", - clk_base + SUPER_CCLKG_DIVIDER, 0, + clk_base + SUPER_CCLKLP_DIVIDER, 0, TEGRA_DIVIDER_INT, 16, 8, 1, NULL); clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL); diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 59bb4b39d12e799f6d32d8f5a3d898e4dc9d1c46..d41b83239a3c12db2876d58cec0be7cc1ec0669e 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -259,7 +259,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) /* Get configuration for the ATL instances */ snprintf(prop, sizeof(prop), "atl%u", i); - cfg_node = of_find_node_by_name(node, prop); + cfg_node = of_get_child_by_name(node, prop); if (cfg_node) { ret = of_property_read_u32(cfg_node, "bws", &cdesc->bws); @@ -272,6 +272,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) atl_write(cinfo, DRA7_ATL_AWSMUX_REG(i), cdesc->aws); } + of_node_put(cfg_node); } cdesc->probed = true; diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 454227d4f895296a04414fe60d966d9b232f60a9..de38acab96025724e16b10faf539562c1176d3b5 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -282,7 +282,7 @@ static int __init __ftm_clk_init(struct device_node *np, char *cnt_name, static unsigned long __init ftm_clk_init(struct device_node *np) { - unsigned long freq; + long freq; freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt"); if (freq <= 0) diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 733aa5153e7451f645a65e3452ed44d6d488054a..e23fd9a9b8c4d6f16017e0c44e94c8cb24d88037 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -364,7 +364,13 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) static int s3c_cpufreq_init(struct cpufreq_policy *policy) { policy->clk = clk_arm; - return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency); + + policy->cpuinfo.transition_latency = cpu_cur.info->latency; + + if (ftab) + return cpufreq_table_validate_and_show(policy, ftab); + + return 0; } static int __init s3c_cpufreq_initclks(void) diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index 86628e22b2a36827d37f35d552f0624bc9dc387c..719c3d9f07fb1adbb0e4e528d00c3f49bb39be33 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -30,54 +30,63 @@ static DEFINE_PER_CPU(struct clk, sh_cpuclk); +struct cpufreq_target { + struct cpufreq_policy *policy; + unsigned int freq; +}; + static unsigned int sh_cpufreq_get(unsigned int cpu) { return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000; } -/* - * Here we notify other drivers of the proposed change and the final change. - */ -static int sh_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static long __sh_cpufreq_target(void *arg) { - unsigned int cpu = policy->cpu; + struct cpufreq_target *target = arg; + struct cpufreq_policy *policy = target->policy; + int cpu = policy->cpu; struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); - cpumask_t cpus_allowed; struct cpufreq_freqs freqs; struct device *dev; long freq; - cpus_allowed = current->cpus_allowed; - set_cpus_allowed_ptr(current, cpumask_of(cpu)); - - BUG_ON(smp_processor_id() != cpu); + if (smp_processor_id() != cpu) + return -ENODEV; dev = get_cpu_device(cpu); /* Convert target_freq from kHz to Hz */ - freq = clk_round_rate(cpuclk, target_freq * 1000); + freq = clk_round_rate(cpuclk, target->freq * 1000); if (freq < (policy->min * 1000) || freq > (policy->max * 1000)) return -EINVAL; - dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000); + dev_dbg(dev, "requested frequency %u Hz\n", target->freq * 1000); freqs.old = sh_cpufreq_get(cpu); freqs.new = (freq + 500) / 1000; freqs.flags = 0; - cpufreq_freq_transition_begin(policy, &freqs); - set_cpus_allowed_ptr(current, &cpus_allowed); + cpufreq_freq_transition_begin(target->policy, &freqs); clk_set_rate(cpuclk, freq); - cpufreq_freq_transition_end(policy, &freqs, 0); + cpufreq_freq_transition_end(target->policy, &freqs, 0); dev_dbg(dev, "set frequency %lu Hz\n", freq); - return 0; } +/* + * Here we notify other drivers of the proposed change and the final change. + */ +static int sh_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_target data = { .policy = policy, .freq = target_freq }; + + return work_on_cpu(policy->cpu, __sh_cpufreq_target, &data); +} + static int sh_cpufreq_verify(struct cpufreq_policy *policy) { struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu); diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index 7d3a3497dd4cfeef09f7d4fbaf88ecace4c4c5bf..fe860907b8542f0122ed095aea68fb4d10e48a49 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -154,6 +154,24 @@ static int powernv_cpuidle_driver_init(void) drv->state_count += 1; } + /* + * On the PowerNV platform cpu_present may be less than cpu_possible in + * cases when firmware detects the CPU, but it is not available to the + * OS. If CONFIG_HOTPLUG_CPU=n, then such CPUs are not hotplugable at + * run time and hence cpu_devices are not created for those CPUs by the + * generic topology_init(). + * + * drv->cpumask defaults to cpu_possible_mask in + * __cpuidle_driver_init(). This breaks cpuidle on PowerNV where + * cpu_devices are not created for CPUs in cpu_possible_mask that + * cannot be hot-added later at run time. + * + * Trying cpuidle_register_device() on a CPU without a cpu_device is + * incorrect, so pass a correct CPU mask to the generic cpuidle driver. + */ + + drv->cpumask = (struct cpumask *)cpu_present_mask; + return 0; } diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index df60c3ea077f49ddfced38404e2ad375f04572f1..cfbcfa4a66e9c6f0844662f5eedac5553e647c33 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -358,7 +358,8 @@ static int parse_legacy_cluster_params(struct device_node *node, int ret; struct lpm_match { char *devname; - int (*set_mode)(struct low_power_ops *, int, bool); + int (*set_mode)(struct low_power_ops *, int, + struct lpm_cluster_level *); }; struct lpm_match match_tbl[] = { {"l2", set_l2_mode}, @@ -591,6 +592,8 @@ static int parse_cluster_level(struct device_node *node, "qcom,disable-dynamic-int-routing"); level->last_core_only = of_property_read_bool(node, "qcom,last-core-only"); + level->no_cache_flush = of_property_read_bool(node, + "qcom,no-cache-flush"); key = "parse_power_params"; ret = parse_power_params(node, &level->pwr); diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 3786ccaaad7e819475f356fda81ce2bf79576cc2..061b1af8601e809856256b1fadc932cfb823ee5e 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -354,10 +354,12 @@ static void msm_pm_set_timer(uint32_t modified_time_us) hrtimer_start(&lpm_hrtimer, modified_ktime, HRTIMER_MODE_REL_PINNED); } -int set_l2_mode(struct low_power_ops *ops, int mode, bool notify_rpm) +int set_l2_mode(struct low_power_ops *ops, int mode, + struct lpm_cluster_level *level) { int lpm = mode; int rc = 0; + bool notify_rpm = level->notify_rpm; struct low_power_ops *cpu_ops = per_cpu(cpu_cluster, smp_processor_id())->lpm_dev; @@ -369,7 +371,10 @@ int set_l2_mode(struct low_power_ops *ops, int mode, bool notify_rpm) case MSM_SPM_MODE_STANDALONE_POWER_COLLAPSE: case MSM_SPM_MODE_POWER_COLLAPSE: case MSM_SPM_MODE_FASTPC: - cpu_ops->tz_flag = MSM_SCM_L2_OFF; + if (level->no_cache_flush) + cpu_ops->tz_flag = MSM_SCM_L2_GDHS; + else + cpu_ops->tz_flag = MSM_SCM_L2_OFF; coresight_cti_ctx_save(); break; case MSM_SPM_MODE_GDHS: @@ -400,8 +405,10 @@ int set_l2_mode(struct low_power_ops *ops, int mode, bool notify_rpm) return rc; } -int set_l3_mode(struct low_power_ops *ops, int mode, bool notify_rpm) +int set_l3_mode(struct low_power_ops *ops, int mode, + struct lpm_cluster_level *level) { + bool notify_rpm = level->notify_rpm; struct low_power_ops *cpu_ops = per_cpu(cpu_cluster, smp_processor_id())->lpm_dev; @@ -418,8 +425,10 @@ int set_l3_mode(struct low_power_ops *ops, int mode, bool notify_rpm) } -int set_system_mode(struct low_power_ops *ops, int mode, bool notify_rpm) +int set_system_mode(struct low_power_ops *ops, int mode, + struct lpm_cluster_level *level) { + bool notify_rpm = level->notify_rpm; return msm_spm_config_low_power_mode(ops->spm, mode, notify_rpm); } @@ -434,7 +443,7 @@ static int set_device_mode(struct lpm_cluster *cluster, int ndevice, ops = &cluster->lpm_dev[ndevice]; if (ops && ops->set_mode) return ops->set_mode(ops, level->mode[ndevice], - level->notify_rpm); + level); else return -EINVAL; } @@ -806,6 +815,9 @@ static void cluster_unprepare(struct lpm_cluster *cluster, if (cluster->no_saw_devices && !use_psci) msm_spm_set_rpm_hs(false); + + if (!from_idle) + suspend_wake_time = 0; } update_debug_pc_event(CLUSTER_EXIT, cluster->last_level, @@ -1157,7 +1169,7 @@ static int cluster_cpuidle_register(struct lpm_cluster *cl) struct cpuidle_state *st = &cl->drv->states[i]; struct lpm_cpu_level *cpu_level = &cl->cpu->levels[i]; snprintf(st->name, CPUIDLE_NAME_LEN, "C%u\n", i); - snprintf(st->desc, CPUIDLE_DESC_LEN, cpu_level->name); + snprintf(st->desc, CPUIDLE_DESC_LEN, "%s", cpu_level->name); st->flags = 0; st->exit_latency = cpu_level->pwr.latency_us; st->power_usage = cpu_level->pwr.ss_power; diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index f6979c4d4d9fb9f746bce99ec197e607142c2af5..e91a16d04fa44f51f1d93112f256e82e245a72ce 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * 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 @@ -76,11 +76,13 @@ struct lpm_cluster_level { unsigned int psci_id; bool is_reset; int reset_level; + bool no_cache_flush; }; struct low_power_ops { struct msm_spm_device *spm; - int (*set_mode)(struct low_power_ops *ops, int mode, bool notify_rpm); + int (*set_mode)(struct low_power_ops *ops, int mode, + struct lpm_cluster_level *level); enum msm_pm_l2_scm_flag tz_flag; }; @@ -110,9 +112,12 @@ struct lpm_cluster { bool no_saw_devices; }; -int set_l2_mode(struct low_power_ops *ops, int mode, bool notify_rpm); -int set_system_mode(struct low_power_ops *ops, int mode, bool notify_rpm); -int set_l3_mode(struct low_power_ops *ops, int mode, bool notify_rpm); +int set_l2_mode(struct low_power_ops *ops, int mode, + struct lpm_cluster_level *level); +int set_system_mode(struct low_power_ops *ops, int mode, + struct lpm_cluster_level *level); +int set_l3_mode(struct low_power_ops *ops, int mode, + struct lpm_cluster_level *level); void lpm_suspend_wake_time(uint64_t wakeup_time); struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 832a2c3f01ffccf691842507955078299799eb86..9e98a5fbbc1d7fadafc7861ceae1967d8032f956 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -613,6 +613,18 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); int error; + /* + * Return if cpu_device is not setup for this CPU. + * + * This could happen if the arch did not set up cpu_device + * since this CPU is not in cpu_present mask and the + * driver did not send a correct CPU mask during registration. + * Without this check we would end up passing bogus + * value for &cpu_dev->kobj in kobject_init_and_add() + */ + if (!cpu_dev) + return -ENODEV; + kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); if (!kdev) return -ENOMEM; diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index e4c6c58fbb03ec66c475278adb07ff389e896599..45df1c74fa035329b14eced8fb4617a77feb6d95 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -207,7 +207,7 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) dev->pdr_pa); return -ENOMEM; } - memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD); + memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD); dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD, &dev->shadow_sa_pool_pa, @@ -240,13 +240,15 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) static void crypto4xx_destroy_pdr(struct crypto4xx_device *dev) { - if (dev->pdr != NULL) + if (dev->pdr) dma_free_coherent(dev->core_dev->device, sizeof(struct ce_pd) * PPC4XX_NUM_PD, dev->pdr, dev->pdr_pa); + if (dev->shadow_sa_pool) dma_free_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD, dev->shadow_sa_pool, dev->shadow_sa_pool_pa); + if (dev->shadow_sr_pool) dma_free_coherent(dev->core_dev->device, sizeof(struct sa_state_record) * PPC4XX_NUM_PD, @@ -416,12 +418,12 @@ static u32 crypto4xx_build_sdr(struct crypto4xx_device *dev) static void crypto4xx_destroy_sdr(struct crypto4xx_device *dev) { - if (dev->sdr != NULL) + if (dev->sdr) dma_free_coherent(dev->core_dev->device, sizeof(struct ce_sd) * PPC4XX_NUM_SD, dev->sdr, dev->sdr_pa); - if (dev->scatter_buffer_va != NULL) + if (dev->scatter_buffer_va) dma_free_coherent(dev->core_dev->device, dev->scatter_buffer_size * PPC4XX_NUM_SD, dev->scatter_buffer_va, @@ -1049,12 +1051,10 @@ int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, break; } - if (rc) { - list_del(&alg->entry); + if (rc) kfree(alg); - } else { + else list_add_tail(&alg->entry, &sec_dev->alg_list); - } } return 0; @@ -1208,7 +1208,7 @@ static int __init crypto4xx_probe(struct platform_device *ofdev) rc = crypto4xx_build_gdr(core_dev->dev); if (rc) - goto err_build_gdr; + goto err_build_pdr; rc = crypto4xx_build_sdr(core_dev->dev); if (rc) @@ -1250,12 +1250,11 @@ err_iomap: err_request_irq: irq_dispose_mapping(core_dev->irq); tasklet_kill(&core_dev->tasklet); - crypto4xx_destroy_sdr(core_dev->dev); err_build_sdr: + crypto4xx_destroy_sdr(core_dev->dev); crypto4xx_destroy_gdr(core_dev->dev); -err_build_gdr: - crypto4xx_destroy_pdr(core_dev->dev); err_build_pdr: + crypto4xx_destroy_pdr(core_dev->dev); kfree(core_dev->dev); err_alloc_dev: kfree(core_dev); diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index bac0bdeb4b5f9955c193e6896a7f5bb182c19e63..b6529b9fcbe25733018b4707982e457b3fa0885c 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -32,12 +32,12 @@ #define PPC405EX_CE_RESET 0x00000008 #define CRYPTO4XX_CRYPTO_PRIORITY 300 -#define PPC4XX_LAST_PD 63 -#define PPC4XX_NUM_PD 64 -#define PPC4XX_LAST_GD 1023 +#define PPC4XX_NUM_PD 256 +#define PPC4XX_LAST_PD (PPC4XX_NUM_PD - 1) #define PPC4XX_NUM_GD 1024 -#define PPC4XX_LAST_SD 63 -#define PPC4XX_NUM_SD 64 +#define PPC4XX_LAST_GD (PPC4XX_NUM_GD - 1) +#define PPC4XX_NUM_SD 256 +#define PPC4XX_LAST_SD (PPC4XX_NUM_SD - 1) #define PPC4XX_SD_BUFFER_SIZE 2048 #define PD_ENTRY_INUSE 1 diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index a23062eef7516622b4d74bcf5342c8eb3367ba85..a5a86c6b787b40fcf68a49b2e3955bf0c4656ed1 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -209,12 +209,16 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask, * without any error (HW optimizations for later * CAAM eras), then try again. */ + if (ret) + break; + rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK; - if (status || !(rdsta_val & (1 << sh_idx))) + if (status || !(rdsta_val & (1 << sh_idx))) { ret = -EAGAIN; - if (ret) break; + } + dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); /* Clear the contents before recreating the descriptor */ memset(desc, 0x00, CAAM_CMD_SZ * 7); diff --git a/drivers/crypto/msm/Makefile b/drivers/crypto/msm/Makefile index 5870cfc721448f05533a04e9c7d7247855c320d0..993840ca12eb70d6506489de050091560ed35dc2 100644 --- a/drivers/crypto/msm/Makefile +++ b/drivers/crypto/msm/Makefile @@ -7,14 +7,6 @@ endif ifdef CONFIG_COMPAT obj-$(CONFIG_CRYPTO_DEV_QCOM_MSM_QCE) += compat_qcedev.o endif -ifeq ($(CONFIG_FIPS_ENABLE), y) - obj-$(CONFIG_CRYPTO_DEV_QCEDEV) += qcedev_fips.o - obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto_fips.o -endif obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto.o obj-$(CONFIG_CRYPTO_DEV_OTA_CRYPTO) += ota_crypto.o obj-$(CONFIG_CRYPTO_DEV_QCOM_ICE) += ice.o - -# TODO: remove me b/62058353 -subdir-ccflags-y += \ - $(call cc-option,-Wno-frame-larger-than=) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index bdce8aaedf528a4699e77abd981df18c03caf45e..372c5099dbb93800fa79ddbc56c430bd7367c21a 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * 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 @@ -1534,6 +1534,7 @@ struct platform_device *qcom_ice_get_pdevice(struct device_node *node) break; } } + if(ice_pdev) pr_info("%s: matching platform device %pK\n", __func__, ice_pdev); out: @@ -1666,7 +1667,7 @@ int qcom_ice_setup_ice_hw(const char *storage_type, int enable) if (ice_dev == ERR_PTR(-EPROBE_DEFER)) return -EPROBE_DEFER; - if (!ice_dev) + if (!ice_dev || (ice_dev->is_ice_enabled == false)) return ret; if (enable) diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h index 6937c9e20a47238092191258abfb80329c3fc063..7455a122922c7f8d61bbe5116f6e5a71c2771939 100644 --- a/drivers/crypto/msm/qce.h +++ b/drivers/crypto/msm/qce.h @@ -1,6 +1,6 @@ /* Qualcomm Crypto Engine driver API * - * Copyright (c) 2010-2015, 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. * * 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 @@ -157,8 +157,8 @@ struct qce_req { unsigned int authsize; /* authentication key kength */ unsigned char nonce[MAX_NONCE];/* nonce for ccm mode */ unsigned char *assoc; /* Ptr to formatted associated data */ - size_t assoclen; /* Formatted associated data length */ - size_t trail_assoclen; /* trail associated data length */ + unsigned int assoclen; /* Formatted associated data length */ + struct scatterlist *asg; /* Formatted associated data sg */ unsigned char *enckey; /* cipher key */ unsigned int encklen; /* cipher key length */ unsigned char *iv; /* initialization vector */ diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 4061a5d996f4844f6099197e00f560b2bc6ea341..e0f26801cf2798131b6ca71dbae5fff4108799d1 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -38,16 +38,22 @@ #include "qcryptohw_50.h" #include "qce_ota.h" -#define CRYPTO_CONFIG_RESET 0xE001F -#define QCE_MAX_NUM_DSCR 0x500 +#define CRYPTO_CONFIG_RESET 0xE01EF +#define MAX_SPS_DESC_FIFO_SIZE 0xfff0 +#define QCE_MAX_NUM_DSCR 0x200 #define QCE_SECTOR_SIZE 0x200 #define CE_CLK_100MHZ 100000000 #define CE_CLK_DIV 1000000 #define CRYPTO_CORE_MAJOR_VER_NUM 0x05 #define CRYPTO_CORE_MINOR_VER_NUM 0x03 +#define CRYPTO_CORE_STEP_VER_NUM 0x1 + +#define CRYPTO_REQ_USER_PAT 0xdead0000 static DEFINE_MUTEX(bam_register_lock); +static DEFINE_MUTEX(qce_iomap_mutex); + struct bam_registration_info { struct list_head qlist; unsigned long handle; @@ -58,6 +64,40 @@ struct bam_registration_info { }; static LIST_HEAD(qce50_bam_list); +/* Used to determine the mode */ +#define MAX_BUNCH_MODE_REQ 2 +/* Max number of request supported */ +#define MAX_QCE_BAM_REQ 8 +/* Interrupt flag will be set for every SET_INTR_AT_REQ request */ +#define SET_INTR_AT_REQ (MAX_QCE_BAM_REQ / 2) +/* To create extra request space to hold dummy request */ +#define MAX_QCE_BAM_REQ_WITH_DUMMY_REQ (MAX_QCE_BAM_REQ + 1) +/* Allocate the memory for MAX_QCE_BAM_REQ + 1 (for dummy request) */ +#define MAX_QCE_ALLOC_BAM_REQ MAX_QCE_BAM_REQ_WITH_DUMMY_REQ +/* QCE driver modes */ +#define IN_INTERRUPT_MODE 0 +#define IN_BUNCH_MODE 1 +/* Dummy request data length */ +#define DUMMY_REQ_DATA_LEN 64 +/* Delay timer to expire when in bunch mode */ +#define DELAY_IN_JIFFIES 5 +/* Index to point the dummy request */ +#define DUMMY_REQ_INDEX MAX_QCE_BAM_REQ + +#define TOTAL_IOVEC_SPACE_PER_PIPE (QCE_MAX_NUM_DSCR * sizeof(struct sps_iovec)) + +enum qce_owner { + QCE_OWNER_NONE = 0, + QCE_OWNER_CLIENT = 1, + QCE_OWNER_TIMEOUT = 2 +}; + +struct dummy_request { + struct qce_sha_req sreq; + struct scatterlist sg; + struct ahash_request areq; +}; + /* * CE HW device structure. * Each engine has an instance of the structure. @@ -71,6 +111,8 @@ struct qce_device { unsigned char *coh_vmem; /* Allocated coherent virtual memory */ dma_addr_t coh_pmem; /* Allocated coherent physical memory */ int memsize; /* Memory allocated */ + unsigned char *iovec_vmem; /* Allocate iovec virtual memory */ + int iovec_memsize; /* Memory allocated */ uint32_t bam_mem; /* bam physical address, from DT */ uint32_t bam_mem_size; /* bam io size, from DT */ int is_shared; /* CE HW is shared */ @@ -86,37 +128,40 @@ struct qce_device { struct clk *ce_core_clk; /* Handle to CE clk */ struct clk *ce_clk; /* Handle to CE clk */ struct clk *ce_bus_clk; /* Handle to CE AXI clk*/ - bool no_get_around; - qce_comp_func_ptr_t qce_cb; /* qce callback function pointer */ - - int assoc_nents; - int ivsize; - int authsize; - int src_nents; - int dst_nents; - - dma_addr_t phy_iv_in; - unsigned char dec_iv[16]; - int dir; - void *areq; - enum qce_cipher_mode_enum mode; - struct qce_ce_cfg_reg_setting reg; - struct ce_sps_data ce_sps; - uint32_t engines_avail; - dma_addr_t phy_ota_src; - dma_addr_t phy_ota_dst; - unsigned int ota_size; + bool no_ccm_mac_status_get_around; unsigned int ce_opp_freq_hz; - bool use_sw_aes_cbc_ecb_ctr_algo; bool use_sw_aead_algo; bool use_sw_aes_xts_algo; bool use_sw_ahash_algo; bool use_sw_hmac_algo; bool use_sw_aes_ccm_algo; + uint32_t engines_avail; + struct qce_ce_cfg_reg_setting reg; + struct ce_bam_info ce_bam_info; + struct ce_request_info ce_request_info[MAX_QCE_ALLOC_BAM_REQ]; + unsigned int ce_request_index; + enum qce_owner owner; + atomic_t no_of_queued_req; + struct timer_list timer; + struct dummy_request dummyreq; + unsigned int mode; + unsigned int intr_cadence; + unsigned int dev_no; + struct qce_driver_stats qce_stats; + atomic_t bunch_cmd_seq; + atomic_t last_intr_seq; + bool cadence_flag; + uint8_t *dummyreq_in_buf; }; +static void print_notify_debug(struct sps_event_notify *notify); +static void _sps_producer_callback(struct sps_event_notify *notify); +static int qce_dummy_req(struct qce_device *pce_dev); + +static int _qce50_disp_stats; + /* Standard initialization vector for SHA-1, source: FIPS 180-2 */ static uint32_t _std_init_vector_sha1[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 @@ -173,8 +218,8 @@ static int count_sg(struct scatterlist *sg, int nbytes) int i; for (i = 0; nbytes > 0; i++, sg = scatterwalk_sg_next(sg)) { - if (sg == NULL) { - pr_err("qce50: count_sg, sg = NULL\n"); + if (NULL == sg) { + pr_err("qce50.c: count_sg, sg = NULL"); break; } nbytes -= sg->length; @@ -188,8 +233,8 @@ static int qce_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int i; for (i = 0; i < nents; ++i) { - if (sg == NULL) { - pr_err("qce50: qce_dma_map_sg, sg = NULL\n"); + if (NULL == sg) { + pr_err("qce50.c: qce_dma_map_sg, sg = NULL"); break; } dma_map_sg(dev, sg, 1, direction); @@ -205,8 +250,8 @@ static int qce_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int i; for (i = 0; i < nents; ++i) { - if (sg == NULL) { - pr_err("qce50: qce_dma_unmap_sg, sg = NULL\n"); + if (NULL == sg) { + pr_err("qce50.c: qce_dma_unmap_sg, sg = NULL"); break; } dma_unmap_sg(dev, sg, 1, direction); @@ -232,18 +277,34 @@ static int _probe_ce_engine(struct qce_device *pce_dev) pce_dev->phy_iobase, maj_rev, min_rev, step_rev); return -EIO; } else { + /* + * The majority of crypto HW bugs have been fixed in 5.3.0 and + * above. That allows a single sps transfer of consumer + * pipe, and a single sps transfer of producer pipe + * for a crypto request. no_get_around flag indicates this. + * + * In 5.3.1, the CCM MAC_FAILED in result dump issue is + * fixed. no_ccm_mac_status_get_around flag indicates this. + */ pce_dev->no_get_around = (min_rev >= CRYPTO_CORE_MINOR_VER_NUM) ? true : false; + if (min_rev > CRYPTO_CORE_MINOR_VER_NUM) + pce_dev->no_ccm_mac_status_get_around = true; + else if ((min_rev == CRYPTO_CORE_MINOR_VER_NUM) && + (step_rev >= CRYPTO_CORE_STEP_VER_NUM)) + pce_dev->no_ccm_mac_status_get_around = true; + else + pce_dev->no_ccm_mac_status_get_around = false; } - pce_dev->ce_sps.minor_version = min_rev; + pce_dev->ce_bam_info.minor_version = min_rev; pce_dev->engines_avail = readl_relaxed(pce_dev->iobase + CRYPTO_ENGINES_AVAIL); dev_info(pce_dev->pdev, "Qualcomm Crypto %d.%d.%d device found @0x%x\n", maj_rev, min_rev, step_rev, pce_dev->phy_iobase); - pce_dev->ce_sps.ce_burst_size = MAX_CE_BAM_BURST_SIZE; + pce_dev->ce_bam_info.ce_burst_size = MAX_CE_BAM_BURST_SIZE; dev_info(pce_dev->pdev, "CE device = 0x%x\n" @@ -253,21 +314,25 @@ static int _probe_ce_engine(struct qce_device *pce_dev) "IO base BAM = 0x%pK\n" "BAM IRQ %d\n" "Engines Availability = 0x%x\n", - pce_dev->ce_sps.ce_device, + pce_dev->ce_bam_info.ce_device, pce_dev->iobase, - pce_dev->ce_sps.dest_pipe_index, - pce_dev->ce_sps.src_pipe_index, - pce_dev->ce_sps.bam_iobase, - pce_dev->ce_sps.bam_irq, + pce_dev->ce_bam_info.dest_pipe_index, + pce_dev->ce_bam_info.src_pipe_index, + pce_dev->ce_bam_info.bam_iobase, + pce_dev->ce_bam_info.bam_irq, pce_dev->engines_avail); return 0; }; static struct qce_cmdlist_info *_ce_get_hash_cmdlistinfo( - struct qce_device *pce_dev, struct qce_sha_req *sreq) + struct qce_device *pce_dev, + int req_info, struct qce_sha_req *sreq) { - struct qce_cmdlistptr_ops *cmdlistptr = &pce_dev->ce_sps.cmdlistptr; + struct ce_sps_data *pce_sps_data; + struct qce_cmdlistptr_ops *cmdlistptr; + pce_sps_data = &pce_dev->ce_request_info[req_info].ce_sps; + cmdlistptr = &pce_sps_data->cmdlistptr; switch (sreq->alg) { case QCE_HASH_SHA1: return &cmdlistptr->auth_sha1; @@ -291,7 +356,7 @@ static int _ce_setup_hash(struct qce_device *pce_dev, struct qce_sha_req *sreq, struct qce_cmdlist_info *cmdlistinfo) { - uint32_t auth32[(SHA256_DIGEST_SIZE / sizeof(uint32_t)) + 1]; + uint32_t auth32[(SHA256_DIGEST_SIZE / sizeof(uint32_t))+1]; uint32_t diglen; int i; uint32_t mackey32[SHA_HMAC_KEY_SIZE/sizeof(uint32_t)] = { @@ -416,24 +481,28 @@ go_proc: if (sreq->size) pce->data = sreq->size; else - pce->data = pce_dev->ce_sps.ce_burst_size; + pce->data = pce_dev->ce_bam_info.ce_burst_size; return 0; } static struct qce_cmdlist_info *_ce_get_aead_cmdlistinfo( - struct qce_device *pce_dev, struct qce_req *creq) + struct qce_device *pce_dev, + int req_info, struct qce_req *creq) { + struct ce_sps_data *pce_sps_data; + struct qce_cmdlistptr_ops *cmdlistptr; + + pce_sps_data = &pce_dev->ce_request_info[req_info].ce_sps; + cmdlistptr = &pce_sps_data->cmdlistptr; switch (creq->alg) { case CIPHER_ALG_DES: switch (creq->mode) { case QCE_MODE_CBC: if (creq->auth_alg == QCE_HASH_SHA1_HMAC) - return &pce_dev->ce_sps. - cmdlistptr.aead_hmac_sha1_cbc_des; + return &cmdlistptr->aead_hmac_sha1_cbc_des; else if (creq->auth_alg == QCE_HASH_SHA256_HMAC) - return &pce_dev->ce_sps. - cmdlistptr.aead_hmac_sha256_cbc_des; + return &cmdlistptr->aead_hmac_sha256_cbc_des; else return NULL; break; @@ -445,11 +514,9 @@ static struct qce_cmdlist_info *_ce_get_aead_cmdlistinfo( switch (creq->mode) { case QCE_MODE_CBC: if (creq->auth_alg == QCE_HASH_SHA1_HMAC) - return &pce_dev->ce_sps. - cmdlistptr.aead_hmac_sha1_cbc_3des; + return &cmdlistptr->aead_hmac_sha1_cbc_3des; else if (creq->auth_alg == QCE_HASH_SHA256_HMAC) - return &pce_dev->ce_sps. - cmdlistptr.aead_hmac_sha256_cbc_3des; + return &cmdlistptr->aead_hmac_sha256_cbc_3des; else return NULL; break; @@ -462,21 +529,21 @@ static struct qce_cmdlist_info *_ce_get_aead_cmdlistinfo( case QCE_MODE_CBC: if (creq->encklen == AES128_KEY_SIZE) { if (creq->auth_alg == QCE_HASH_SHA1_HMAC) - return &pce_dev->ce_sps.cmdlistptr. + return &cmdlistptr-> aead_hmac_sha1_cbc_aes_128; else if (creq->auth_alg == QCE_HASH_SHA256_HMAC) - return &pce_dev->ce_sps.cmdlistptr. + return &cmdlistptr-> aead_hmac_sha256_cbc_aes_128; else return NULL; } else if (creq->encklen == AES256_KEY_SIZE) { if (creq->auth_alg == QCE_HASH_SHA1_HMAC) - return &pce_dev->ce_sps.cmdlistptr. + return &cmdlistptr-> aead_hmac_sha1_cbc_aes_256; else if (creq->auth_alg == QCE_HASH_SHA256_HMAC) - return &pce_dev->ce_sps.cmdlistptr. + return &cmdlistptr-> aead_hmac_sha256_cbc_aes_256; else return NULL; @@ -531,19 +598,14 @@ static int _ce_setup_aead(struct qce_device *pce_dev, struct qce_req *q_req, return -EINVAL; } - switch (q_req->mode) { - case QCE_MODE_CBC: - pce_dev->mode = q_req->mode; - break; - default: + /* only support cbc mode */ + if (q_req->mode != QCE_MODE_CBC) return -EINVAL; - } - if (q_req->mode != QCE_MODE_ECB) { - _byte_stream_to_net_words(enciv32, q_req->iv, ivsize); - pce = cmdlistinfo->encr_cntr_iv; - for (i = 0; i < enciv_in_word; i++, pce++) - pce->data = enciv32[i]; - } + + _byte_stream_to_net_words(enciv32, q_req->iv, ivsize); + pce = cmdlistinfo->encr_cntr_iv; + for (i = 0; i < enciv_in_word; i++, pce++) + pce->data = enciv32[i]; /* * write encr key @@ -614,13 +676,19 @@ static int _ce_setup_aead(struct qce_device *pce_dev, struct qce_req *q_req, return 0; -}; +} static struct qce_cmdlist_info *_ce_get_cipher_cmdlistinfo( - struct qce_device *pce_dev, struct qce_req *creq) + struct qce_device *pce_dev, + int req_info, struct qce_req *creq) { - struct qce_cmdlistptr_ops *cmdlistptr = &pce_dev->ce_sps.cmdlistptr; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + struct qce_cmdlistptr_ops *cmdlistptr; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; + cmdlistptr = &pce_sps_data->cmdlistptr; if (creq->alg != CIPHER_ALG_AES) { switch (creq->alg) { case CIPHER_ALG_DES: @@ -787,7 +855,6 @@ static int _ce_setup_cipher(struct qce_device *pce_dev, struct qce_req *creq, encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_256; break; } - pce_dev->mode = creq->mode; switch (creq->alg) { case CIPHER_ALG_DES: @@ -1056,16 +1123,19 @@ static int _ce_f8_setup(struct qce_device *pce_dev, struct qce_f8_req *req, return 0; } -static void _qce_dump_descr_fifos(struct qce_device *pce_dev) +static void _qce_dump_descr_fifos(struct qce_device *pce_dev, int req_info) { int i, j, ents; - struct sps_iovec *iovec = pce_dev->ce_sps.in_transfer.iovec; + struct ce_sps_data *pce_sps_data; + struct sps_iovec *iovec; uint32_t cmd_flags = SPS_IOVEC_FLAG_CMD; + pce_sps_data = &pce_dev->ce_request_info[req_info].ce_sps; + iovec = pce_sps_data->in_transfer.iovec; pr_info("==============================================\n"); pr_info("CONSUMER (TX/IN/DEST) PIPE DESCRIPTOR\n"); pr_info("==============================================\n"); - for (i = 0; i < pce_dev->ce_sps.in_transfer.iovec_count; i++) { + for (i = 0; i < pce_sps_data->in_transfer.iovec_count; i++) { pr_info(" [%d] addr=0x%x size=0x%x flags=0x%x\n", i, iovec->addr, iovec->size, iovec->flags); if (iovec->flags & cmd_flags) { @@ -1086,8 +1156,8 @@ static void _qce_dump_descr_fifos(struct qce_device *pce_dev) pr_info("==============================================\n"); pr_info("PRODUCER (RX/OUT/SRC) PIPE DESCRIPTOR\n"); pr_info("==============================================\n"); - iovec = pce_dev->ce_sps.out_transfer.iovec; - for (i = 0; i < pce_dev->ce_sps.out_transfer.iovec_count; i++) { + iovec = pce_sps_data->out_transfer.iovec; + for (i = 0; i < pce_sps_data->out_transfer.iovec_count; i++) { pr_info(" [%d] addr=0x%x size=0x%x flags=0x%x\n", i, iovec->addr, iovec->size, iovec->flags); iovec++; @@ -1096,9 +1166,9 @@ static void _qce_dump_descr_fifos(struct qce_device *pce_dev) #ifdef QCE_DEBUG -static void _qce_dump_descr_fifos_dbg(struct qce_device *pce_dev) +static void _qce_dump_descr_fifos_dbg(struct qce_device *pce_dev, int req_info) { - _qce_dump_descr_fifos(pce_dev); + _qce_dump_descr_fifos(pce_dev, req_info); } #define QCE_WRITE_REG(val, addr) \ @@ -1109,7 +1179,7 @@ static void _qce_dump_descr_fifos_dbg(struct qce_device *pce_dev) #else -static void _qce_dump_descr_fifos_dbg(struct qce_device *pce_dev) +static void _qce_dump_descr_fifos_dbg(struct qce_device *pce_dev, int req_info) { } @@ -1121,7 +1191,7 @@ static void _qce_dump_descr_fifos_dbg(struct qce_device *pce_dev) static int _ce_setup_hash_direct(struct qce_device *pce_dev, struct qce_sha_req *sreq) { - uint32_t auth32[(SHA256_DIGEST_SIZE / sizeof(uint32_t)) + 1]; + uint32_t auth32[(SHA256_DIGEST_SIZE / sizeof(uint32_t))+1]; uint32_t diglen; bool use_hw_key = false; bool use_pipe_key = false; @@ -1388,7 +1458,9 @@ static int _ce_setup_aead_direct(struct qce_device *pce_dev, return -EINVAL; } - pce_dev->mode = q_req->mode; + + + /* write CNTR0_IV0_REG */ if (q_req->mode != QCE_MODE_ECB) { _byte_stream_to_net_words(enciv32, q_req->iv, ivsize); @@ -1625,7 +1697,6 @@ static int _ce_setup_cipher_direct(struct qce_device *pce_dev, encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_256; break; } - pce_dev->mode = creq->mode; switch (creq->alg) { case CIPHER_ALG_DES: @@ -1881,7 +1952,8 @@ static int _ce_f9_setup_direct(struct qce_device *pce_dev, CRYPTO_CONFIG_REG)); /* write go */ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | - (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); + (1 << CRYPTO_CLR_CNTXT)), + pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) * was completed before issuing a DMA transfer request @@ -1958,7 +2030,8 @@ static int _ce_f8_setup_direct(struct qce_device *pce_dev, CRYPTO_CONFIG_REG)); /* write go */ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | - (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); + (1 << CRYPTO_CLR_CNTXT)), + pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) * was completed before issuing a DMA transfer request @@ -1968,77 +2041,99 @@ static int _ce_f8_setup_direct(struct qce_device *pce_dev, } -static int _qce_unlock_other_pipes(struct qce_device *pce_dev) +static int _qce_unlock_other_pipes(struct qce_device *pce_dev, int req_info) { int rc = 0; + struct ce_sps_data *pce_sps_data = &pce_dev->ce_request_info + [req_info].ce_sps; if (pce_dev->no_get_around || pce_dev->support_cmd_dscr == false) return rc; - pce_dev->ce_sps.consumer.event.callback = NULL; - rc = sps_transfer_one(pce_dev->ce_sps.consumer.pipe, - GET_PHYS_ADDR(pce_dev->ce_sps.cmdlistptr.unlock_all_pipes.cmdlist), - 0, NULL, (SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_UNLOCK)); + rc = sps_transfer_one(pce_dev->ce_bam_info.consumer.pipe, + GET_PHYS_ADDR(pce_sps_data-> + cmdlistptr.unlock_all_pipes.cmdlist), + 0, NULL, (SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_UNLOCK)); if (rc) { - pr_err("sps_xfr_one() fail rc=%d\n", rc); + pr_err("sps_xfr_one() fail rc=%d", rc); rc = -EINVAL; } return rc; } -static int _aead_complete(struct qce_device *pce_dev) +static inline void qce_free_req_info(struct qce_device *pce_dev, int req_info, + bool is_complete); +static int _aead_complete(struct qce_device *pce_dev, int req_info) { struct aead_request *areq; unsigned char mac[SHA256_DIGEST_SIZE]; - uint32_t status; + uint32_t ccm_fail_status = 0; uint32_t result_dump_status; - int32_t result_status; - - areq = (struct aead_request *) pce_dev->areq; + int32_t result_status = 0; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + qce_comp_func_ptr_t qce_callback; + + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; + qce_callback = preq_info->qce_cb; + areq = (struct aead_request *) preq_info->areq; if (areq->src != areq->dst) { - qce_dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents, + qce_dma_unmap_sg(pce_dev->pdev, areq->dst, preq_info->dst_nents, DMA_FROM_DEVICE); } - qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); - qce_dma_unmap_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents, + qce_dma_unmap_sg(pce_dev->pdev, areq->assoc, preq_info->assoc_nents, DMA_TO_DEVICE); /* check MAC */ - memcpy(mac, (char *)(&pce_dev->ce_sps.result->auth_iv[0]), + memcpy(mac, (char *)(&pce_sps_data->result->auth_iv[0]), SHA256_DIGEST_SIZE); /* read status before unlock */ - status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG); - - if (_qce_unlock_other_pipes(pce_dev)) { - pce_dev->qce_cb(areq, mac, NULL, -ENXIO); + if (preq_info->dir == QCE_DECRYPT) { + if (pce_dev->no_get_around) + if (pce_dev->no_ccm_mac_status_get_around) + ccm_fail_status = be32_to_cpu(pce_sps_data-> + result->status); + else + ccm_fail_status = be32_to_cpu(pce_sps_data-> + result_null->status); + else + ccm_fail_status = readl_relaxed(pce_dev->iobase + + CRYPTO_STATUS_REG); + } + if (_qce_unlock_other_pipes(pce_dev, req_info)) { + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, mac, NULL, -ENXIO); return -ENXIO; } - result_status = 0; - result_dump_status = be32_to_cpu(pce_dev->ce_sps.result->status); - pce_dev->ce_sps.result->status = 0; + result_dump_status = be32_to_cpu(pce_sps_data->result->status); + pce_sps_data->result->status = 0; if (result_dump_status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR) | (1 << CRYPTO_HSD_ERR))) { pr_err("aead operation error. Status %x\n", result_dump_status); result_status = -ENXIO; - } else if (pce_dev->ce_sps.consumer_status | - pce_dev->ce_sps.producer_status) { + } else if (pce_sps_data->consumer_status | + pce_sps_data->producer_status) { pr_err("aead sps operation error. sps status %x %x\n", - pce_dev->ce_sps.consumer_status, - pce_dev->ce_sps.producer_status); + pce_sps_data->consumer_status, + pce_sps_data->producer_status); result_status = -ENXIO; } - if (pce_dev->mode == QCE_MODE_CCM) { + if (preq_info->mode == QCE_MODE_CCM) { /* * Not from result dump, instead, use the status we just * read of device for MAC_FAILED. */ - if (result_status == 0 && (status & (1 << CRYPTO_MAC_FAILED))) + if (result_status == 0 && (preq_info->dir == QCE_DECRYPT) && + (ccm_fail_status & (1 << CRYPTO_MAC_FAILED))) result_status = -EBADMSG; - pce_dev->qce_cb(areq, mac, NULL, result_status); + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, mac, NULL, result_status); } else { uint32_t ivsize = 0; @@ -2046,145 +2141,166 @@ static int _aead_complete(struct qce_device *pce_dev) unsigned char iv[NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE]; aead = crypto_aead_reqtfm(areq); ivsize = crypto_aead_ivsize(aead); - if (pce_dev->ce_sps.minor_version != 0) - dma_unmap_single(pce_dev->pdev, pce_dev->phy_iv_in, + if (pce_dev->ce_bam_info.minor_version != 0) + dma_unmap_single(pce_dev->pdev, preq_info->phy_iv_in, ivsize, DMA_TO_DEVICE); - memcpy(iv, (char *)(pce_dev->ce_sps.result->encr_cntr_iv), + memcpy(iv, (char *)(pce_sps_data->result->encr_cntr_iv), sizeof(iv)); - pce_dev->qce_cb(areq, mac, iv, result_status); + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, mac, iv, result_status); } return 0; }; -static int _sha_complete(struct qce_device *pce_dev) +static int _sha_complete(struct qce_device *pce_dev, int req_info) { struct ahash_request *areq; unsigned char digest[SHA256_DIGEST_SIZE]; uint32_t bytecount32[2]; - int32_t result_status; + int32_t result_status = 0; uint32_t result_dump_status; - - areq = (struct ahash_request *) pce_dev->areq; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + qce_comp_func_ptr_t qce_callback; + + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; + qce_callback = preq_info->qce_cb; + areq = (struct ahash_request *) preq_info->areq; if (!areq) { pr_err("sha operation error. areq is NULL\n"); return -ENXIO; } - qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents, DMA_TO_DEVICE); - memcpy(digest, (char *)(&pce_dev->ce_sps.result->auth_iv[0]), + memcpy(digest, (char *)(&pce_sps_data->result->auth_iv[0]), SHA256_DIGEST_SIZE); _byte_stream_to_net_words(bytecount32, - (unsigned char *)pce_dev->ce_sps.result->auth_byte_count, + (unsigned char *)pce_sps_data->result->auth_byte_count, 2 * CRYPTO_REG_SIZE); - if (_qce_unlock_other_pipes(pce_dev)) { - pce_dev->qce_cb(areq, digest, (char *)bytecount32, + if (_qce_unlock_other_pipes(pce_dev, req_info)) { + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, digest, (char *)bytecount32, -ENXIO); return -ENXIO; } - result_status = 0; - result_dump_status = be32_to_cpu(pce_dev->ce_sps.result->status); - pce_dev->ce_sps.result->status = 0; + result_dump_status = be32_to_cpu(pce_sps_data->result->status); + pce_sps_data->result->status = 0; if (result_dump_status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR) | (1 << CRYPTO_HSD_ERR))) { pr_err("sha operation error. Status %x\n", result_dump_status); result_status = -ENXIO; - } else if (pce_dev->ce_sps.consumer_status) { + } else if (pce_sps_data->consumer_status) { pr_err("sha sps operation error. sps status %x\n", - pce_dev->ce_sps.consumer_status); + pce_sps_data->consumer_status); result_status = -ENXIO; } - pce_dev->qce_cb(areq, digest, (char *)bytecount32, - result_status); + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, digest, (char *)bytecount32, result_status); return 0; -}; +} -static int _f9_complete(struct qce_device *pce_dev) +static int _f9_complete(struct qce_device *pce_dev, int req_info) { uint32_t mac_i; - int32_t result_status; + int32_t result_status = 0; uint32_t result_dump_status; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + qce_comp_func_ptr_t qce_callback; + void *areq; - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src, - pce_dev->ota_size, DMA_TO_DEVICE); + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; + qce_callback = preq_info->qce_cb; + areq = preq_info->areq; + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_src, + preq_info->ota_size, DMA_TO_DEVICE); _byte_stream_to_net_words(&mac_i, - (char *)(&pce_dev->ce_sps.result->auth_iv[0]), + (char *)(&pce_sps_data->result->auth_iv[0]), CRYPTO_REG_SIZE); - if (_qce_unlock_other_pipes(pce_dev)) { - pce_dev->qce_cb(pce_dev->areq, NULL, NULL, -ENXIO); + if (_qce_unlock_other_pipes(pce_dev, req_info)) { + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, NULL, NULL, -ENXIO); return -ENXIO; } - result_status = 0; - result_dump_status = be32_to_cpu(pce_dev->ce_sps.result->status); - pce_dev->ce_sps.result->status = 0; + result_dump_status = be32_to_cpu(pce_sps_data->result->status); + pce_sps_data->result->status = 0; if (result_dump_status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR) | (1 << CRYPTO_HSD_ERR))) { pr_err("f9 operation error. Status %x\n", result_dump_status); result_status = -ENXIO; - } else if (pce_dev->ce_sps.consumer_status | - pce_dev->ce_sps.producer_status) { + } else if (pce_sps_data->consumer_status | + pce_sps_data->producer_status) { pr_err("f9 sps operation error. sps status %x %x\n", - pce_dev->ce_sps.consumer_status, - pce_dev->ce_sps.producer_status); + pce_sps_data->consumer_status, + pce_sps_data->producer_status); result_status = -ENXIO; } - pce_dev->qce_cb(pce_dev->areq, (char *)&mac_i, NULL, result_status); + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, (char *)&mac_i, NULL, result_status); return 0; } -static int _ablk_cipher_complete(struct qce_device *pce_dev) +static int _ablk_cipher_complete(struct qce_device *pce_dev, int req_info) { struct ablkcipher_request *areq; unsigned char iv[NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE]; - int32_t result_status; + int32_t result_status = 0; uint32_t result_dump_status; - - areq = (struct ablkcipher_request *) pce_dev->areq; - + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + qce_comp_func_ptr_t qce_callback; + + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; + qce_callback = preq_info->qce_cb; + areq = (struct ablkcipher_request *) preq_info->areq; if (areq->src != areq->dst) { qce_dma_unmap_sg(pce_dev->pdev, areq->dst, - pce_dev->dst_nents, DMA_FROM_DEVICE); + preq_info->dst_nents, DMA_FROM_DEVICE); } - qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); - if (_qce_unlock_other_pipes(pce_dev)) { - pce_dev->qce_cb(areq, NULL, NULL, -ENXIO); + if (_qce_unlock_other_pipes(pce_dev, req_info)) { + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, NULL, NULL, -ENXIO); return -ENXIO; } - result_status = 0; - result_dump_status = be32_to_cpu(pce_dev->ce_sps.result->status); - pce_dev->ce_sps.result->status = 0; + result_dump_status = be32_to_cpu(pce_sps_data->result->status); + pce_sps_data->result->status = 0; if (result_dump_status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR) | (1 << CRYPTO_HSD_ERR))) { pr_err("ablk_cipher operation error. Status %x\n", result_dump_status); result_status = -ENXIO; - } else if (pce_dev->ce_sps.consumer_status | - pce_dev->ce_sps.producer_status) { + } else if (pce_sps_data->consumer_status | + pce_sps_data->producer_status) { pr_err("ablk_cipher sps operation error. sps status %x %x\n", - pce_dev->ce_sps.consumer_status, - pce_dev->ce_sps.producer_status); + pce_sps_data->consumer_status, + pce_sps_data->producer_status); result_status = -ENXIO; } - if (pce_dev->mode == QCE_MODE_ECB) { - pce_dev->qce_cb(areq, NULL, NULL, - pce_dev->ce_sps.consumer_status | - result_status); + if (preq_info->mode == QCE_MODE_ECB) { + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, NULL, NULL, pce_sps_data->consumer_status | + result_status); } else { - if (pce_dev->ce_sps.minor_version == 0) { - if (pce_dev->mode == QCE_MODE_CBC) { - if (pce_dev->dir == QCE_DECRYPT) - memcpy(iv, (char *)pce_dev->dec_iv, + if (pce_dev->ce_bam_info.minor_version == 0) { + if (preq_info->mode == QCE_MODE_CBC) { + if (preq_info->dir == QCE_DECRYPT) + memcpy(iv, (char *)preq_info->dec_iv, sizeof(iv)); else memcpy(iv, (unsigned char *) @@ -2192,15 +2308,15 @@ static int _ablk_cipher_complete(struct qce_device *pce_dev) areq->src->length - 16), sizeof(iv)); } - if ((pce_dev->mode == QCE_MODE_CTR) || - (pce_dev->mode == QCE_MODE_XTS)) { + if ((preq_info->mode == QCE_MODE_CTR) || + (preq_info->mode == QCE_MODE_XTS)) { uint32_t num_blk = 0; uint32_t cntr_iv3 = 0; unsigned long long cntr_iv64 = 0; unsigned char *b = (unsigned char *)(&cntr_iv3); memcpy(iv, areq->info, sizeof(iv)); - if (pce_dev->mode != QCE_MODE_XTS) + if (preq_info->mode != QCE_MODE_XTS) num_blk = areq->nbytes/16; else num_blk = 1; @@ -2222,54 +2338,71 @@ static int _ablk_cipher_complete(struct qce_device *pce_dev) } } else { memcpy(iv, - (char *)(pce_dev->ce_sps.result->encr_cntr_iv), + (char *)(pce_sps_data->result->encr_cntr_iv), sizeof(iv)); } - pce_dev->qce_cb(areq, NULL, iv, result_status); + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, NULL, iv, result_status); } return 0; -}; +} -static int _f8_complete(struct qce_device *pce_dev) +static int _f8_complete(struct qce_device *pce_dev, int req_info) { - int32_t result_status; + int32_t result_status = 0; uint32_t result_dump_status; + uint32_t result_dump_status2; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + qce_comp_func_ptr_t qce_callback; + void *areq; - if (pce_dev->phy_ota_dst != 0) - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_dst, - pce_dev->ota_size, DMA_FROM_DEVICE); - if (pce_dev->phy_ota_src != 0) - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src, - pce_dev->ota_size, (pce_dev->phy_ota_dst) ? + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; + qce_callback = preq_info->qce_cb; + areq = preq_info->areq; + if (preq_info->phy_ota_dst) + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_dst, + preq_info->ota_size, DMA_FROM_DEVICE); + if (preq_info->phy_ota_src) + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_src, + preq_info->ota_size, (preq_info->phy_ota_dst) ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL); - if (_qce_unlock_other_pipes(pce_dev)) { - pce_dev->qce_cb(pce_dev->areq, NULL, NULL, -ENXIO); + if (_qce_unlock_other_pipes(pce_dev, req_info)) { + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, NULL, NULL, -ENXIO); return -ENXIO; } - result_status = 0; - result_dump_status = be32_to_cpu(pce_dev->ce_sps.result->status); - pce_dev->ce_sps.result->status = 0; + result_dump_status = be32_to_cpu(pce_sps_data->result->status); + result_dump_status2 = be32_to_cpu(pce_sps_data->result->status2); - if (result_dump_status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR) - | (1 << CRYPTO_HSD_ERR))) { - pr_err("f8 operation error. Status %x\n", result_dump_status); + if ((result_dump_status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR) + | (1 << CRYPTO_HSD_ERR)))) { + pr_err( + "f8 oper error. Dump Sta %x Sta2 %x req %d\n", + result_dump_status, result_dump_status2, req_info); result_status = -ENXIO; - } else if (pce_dev->ce_sps.consumer_status | - pce_dev->ce_sps.producer_status) { + } else if (pce_sps_data->consumer_status | + pce_sps_data->producer_status) { pr_err("f8 sps operation error. sps status %x %x\n", - pce_dev->ce_sps.consumer_status, - pce_dev->ce_sps.producer_status); + pce_sps_data->consumer_status, + pce_sps_data->producer_status); result_status = -ENXIO; } - pce_dev->qce_cb(pce_dev->areq, NULL, NULL, result_status); + pce_sps_data->result->status = 0; + pce_sps_data->result->status2 = 0; + qce_free_req_info(pce_dev, req_info, true); + qce_callback(areq, NULL, NULL, result_status); return 0; } -static void _qce_sps_iovec_count_init(struct qce_device *pce_dev) +static void _qce_sps_iovec_count_init(struct qce_device *pce_dev, int req_info) { - pce_dev->ce_sps.in_transfer.iovec_count = 0; - pce_dev->ce_sps.out_transfer.iovec_count = 0; + struct ce_sps_data *pce_sps_data = &pce_dev->ce_request_info[req_info] + .ce_sps; + pce_sps_data->in_transfer.iovec_count = 0; + pce_sps_data->out_transfer.iovec_count = 0; } static void _qce_set_flag(struct sps_transfer *sps_bam_pipe, uint32_t flag) @@ -2282,7 +2415,7 @@ static void _qce_set_flag(struct sps_transfer *sps_bam_pipe, uint32_t flag) iovec->flags |= flag; } -static int _qce_sps_add_data(uint32_t addr, uint32_t len, +static int _qce_sps_add_data(dma_addr_t paddr, uint32_t len, struct sps_transfer *sps_bam_pipe) { struct sps_iovec *iovec = sps_bam_pipe->iovec + @@ -2301,11 +2434,11 @@ static int _qce_sps_add_data(uint32_t addr, uint32_t len, else data_cnt = len; iovec->size = data_cnt; - iovec->addr = addr; - iovec->flags = 0; + iovec->addr = SPS_GET_LOWER_ADDR(paddr); + iovec->flags = SPS_GET_UPPER_ADDR(paddr); sps_bam_pipe->iovec_count++; iovec++; - addr += data_cnt; + paddr += data_cnt; len -= data_cnt; } return 0; @@ -2315,20 +2448,21 @@ static int _qce_sps_add_sg_data(struct qce_device *pce_dev, struct scatterlist *sg_src, uint32_t nbytes, struct sps_transfer *sps_bam_pipe) { - uint32_t addr, data_cnt, len; + uint32_t data_cnt, len; + dma_addr_t addr; struct sps_iovec *iovec = sps_bam_pipe->iovec + sps_bam_pipe->iovec_count; while (nbytes > 0) { - if (sg_src == NULL) { - pr_err("qce50: _qce_sps_add_sg_data, sg = NULL\n"); - break; + if (NULL == sg_src) { + pr_err("qce50.c: _qce_sps_add_sg_data, sg_src = NULL"); + return -ENOENT; } len = min(nbytes, sg_dma_len(sg_src)); nbytes -= len; addr = sg_dma_address(sg_src); - if (pce_dev->ce_sps.minor_version == 0) - len = ALIGN(len, pce_dev->ce_sps.ce_burst_size); + if (pce_dev->ce_bam_info.minor_version == 0) + len = ALIGN(len, pce_dev->ce_bam_info.ce_burst_size); while (len > 0) { if (sps_bam_pipe->iovec_count == QCE_MAX_NUM_DSCR) { pr_err("Num of descrptor %d exceed max (%d)", @@ -2339,13 +2473,13 @@ static int _qce_sps_add_sg_data(struct qce_device *pce_dev, if (len > SPS_MAX_PKT_SIZE) { data_cnt = SPS_MAX_PKT_SIZE; iovec->size = data_cnt; - iovec->addr = addr; - iovec->flags = 0; + iovec->addr = SPS_GET_LOWER_ADDR(addr); + iovec->flags = SPS_GET_UPPER_ADDR(addr); } else { data_cnt = len; iovec->size = data_cnt; - iovec->addr = addr; - iovec->flags = 0; + iovec->addr = SPS_GET_LOWER_ADDR(addr); + iovec->flags = SPS_GET_UPPER_ADDR(addr); } iovec++; sps_bam_pipe->iovec_count++; @@ -2361,38 +2495,53 @@ static int _qce_sps_add_cmd(struct qce_device *pce_dev, uint32_t flag, struct qce_cmdlist_info *cmdptr, struct sps_transfer *sps_bam_pipe) { + dma_addr_t paddr = GET_PHYS_ADDR(cmdptr->cmdlist); struct sps_iovec *iovec = sps_bam_pipe->iovec + sps_bam_pipe->iovec_count; iovec->size = cmdptr->size; - iovec->addr = GET_PHYS_ADDR(cmdptr->cmdlist); - iovec->flags = SPS_IOVEC_FLAG_CMD | flag; + iovec->addr = SPS_GET_LOWER_ADDR(paddr); + iovec->flags = SPS_GET_UPPER_ADDR(paddr) | SPS_IOVEC_FLAG_CMD | flag; sps_bam_pipe->iovec_count++; - + if (sps_bam_pipe->iovec_count >= QCE_MAX_NUM_DSCR) { + pr_err("Num of descrptor %d exceed max (%d)", + sps_bam_pipe->iovec_count, (uint32_t)QCE_MAX_NUM_DSCR); + return -ENOMEM; + } return 0; } -static int _qce_sps_transfer(struct qce_device *pce_dev) +static int _qce_sps_transfer(struct qce_device *pce_dev, int req_info) { int rc = 0; - - _qce_dump_descr_fifos_dbg(pce_dev); - if (pce_dev->ce_sps.in_transfer.iovec_count) { - rc = sps_transfer(pce_dev->ce_sps.consumer.pipe, - &pce_dev->ce_sps.in_transfer); + struct ce_sps_data *pce_sps_data; + + pce_sps_data = &pce_dev->ce_request_info[req_info].ce_sps; + pce_sps_data->out_transfer.user = + (void *)((uintptr_t)(CRYPTO_REQ_USER_PAT | + (unsigned int) req_info)); + pce_sps_data->in_transfer.user = + (void *)((uintptr_t)(CRYPTO_REQ_USER_PAT | + (unsigned int) req_info)); + _qce_dump_descr_fifos_dbg(pce_dev, req_info); + + if (pce_sps_data->in_transfer.iovec_count) { + rc = sps_transfer(pce_dev->ce_bam_info.consumer.pipe, + &pce_sps_data->in_transfer); if (rc) { pr_err("sps_xfr() fail (consumer pipe=0x%lx) rc = %d\n", - (uintptr_t)pce_dev->ce_sps.consumer.pipe, rc); - _qce_dump_descr_fifos(pce_dev); - return rc; + (uintptr_t)pce_dev->ce_bam_info.consumer.pipe, + rc); + goto ret; } } - rc = sps_transfer(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.out_transfer); - if (rc) { + rc = sps_transfer(pce_dev->ce_bam_info.producer.pipe, + &pce_sps_data->out_transfer); + if (rc) pr_err("sps_xfr() fail (producer pipe=0x%lx) rc = %d\n", - (uintptr_t)pce_dev->ce_sps.producer.pipe, rc); - return rc; - } + (uintptr_t)pce_dev->ce_bam_info.producer.pipe, rc); +ret: + if (rc) + _qce_dump_descr_fifos(pce_dev, req_info); return rc; } @@ -2429,7 +2578,7 @@ static int qce_sps_init_ep_conn(struct qce_device *pce_dev, /* Allocate endpoint context */ sps_pipe_info = sps_alloc_endpoint(); if (!sps_pipe_info) { - pr_err("sps_alloc_endpoint() failed!!! is_producer=%d\n", + pr_err("sps_alloc_endpoint() failed!!! is_producer=%d", is_producer); rc = -ENOMEM; goto out; @@ -2452,7 +2601,7 @@ static int qce_sps_init_ep_conn(struct qce_device *pce_dev, * CE peripheral where as destination should * be system memory. */ - sps_connect_info->source = pce_dev->ce_sps.bam_handle; + sps_connect_info->source = pce_dev->ce_bam_info.bam_handle; sps_connect_info->destination = SPS_DEV_HANDLE_MEM; /* Producer pipe will handle this connection */ sps_connect_info->mode = SPS_MODE_SRC; @@ -2464,18 +2613,20 @@ static int qce_sps_init_ep_conn(struct qce_device *pce_dev, * CE peripheral */ sps_connect_info->source = SPS_DEV_HANDLE_MEM; - sps_connect_info->destination = pce_dev->ce_sps.bam_handle; + sps_connect_info->destination = pce_dev->ce_bam_info.bam_handle; sps_connect_info->mode = SPS_MODE_DEST; sps_connect_info->options = - SPS_O_AUTO_ENABLE | SPS_O_EOT; + SPS_O_AUTO_ENABLE; } /* Producer pipe index */ - sps_connect_info->src_pipe_index = pce_dev->ce_sps.src_pipe_index; + sps_connect_info->src_pipe_index = + pce_dev->ce_bam_info.src_pipe_index; /* Consumer pipe index */ - sps_connect_info->dest_pipe_index = pce_dev->ce_sps.dest_pipe_index; + sps_connect_info->dest_pipe_index = + pce_dev->ce_bam_info.dest_pipe_index; /* Set pipe group */ - sps_connect_info->lock_group = pce_dev->ce_sps.pipe_pair_index; + sps_connect_info->lock_group = pce_dev->ce_bam_info.pipe_pair_index; sps_connect_info->event_thresh = 0x10; /* * Max. no of scatter/gather buffers that can @@ -2487,8 +2638,10 @@ static int qce_sps_init_ep_conn(struct qce_device *pce_dev, * descriptor memory (256 bytes + 8 bytes). But in order to be * in power of 2, we are allocating 512 bytes of memory. */ - sps_connect_info->desc.size = QCE_MAX_NUM_DSCR * + sps_connect_info->desc.size = QCE_MAX_NUM_DSCR * MAX_QCE_ALLOC_BAM_REQ * sizeof(struct sps_iovec); + if (sps_connect_info->desc.size > MAX_SPS_DESC_FIFO_SIZE) + sps_connect_info->desc.size = MAX_SPS_DESC_FIFO_SIZE; sps_connect_info->desc.base = dma_alloc_coherent(pce_dev->pdev, sps_connect_info->desc.size, &sps_connect_info->desc.phys_base, @@ -2510,12 +2663,21 @@ static int qce_sps_init_ep_conn(struct qce_device *pce_dev, } sps_event->mode = SPS_TRIGGER_CALLBACK; - if (is_producer) - sps_event->options = SPS_O_EOT | SPS_O_DESC_DONE; - else - sps_event->options = SPS_O_EOT; sps_event->xfer_done = NULL; sps_event->user = (void *)pce_dev; + if (is_producer) { + sps_event->options = SPS_O_EOT | SPS_O_DESC_DONE; + sps_event->callback = _sps_producer_callback; + rc = sps_register_event(ep->pipe, sps_event); + if (rc) { + pr_err("Producer callback registration failed rc=%d\n", + rc); + goto sps_connect_err; + } + } else { + sps_event->options = SPS_O_EOT; + sps_event->callback = NULL; + } pr_debug("success, %s : pipe_handle=0x%lx, desc fifo base (phy) = 0x%pK\n", is_producer ? "PRODUCER(RX/OUT)" : "CONSUMER(TX/IN)", @@ -2573,12 +2735,12 @@ static void qce_sps_release_bam(struct qce_device *pce_dev) if (pbam->cnt > 0) goto ret; - if (pce_dev->ce_sps.bam_handle) { - sps_deregister_bam_device(pce_dev->ce_sps.bam_handle); + if (pce_dev->ce_bam_info.bam_handle) { + sps_deregister_bam_device(pce_dev->ce_bam_info.bam_handle); pr_debug("deregister bam handle 0x%lx\n", - pce_dev->ce_sps.bam_handle); - pce_dev->ce_sps.bam_handle = 0; + pce_dev->ce_bam_info.bam_handle); + pce_dev->ce_bam_info.bam_handle = 0; } iounmap(pbam->bam_iobase); pr_debug("delete bam 0x%x\n", pbam->bam_mem); @@ -2611,9 +2773,9 @@ static int qce_sps_get_bam(struct qce_device *pce_dev) if (pbam) { pr_debug("found bam 0x%x\n", pbam->bam_mem); pbam->cnt++; - pce_dev->ce_sps.bam_handle = pbam->handle; - pce_dev->ce_sps.bam_mem = pbam->bam_mem; - pce_dev->ce_sps.bam_iobase = pbam->bam_iobase; + pce_dev->ce_bam_info.bam_handle = pbam->handle; + pce_dev->ce_bam_info.bam_mem = pbam->bam_mem; + pce_dev->ce_bam_info.bam_iobase = pbam->bam_iobase; pce_dev->pbam = pbam; pce_dev->support_cmd_dscr = pbam->support_cmd_dscr; goto ret; @@ -2637,11 +2799,11 @@ static int qce_sps_get_bam(struct qce_device *pce_dev) pr_err("Can not map BAM io memory\n"); goto ret; } - pce_dev->ce_sps.bam_mem = pbam->bam_mem; - pce_dev->ce_sps.bam_iobase = pbam->bam_iobase; + pce_dev->ce_bam_info.bam_mem = pbam->bam_mem; + pce_dev->ce_bam_info.bam_iobase = pbam->bam_iobase; pbam->handle = 0; pr_debug("allocate bam 0x%x\n", pbam->bam_mem); - bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase + + bam_cfg = readl_relaxed(pce_dev->ce_bam_info.bam_iobase + CRYPTO_BAM_CNFG_BITS_REG); pbam->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ? true : false; @@ -2652,8 +2814,8 @@ static int qce_sps_get_bam(struct qce_device *pce_dev) } pce_dev->support_cmd_dscr = pbam->support_cmd_dscr; - bam.phys_addr = pce_dev->ce_sps.bam_mem; - bam.virt_addr = (void *)pce_dev->ce_sps.bam_iobase; + bam.phys_addr = pce_dev->ce_bam_info.bam_mem; + bam.virt_addr = pce_dev->ce_bam_info.bam_iobase; /* * This event thresold value is only significant for BAM-to-BAM @@ -2668,7 +2830,7 @@ static int qce_sps_get_bam(struct qce_device *pce_dev) */ bam.summing_threshold = 64; /* SPS driver wll handle the crypto BAM IRQ */ - bam.irq = (u32)pce_dev->ce_sps.bam_irq; + bam.irq = (u32)pce_dev->ce_bam_info.bam_irq; /* * Set flag to indicate BAM global device control is managed * remotely. @@ -2678,15 +2840,16 @@ static int qce_sps_get_bam(struct qce_device *pce_dev) else bam.manage = SPS_BAM_MGR_LOCAL; - bam.ee = 1; - + bam.ee = pce_dev->ce_bam_info.bam_ee; + bam.ipc_loglevel = QCE_BAM_DEFAULT_IPC_LOGLVL; + bam.options |= SPS_BAM_CACHED_WP; pr_debug("bam physical base=0x%lx\n", (uintptr_t)bam.phys_addr); pr_debug("bam virtual base=0x%pK\n", bam.virt_addr); /* Register CE Peripheral BAM device to SPS driver */ rc = sps_register_bam_device(&bam, &pbam->handle); if (rc) { - pr_err("sps_register_bam_device() failed! err=%d\n", rc); + pr_err("sps_register_bam_device() failed! err=%d", rc); rc = -EIO; iounmap(pbam->bam_iobase); kfree(pbam); @@ -2695,7 +2858,7 @@ static int qce_sps_get_bam(struct qce_device *pce_dev) pce_dev->pbam = pbam; list_add_tail(&pbam->qlist, &qce50_bam_list); - pce_dev->ce_sps.bam_handle = pbam->handle; + pce_dev->ce_bam_info.bam_handle = pbam->handle; ret: mutex_unlock(&bam_register_lock); @@ -2724,52 +2887,67 @@ static int qce_sps_init(struct qce_device *pce_dev) if (rc) return rc; pr_debug("BAM device registered. bam_handle=0x%lx\n", - pce_dev->ce_sps.bam_handle); + pce_dev->ce_bam_info.bam_handle); - rc = qce_sps_init_ep_conn(pce_dev, &pce_dev->ce_sps.producer, true); + rc = qce_sps_init_ep_conn(pce_dev, + &pce_dev->ce_bam_info.producer, true); if (rc) goto sps_connect_producer_err; - rc = qce_sps_init_ep_conn(pce_dev, &pce_dev->ce_sps.consumer, false); + rc = qce_sps_init_ep_conn(pce_dev, + &pce_dev->ce_bam_info.consumer, false); if (rc) goto sps_connect_consumer_err; - pce_dev->ce_sps.out_transfer.user = pce_dev->ce_sps.producer.pipe; - pce_dev->ce_sps.in_transfer.user = pce_dev->ce_sps.consumer.pipe; pr_info(" Qualcomm MSM CE-BAM at 0x%016llx irq %d\n", - (unsigned long long)pce_dev->ce_sps.bam_mem, - (unsigned int)pce_dev->ce_sps.bam_irq); + (unsigned long long)pce_dev->ce_bam_info.bam_mem, + (unsigned int)pce_dev->ce_bam_info.bam_irq); return rc; sps_connect_consumer_err: - qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer); + qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_bam_info.producer); sps_connect_producer_err: qce_sps_release_bam(pce_dev); return rc; } -/** - * De-initialize SPS HW connected with CE core - * - * This function deinitialize SPS endpoints and then - * deregisters BAM resources from SPS driver. - * - * This function should only be called once typically - * during driver remove. - * - * @pce_dev - Pointer to qce_device structure - * - */ -static void qce_sps_exit(struct qce_device *pce_dev) +static inline int qce_alloc_req_info(struct qce_device *pce_dev) { - qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.consumer); - qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer); - qce_sps_release_bam(pce_dev); + int i; + int request_index = pce_dev->ce_request_index; + + for (i = 0; i < MAX_QCE_BAM_REQ; i++) { + request_index++; + if (request_index >= MAX_QCE_BAM_REQ) + request_index = 0; + if (atomic_xchg(&pce_dev->ce_request_info[request_index]. + in_use, true) == false) { + pce_dev->ce_request_index = request_index; + return request_index; + } + } + pr_warn("pcedev %d no reqs available no_of_queued_req %d\n", + pce_dev->dev_no, atomic_read( + &pce_dev->no_of_queued_req)); + return -EBUSY; +} + +static inline void qce_free_req_info(struct qce_device *pce_dev, int req_info, + bool is_complete) +{ + pce_dev->ce_request_info[req_info].xfer_type = QCE_XFER_TYPE_LAST; + if (atomic_xchg(&pce_dev->ce_request_info[req_info].in_use, + false) == true) { + if (req_info < MAX_QCE_BAM_REQ && is_complete) + atomic_dec(&pce_dev->no_of_queued_req); + } else + pr_warn("request info %d free already\n", req_info); } static void print_notify_debug(struct sps_event_notify *notify) { - phys_addr_t addr = DESC_FULL_ADDR(notify->data.transfer.iovec.flags, - notify->data.transfer.iovec.addr); + phys_addr_t addr = + DESC_FULL_ADDR((phys_addr_t) notify->data.transfer.iovec.flags, + notify->data.transfer.iovec.addr); pr_debug("sps ev_id=%d, addr=0x%pa, size=0x%x, flags=0x%x user=0x%pK\n", notify->event_id, &addr, notify->data.transfer.iovec.size, @@ -2777,91 +2955,173 @@ static void print_notify_debug(struct sps_event_notify *notify) notify->data.transfer.user); } -static void _aead_sps_producer_callback(struct sps_event_notify *notify) +static void _qce_req_complete(struct qce_device *pce_dev, unsigned int req_info) { - struct qce_device *pce_dev = (struct qce_device *) - ((struct sps_event_notify *)notify)->user; - int rc = 0; + struct ce_request_info *preq_info; - pce_dev->ce_sps.notify = *notify; - print_notify_debug(notify); - if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE; - _aead_complete(pce_dev); - } else { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP; - pce_dev->ce_sps.out_transfer.iovec_count = 0; - _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), - CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer); - _qce_set_flag(&pce_dev->ce_sps.out_transfer, - SPS_IOVEC_FLAG_INT); - rc = sps_transfer(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.out_transfer); - if (rc) { - pr_err("sps_xfr() fail (producer pipe=0x%lx) rc = %d\n", - (uintptr_t)pce_dev->ce_sps.producer.pipe, rc); - } + preq_info = &pce_dev->ce_request_info[req_info]; + + switch (preq_info->xfer_type) { + case QCE_XFER_CIPHERING: + _ablk_cipher_complete(pce_dev, req_info); + break; + case QCE_XFER_HASHING: + _sha_complete(pce_dev, req_info); + break; + case QCE_XFER_AEAD: + _aead_complete(pce_dev, req_info); + break; + case QCE_XFER_F8: + _f8_complete(pce_dev, req_info); + break; + case QCE_XFER_F9: + _f9_complete(pce_dev, req_info); + break; + default: + qce_free_req_info(pce_dev, req_info, true); + break; } } -static void _sha_sps_producer_callback(struct sps_event_notify *notify) +static void qce_multireq_timeout(unsigned long data) { - struct qce_device *pce_dev = (struct qce_device *) - ((struct sps_event_notify *)notify)->user; + struct qce_device *pce_dev = (struct qce_device *)data; + int ret = 0; + int last_seq; + unsigned long flags; + + last_seq = atomic_read(&pce_dev->bunch_cmd_seq); + if (last_seq == 0 || + last_seq != atomic_read(&pce_dev->last_intr_seq)) { + atomic_set(&pce_dev->last_intr_seq, last_seq); + mod_timer(&(pce_dev->timer), (jiffies + DELAY_IN_JIFFIES)); + return; + } + /* last bunch mode command time out */ - pce_dev->ce_sps.notify = *notify; - print_notify_debug(notify); - _sha_complete(pce_dev); + /* + * From here to dummy request finish sps request and set owner back + * to none, we disable interrupt. + * So it won't get preempted or interrupted. If bam inerrupts happen + * between, and completion callback gets called from BAM, a new + * request may be issued by the client driver. Deadlock may happen. + */ + local_irq_save(flags); + if (cmpxchg(&pce_dev->owner, QCE_OWNER_NONE, QCE_OWNER_TIMEOUT) + != QCE_OWNER_NONE) { + local_irq_restore(flags); + mod_timer(&(pce_dev->timer), (jiffies + DELAY_IN_JIFFIES)); + return; + } + + ret = qce_dummy_req(pce_dev); + if (ret) + pr_warn("pcedev %d: Failed to insert dummy req\n", + pce_dev->dev_no); + cmpxchg(&pce_dev->owner, QCE_OWNER_TIMEOUT, QCE_OWNER_NONE); + pce_dev->mode = IN_INTERRUPT_MODE; + local_irq_restore(flags); + + del_timer(&(pce_dev->timer)); + pce_dev->qce_stats.no_of_timeouts++; + pr_debug("pcedev %d mode switch to INTR\n", pce_dev->dev_no); } -static void _f9_sps_producer_callback(struct sps_event_notify *notify) +void qce_get_driver_stats(void *handle) { - struct qce_device *pce_dev = (struct qce_device *) - ((struct sps_event_notify *)notify)->user; + struct qce_device *pce_dev = (struct qce_device *) handle; - pce_dev->ce_sps.notify = *notify; - print_notify_debug(notify); - _f9_complete(pce_dev); + if (!_qce50_disp_stats) + return; + pr_info("Engine %d timeout occuured %d\n", pce_dev->dev_no, + pce_dev->qce_stats.no_of_timeouts); + pr_info("Engine %d dummy request inserted %d\n", pce_dev->dev_no, + pce_dev->qce_stats.no_of_dummy_reqs); + if (pce_dev->mode) + pr_info("Engine %d is in BUNCH MODE\n", pce_dev->dev_no); + else + pr_info("Engine %d is in INTERRUPT MODE\n", pce_dev->dev_no); + pr_info("Engine %d outstanding request %d\n", pce_dev->dev_no, + atomic_read(&pce_dev->no_of_queued_req)); } +EXPORT_SYMBOL(qce_get_driver_stats); -static void _f8_sps_producer_callback(struct sps_event_notify *notify) +void qce_clear_driver_stats(void *handle) { - struct qce_device *pce_dev = (struct qce_device *) - ((struct sps_event_notify *)notify)->user; + struct qce_device *pce_dev = (struct qce_device *) handle; - pce_dev->ce_sps.notify = *notify; - print_notify_debug(notify); - _f8_complete(pce_dev); + pce_dev->qce_stats.no_of_timeouts = 0; + pce_dev->qce_stats.no_of_dummy_reqs = 0; } +EXPORT_SYMBOL(qce_clear_driver_stats); -static void _ablk_cipher_sps_producer_callback(struct sps_event_notify *notify) +static void _sps_producer_callback(struct sps_event_notify *notify) { struct qce_device *pce_dev = (struct qce_device *) ((struct sps_event_notify *)notify)->user; int rc = 0; + unsigned int req_info; + struct ce_sps_data *pce_sps_data; + struct ce_request_info *preq_info; - pce_dev->ce_sps.notify = *notify; print_notify_debug(notify); - if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE; - _ablk_cipher_complete(pce_dev); - } else { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP; - pce_dev->ce_sps.out_transfer.iovec_count = 0; - _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + + req_info = (unsigned int)((uintptr_t)notify->data.transfer.user); + if ((req_info & 0xffff0000) != CRYPTO_REQ_USER_PAT) { + pr_warn("request information %d out of range\n", req_info); + return; + } + + req_info = req_info & 0x00ff; + if (req_info < 0 || req_info >= MAX_QCE_ALLOC_BAM_REQ) { + pr_warn("request information %d out of range\n", req_info); + return; + } + + preq_info = &pce_dev->ce_request_info[req_info]; + + pce_sps_data = &preq_info->ce_sps; + if ((preq_info->xfer_type == QCE_XFER_CIPHERING || + preq_info->xfer_type == QCE_XFER_AEAD) && + pce_sps_data->producer_state == QCE_PIPE_STATE_IDLE) { + pce_sps_data->producer_state = QCE_PIPE_STATE_COMP; + pce_sps_data->out_transfer.iovec_count = 0; + _qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer); - _qce_set_flag(&pce_dev->ce_sps.out_transfer, + &pce_sps_data->out_transfer); + _qce_set_flag(&pce_sps_data->out_transfer, SPS_IOVEC_FLAG_INT); - rc = sps_transfer(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.out_transfer); + rc = sps_transfer(pce_dev->ce_bam_info.producer.pipe, + &pce_sps_data->out_transfer); if (rc) { pr_err("sps_xfr() fail (producer pipe=0x%lx) rc = %d\n", - (uintptr_t)pce_dev->ce_sps.producer.pipe, rc); + (uintptr_t)pce_dev->ce_bam_info.producer.pipe, + rc); } + return; } -}; + + _qce_req_complete(pce_dev, req_info); +} + +/** + * De-initialize SPS HW connected with CE core + * + * This function deinitialize SPS endpoints and then + * deregisters BAM resources from SPS driver. + * + * This function should only be called once typically + * during driver remove. + * + * @pce_dev - Pointer to qce_device structure + * + */ +static void qce_sps_exit(struct qce_device *pce_dev) +{ + qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_bam_info.consumer); + qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_bam_info.producer); + qce_sps_release_bam(pce_dev); +} static void qce_add_cmd_element(struct qce_device *pdev, struct sps_command_element **cmd_ptr, u32 addr, @@ -2877,13 +3137,13 @@ static void qce_add_cmd_element(struct qce_device *pdev, (*cmd_ptr)++; } -static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev, +static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev, int cri_index, unsigned char **pvaddr, enum qce_cipher_mode_enum mode, bool key_128) { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start; - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; int i = 0; uint32_t encr_cfg = 0; @@ -2891,8 +3151,9 @@ static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev, uint32_t xts_key_reg = 0; uint32_t iv_reg = 0; + cmdlistptr = &pdev->ce_request_info[cri_index].ce_sps.cmdlistptr; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr = (struct sps_command_element *)(*pvaddr); ce_vaddr_start = (uintptr_t)(*pvaddr); /* @@ -3049,22 +3310,23 @@ static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev, return 0; } -static int _setup_cipher_des_cmdlistptrs(struct qce_device *pdev, +static int _setup_cipher_des_cmdlistptrs(struct qce_device *pdev, int cri_index, unsigned char **pvaddr, enum qce_cipher_alg_enum alg, bool mode_cbc) { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start; - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; int i = 0; uint32_t encr_cfg = 0; uint32_t key_reg = 0; uint32_t iv_reg = 0; + cmdlistptr = &pdev->ce_request_info[cri_index].ce_sps.cmdlistptr; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr = (struct sps_command_element *)(*pvaddr); ce_vaddr_start = (uintptr_t)(*pvaddr); @@ -3162,21 +3424,65 @@ static int _setup_cipher_des_cmdlistptrs(struct qce_device *pdev, return 0; } -static int _setup_auth_cmdlistptrs(struct qce_device *pdev, +static int _setup_cipher_null_cmdlistptrs(struct qce_device *pdev, + int cri_index, unsigned char **pvaddr) +{ + struct sps_command_element *ce_vaddr; + uintptr_t ce_vaddr_start; + struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_request_info + [cri_index].ce_sps.cmdlistptr; + struct qce_cmdlist_info *pcl_info = NULL; + + *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), + pdev->ce_bam_info.ce_burst_size); + ce_vaddr_start = (uintptr_t)(*pvaddr); + ce_vaddr = (struct sps_command_element *)(*pvaddr); + + cmdlistptr->cipher_null.cmdlist = (uintptr_t)ce_vaddr; + pcl_info = &(cmdlistptr->cipher_null); + + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, + pdev->ce_bam_info.ce_burst_size, NULL); + + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, + pdev->reg.encr_cfg_aes_ecb_128, NULL); + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0, + NULL); + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0, + NULL); + + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG, + 0, NULL); + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG, + 0, NULL); + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG, 0, + NULL); + + qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); + + pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; + *pvaddr = (unsigned char *) ce_vaddr; + return 0; +} + +static int _setup_auth_cmdlistptrs(struct qce_device *pdev, int cri_index, unsigned char **pvaddr, enum qce_hash_alg_enum alg, bool key_128) { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start; - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; int i = 0; uint32_t key_reg = 0; uint32_t auth_cfg = 0; uint32_t iv_reg = 0; + cmdlistptr = &pdev->ce_request_info[cri_index].ce_sps.cmdlistptr; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr_start = (uintptr_t)(*pvaddr); ce_vaddr = (struct sps_command_element *)(*pvaddr); @@ -3341,6 +3647,7 @@ static int _setup_auth_cmdlistptrs(struct qce_device *pdev, } static int _setup_aead_cmdlistptrs(struct qce_device *pdev, + int cri_index, unsigned char **pvaddr, uint32_t alg, uint32_t mode, @@ -3349,7 +3656,7 @@ static int _setup_aead_cmdlistptrs(struct qce_device *pdev, { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start; - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; uint32_t key_reg; uint32_t iv_reg; @@ -3357,8 +3664,9 @@ static int _setup_aead_cmdlistptrs(struct qce_device *pdev, uint32_t enciv_in_word; uint32_t encr_cfg; + cmdlistptr = &pdev->ce_request_info[cri_index].ce_sps.cmdlistptr; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr_start = (uintptr_t)(*pvaddr); ce_vaddr = (struct sps_command_element *)(*pvaddr); @@ -3554,12 +3862,13 @@ static int _setup_aead_cmdlistptrs(struct qce_device *pdev, return 0; } -static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev, +static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev, int cri_index, unsigned char **pvaddr, bool key_128) { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start; - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_request_info + [cri_index].ce_sps.cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; int i = 0; uint32_t encr_cfg = 0; @@ -3567,7 +3876,7 @@ static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev, uint32_t key_reg = 0; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr_start = (uintptr_t)(*pvaddr); ce_vaddr = (struct sps_command_element *)(*pvaddr); @@ -3687,19 +3996,20 @@ static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev, return 0; } -static int _setup_f8_cmdlistptrs(struct qce_device *pdev, +static int _setup_f8_cmdlistptrs(struct qce_device *pdev, int cri_index, unsigned char **pvaddr, enum qce_ota_algo_enum alg) { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start; - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; int i = 0; uint32_t encr_cfg = 0; uint32_t key_reg = 4; + cmdlistptr = &pdev->ce_request_info[cri_index].ce_sps.cmdlistptr; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr = (struct sps_command_element *)(*pvaddr); ce_vaddr_start = (uintptr_t)(*pvaddr); @@ -3772,19 +4082,20 @@ static int _setup_f8_cmdlistptrs(struct qce_device *pdev, return 0; } -static int _setup_f9_cmdlistptrs(struct qce_device *pdev, +static int _setup_f9_cmdlistptrs(struct qce_device *pdev, int cri_index, unsigned char **pvaddr, enum qce_ota_algo_enum alg) { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start; - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; int i = 0; uint32_t auth_cfg = 0; uint32_t iv_reg = 0; + cmdlistptr = &pdev->ce_request_info[cri_index].ce_sps.cmdlistptr; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr_start = (uintptr_t)(*pvaddr); ce_vaddr = (struct sps_command_element *)(*pvaddr); @@ -3854,15 +4165,16 @@ static int _setup_f9_cmdlistptrs(struct qce_device *pdev, } static int _setup_unlock_pipe_cmdlistptrs(struct qce_device *pdev, - unsigned char **pvaddr) + int cri_index, unsigned char **pvaddr) { struct sps_command_element *ce_vaddr; uintptr_t ce_vaddr_start = (uintptr_t)(*pvaddr); - struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr; + struct qce_cmdlistptr_ops *cmdlistptr; struct qce_cmdlist_info *pcl_info = NULL; + cmdlistptr = &pdev->ce_request_info[cri_index].ce_sps.cmdlistptr; *pvaddr = (unsigned char *)ALIGN(((uintptr_t)(*pvaddr)), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); ce_vaddr = (struct sps_command_element *)(*pvaddr); cmdlistptr->unlock_all_pipes.cmdlist = (uintptr_t)ce_vaddr; pcl_info = &(cmdlistptr->unlock_all_pipes); @@ -3879,7 +4191,7 @@ static int _setup_unlock_pipe_cmdlistptrs(struct qce_device *pdev, return 0; } -static int qce_setup_cmdlistptrs(struct qce_device *pdev, +static int qce_setup_cmdlistptrs(struct qce_device *pdev, int cri_index, unsigned char **pvaddr) { struct sps_command_element *ce_vaddr = @@ -3891,56 +4203,76 @@ static int qce_setup_cmdlistptrs(struct qce_device *pdev, */ ce_vaddr = (struct sps_command_element *)ALIGN(((uintptr_t) ce_vaddr), - pdev->ce_sps.ce_burst_size); + pdev->ce_bam_info.ce_burst_size); *pvaddr = (unsigned char *) ce_vaddr; - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_CBC, true); - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_CTR, true); - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_ECB, true); - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_XTS, true); - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_CBC, false); - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_CTR, false); - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_ECB, false); - _setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_XTS, false); - - _setup_cipher_des_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_DES, true); - _setup_cipher_des_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_DES, false); - _setup_cipher_des_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_3DES, true); - _setup_cipher_des_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_3DES, false); - - _setup_auth_cmdlistptrs(pdev, pvaddr, QCE_HASH_SHA1, false); - _setup_auth_cmdlistptrs(pdev, pvaddr, QCE_HASH_SHA256, false); - - _setup_auth_cmdlistptrs(pdev, pvaddr, QCE_HASH_SHA1_HMAC, false); - _setup_auth_cmdlistptrs(pdev, pvaddr, QCE_HASH_SHA256_HMAC, false); - - _setup_auth_cmdlistptrs(pdev, pvaddr, QCE_HASH_AES_CMAC, true); - _setup_auth_cmdlistptrs(pdev, pvaddr, QCE_HASH_AES_CMAC, false); - - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_DES, QCE_MODE_CBC, - DES_KEY_SIZE, true); - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_3DES, QCE_MODE_CBC, - DES3_EDE_KEY_SIZE, true); - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_AES, QCE_MODE_CBC, - AES128_KEY_SIZE, true); - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_AES, QCE_MODE_CBC, - AES256_KEY_SIZE, true); - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_DES, QCE_MODE_CBC, - DES_KEY_SIZE, false); - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_3DES, QCE_MODE_CBC, - DES3_EDE_KEY_SIZE, false); - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_AES, QCE_MODE_CBC, - AES128_KEY_SIZE, false); - _setup_aead_cmdlistptrs(pdev, pvaddr, CIPHER_ALG_AES, QCE_MODE_CBC, - AES256_KEY_SIZE, false); - - _setup_aead_ccm_cmdlistptrs(pdev, pvaddr, true); - _setup_aead_ccm_cmdlistptrs(pdev, pvaddr, false); - _setup_f8_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_KASUMI); - _setup_f8_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_SNOW3G); - _setup_f9_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_KASUMI); - _setup_f9_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_SNOW3G); - _setup_unlock_pipe_cmdlistptrs(pdev, pvaddr); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_CBC, + true); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_CTR, + true); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_ECB, + true); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_XTS, + true); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_CBC, + false); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_CTR, + false); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_ECB, + false); + _setup_cipher_aes_cmdlistptrs(pdev, cri_index, pvaddr, QCE_MODE_XTS, + false); + + _setup_cipher_des_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_DES, + true); + _setup_cipher_des_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_DES, + false); + _setup_cipher_des_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_3DES, + true); + _setup_cipher_des_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_3DES, + false); + + _setup_auth_cmdlistptrs(pdev, cri_index, pvaddr, QCE_HASH_SHA1, + false); + _setup_auth_cmdlistptrs(pdev, cri_index, pvaddr, QCE_HASH_SHA256, + false); + + _setup_auth_cmdlistptrs(pdev, cri_index, pvaddr, QCE_HASH_SHA1_HMAC, + false); + _setup_auth_cmdlistptrs(pdev, cri_index, pvaddr, QCE_HASH_SHA256_HMAC, + false); + + _setup_auth_cmdlistptrs(pdev, cri_index, pvaddr, QCE_HASH_AES_CMAC, + true); + _setup_auth_cmdlistptrs(pdev, cri_index, pvaddr, QCE_HASH_AES_CMAC, + false); + + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_DES, + QCE_MODE_CBC, DES_KEY_SIZE, true); + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_3DES, + QCE_MODE_CBC, DES3_EDE_KEY_SIZE, true); + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_AES, + QCE_MODE_CBC, AES128_KEY_SIZE, true); + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_AES, + QCE_MODE_CBC, AES256_KEY_SIZE, true); + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_DES, + QCE_MODE_CBC, DES_KEY_SIZE, false); + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_3DES, + QCE_MODE_CBC, DES3_EDE_KEY_SIZE, false); + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_AES, + QCE_MODE_CBC, AES128_KEY_SIZE, false); + _setup_aead_cmdlistptrs(pdev, cri_index, pvaddr, CIPHER_ALG_AES, + QCE_MODE_CBC, AES256_KEY_SIZE, false); + + _setup_cipher_null_cmdlistptrs(pdev, cri_index, pvaddr); + + _setup_aead_ccm_cmdlistptrs(pdev, cri_index, pvaddr, true); + _setup_aead_ccm_cmdlistptrs(pdev, cri_index, pvaddr, false); + _setup_f8_cmdlistptrs(pdev, cri_index, pvaddr, QCE_OTA_ALGO_KASUMI); + _setup_f8_cmdlistptrs(pdev, cri_index, pvaddr, QCE_OTA_ALGO_SNOW3G); + _setup_f9_cmdlistptrs(pdev, cri_index, pvaddr, QCE_OTA_ALGO_KASUMI); + _setup_f9_cmdlistptrs(pdev, cri_index, pvaddr, QCE_OTA_ALGO_SNOW3G); + _setup_unlock_pipe_cmdlistptrs(pdev, cri_index, pvaddr); return 0; } @@ -3948,33 +4280,57 @@ static int qce_setup_cmdlistptrs(struct qce_device *pdev, static int qce_setup_ce_sps_data(struct qce_device *pce_dev) { unsigned char *vaddr; + int i; + unsigned char *iovec_vaddr; + int iovec_memsize; vaddr = pce_dev->coh_vmem; vaddr = (unsigned char *)ALIGN(((uintptr_t)vaddr), - pce_dev->ce_sps.ce_burst_size); - /* Allow for 256 descriptor (cmd and data) entries per pipe */ - pce_dev->ce_sps.in_transfer.iovec = (struct sps_iovec *)vaddr; - pce_dev->ce_sps.in_transfer.iovec_phys = - (uintptr_t)GET_PHYS_ADDR(vaddr); - vaddr += QCE_MAX_NUM_DSCR * sizeof(struct sps_iovec); - - pce_dev->ce_sps.out_transfer.iovec = (struct sps_iovec *)vaddr; - pce_dev->ce_sps.out_transfer.iovec_phys = - (uintptr_t)GET_PHYS_ADDR(vaddr); - vaddr += QCE_MAX_NUM_DSCR * sizeof(struct sps_iovec); - - if (pce_dev->support_cmd_dscr) - qce_setup_cmdlistptrs(pce_dev, &vaddr); - vaddr = (unsigned char *)ALIGN(((uintptr_t)vaddr), - pce_dev->ce_sps.ce_burst_size); - pce_dev->ce_sps.result_dump = (uintptr_t)vaddr; - pce_dev->ce_sps.result = (struct ce_result_dump_format *)vaddr; - vaddr += CRYPTO_RESULT_DUMP_SIZE; - - pce_dev->ce_sps.ignore_buffer = (uintptr_t)vaddr; - vaddr += pce_dev->ce_sps.ce_burst_size * 2; - - if ((vaddr - pce_dev->coh_vmem) > pce_dev->memsize) + pce_dev->ce_bam_info.ce_burst_size); + iovec_vaddr = pce_dev->iovec_vmem; + iovec_memsize = pce_dev->iovec_memsize; + for (i = 0; i < MAX_QCE_ALLOC_BAM_REQ; i++) { + /* Allow for 256 descriptor (cmd and data) entries per pipe */ + pce_dev->ce_request_info[i].ce_sps.in_transfer.iovec = + (struct sps_iovec *)iovec_vaddr; + pce_dev->ce_request_info[i].ce_sps.in_transfer.iovec_phys = + virt_to_phys(pce_dev->ce_request_info[i]. + ce_sps.in_transfer.iovec); + iovec_vaddr += TOTAL_IOVEC_SPACE_PER_PIPE; + iovec_memsize -= TOTAL_IOVEC_SPACE_PER_PIPE; + pce_dev->ce_request_info[i].ce_sps.out_transfer.iovec = + (struct sps_iovec *)iovec_vaddr; + pce_dev->ce_request_info[i].ce_sps.out_transfer.iovec_phys = + virt_to_phys(pce_dev->ce_request_info[i]. + ce_sps.out_transfer.iovec); + iovec_vaddr += TOTAL_IOVEC_SPACE_PER_PIPE; + iovec_memsize -= TOTAL_IOVEC_SPACE_PER_PIPE; + if (pce_dev->support_cmd_dscr) + qce_setup_cmdlistptrs(pce_dev, i, &vaddr); + vaddr = (unsigned char *)ALIGN(((uintptr_t)vaddr), + pce_dev->ce_bam_info.ce_burst_size); + pce_dev->ce_request_info[i].ce_sps.result_dump = + (uintptr_t)vaddr; + pce_dev->ce_request_info[i].ce_sps.result_dump_phy = + GET_PHYS_ADDR((uintptr_t)vaddr); + pce_dev->ce_request_info[i].ce_sps.result = + (struct ce_result_dump_format *)vaddr; + vaddr += CRYPTO_RESULT_DUMP_SIZE; + + pce_dev->ce_request_info[i].ce_sps.result_dump_null = + (uintptr_t)vaddr; + pce_dev->ce_request_info[i].ce_sps.result_dump_null_phy = + GET_PHYS_ADDR((uintptr_t)vaddr); + pce_dev->ce_request_info[i].ce_sps.result_null = + (struct ce_result_dump_format *)vaddr; + vaddr += CRYPTO_RESULT_DUMP_SIZE; + + pce_dev->ce_request_info[i].ce_sps.ignore_buffer = + (uintptr_t)vaddr; + vaddr += pce_dev->ce_bam_info.ce_burst_size * 2; + } + if ((vaddr - pce_dev->coh_vmem) > pce_dev->memsize || + iovec_memsize < 0) panic("qce50: Not enough coherent memory. Allocate %x , need %lx\n", pce_dev->memsize, (uintptr_t)vaddr - (uintptr_t)pce_dev->coh_vmem); @@ -3983,8 +4339,8 @@ static int qce_setup_ce_sps_data(struct qce_device *pce_dev) static int qce_init_ce_cfg_val(struct qce_device *pce_dev) { - uint32_t beats = (pce_dev->ce_sps.ce_burst_size >> 3) - 1; - uint32_t pipe_pair = pce_dev->ce_sps.pipe_pair_index; + uint32_t beats = (pce_dev->ce_bam_info.ce_burst_size >> 3) - 1; + uint32_t pipe_pair = pce_dev->ce_bam_info.pipe_pair_index; pce_dev->reg.crypto_cfg_be = (beats << CRYPTO_REQ_SIZE) | BIT(CRYPTO_MASK_DOUT_INTR) | BIT(CRYPTO_MASK_DIN_INTR) | @@ -4155,6 +4511,122 @@ static int qce_init_ce_cfg_val(struct qce_device *pce_dev) return 0; } +static void _qce_ccm_get_around_input(struct qce_device *pce_dev, + struct ce_request_info *preq_info, enum qce_cipher_dir_enum dir) +{ + struct qce_cmdlist_info *cmdlistinfo; + struct ce_sps_data *pce_sps_data; + + pce_sps_data = &preq_info->ce_sps; + if ((dir == QCE_DECRYPT) && pce_dev->no_get_around && + !(pce_dev->no_ccm_mac_status_get_around)) { + cmdlistinfo = &pce_sps_data->cmdlistptr.cipher_null; + _qce_sps_add_cmd(pce_dev, 0, cmdlistinfo, + &pce_sps_data->in_transfer); + _qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->ignore_buffer), + pce_dev->ce_bam_info.ce_burst_size, + &pce_sps_data->in_transfer); + _qce_set_flag(&pce_sps_data->in_transfer, + SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_NWD); + } +} + +static void _qce_ccm_get_around_output(struct qce_device *pce_dev, + struct ce_request_info *preq_info, enum qce_cipher_dir_enum dir) +{ + struct ce_sps_data *pce_sps_data; + + pce_sps_data = &preq_info->ce_sps; + + if ((dir == QCE_DECRYPT) && pce_dev->no_get_around && + !(pce_dev->no_ccm_mac_status_get_around)) { + _qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->ignore_buffer), + pce_dev->ce_bam_info.ce_burst_size, + &pce_sps_data->out_transfer); + _qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->result_dump_null), + CRYPTO_RESULT_DUMP_SIZE, &pce_sps_data->out_transfer); + } +} + +/* QCE_DUMMY_REQ */ +static void qce_dummy_complete(void *cookie, unsigned char *digest, + unsigned char *authdata, int ret) +{ + if (!cookie) + pr_err("invalid cookie\n"); +} + +static int qce_dummy_req(struct qce_device *pce_dev) +{ + int ret = 0; + + if (!(atomic_xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX]. + in_use, true) == false)) + return -EBUSY; + ret = qce_process_sha_req(pce_dev, NULL); + pce_dev->qce_stats.no_of_dummy_reqs++; + return ret; +} + +static int select_mode(struct qce_device *pce_dev, + struct ce_request_info *preq_info) +{ + struct ce_sps_data *pce_sps_data = &preq_info->ce_sps; + unsigned int no_of_queued_req; + unsigned int cadence; + + if (!pce_dev->no_get_around) { + _qce_set_flag(&pce_sps_data->out_transfer, SPS_IOVEC_FLAG_INT); + return 0; + } + + /* + * claim ownership of device + */ +again: + if (cmpxchg(&pce_dev->owner, QCE_OWNER_NONE, QCE_OWNER_CLIENT) + != QCE_OWNER_NONE) { + ndelay(40); + goto again; + } + no_of_queued_req = atomic_inc_return(&pce_dev->no_of_queued_req); + if (pce_dev->mode == IN_INTERRUPT_MODE) { + if (no_of_queued_req >= MAX_BUNCH_MODE_REQ) { + pce_dev->mode = IN_BUNCH_MODE; + pr_debug("pcedev %d mode switch to BUNCH\n", + pce_dev->dev_no); + _qce_set_flag(&pce_sps_data->out_transfer, + SPS_IOVEC_FLAG_INT); + pce_dev->intr_cadence = 0; + atomic_set(&pce_dev->bunch_cmd_seq, 1); + atomic_set(&pce_dev->last_intr_seq, 1); + mod_timer(&(pce_dev->timer), + (jiffies + DELAY_IN_JIFFIES)); + } else { + _qce_set_flag(&pce_sps_data->out_transfer, + SPS_IOVEC_FLAG_INT); + } + } else { + pce_dev->intr_cadence++; + cadence = (preq_info->req_len >> 7) + 1; + if (cadence > SET_INTR_AT_REQ) + cadence = SET_INTR_AT_REQ; + if (pce_dev->intr_cadence < cadence || ((pce_dev->intr_cadence + == cadence) && pce_dev->cadence_flag)) + atomic_inc(&pce_dev->bunch_cmd_seq); + else { + _qce_set_flag(&pce_sps_data->out_transfer, + SPS_IOVEC_FLAG_INT); + pce_dev->intr_cadence = 0; + atomic_set(&pce_dev->bunch_cmd_seq, 0); + atomic_set(&pce_dev->last_intr_seq, 0); + pce_dev->cadence_flag = ~pce_dev->cadence_flag; + } + } + + return 0; +} + static int _qce_aead_ccm_req(void *handle, struct qce_req *q_req) { struct qce_device *pce_dev = (struct qce_device *) handle; @@ -4165,8 +4637,17 @@ static int _qce_aead_ccm_req(void *handle, struct qce_req *q_req) int rc = 0; int ce_burst_size; struct qce_cmdlist_info *cmdlistinfo = NULL; + int req_info = -1; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; - ce_burst_size = pce_dev->ce_sps.ce_burst_size; + req_info = qce_alloc_req_info(pce_dev); + if (req_info < 0) + return -EBUSY; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; + + ce_burst_size = pce_dev->ce_bam_info.ce_burst_size; totallen_in = areq->cryptlen + areq->assoclen; if (q_req->dir == QCE_ENCRYPT) { q_req->cryptlen = areq->cryptlen; @@ -4178,56 +4659,56 @@ static int _qce_aead_ccm_req(void *handle, struct qce_req *q_req) hw_pad_out = authsize; } - if (pce_dev->ce_sps.minor_version == 0) { - /* - * For crypto 5.0 that has burst size alignment requirement - * for data descritpor, - * the agent above(qcrypto) prepares the src scatter list with - * memory starting with associated data, followed by - * data stream to be ciphered. - * The destination scatter list is pointing to the same - * data area as source. - */ - pce_dev->src_nents = count_sg(areq->src, totallen_in); - } else { - pce_dev->src_nents = count_sg(areq->src, areq->cryptlen); - } + /* + * For crypto 5.0 that has burst size alignment requirement + * for data descritpor, + * the agent above(qcrypto) prepares the src scatter list with + * memory starting with associated data, followed by + * data stream to be ciphered. + * The destination scatter list is pointing to the same + * data area as source. + */ + if (pce_dev->ce_bam_info.minor_version == 0) + preq_info->src_nents = count_sg(areq->src, totallen_in); + else + preq_info->src_nents = count_sg(areq->src, areq->cryptlen); - pce_dev->assoc_nents = count_sg(areq->assoc, areq->assoclen); - pce_dev->authsize = q_req->authsize; + preq_info->assoc_nents = count_sg(areq->assoc, areq->assoclen); /* associated data input */ - qce_dma_map_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents, + qce_dma_map_sg(pce_dev->pdev, areq->assoc, preq_info->assoc_nents, DMA_TO_DEVICE); /* cipher input */ - qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + qce_dma_map_sg(pce_dev->pdev, areq->src, preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); /* cipher + mac output for encryption */ if (areq->src != areq->dst) { - if (pce_dev->ce_sps.minor_version == 0) + if (pce_dev->ce_bam_info.minor_version == 0) /* * The destination scatter list is pointing to the same * data area as src. * Note, the associated data will be pass-through * at the begining of destination area. */ - pce_dev->dst_nents = count_sg(areq->dst, + preq_info->dst_nents = count_sg(areq->dst, out_len + areq->assoclen); else - pce_dev->dst_nents = count_sg(areq->dst, out_len); + preq_info->dst_nents = count_sg(areq->dst, out_len); - qce_dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents, + qce_dma_map_sg(pce_dev->pdev, areq->dst, preq_info->dst_nents, DMA_FROM_DEVICE); } else { - pce_dev->dst_nents = pce_dev->src_nents; + preq_info->dst_nents = preq_info->src_nents; } if (pce_dev->support_cmd_dscr) { - cmdlistinfo = _ce_get_cipher_cmdlistinfo(pce_dev, q_req); + cmdlistinfo = _ce_get_cipher_cmdlistinfo(pce_dev, req_info, + q_req); if (cmdlistinfo == NULL) { pr_err("Unsupported cipher algorithm %d, mode %d\n", q_req->alg, q_req->mode); + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; } /* set up crypto device */ @@ -4238,34 +4719,33 @@ static int _qce_aead_ccm_req(void *handle, struct qce_req *q_req) rc = _ce_setup_cipher_direct(pce_dev, q_req, totallen_in, areq->assoclen); } + if (rc < 0) goto bad; + preq_info->mode = q_req->mode; + /* setup for callback, and issue command to bam */ - pce_dev->areq = q_req->areq; - pce_dev->qce_cb = q_req->qce_cb; - - /* Register callback event for EOT (End of transfer) event. */ - pce_dev->ce_sps.producer.event.callback = _aead_sps_producer_callback; - pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE; - rc = sps_register_event(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.producer.event); - if (rc) { - pr_err("Producer callback registration failed rc = %d\n", rc); - goto bad; - } - _qce_sps_iovec_count_init(pce_dev); + preq_info->areq = q_req->areq; + preq_info->qce_cb = q_req->qce_cb; + preq_info->dir = q_req->dir; + + /* setup xfer type for producer callback handling */ + preq_info->xfer_type = QCE_XFER_AEAD; + preq_info->req_len = totallen_in; + + _qce_sps_iovec_count_init(pce_dev, req_info); if (pce_dev->support_cmd_dscr) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->in_transfer); - if (pce_dev->ce_sps.minor_version == 0) { + if (pce_dev->ce_bam_info.minor_version == 0) { if (_qce_sps_add_sg_data(pce_dev, areq->src, totallen_in, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); /* @@ -4274,85 +4754,91 @@ static int _qce_aead_ccm_req(void *handle, struct qce_req *q_req) */ if (_qce_sps_add_sg_data(pce_dev, areq->dst, out_len + areq->assoclen + hw_pad_out, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; if (totallen_in > SPS_MAX_PKT_SIZE) { - _qce_set_flag(&pce_dev->ce_sps.out_transfer, + _qce_set_flag(&pce_sps_data->out_transfer, SPS_IOVEC_FLAG_INT); - pce_dev->ce_sps.producer.event.options = - SPS_O_DESC_DONE; - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE; + pce_sps_data->producer_state = QCE_PIPE_STATE_IDLE; } else { if (_qce_sps_add_data(GET_PHYS_ADDR( - pce_dev->ce_sps.result_dump), + pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.out_transfer, + _qce_set_flag(&pce_sps_data->out_transfer, SPS_IOVEC_FLAG_INT); - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP; + pce_sps_data->producer_state = QCE_PIPE_STATE_COMP; } + rc = _qce_sps_transfer(pce_dev, req_info); } else { if (_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->cryptlen, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); + + _qce_ccm_get_around_input(pce_dev, preq_info, q_req->dir); + if (pce_dev->no_get_around) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_UNLOCK, - &pce_dev->ce_sps.cmdlistptr.unlock_all_pipes, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->cmdlistptr.unlock_all_pipes, + &pce_sps_data->in_transfer); /* Pass through to ignore associated data*/ if (_qce_sps_add_data( - GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer), + GET_PHYS_ADDR(pce_sps_data->ignore_buffer), areq->assoclen, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; if (_qce_sps_add_sg_data(pce_dev, areq->dst, out_len, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; /* Pass through to ignore hw_pad (padding of the MAC data) */ if (_qce_sps_add_data( - GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer), - hw_pad_out, &pce_dev->ce_sps.out_transfer)) + GET_PHYS_ADDR(pce_sps_data->ignore_buffer), + hw_pad_out, &pce_sps_data->out_transfer)) goto bad; if (pce_dev->no_get_around || totallen_in <= SPS_MAX_PKT_SIZE) { if (_qce_sps_add_data( - GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP; + pce_sps_data->producer_state = QCE_PIPE_STATE_COMP; } else { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE; + pce_sps_data->producer_state = QCE_PIPE_STATE_IDLE; } - _qce_set_flag(&pce_dev->ce_sps.out_transfer, - SPS_IOVEC_FLAG_INT); + + _qce_ccm_get_around_output(pce_dev, preq_info, q_req->dir); + + select_mode(pce_dev, preq_info); + rc = _qce_sps_transfer(pce_dev, req_info); + cmpxchg(&pce_dev->owner, QCE_OWNER_CLIENT, QCE_OWNER_NONE); } - rc = _qce_sps_transfer(pce_dev); if (rc) goto bad; return 0; bad: - if (pce_dev->assoc_nents) { + if (preq_info->assoc_nents) { qce_dma_unmap_sg(pce_dev->pdev, areq->assoc, - pce_dev->assoc_nents, DMA_TO_DEVICE); + preq_info->assoc_nents, DMA_TO_DEVICE); } - if (pce_dev->src_nents) { - qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + if (preq_info->src_nents) { + qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); } if (areq->src != areq->dst) { - qce_dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents, + qce_dma_unmap_sg(pce_dev->pdev, areq->dst, preq_info->dst_nents, DMA_FROM_DEVICE); } + qce_free_req_info(pce_dev, req_info, false); return rc; } @@ -4367,10 +4853,10 @@ static int _qce_suspend(void *handle) qce_enable_clk(pce_dev); - sps_pipe_info = pce_dev->ce_sps.consumer.pipe; + sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe; sps_disconnect(sps_pipe_info); - sps_pipe_info = pce_dev->ce_sps.producer.pipe; + sps_pipe_info = pce_dev->ce_bam_info.producer.pipe; sps_disconnect(sps_pipe_info); qce_disable_clk(pce_dev); @@ -4389,8 +4875,8 @@ static int _qce_resume(void *handle) qce_enable_clk(pce_dev); - sps_pipe_info = pce_dev->ce_sps.consumer.pipe; - sps_connect_info = &pce_dev->ce_sps.consumer.connect; + sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe; + sps_connect_info = &pce_dev->ce_bam_info.consumer.connect; memset(sps_connect_info->desc.base, 0x00, sps_connect_info->desc.size); rc = sps_connect(sps_pipe_info, sps_connect_info); if (rc) { @@ -4398,16 +4884,18 @@ static int _qce_resume(void *handle) (uintptr_t)sps_pipe_info, rc); return rc; } - sps_pipe_info = pce_dev->ce_sps.producer.pipe; - sps_connect_info = &pce_dev->ce_sps.producer.connect; + sps_pipe_info = pce_dev->ce_bam_info.producer.pipe; + sps_connect_info = &pce_dev->ce_bam_info.producer.connect; memset(sps_connect_info->desc.base, 0x00, sps_connect_info->desc.size); rc = sps_connect(sps_pipe_info, sps_connect_info); if (rc) pr_err("sps_connect() fail pipe_handle=0x%lx, rc = %d\n", (uintptr_t)sps_pipe_info, rc); - pce_dev->ce_sps.out_transfer.user = pce_dev->ce_sps.producer.pipe; - pce_dev->ce_sps.in_transfer.user = pce_dev->ce_sps.consumer.pipe; + rc = sps_register_event(sps_pipe_info, + &pce_dev->ce_bam_info.producer.event); + if (rc) + pr_err("Producer callback registration failed rc = %d\n", rc); qce_disable_clk(pce_dev); return rc; @@ -4418,19 +4906,26 @@ EXPORT_SYMBOL(qce_pm_table); int qce_aead_req(void *handle, struct qce_req *q_req) { - struct qce_device *pce_dev; + struct qce_device *pce_dev = (struct qce_device *)handle; struct aead_request *areq; uint32_t authsize; struct crypto_aead *aead; uint32_t ivsize; uint32_t totallen; - int rc; + int rc = 0; struct qce_cmdlist_info *cmdlistinfo = NULL; + int req_info = -1; + struct ce_sps_data *pce_sps_data; + struct ce_request_info *preq_info; if (q_req->mode == QCE_MODE_CCM) return _qce_aead_ccm_req(handle, q_req); - pce_dev = (struct qce_device *) handle; + req_info = qce_alloc_req_info(pce_dev); + if (req_info < 0) + return -EBUSY; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; areq = (struct aead_request *) q_req->areq; aead = crypto_aead_reqtfm(areq); ivsize = crypto_aead_ivsize(aead); @@ -4450,87 +4945,83 @@ int qce_aead_req(void *handle, struct qce_req *q_req) totallen = q_req->cryptlen + areq->assoclen + ivsize; if (pce_dev->support_cmd_dscr) { - cmdlistinfo = _ce_get_aead_cmdlistinfo(pce_dev, q_req); + cmdlistinfo = _ce_get_aead_cmdlistinfo(pce_dev, + req_info, q_req); if (cmdlistinfo == NULL) { pr_err("Unsupported aead ciphering algorithm %d, mode %d, ciphering key length %d, auth digest size %d\n", q_req->alg, q_req->mode, q_req->encklen, q_req->authsize); + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; } /* set up crypto device */ rc = _ce_setup_aead(pce_dev, q_req, totallen, areq->assoclen + ivsize, cmdlistinfo); - if (rc < 0) + if (rc < 0) { + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; - }; - + } + } - pce_dev->assoc_nents = count_sg(areq->assoc, areq->assoclen); + preq_info->assoc_nents = count_sg(areq->assoc, areq->assoclen); - if (pce_dev->ce_sps.minor_version == 0) { - /* - * For crypto 5.0 that has burst size alignment requirement - * for data descritpor, - * the agent above(qcrypto) prepares the src scatter list with - * memory starting with associated data, followed by - * iv, and data stream to be ciphered. - */ - pce_dev->src_nents = count_sg(areq->src, totallen); - } else { - pce_dev->src_nents = count_sg(areq->src, q_req->cryptlen); - }; + /* + * For crypto 5.0 that has burst size alignment requirement + * for data descritpor, + * the agent above(qcrypto) prepares the src scatter list with + * memory starting with associated data, followed by + * iv, and data stream to be ciphered. + */ + if (pce_dev->ce_bam_info.minor_version == 0) + preq_info->src_nents = count_sg(areq->src, totallen); + else + preq_info->src_nents = count_sg(areq->src, q_req->cryptlen); - pce_dev->ivsize = q_req->ivsize; - pce_dev->authsize = q_req->authsize; - pce_dev->phy_iv_in = 0; + preq_info->phy_iv_in = 0; /* associated data input */ - qce_dma_map_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents, + qce_dma_map_sg(pce_dev->pdev, areq->assoc, preq_info->assoc_nents, DMA_TO_DEVICE); /* cipher input */ - qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + qce_dma_map_sg(pce_dev->pdev, areq->src, preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); /* cipher output for encryption */ if (areq->src != areq->dst) { - if (pce_dev->ce_sps.minor_version == 0) + if (pce_dev->ce_bam_info.minor_version == 0) /* * The destination scatter list is pointing to the same * data area as source. */ - pce_dev->dst_nents = count_sg(areq->dst, totallen); + preq_info->dst_nents = count_sg(areq->dst, totallen); else - pce_dev->dst_nents = count_sg(areq->dst, + preq_info->dst_nents = count_sg(areq->dst, q_req->cryptlen); - qce_dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents, + qce_dma_map_sg(pce_dev->pdev, areq->dst, preq_info->dst_nents, DMA_FROM_DEVICE); } /* cipher iv for input */ - if (pce_dev->ce_sps.minor_version != 0) - pce_dev->phy_iv_in = dma_map_single(pce_dev->pdev, q_req->iv, + if (pce_dev->ce_bam_info.minor_version != 0) + preq_info->phy_iv_in = dma_map_single(pce_dev->pdev, q_req->iv, ivsize, DMA_TO_DEVICE); /* setup for callback, and issue command to bam */ - pce_dev->areq = q_req->areq; - pce_dev->qce_cb = q_req->qce_cb; - - /* Register callback event for EOT (End of transfer) event. */ - pce_dev->ce_sps.producer.event.callback = _aead_sps_producer_callback; - pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE; - rc = sps_register_event(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.producer.event); - if (rc) { - pr_err("Producer callback registration failed rc = %d\n", rc); - goto bad; - } - _qce_sps_iovec_count_init(pce_dev); + preq_info->areq = q_req->areq; + preq_info->qce_cb = q_req->qce_cb; + preq_info->dir = q_req->dir; + + /* setup xfer type for producer callback handling */ + preq_info->xfer_type = QCE_XFER_AEAD; + preq_info->req_len = totallen; + + _qce_sps_iovec_count_init(pce_dev, req_info); if (pce_dev->support_cmd_dscr) { _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->in_transfer); } else { rc = _ce_setup_aead_direct(pce_dev, q_req, totallen, areq->assoclen + ivsize); @@ -4538,97 +5029,95 @@ int qce_aead_req(void *handle, struct qce_req *q_req) goto bad; } - if (pce_dev->ce_sps.minor_version == 0) { + preq_info->mode = q_req->mode; + + if (pce_dev->ce_bam_info.minor_version == 0) { if (_qce_sps_add_sg_data(pce_dev, areq->src, totallen, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); if (_qce_sps_add_sg_data(pce_dev, areq->dst, totallen, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; if (totallen > SPS_MAX_PKT_SIZE) { - _qce_set_flag(&pce_dev->ce_sps.out_transfer, + _qce_set_flag(&pce_sps_data->out_transfer, SPS_IOVEC_FLAG_INT); - pce_dev->ce_sps.producer.event.options = - SPS_O_DESC_DONE; - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE; + pce_sps_data->producer_state = QCE_PIPE_STATE_IDLE; } else { if (_qce_sps_add_data(GET_PHYS_ADDR( - pce_dev->ce_sps.result_dump), + pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.out_transfer, + _qce_set_flag(&pce_sps_data->out_transfer, SPS_IOVEC_FLAG_INT); - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP; + pce_sps_data->producer_state = QCE_PIPE_STATE_COMP; } + rc = _qce_sps_transfer(pce_dev, req_info); } else { if (_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; - if (_qce_sps_add_data((uint32_t)pce_dev->phy_iv_in, ivsize, - &pce_dev->ce_sps.in_transfer)) + if (_qce_sps_add_data((uint32_t)preq_info->phy_iv_in, ivsize, + &pce_sps_data->in_transfer)) goto bad; if (_qce_sps_add_sg_data(pce_dev, areq->src, q_req->cryptlen, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); if (pce_dev->no_get_around) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_UNLOCK, - &pce_dev->ce_sps.cmdlistptr.unlock_all_pipes, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->cmdlistptr.unlock_all_pipes, + &pce_sps_data->in_transfer); /* Pass through to ignore associated + iv data*/ if (_qce_sps_add_data( - GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer), + GET_PHYS_ADDR(pce_sps_data->ignore_buffer), (ivsize + areq->assoclen), - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; if (_qce_sps_add_sg_data(pce_dev, areq->dst, q_req->cryptlen, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; if (pce_dev->no_get_around || totallen <= SPS_MAX_PKT_SIZE) { if (_qce_sps_add_data( - GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP; + pce_sps_data->producer_state = QCE_PIPE_STATE_COMP; } else { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE; + pce_sps_data->producer_state = QCE_PIPE_STATE_IDLE; } - _qce_set_flag(&pce_dev->ce_sps.out_transfer, - SPS_IOVEC_FLAG_INT); + select_mode(pce_dev, preq_info); + rc = _qce_sps_transfer(pce_dev, req_info); + cmpxchg(&pce_dev->owner, QCE_OWNER_CLIENT, QCE_OWNER_NONE); } - rc = _qce_sps_transfer(pce_dev); if (rc) goto bad; return 0; bad: - if (pce_dev->assoc_nents) { + if (preq_info->assoc_nents) qce_dma_unmap_sg(pce_dev->pdev, areq->assoc, - pce_dev->assoc_nents, DMA_TO_DEVICE); - } - if (pce_dev->src_nents) { - qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + preq_info->assoc_nents, DMA_TO_DEVICE); + if (preq_info->src_nents) + qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); - } - if (areq->src != areq->dst) { - qce_dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents, + if (areq->src != areq->dst) + qce_dma_unmap_sg(pce_dev->pdev, areq->dst, preq_info->dst_nents, DMA_FROM_DEVICE); - } - if (pce_dev->phy_iv_in) { - dma_unmap_single(pce_dev->pdev, pce_dev->phy_iv_in, + if (preq_info->phy_iv_in) + dma_unmap_single(pce_dev->pdev, preq_info->phy_iv_in, ivsize, DMA_TO_DEVICE); - } + qce_free_req_info(pce_dev, req_info, false); return rc; } @@ -4641,38 +5130,50 @@ int qce_ablk_cipher_req(void *handle, struct qce_req *c_req) struct ablkcipher_request *areq = (struct ablkcipher_request *) c_req->areq; struct qce_cmdlist_info *cmdlistinfo = NULL; + int req_info = -1; + struct ce_sps_data *pce_sps_data; + struct ce_request_info *preq_info; + + req_info = qce_alloc_req_info(pce_dev); + if (req_info < 0) + return -EBUSY; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; - pce_dev->src_nents = 0; - pce_dev->dst_nents = 0; + preq_info->src_nents = 0; + preq_info->dst_nents = 0; /* cipher input */ - pce_dev->src_nents = count_sg(areq->src, areq->nbytes); + preq_info->src_nents = count_sg(areq->src, areq->nbytes); - qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + qce_dma_map_sg(pce_dev->pdev, areq->src, preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); /* cipher output */ if (areq->src != areq->dst) { - pce_dev->dst_nents = count_sg(areq->dst, areq->nbytes); + preq_info->dst_nents = count_sg(areq->dst, areq->nbytes); qce_dma_map_sg(pce_dev->pdev, areq->dst, - pce_dev->dst_nents, DMA_FROM_DEVICE); + preq_info->dst_nents, DMA_FROM_DEVICE); } else { - pce_dev->dst_nents = pce_dev->src_nents; - } - pce_dev->dir = c_req->dir; - if ((pce_dev->ce_sps.minor_version == 0) && (c_req->dir == QCE_DECRYPT) - && (c_req->mode == QCE_MODE_CBC)) { - memcpy(pce_dev->dec_iv, (unsigned char *)sg_virt(areq->src) + - areq->src->length - 16, + preq_info->dst_nents = preq_info->src_nents; + } + preq_info->dir = c_req->dir; + if ((pce_dev->ce_bam_info.minor_version == 0) && + (preq_info->dir == QCE_DECRYPT) && + (c_req->mode == QCE_MODE_CBC)) { + memcpy(preq_info->dec_iv, (unsigned char *) + sg_virt(areq->src) + areq->src->length - 16, NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE); } /* set up crypto device */ if (pce_dev->support_cmd_dscr) { - cmdlistinfo = _ce_get_cipher_cmdlistinfo(pce_dev, c_req); + cmdlistinfo = _ce_get_cipher_cmdlistinfo(pce_dev, + req_info, c_req); if (cmdlistinfo == NULL) { pr_err("Unsupported cipher algorithm %d, mode %d\n", c_req->alg, c_req->mode); + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; } rc = _ce_setup_cipher(pce_dev, c_req, areq->nbytes, 0, @@ -4683,66 +5184,66 @@ int qce_ablk_cipher_req(void *handle, struct qce_req *c_req) if (rc < 0) goto bad; + preq_info->mode = c_req->mode; + /* setup for client callback, and issue command to BAM */ - pce_dev->areq = areq; - pce_dev->qce_cb = c_req->qce_cb; - - /* Register callback event for EOT (End of transfer) event. */ - pce_dev->ce_sps.producer.event.callback = - _ablk_cipher_sps_producer_callback; - pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE; - rc = sps_register_event(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.producer.event); - if (rc) { - pr_err("Producer callback registration failed rc = %d\n", rc); - goto bad; - } - _qce_sps_iovec_count_init(pce_dev); + preq_info->areq = areq; + preq_info->qce_cb = c_req->qce_cb; + + /* setup xfer type for producer callback handling */ + preq_info->xfer_type = QCE_XFER_CIPHERING; + preq_info->req_len = areq->nbytes; + + _qce_sps_iovec_count_init(pce_dev, req_info); if (pce_dev->support_cmd_dscr) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->in_transfer); if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); if (pce_dev->no_get_around) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_UNLOCK, - &pce_dev->ce_sps.cmdlistptr.unlock_all_pipes, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->cmdlistptr.unlock_all_pipes, + &pce_sps_data->in_transfer); if (_qce_sps_add_sg_data(pce_dev, areq->dst, areq->nbytes, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; if (pce_dev->no_get_around || areq->nbytes <= SPS_MAX_PKT_SIZE) { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP; + pce_sps_data->producer_state = QCE_PIPE_STATE_COMP; if (_qce_sps_add_data( - GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; } else { - pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE; + pce_sps_data->producer_state = QCE_PIPE_STATE_IDLE; } - _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT); - rc = _qce_sps_transfer(pce_dev); + + select_mode(pce_dev, preq_info); + rc = _qce_sps_transfer(pce_dev, req_info); + cmpxchg(&pce_dev->owner, QCE_OWNER_CLIENT, QCE_OWNER_NONE); if (rc) goto bad; - return 0; + + return 0; bad: if (areq->src != areq->dst) { - if (pce_dev->dst_nents) { + if (preq_info->dst_nents) { qce_dma_unmap_sg(pce_dev->pdev, areq->dst, - pce_dev->dst_nents, DMA_FROM_DEVICE); + preq_info->dst_nents, DMA_FROM_DEVICE); } } - if (pce_dev->src_nents) { + if (preq_info->src_nents) { qce_dma_unmap_sg(pce_dev->pdev, areq->src, - pce_dev->src_nents, + preq_info->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); } + qce_free_req_info(pce_dev, req_info, false); return rc; } EXPORT_SYMBOL(qce_ablk_cipher_req); @@ -4752,17 +5253,36 @@ int qce_process_sha_req(void *handle, struct qce_sha_req *sreq) struct qce_device *pce_dev = (struct qce_device *) handle; int rc; - struct ahash_request *areq = (struct ahash_request *)sreq->areq; + struct ahash_request *areq; struct qce_cmdlist_info *cmdlistinfo = NULL; + int req_info = -1; + struct ce_sps_data *pce_sps_data; + struct ce_request_info *preq_info; + bool is_dummy = false; + + if (!sreq) { + sreq = &(pce_dev->dummyreq.sreq); + req_info = DUMMY_REQ_INDEX; + is_dummy = true; + } else { + req_info = qce_alloc_req_info(pce_dev); + if (req_info < 0) + return -EBUSY; + } + + areq = (struct ahash_request *)sreq->areq; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; - pce_dev->src_nents = count_sg(sreq->src, sreq->size); - qce_dma_map_sg(pce_dev->pdev, sreq->src, pce_dev->src_nents, + preq_info->src_nents = count_sg(sreq->src, sreq->size); + qce_dma_map_sg(pce_dev->pdev, sreq->src, preq_info->src_nents, DMA_TO_DEVICE); if (pce_dev->support_cmd_dscr) { - cmdlistinfo = _ce_get_hash_cmdlistinfo(pce_dev, sreq); + cmdlistinfo = _ce_get_hash_cmdlistinfo(pce_dev, req_info, sreq); if (cmdlistinfo == NULL) { pr_err("Unsupported hash algorithm %d\n", sreq->alg); + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; } rc = _ce_setup_hash(pce_dev, sreq, cmdlistinfo); @@ -4772,57 +5292,61 @@ int qce_process_sha_req(void *handle, struct qce_sha_req *sreq) if (rc < 0) goto bad; - pce_dev->areq = areq; - pce_dev->qce_cb = sreq->qce_cb; + preq_info->areq = areq; + preq_info->qce_cb = sreq->qce_cb; - /* Register callback event for EOT (End of transfer) event. */ - pce_dev->ce_sps.producer.event.callback = _sha_sps_producer_callback; - pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE; - rc = sps_register_event(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.producer.event); - if (rc) { - pr_err("Producer callback registration failed rc = %d\n", rc); - goto bad; - } - _qce_sps_iovec_count_init(pce_dev); + /* setup xfer type for producer callback handling */ + preq_info->xfer_type = QCE_XFER_HASHING; + preq_info->req_len = sreq->size; + + _qce_sps_iovec_count_init(pce_dev, req_info); if (pce_dev->support_cmd_dscr) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->in_transfer); if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes, - &pce_dev->ce_sps.in_transfer)) + &pce_sps_data->in_transfer)) goto bad; /* always ensure there is input data. ZLT does not work for bam-ndp */ if (!areq->nbytes) _qce_sps_add_data( - GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer), - pce_dev->ce_sps.ce_burst_size, - &pce_dev->ce_sps.in_transfer); - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + GET_PHYS_ADDR(pce_sps_data->ignore_buffer), + pce_dev->ce_bam_info.ce_burst_size, + &pce_sps_data->in_transfer); + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); if (pce_dev->no_get_around) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_UNLOCK, - &pce_dev->ce_sps.cmdlistptr.unlock_all_pipes, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->cmdlistptr.unlock_all_pipes, + &pce_sps_data->in_transfer); - if (_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + if (_qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer)) + &pce_sps_data->out_transfer)) goto bad; - _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT); - rc = _qce_sps_transfer(pce_dev); + + if (is_dummy) { + _qce_set_flag(&pce_sps_data->out_transfer, SPS_IOVEC_FLAG_INT); + rc = _qce_sps_transfer(pce_dev, req_info); + } else { + select_mode(pce_dev, preq_info); + rc = _qce_sps_transfer(pce_dev, req_info); + cmpxchg(&pce_dev->owner, QCE_OWNER_CLIENT, QCE_OWNER_NONE); + } if (rc) goto bad; - return 0; + return 0; bad: - if (pce_dev->src_nents) { + if (preq_info->src_nents) { qce_dma_unmap_sg(pce_dev->pdev, sreq->src, - pce_dev->src_nents, DMA_TO_DEVICE); + preq_info->src_nents, DMA_TO_DEVICE); } + qce_free_req_info(pce_dev, req_info, false); return rc; } EXPORT_SYMBOL(qce_process_sha_req); + int qce_f8_req(void *handle, struct qce_f8_req *req, void *cookie, qce_comp_func_ptr_t qce_cb) { @@ -4831,15 +5355,25 @@ int qce_f8_req(void *handle, struct qce_f8_req *req, dma_addr_t dst; int rc; struct qce_cmdlist_info *cmdlistinfo; + int req_info = -1; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + + req_info = qce_alloc_req_info(pce_dev); + if (req_info < 0) + return -EBUSY; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; switch (req->algorithm) { case QCE_OTA_ALGO_KASUMI: - cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_kasumi; + cmdlistinfo = &pce_sps_data->cmdlistptr.f8_kasumi; break; case QCE_OTA_ALGO_SNOW3G: - cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_snow3g; + cmdlistinfo = &pce_sps_data->cmdlistptr.f8_snow3g; break; default: + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; }; @@ -4847,11 +5381,13 @@ int qce_f8_req(void *handle, struct qce_f8_req *req, /* don't support key stream mode */ - if (key_stream_mode || (req->bearer >= QCE_OTA_MAX_BEARER)) + if (key_stream_mode || (req->bearer >= QCE_OTA_MAX_BEARER)) { + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; + } /* F8 cipher input */ - pce_dev->phy_ota_src = dma_map_single(pce_dev->pdev, + preq_info->phy_ota_src = dma_map_single(pce_dev->pdev, req->data_in, req->data_len, (req->data_in == req->data_out) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); @@ -4860,13 +5396,13 @@ int qce_f8_req(void *handle, struct qce_f8_req *req, if (req->data_in != req->data_out) { dst = dma_map_single(pce_dev->pdev, req->data_out, req->data_len, DMA_FROM_DEVICE); - pce_dev->phy_ota_dst = dst; + preq_info->phy_ota_dst = dst; } else { /* in place ciphering */ - dst = pce_dev->phy_ota_src; - pce_dev->phy_ota_dst = 0; + dst = preq_info->phy_ota_src; + preq_info->phy_ota_dst = 0; } - pce_dev->ota_size = req->data_len; + preq_info->ota_size = req->data_len; /* set up crypto device */ @@ -4880,54 +5416,52 @@ int qce_f8_req(void *handle, struct qce_f8_req *req, goto bad; /* setup for callback, and issue command to sps */ - pce_dev->areq = cookie; - pce_dev->qce_cb = qce_cb; - - /* Register producer callback event for DESC_DONE event. */ - pce_dev->ce_sps.producer.event.callback = - _f8_sps_producer_callback; - pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE; - rc = sps_register_event(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.producer.event); - if (rc) { - pr_err("Producer callback registration failed rc = %d\n", rc); - goto bad; - } - _qce_sps_iovec_count_init(pce_dev); + preq_info->areq = cookie; + preq_info->qce_cb = qce_cb; + + /* setup xfer type for producer callback handling */ + preq_info->xfer_type = QCE_XFER_F8; + preq_info->req_len = req->data_len; + + _qce_sps_iovec_count_init(pce_dev, req_info); if (pce_dev->support_cmd_dscr) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->in_transfer); - _qce_sps_add_data((uint32_t)pce_dev->phy_ota_src, req->data_len, - &pce_dev->ce_sps.in_transfer); - _qce_set_flag(&pce_dev->ce_sps.in_transfer, - SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); + _qce_sps_add_data((uint32_t)preq_info->phy_ota_src, req->data_len, + &pce_sps_data->in_transfer); + + _qce_set_flag(&pce_sps_data->in_transfer, + SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_UNLOCK, - &pce_dev->ce_sps.cmdlistptr.unlock_all_pipes, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->cmdlistptr.unlock_all_pipes, + &pce_sps_data->in_transfer); _qce_sps_add_data((uint32_t)dst, req->data_len, - &pce_dev->ce_sps.out_transfer); + &pce_sps_data->out_transfer); - _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + _qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer); - _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT); - rc = _qce_sps_transfer(pce_dev); + &pce_sps_data->out_transfer); + + select_mode(pce_dev, preq_info); + rc = _qce_sps_transfer(pce_dev, req_info); + cmpxchg(&pce_dev->owner, QCE_OWNER_CLIENT, QCE_OWNER_NONE); if (rc) goto bad; return 0; bad: - if (pce_dev->phy_ota_dst != 0) - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_dst, + if (preq_info->phy_ota_dst != 0) + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_dst, req->data_len, DMA_FROM_DEVICE); - if (pce_dev->phy_ota_src != 0) - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src, + if (preq_info->phy_ota_src != 0) + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_src, req->data_len, (req->data_in == req->data_out) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + qce_free_req_info(pce_dev, req_info, false); return rc; } EXPORT_SYMBOL(qce_f8_req); @@ -4944,22 +5478,32 @@ int qce_f8_multi_pkt_req(void *handle, struct qce_f8_multi_pkt_req *mreq, dma_addr_t dst = 0; int rc = 0; struct qce_cmdlist_info *cmdlistinfo; + int req_info = -1; + struct ce_request_info *preq_info; + struct ce_sps_data *pce_sps_data; + + req_info = qce_alloc_req_info(pce_dev); + if (req_info < 0) + return -EBUSY; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; switch (req->algorithm) { case QCE_OTA_ALGO_KASUMI: - cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_kasumi; + cmdlistinfo = &pce_sps_data->cmdlistptr.f8_kasumi; break; case QCE_OTA_ALGO_SNOW3G: - cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_snow3g; + cmdlistinfo = &pce_sps_data->cmdlistptr.f8_snow3g; break; default: + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; }; total = num_pkt * req->data_len; /* F8 cipher input */ - pce_dev->phy_ota_src = dma_map_single(pce_dev->pdev, + preq_info->phy_ota_src = dma_map_single(pce_dev->pdev, req->data_in, total, (req->data_in == req->data_out) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); @@ -4968,14 +5512,14 @@ int qce_f8_multi_pkt_req(void *handle, struct qce_f8_multi_pkt_req *mreq, if (req->data_in != req->data_out) { dst = dma_map_single(pce_dev->pdev, req->data_out, total, DMA_FROM_DEVICE); - pce_dev->phy_ota_dst = dst; + preq_info->phy_ota_dst = dst; } else { /* in place ciphering */ - dst = pce_dev->phy_ota_src; - pce_dev->phy_ota_dst = 0; + dst = preq_info->phy_ota_src; + preq_info->phy_ota_dst = 0; } - pce_dev->ota_size = total; + preq_info->ota_size = total; /* set up crypto device */ if (pce_dev->support_cmd_dscr) @@ -4988,52 +5532,49 @@ int qce_f8_multi_pkt_req(void *handle, struct qce_f8_multi_pkt_req *mreq, goto bad; /* setup for callback, and issue command to sps */ - pce_dev->areq = cookie; - pce_dev->qce_cb = qce_cb; - - /* Register producer callback event for DESC_DONE event. */ - pce_dev->ce_sps.producer.event.callback = - _f8_sps_producer_callback; - pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE; - rc = sps_register_event(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.producer.event); - if (rc) { - pr_err("Producer callback registration failed rc = %d\n", rc); - goto bad; - } - _qce_sps_iovec_count_init(pce_dev); + preq_info->areq = cookie; + preq_info->qce_cb = qce_cb; + + /* setup xfer type for producer callback handling */ + preq_info->xfer_type = QCE_XFER_F8; + preq_info->req_len = total; + + _qce_sps_iovec_count_init(pce_dev, req_info); if (pce_dev->support_cmd_dscr) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->in_transfer); - _qce_sps_add_data((uint32_t)pce_dev->phy_ota_src, total, - &pce_dev->ce_sps.in_transfer); - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + _qce_sps_add_data((uint32_t)preq_info->phy_ota_src, total, + &pce_sps_data->in_transfer); + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_UNLOCK, - &pce_dev->ce_sps.cmdlistptr.unlock_all_pipes, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->cmdlistptr.unlock_all_pipes, + &pce_sps_data->in_transfer); _qce_sps_add_data((uint32_t)dst, total, - &pce_dev->ce_sps.out_transfer); + &pce_sps_data->out_transfer); - _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + _qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer); - _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT); - rc = _qce_sps_transfer(pce_dev); + &pce_sps_data->out_transfer); + + select_mode(pce_dev, preq_info); + rc = _qce_sps_transfer(pce_dev, req_info); + cmpxchg(&pce_dev->owner, QCE_OWNER_CLIENT, QCE_OWNER_NONE); if (rc == 0) return 0; bad: - if (pce_dev->phy_ota_dst) - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_dst, total, + if (preq_info->phy_ota_dst) + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_dst, total, DMA_FROM_DEVICE); - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src, total, + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_src, total, (req->data_in == req->data_out) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + qce_free_req_info(pce_dev, req_info, false); return rc; } EXPORT_SYMBOL(qce_f8_multi_pkt_req); @@ -5044,22 +5585,31 @@ int qce_f9_req(void *handle, struct qce_f9_req *req, void *cookie, struct qce_device *pce_dev = (struct qce_device *) handle; int rc; struct qce_cmdlist_info *cmdlistinfo; - + int req_info = -1; + struct ce_sps_data *pce_sps_data; + struct ce_request_info *preq_info; + + req_info = qce_alloc_req_info(pce_dev); + if (req_info < 0) + return -EBUSY; + preq_info = &pce_dev->ce_request_info[req_info]; + pce_sps_data = &preq_info->ce_sps; switch (req->algorithm) { case QCE_OTA_ALGO_KASUMI: - cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f9_kasumi; + cmdlistinfo = &pce_sps_data->cmdlistptr.f9_kasumi; break; case QCE_OTA_ALGO_SNOW3G: - cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f9_snow3g; + cmdlistinfo = &pce_sps_data->cmdlistptr.f9_snow3g; break; default: + qce_free_req_info(pce_dev, req_info, false); return -EINVAL; }; - pce_dev->phy_ota_src = dma_map_single(pce_dev->pdev, req->message, + preq_info->phy_ota_src = dma_map_single(pce_dev->pdev, req->message, req->msize, DMA_TO_DEVICE); - pce_dev->ota_size = req->msize; + preq_info->ota_size = req->msize; if (pce_dev->support_cmd_dscr) rc = _ce_f9_setup(pce_dev, req, cmdlistinfo); @@ -5069,43 +5619,40 @@ int qce_f9_req(void *handle, struct qce_f9_req *req, void *cookie, goto bad; /* setup for callback, and issue command to sps */ - pce_dev->areq = cookie; - pce_dev->qce_cb = qce_cb; - - /* Register producer callback event for DESC_DONE event. */ - pce_dev->ce_sps.producer.event.callback = _f9_sps_producer_callback; - pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE; - rc = sps_register_event(pce_dev->ce_sps.producer.pipe, - &pce_dev->ce_sps.producer.event); - if (rc) { - pr_err("Producer callback registration failed rc = %d\n", rc); - goto bad; - } + preq_info->areq = cookie; + preq_info->qce_cb = qce_cb; - _qce_sps_iovec_count_init(pce_dev); + /* setup xfer type for producer callback handling */ + preq_info->xfer_type = QCE_XFER_F9; + preq_info->req_len = req->msize; + + _qce_sps_iovec_count_init(pce_dev, req_info); if (pce_dev->support_cmd_dscr) _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo, - &pce_dev->ce_sps.in_transfer); - _qce_sps_add_data((uint32_t)pce_dev->phy_ota_src, req->msize, - &pce_dev->ce_sps.in_transfer); - _qce_set_flag(&pce_dev->ce_sps.in_transfer, + &pce_sps_data->in_transfer); + _qce_sps_add_data((uint32_t)preq_info->phy_ota_src, req->msize, + &pce_sps_data->in_transfer); + _qce_set_flag(&pce_sps_data->in_transfer, SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD); _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_UNLOCK, - &pce_dev->ce_sps.cmdlistptr.unlock_all_pipes, - &pce_dev->ce_sps.in_transfer); + &pce_sps_data->cmdlistptr.unlock_all_pipes, + &pce_sps_data->in_transfer); - _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump), + _qce_sps_add_data(GET_PHYS_ADDR(pce_sps_data->result_dump), CRYPTO_RESULT_DUMP_SIZE, - &pce_dev->ce_sps.out_transfer); - _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT); - rc = _qce_sps_transfer(pce_dev); + &pce_sps_data->out_transfer); + + select_mode(pce_dev, preq_info); + rc = _qce_sps_transfer(pce_dev, req_info); + cmpxchg(&pce_dev->owner, QCE_OWNER_CLIENT, QCE_OWNER_NONE); if (rc) goto bad; return 0; bad: - dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src, + dma_unmap_single(pce_dev->pdev, preq_info->phy_ota_src, req->msize, DMA_TO_DEVICE); + qce_free_req_info(pce_dev, req_info, false); return rc; } EXPORT_SYMBOL(qce_f9_req); @@ -5146,30 +5693,38 @@ static int __qce_get_device_tree_data(struct platform_device *pdev, if (of_property_read_u32((&pdev->dev)->of_node, "qcom,bam-pipe-pair", - &pce_dev->ce_sps.pipe_pair_index)) { + &pce_dev->ce_bam_info.pipe_pair_index)) { pr_err("Fail to get bam pipe pair information.\n"); return -EINVAL; } if (of_property_read_u32((&pdev->dev)->of_node, "qcom,ce-device", - &pce_dev->ce_sps.ce_device)) { + &pce_dev->ce_bam_info.ce_device)) { pr_err("Fail to get CE device information.\n"); return -EINVAL; } if (of_property_read_u32((&pdev->dev)->of_node, "qcom,ce-hw-instance", - &pce_dev->ce_sps.ce_hw_instance)) { + &pce_dev->ce_bam_info.ce_hw_instance)) { pr_err("Fail to get CE hw instance information.\n"); return -EINVAL; } + if (of_property_read_u32((&pdev->dev)->of_node, + "qcom,bam-ee", + &pce_dev->ce_bam_info.bam_ee)) { + pr_info("BAM Apps EE is not defined, setting to default 1\n"); + pce_dev->ce_bam_info.bam_ee = 1; + } if (of_property_read_u32((&pdev->dev)->of_node, "qcom,ce-opp-freq", &pce_dev->ce_opp_freq_hz)) { pr_info("CE operating frequency is not defined, setting to default 100MHZ\n"); pce_dev->ce_opp_freq_hz = CE_CLK_100MHZ; } - pce_dev->ce_sps.dest_pipe_index = 2 * pce_dev->ce_sps.pipe_pair_index; - pce_dev->ce_sps.src_pipe_index = pce_dev->ce_sps.dest_pipe_index + 1; + pce_dev->ce_bam_info.dest_pipe_index = + 2 * pce_dev->ce_bam_info.pipe_pair_index; + pce_dev->ce_bam_info.src_pipe_index = + pce_dev->ce_bam_info.dest_pipe_index + 1; resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "crypto-base"); @@ -5199,15 +5754,15 @@ static int __qce_get_device_tree_data(struct platform_device *pdev, resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (resource) { - pce_dev->ce_sps.bam_irq = resource->start; + pce_dev->ce_bam_info.bam_irq = resource->start; } else { pr_err("CRYPTO BAM IRQ unavailable.\n"); goto err_dev; } return rc; err_dev: - if (pce_dev->ce_sps.bam_iobase) - iounmap(pce_dev->ce_sps.bam_iobase); + if (pce_dev->ce_bam_info.bam_iobase) + iounmap(pce_dev->ce_bam_info.bam_iobase); err_getting_bam_info: if (pce_dev->iobase) @@ -5230,12 +5785,21 @@ static int __qce_init_clk(struct qce_device *pce_dev) goto exit_put_core_src_clk; } } else { - pr_warn("Unable to get CE core src clk, set to NULL\n"); - pce_dev->ce_core_src_clk = NULL; + if (pce_dev->support_only_core_src_clk) { + rc = PTR_ERR(pce_dev->ce_core_src_clk); + pce_dev->ce_core_src_clk = NULL; + pr_err("Unable to get CE core src clk\n"); + return rc; + } else { + pr_warn("Unable to get CE core src clk, set to NULL\n"); + pce_dev->ce_core_src_clk = NULL; + } } if (pce_dev->support_only_core_src_clk) { pce_dev->ce_core_clk = NULL; + pce_dev->ce_clk = NULL; + pce_dev->ce_bus_clk = NULL; } else { pce_dev->ce_core_clk = clk_get(pce_dev->pdev, "core_clk"); if (IS_ERR(pce_dev->ce_core_clk)) { @@ -5243,30 +5807,31 @@ static int __qce_init_clk(struct qce_device *pce_dev) pr_err("Unable to get CE core clk\n"); goto exit_put_core_src_clk; } - } - - pce_dev->ce_clk = clk_get(pce_dev->pdev, "iface_clk"); - if (IS_ERR(pce_dev->ce_clk)) { - rc = PTR_ERR(pce_dev->ce_clk); - pr_err("Unable to get CE interface clk\n"); - goto exit_put_core_clk; - } + pce_dev->ce_clk = clk_get(pce_dev->pdev, "iface_clk"); + if (IS_ERR(pce_dev->ce_clk)) { + rc = PTR_ERR(pce_dev->ce_clk); + pr_err("Unable to get CE interface clk\n"); + goto exit_put_core_clk; + } - pce_dev->ce_bus_clk = clk_get(pce_dev->pdev, "bus_clk"); - if (IS_ERR(pce_dev->ce_bus_clk)) { - rc = PTR_ERR(pce_dev->ce_bus_clk); - pr_err("Unable to get CE BUS interface clk\n"); - goto exit_put_iface_clk; + pce_dev->ce_bus_clk = clk_get(pce_dev->pdev, "bus_clk"); + if (IS_ERR(pce_dev->ce_bus_clk)) { + rc = PTR_ERR(pce_dev->ce_bus_clk); + pr_err("Unable to get CE BUS interface clk\n"); + goto exit_put_iface_clk; + } } return rc; exit_put_iface_clk: - clk_put(pce_dev->ce_clk); + if (pce_dev->ce_clk) + clk_put(pce_dev->ce_clk); exit_put_core_clk: if (pce_dev->ce_core_clk) clk_put(pce_dev->ce_core_clk); exit_put_core_src_clk: - clk_put(pce_dev->ce_core_src_clk); + if (pce_dev->ce_core_src_clk) + clk_put(pce_dev->ce_core_src_clk); pr_err("Unable to init CE clks, rc = %d\n", rc); return rc; } @@ -5288,16 +5853,23 @@ int qce_enable_clk(void *handle) struct qce_device *pce_dev = (struct qce_device *)handle; int rc = 0; - if (pce_dev->support_only_core_src_clk) { - if (pce_dev->ce_core_src_clk) - rc = clk_prepare_enable(pce_dev->ce_core_src_clk); - } else { - if (pce_dev->ce_core_clk) - rc = clk_prepare_enable(pce_dev->ce_core_clk); + if (pce_dev->ce_core_src_clk) { + rc = clk_prepare_enable(pce_dev->ce_core_src_clk); + if (rc) { + pr_err("Unable to enable/prepare CE core src clk\n"); + return rc; + } } - if (rc) { - pr_err("Unable to enable/prepare CE core clk\n"); + + if (pce_dev->support_only_core_src_clk) return rc; + + if (pce_dev->ce_core_clk) { + rc = clk_prepare_enable(pce_dev->ce_core_clk); + if (rc) { + pr_err("Unable to enable/prepare CE core clk\n"); + goto exit_disable_core_src_clk; + } } if (pce_dev->ce_clk) { @@ -5318,12 +5890,14 @@ int qce_enable_clk(void *handle) return rc; exit_disable_ce_clk: - clk_disable_unprepare(pce_dev->ce_clk); + if (pce_dev->ce_clk) + clk_disable_unprepare(pce_dev->ce_clk); exit_disable_core_clk: - if (pce_dev->support_only_core_src_clk) - clk_disable_unprepare(pce_dev->ce_core_src_clk); - else + if (pce_dev->ce_core_clk) clk_disable_unprepare(pce_dev->ce_core_clk); +exit_disable_core_src_clk: + if (pce_dev->ce_core_src_clk) + clk_disable_unprepare(pce_dev->ce_core_src_clk); return rc; } EXPORT_SYMBOL(qce_enable_clk); @@ -5337,22 +5911,52 @@ int qce_disable_clk(void *handle) clk_disable_unprepare(pce_dev->ce_bus_clk); if (pce_dev->ce_clk) clk_disable_unprepare(pce_dev->ce_clk); - if (pce_dev->support_only_core_src_clk) { - if (pce_dev->ce_core_src_clk) - clk_disable_unprepare(pce_dev->ce_core_src_clk); - } else { - if (pce_dev->ce_core_clk) - clk_disable_unprepare(pce_dev->ce_core_clk); - } + if (pce_dev->ce_core_clk) + clk_disable_unprepare(pce_dev->ce_core_clk); + if (pce_dev->ce_core_src_clk) + clk_disable_unprepare(pce_dev->ce_core_src_clk); return rc; } EXPORT_SYMBOL(qce_disable_clk); +/* dummy req setup */ +static int setup_dummy_req(struct qce_device *pce_dev) +{ + char *input = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopqopqrpqrs"; + int len = DUMMY_REQ_DATA_LEN; + + memcpy(pce_dev->dummyreq_in_buf, input, len); + sg_set_buf(&pce_dev->dummyreq.sg, pce_dev->dummyreq_in_buf, len); + sg_mark_end(&pce_dev->dummyreq.sg); + + pce_dev->dummyreq.sreq.alg = QCE_HASH_SHA1; + pce_dev->dummyreq.sreq.qce_cb = qce_dummy_complete; + pce_dev->dummyreq.sreq.src = &pce_dev->dummyreq.sg; + pce_dev->dummyreq.sreq.auth_data[0] = 0; + pce_dev->dummyreq.sreq.auth_data[1] = 0; + pce_dev->dummyreq.sreq.auth_data[2] = 0; + pce_dev->dummyreq.sreq.auth_data[3] = 0; + pce_dev->dummyreq.sreq.first_blk = 1; + pce_dev->dummyreq.sreq.last_blk = 1; + pce_dev->dummyreq.sreq.size = len; + pce_dev->dummyreq.sreq.areq = &pce_dev->dummyreq.areq; + pce_dev->dummyreq.sreq.flags = 0; + pce_dev->dummyreq.sreq.authkey = NULL; + + pce_dev->dummyreq.areq.src = pce_dev->dummyreq.sreq.src; + pce_dev->dummyreq.areq.nbytes = pce_dev->dummyreq.sreq.size; + + return 0; +} + /* crypto engine open function. */ void *qce_open(struct platform_device *pdev, int *rc) { struct qce_device *pce_dev; + int i; + static int pcedev_no = 1; pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL); if (!pce_dev) { @@ -5362,6 +5966,7 @@ void *qce_open(struct platform_device *pdev, int *rc) } pce_dev->pdev = &pdev->dev; + mutex_lock(&qce_iomap_mutex); if (pdev->dev.of_node) { *rc = __qce_get_device_tree_data(pdev, pce_dev); if (*rc) @@ -5372,19 +5977,33 @@ void *qce_open(struct platform_device *pdev, int *rc) goto err_pce_dev; } - pce_dev->memsize = 10 * PAGE_SIZE; + for (i = 0; i < MAX_QCE_ALLOC_BAM_REQ; i++) + atomic_set(&pce_dev->ce_request_info[i].in_use, false); + pce_dev->ce_request_index = 0; + + pce_dev->memsize = 10 * PAGE_SIZE * MAX_QCE_ALLOC_BAM_REQ; pce_dev->coh_vmem = dma_alloc_coherent(pce_dev->pdev, pce_dev->memsize, &pce_dev->coh_pmem, GFP_KERNEL); + if (pce_dev->coh_vmem == NULL) { *rc = -ENOMEM; pr_err("Can not allocate coherent memory for sps data\n"); goto err_iobase; } + pce_dev->iovec_memsize = TOTAL_IOVEC_SPACE_PER_PIPE * + MAX_QCE_ALLOC_BAM_REQ * 2; + pce_dev->iovec_vmem = kzalloc(pce_dev->iovec_memsize, GFP_KERNEL); + if (pce_dev->iovec_vmem == NULL) + goto err_mem; + + pce_dev->dummyreq_in_buf = kzalloc(DUMMY_REQ_DATA_LEN, GFP_KERNEL); + if (pce_dev->dummyreq_in_buf == NULL) + goto err_mem; + *rc = __qce_init_clk(pce_dev); if (*rc) goto err_mem; - *rc = qce_enable_clk(pce_dev); if (*rc) goto err_enable_clk; @@ -5401,7 +6020,18 @@ void *qce_open(struct platform_device *pdev, int *rc) goto err; qce_setup_ce_sps_data(pce_dev); qce_disable_clk(pce_dev); - + setup_dummy_req(pce_dev); + atomic_set(&pce_dev->no_of_queued_req, 0); + pce_dev->mode = IN_INTERRUPT_MODE; + init_timer(&(pce_dev->timer)); + pce_dev->timer.function = qce_multireq_timeout; + pce_dev->timer.data = (unsigned long)pce_dev; + pce_dev->timer.expires = jiffies + DELAY_IN_JIFFIES; + pce_dev->intr_cadence = 0; + pce_dev->dev_no = pcedev_no; + pcedev_no++; + pce_dev->owner = QCE_OWNER_NONE; + mutex_unlock(&qce_iomap_mutex); return pce_dev; err: qce_disable_clk(pce_dev); @@ -5410,6 +6040,8 @@ err_enable_clk: __qce_deinit_clk(pce_dev); err_mem: + kfree(pce_dev->dummyreq_in_buf); + kfree(pce_dev->iovec_vmem); if (pce_dev->coh_vmem) dma_free_coherent(pce_dev->pdev, pce_dev->memsize, pce_dev->coh_vmem, pce_dev->coh_pmem); @@ -5417,6 +6049,7 @@ err_iobase: if (pce_dev->iobase) iounmap(pce_dev->iobase); err_pce_dev: + mutex_unlock(&qce_iomap_mutex); kfree(pce_dev); return NULL; } @@ -5430,6 +6063,7 @@ int qce_close(void *handle) if (handle == NULL) return -ENODEV; + mutex_lock(&qce_iomap_mutex); qce_enable_clk(pce_dev); qce_sps_exit(pce_dev); @@ -5438,10 +6072,12 @@ int qce_close(void *handle) if (pce_dev->coh_vmem) dma_free_coherent(pce_dev->pdev, pce_dev->memsize, pce_dev->coh_vmem, pce_dev->coh_pmem); + kfree(pce_dev->dummyreq_in_buf); + kfree(pce_dev->iovec_vmem); qce_disable_clk(pce_dev); __qce_deinit_clk(pce_dev); - + mutex_unlock(&qce_iomap_mutex); kfree(handle); return 0; @@ -5476,7 +6112,7 @@ int qce_hw_support(void *handle, struct ce_hw_support *ce_support) ce_support->hw_key = pce_dev->support_hw_key; ce_support->aes_ccm = true; ce_support->clk_mgmt_sus_res = pce_dev->support_clk_mgmt_sus_res; - if (pce_dev->ce_sps.minor_version) + if (pce_dev->ce_bam_info.minor_version) ce_support->aligned_only = false; else ce_support->aligned_only = true; @@ -5493,12 +6129,30 @@ int qce_hw_support(void *handle, struct ce_hw_support *ce_support) pce_dev->use_sw_hmac_algo; ce_support->use_sw_aes_ccm_algo = pce_dev->use_sw_aes_ccm_algo; - ce_support->ce_device = pce_dev->ce_sps.ce_device; - ce_support->ce_hw_instance = pce_dev->ce_sps.ce_hw_instance; + ce_support->ce_device = pce_dev->ce_bam_info.ce_device; + ce_support->ce_hw_instance = pce_dev->ce_bam_info.ce_hw_instance; + if (pce_dev->no_get_around) + ce_support->max_request = MAX_QCE_BAM_REQ; + else + ce_support->max_request = 1; return 0; } EXPORT_SYMBOL(qce_hw_support); +void qce_dump_req(void *handle) +{ + int i; + bool req_in_use; + struct qce_device *pce_dev = (struct qce_device *)handle; + + for (i = 0; i < MAX_QCE_BAM_REQ; i++) { + req_in_use = atomic_read(&pce_dev->ce_request_info[i].in_use); + pr_info("qce_dump_req %d %d\n", i, req_in_use); + if (req_in_use == true) + _qce_dump_descr_fifos(pce_dev, i); + } +} +EXPORT_SYMBOL(qce_dump_req); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Crypto Engine driver"); diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h index 8b832c80a6e39a1ca0aa621b6a1b7ef9e01f5e24..765eede0b583c5f39bbb86cc2f19cc3aaaf216c8 100644 --- a/drivers/crypto/msm/qce50.h +++ b/drivers/crypto/msm/qce50.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * 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 @@ -22,8 +22,8 @@ ((uintptr_t)pce_dev->coh_vmem + \ ((uintptr_t)x - (uintptr_t)pce_dev->coh_pmem)) #define GET_PHYS_ADDR(x) \ - ((uintptr_t)pce_dev->coh_pmem + \ - ((uintptr_t)x - (uintptr_t)pce_dev->coh_vmem)) + (phys_addr_t)(((uintptr_t)pce_dev->coh_pmem + \ + ((uintptr_t)x - (uintptr_t)pce_dev->coh_vmem))) #define CRYPTO_REG_SIZE 4 #define NUM_OF_CRYPTO_AUTH_IV_REG 16 @@ -38,6 +38,9 @@ #define QCE_MAX_NUM_DESC 128 #define SPS_MAX_PKT_SIZE (32 * 1024 - 64) +/* default bam ipc log level */ +#define QCE_BAM_DEFAULT_IPC_LOGLVL 2 + /* State of consumer/producer Pipe */ enum qce_pipe_st_enum { QCE_PIPE_STATE_IDLE = 0, @@ -46,6 +49,15 @@ enum qce_pipe_st_enum { QCE_PIPE_STATE_LAST }; +enum qce_xfer_type_enum { + QCE_XFER_HASHING, + QCE_XFER_CIPHERING, + QCE_XFER_AEAD, + QCE_XFER_F8, + QCE_XFER_F9, + QCE_XFER_TYPE_LAST +}; + struct qce_sps_ep_conn_data { struct sps_pipe *pipe; struct sps_connect connect; @@ -114,6 +126,7 @@ struct qce_cmdlistptr_ops { struct qce_cmdlist_info aead_hmac_sha256_cbc_3des; struct qce_cmdlist_info aead_aes_128_ccm; struct qce_cmdlist_info aead_aes_256_ccm; + struct qce_cmdlist_info cipher_null; struct qce_cmdlist_info f8_kasumi; struct qce_cmdlist_info f8_snow3g; struct qce_cmdlist_info f9_kasumi; @@ -165,40 +178,67 @@ struct qce_ce_cfg_reg_setting { uint32_t auth_cfg_snow3g; }; -/* DM data structure with buffers, commandlists & commmand pointer lists */ -struct ce_sps_data { - +struct ce_bam_info { uint32_t bam_irq; uint32_t bam_mem; void __iomem *bam_iobase; - - struct qce_sps_ep_conn_data producer; - struct qce_sps_ep_conn_data consumer; - struct sps_event_notify notify; - struct scatterlist *src; - struct scatterlist *dst; uint32_t ce_device; uint32_t ce_hw_instance; + uint32_t bam_ee; unsigned int pipe_pair_index; unsigned int src_pipe_index; unsigned int dest_pipe_index; unsigned long bam_handle; + int ce_burst_size; + uint32_t minor_version; + struct qce_sps_ep_conn_data producer; + struct qce_sps_ep_conn_data consumer; +}; - enum qce_pipe_st_enum consumer_state; /* Consumer pipe state */ +/* SPS data structure with buffers, commandlists & commmand pointer lists */ +struct ce_sps_data { enum qce_pipe_st_enum producer_state; /* Producer pipe state */ - int consumer_status; /* consumer pipe status */ int producer_status; /* producer pipe status */ - struct sps_transfer in_transfer; struct sps_transfer out_transfer; + struct qce_cmdlistptr_ops cmdlistptr; + uint32_t result_dump; /* reuslt dump virtual address */ + uint32_t result_dump_null; + uint32_t result_dump_phy; /* result dump physical address (32 bits) */ + uint32_t result_dump_null_phy; + + uint32_t ignore_buffer; /* ignore buffer virtual address */ + struct ce_result_dump_format *result; /* ponter to result dump */ + struct ce_result_dump_format *result_null; +}; - int ce_burst_size; +struct ce_request_info { + atomic_t in_use; + bool in_prog; + enum qce_xfer_type_enum xfer_type; + struct ce_sps_data ce_sps; + qce_comp_func_ptr_t qce_cb; /* qce callback function pointer */ + void *user; + void *areq; + int assoc_nents; + int src_nents; + int dst_nents; + dma_addr_t phy_iv_in; + unsigned char dec_iv[16]; + int dir; + enum qce_cipher_mode_enum mode; + dma_addr_t phy_ota_src; + dma_addr_t phy_ota_dst; + unsigned int ota_size; + unsigned int req_len; +}; - struct qce_cmdlistptr_ops cmdlistptr; - uint32_t result_dump; - uint32_t ignore_buffer; - struct ce_result_dump_format *result; - uint32_t minor_version; +struct qce_driver_stats { + int no_of_timeouts; + int no_of_dummy_reqs; + int current_mode; + int outstanding_reqs; }; + #endif /* _DRIVERS_CRYPTO_MSM_QCE50_H */ diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index d9a99b0c56b58ab411e6971f645ce3c3862e790c..a55f236961b83bf5faf23f482f9829b6b86a84be 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1,6 +1,6 @@ /* Qualcomm CE device driver. * - * Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * 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 @@ -35,21 +35,12 @@ #include "qcedevi.h" #include "qce.h" -#ifdef CONFIG_COMPAT #include #include "compat_qcedev.h" -#endif #define CACHE_LINE_SIZE 32 #define CE_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE -#ifndef U32_MAX -#define U32_MAX ((u32)(~0U)) -#endif - -/* are FIPS integrity tests done ?? */ -static bool is_fips_qcedev_integritytest_done; - static uint8_t _std_init_vector_sha1_uint8[] = { 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89, 0x98, 0xBA, 0xDC, 0xFE, 0x10, 0x32, 0x54, 0x76, @@ -181,12 +172,6 @@ static int qcedev_open(struct inode *inode, struct file *file) struct qcedev_handle *handle; struct qcedev_control *podev; - /* IF FIPS tests not passed, return error */ - if (((g_fips140_status == FIPS140_STATUS_FAIL) || - (g_fips140_status == FIPS140_STATUS_PASS_CRYPTO)) && - is_fips_qcedev_integritytest_done) - return -ENXIO; - podev = qcedev_minor_to_control(MINOR(inode->i_rdev)); if (podev == NULL) { pr_err("%s: no such device %d\n", __func__, @@ -1754,7 +1739,6 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&hash_access_lock); return err; } - if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { pr_err("Invalid sha_ctxt.diglen %d\n", handle->sha_ctxt.diglen); @@ -1797,7 +1781,6 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&hash_access_lock); return err; } - if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { pr_err("Invalid sha_ctxt.diglen %d\n", handle->sha_ctxt.diglen); @@ -1814,55 +1797,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) return -EFAULT; } break; - /* - * This IOCTL call can be called only once - * by FIPS Integrity test. - */ - case QCEDEV_IOCTL_UPDATE_FIPS_STATUS: - { - enum fips_status status; - void *drbg_call_back = NULL; - - if (is_fips_qcedev_integritytest_done) - return -EPERM; - - if (copy_from_user(&status, (void __user *)arg, - sizeof(enum fips_status))) - return -EFAULT; - - g_fips140_status = _fips_update_status(status); - pr_debug("qcedev: FIPS140-2 Global status flag: %d\n", - g_fips140_status); - is_fips_qcedev_integritytest_done = true; - - if (g_fips140_status == FIPS140_STATUS_FAIL) { - pr_err("qcedev: FIPS140-2 Integrity test failed\n"); - break; - } - - if (!(_do_msm_fips_drbg_init(drbg_call_back)) && - (g_fips140_status != FIPS140_STATUS_NA)) - g_fips140_status = FIPS140_STATUS_PASS; - } - - pr_debug("qcedev: FIPS140-2 Global status flag: %d\n", - g_fips140_status); - - break; - - /* Read only IOCTL call to read the - current FIPS140-2 Status */ - case QCEDEV_IOCTL_QUERY_FIPS_STATUS: - { - enum fips_status status; - - status = g_fips140_status; - if (copy_to_user((void __user *)arg, &status, - sizeof(enum fips_status))) - return -EFAULT; - } - break; default: return -ENOTTY; } @@ -1938,24 +1873,6 @@ static int qcedev_probe(struct platform_device *pdev) goto err; } } - /* - * FIPS140-2 Known Answer Tests: - * IN case of any failure, do not Init the module - */ - is_fips_qcedev_integritytest_done = false; - if (g_fips140_status != FIPS140_STATUS_NA) { - if (_fips_qcedev_cipher_selftest(&qce_dev[0]) || - _fips_qcedev_sha_selftest(&qce_dev[0])) { - pr_err("qcedev: FIPS140-2 Known Answer Tests : Failed\n"); - BUG_ON(1); - rc = -1; - } else { - pr_debug("qcedev: FIPS140-2 Known Answer Tests : Successful\n"); - rc = 0; - } - } else { - pr_debug("qcedev: FIPS140-2 Known Answer Tests : Skipped\n"); - } if (rc >= 0) return 0; diff --git a/drivers/crypto/msm/qcedevi.h b/drivers/crypto/msm/qcedevi.h index fced4537e33c18c9f9444a435d5b9656bf1b8353..ca358ac3d4c68a68ec8760476abc00c0537898a9 100644 --- a/drivers/crypto/msm/qcedevi.h +++ b/drivers/crypto/msm/qcedevi.h @@ -1,6 +1,6 @@ /* QTI crypto Driver * - * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * 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,7 +32,6 @@ enum qcedev_crypto_oper_type { }; struct qcedev_handle; -extern enum fips_status g_fips140_status; struct qcedev_cipher_req { struct ablkcipher_request creq; @@ -122,47 +121,4 @@ void qcedev_cipher_req_cb(void *cookie, unsigned char *icv, void qcedev_sha_req_cb(void *cookie, unsigned char *digest, unsigned char *authdata, int ret); -extern int _do_msm_fips_drbg_init(void *rng_dev); - -#ifdef CONFIG_FIPS_ENABLE - -/* - * Self test for Cipher algorithms - */ -int _fips_qcedev_cipher_selftest(struct qcedev_control *podev); - -/* - * Self test for SHA / HMAC - */ - -int _fips_qcedev_sha_selftest(struct qcedev_control *podev); - -/* - * Update FIPs Global status Status - */ -static inline enum fips_status _fips_update_status(enum fips_status status) -{ - return (status == FIPS140_STATUS_PASS) ? - FIPS140_STATUS_QCRYPTO_ALLOWED : - FIPS140_STATUS_FAIL; -} - -#else - -static inline int _fips_qcedev_cipher_selftest(struct qcedev_control *podev) -{ - return 0; -} -static inline int _fips_qcedev_sha_selftest(struct qcedev_control *podev) -{ - return 0; -} - -static inline enum fips_status _fips_update_status(enum fips_status status) -{ - return FIPS140_STATUS_NA; -} - -#endif /* CONFIG_FIPS_ENABLE */ - #endif /* __CRYPTO_MSM_QCEDEVI_H */ diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c index 57401242e373a3dc096a4b8bfc0d69748b156057..f03115371c9582224f9288d42b4ba3674f07a913 100644 --- a/drivers/crypto/msm/qcrypto.c +++ b/drivers/crypto/msm/qcrypto.c @@ -1,6 +1,6 @@ /* Qualcomm Crypto driver * - * Copyright (c) 2010-2017, 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * 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 @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include #include #include @@ -45,11 +48,12 @@ #include #include -#include "qcryptoi.h" + #include "qce.h" #define DEBUG_MAX_FNAME 16 -#define DEBUG_MAX_RW_BUF 2048 +#define DEBUG_MAX_RW_BUF 4096 +#define QCRYPTO_BIG_NUMBER 9999999 /* a big number */ /* * For crypto 5.0 which has burst size alignment requirement. @@ -58,8 +62,20 @@ #define QCRYPTO_HIGH_BANDWIDTH_TIMEOUT 1000 -/* are FIPS self tests done ?? */ -static bool is_fips_qcrypto_tests_done; + + +/* Status of response workq */ +enum resp_workq_sts { + NOT_SCHEDULED = 0, + IS_SCHEDULED = 1, + SCHEDULE_AGAIN = 2 +}; + +/* Status of req processing by CEs */ +enum req_processing_sts { + STOPPED = 0, + IN_PROGRESS = 1 +}; enum qcrypto_bus_state { BUS_NO_BANDWIDTH = 0, @@ -110,15 +126,20 @@ static struct dentry *_debug_dent; static char _debug_read_buf[DEBUG_MAX_RW_BUF]; static bool _qcrypto_init_assign; struct crypto_priv; +struct qcrypto_req_control { + unsigned int index; + bool in_use; + struct crypto_engine *pce; + struct crypto_async_request *req; + struct qcrypto_resp_ctx *arsp; + int res; /* execution result */ +}; + struct crypto_engine { struct list_head elist; void *qce; /* qce handle */ struct platform_device *pdev; /* platform device */ - struct crypto_async_request *req; /* current active request */ - struct qcrypto_resp_ctx *arsp; /* rsp associated with req */ - int res; /* execution result */ struct crypto_priv *pcp; - struct tasklet_struct done_tasklet; uint32_t bus_scale_handle; struct crypto_queue req_queue; /* * request queue for those requests @@ -144,8 +165,18 @@ struct crypto_engine { u32 last_active_seq; bool check_flag; + /*Added to support multi-requests*/ + unsigned int max_req; + struct qcrypto_req_control *preq_pool; + atomic_t req_count; + bool issue_req; /* an request is being issued to qce */ + bool first_engine; /* this engine is the first engine or not */ + unsigned int irq_cpu; /* the cpu running the irq of this engine */ + unsigned int max_req_used; /* debug stats */ }; +#define MAX_SMP_CPU 8 + struct crypto_priv { /* CE features supported by target device*/ struct msm_ce_hw_support platform_support; @@ -173,10 +204,99 @@ struct crypto_priv { * that waiting for an available * engine. */ + struct llist_head ordered_resp_list; /* Queue to maintain + * responses in sequence. + */ + atomic_t resp_cnt; + struct workqueue_struct *resp_wq; + struct work_struct resp_work; /* + * Workq to send responses + * in sequence. + */ + enum resp_workq_sts sched_resp_workq_status; + enum req_processing_sts ce_req_proc_sts; + int cpu_getting_irqs_frm_first_ce; + struct crypto_engine *first_engine; + struct crypto_engine *scheduled_eng; /* last engine scheduled */ + + /* debug stats */ + unsigned no_avail; + unsigned resp_stop; + unsigned resp_start; + unsigned max_qlen; + unsigned int queue_work_eng3; + unsigned int queue_work_not_eng3; + unsigned int queue_work_not_eng3_nz; + unsigned int max_resp_qlen; + unsigned int max_reorder_cnt; + unsigned int cpu_req[MAX_SMP_CPU+1]; }; static struct crypto_priv qcrypto_dev; static struct crypto_engine *_qcrypto_static_assign_engine( struct crypto_priv *cp); +static struct crypto_engine *_avail_eng(struct crypto_priv *cp); +static struct qcrypto_req_control *qcrypto_alloc_req_control( + struct crypto_engine *pce) +{ + int i; + struct qcrypto_req_control *pqcrypto_req_control = pce->preq_pool; + unsigned int req_count; + + for (i = 0; i < pce->max_req; i++) { + if (xchg(&pqcrypto_req_control->in_use, true) == false) { + req_count = atomic_inc_return(&pce->req_count); + if (req_count > pce->max_req_used) + pce->max_req_used = req_count; + return pqcrypto_req_control; + } + pqcrypto_req_control++; + } + return NULL; +} + +static void qcrypto_free_req_control(struct crypto_engine *pce, + struct qcrypto_req_control *preq) +{ + /* do this before free req */ + preq->req = NULL; + preq->arsp = NULL; + /* free req */ + if (xchg(&preq->in_use, false) == false) { + pr_warn("request info %pK free already\n", preq); + } else { + atomic_dec(&pce->req_count); + } +} + +static struct qcrypto_req_control *find_req_control_for_areq( + struct crypto_engine *pce, + struct crypto_async_request *areq) +{ + int i; + struct qcrypto_req_control *pqcrypto_req_control = pce->preq_pool; + + for (i = 0; i < pce->max_req; i++) { + if (pqcrypto_req_control->req == areq) + return pqcrypto_req_control; + pqcrypto_req_control++; + } + return NULL; +} + +static void qcrypto_init_req_control(struct crypto_engine *pce, + struct qcrypto_req_control *pqcrypto_req_control) +{ + int i; + + pce->preq_pool = pqcrypto_req_control; + atomic_set(&pce->req_count, 0); + for (i = 0; i < pce->max_req; i++) { + pqcrypto_req_control->index = i; + pqcrypto_req_control->in_use = false; + pqcrypto_req_control->pce = pce; + pqcrypto_req_control++; + } +} static struct crypto_engine *_qrypto_find_pengine_device(struct crypto_priv *cp, unsigned int device) @@ -296,14 +416,14 @@ struct qcrypto_cipher_ctx { u8 ccm4309_nonce[QCRYPTO_CCM4309_NONCE_LEN]; - union { - struct crypto_ablkcipher *cipher_fb; - struct crypto_aead *aead_fb; - } fallback; + struct crypto_ablkcipher *cipher_aes192_fb; + + struct crypto_ahash *ahash_aead_aes192_fb; }; struct qcrypto_resp_ctx { struct list_head list; + struct llist_node llist; struct crypto_async_request *async_req; /* async req */ int res; /* execution result */ }; @@ -329,12 +449,27 @@ struct qcrypto_cipher_req_ctx { struct scatterlist ssg; /* Source Data sg */ unsigned char *data; /* Incoming data pointer*/ + struct aead_request *aead_req; + struct ahash_request *fb_hash_req; + uint8_t fb_ahash_digest[SHA256_DIGEST_SIZE]; + struct scatterlist fb_ahash_sg[3]; + char *fb_ahash_assoc_iv; + char *fb_aes_iv; + unsigned int fb_ahash_length; + struct ablkcipher_request *fb_aes_req; + struct scatterlist *fb_aes_src; + struct scatterlist *fb_aes_dst; + unsigned int fb_aes_cryptlen; }; #define SHA_MAX_BLOCK_SIZE SHA256_BLOCK_SIZE #define SHA_MAX_STATE_SIZE (SHA256_DIGEST_SIZE / sizeof(u32)) #define SHA_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE -#define MSM_QCRYPTO_REQ_QUEUE_LENGTH 50 + +#define MSM_QCRYPTO_REQ_QUEUE_LENGTH 768 +#define COMPLETION_CB_BACKLOG_LENGTH_STOP 400 +#define COMPLETION_CB_BACKLOG_LENGTH_START \ + (COMPLETION_CB_BACKLOG_LENGTH_STOP / 2) static uint8_t _std_init_vector_sha1_uint8[] = { 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89, @@ -550,11 +685,11 @@ static void qcrypto_bw_reaper_work(struct work_struct *work) (active_seq == pengine->last_active_seq)) { /* check if engine is stuck */ - if (pengine->req) { + if (atomic_read(&pengine->req_count) > 0) { if (pengine->check_flag) dev_warn(&pengine->pdev->dev, - "The engine appears to be stuck seq %d req %pK.\n", - active_seq, pengine->req); + "The engine appears to be stuck seq %d.\n", + active_seq); pengine->check_flag = false; goto ret; } @@ -607,8 +742,8 @@ static size_t qcrypto_sg_copy_from_buffer(struct scatterlist *sgl, size_t offset, len; for (i = 0, offset = 0; i < nents; ++i) { - if (sgl == NULL) { - pr_err("qcrypto: sg_copy_from_buffer, sg = NULL\n"); + if (NULL == sgl) { + pr_err("qcrypto.c: qcrypto_sg_copy_from_buffer, sgl = NULL"); break; } len = sg_copy_from_buffer(sgl, 1, buf, buflen); @@ -628,8 +763,8 @@ static size_t qcrypto_sg_copy_to_buffer(struct scatterlist *sgl, size_t offset, len; for (i = 0, offset = 0; i < nents; ++i) { - if (sgl == NULL) { - pr_err("qcrypto: sg_copy_to_buffer, sg = NULL\n"); + if (NULL == sgl) { + pr_err("qcrypto.c: qcrypto_sg_copy_from_buffer, sgl = NULL"); break; } len = sg_copy_to_buffer(sgl, 1, buf, buflen); @@ -684,11 +819,6 @@ static int _qcrypto_cipher_cra_init(struct crypto_tfm *tfm) struct qcrypto_alg *q_alg; struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - /* IF FIPS tests not passed, return error */ - if (((g_fips140_status == FIPS140_STATUS_FAIL) || - (g_fips140_status == FIPS140_STATUS_PASS_CRYPTO)) && - is_fips_qcrypto_tests_done) - return -ENXIO; q_alg = container_of(alg, struct qcrypto_alg, cipher_alg); ctx->flags = 0; @@ -718,12 +848,6 @@ static int _qcrypto_ahash_cra_init(struct crypto_tfm *tfm) struct qcrypto_alg *q_alg = container_of(alg, struct qcrypto_alg, sha_alg); - /* IF FIPS tests not passed, return error */ - if (((g_fips140_status == FIPS140_STATUS_FAIL) || - (g_fips140_status == FIPS140_STATUS_PASS_CRYPTO)) && - is_fips_qcrypto_tests_done) - return -ENXIO; - crypto_ahash_set_reqsize(ahash, sizeof(struct qcrypto_sha_req_ctx)); /* update context with ptr to cp */ sha_ctx->cp = q_alg->cp; @@ -795,15 +919,15 @@ static int _qcrypto_cra_aes_ablkcipher_init(struct crypto_tfm *tfm) struct crypto_priv *cp = &qcrypto_dev; if (cp->ce_support.use_sw_aes_cbc_ecb_ctr_algo) { - ctx->fallback.cipher_fb = NULL; + ctx->cipher_aes192_fb = NULL; return _qcrypto_cra_ablkcipher_init(tfm); } - ctx->fallback.cipher_fb = crypto_alloc_ablkcipher(name, 0, + ctx->cipher_aes192_fb = crypto_alloc_ablkcipher(name, 0, CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); - if (IS_ERR(ctx->fallback.cipher_fb)) { + if (IS_ERR(ctx->cipher_aes192_fb)) { pr_err("Error allocating fallback algo %s\n", name); - ret = PTR_ERR(ctx->fallback.cipher_fb); - ctx->fallback.cipher_fb = NULL; + ret = PTR_ERR(ctx->cipher_aes192_fb); + ctx->cipher_aes192_fb = NULL; return ret; } return _qcrypto_cra_ablkcipher_init(tfm); @@ -831,6 +955,68 @@ static int _qcrypto_cra_aead_sha256_init(struct crypto_tfm *tfm) return rc; } +static int _qcrypto_cra_aead_aes_sha1_init(struct crypto_tfm *tfm) +{ + int rc; + struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_priv *cp = &qcrypto_dev; + + tfm->crt_aead.reqsize = sizeof(struct qcrypto_cipher_req_ctx); + rc = _qcrypto_cipher_cra_init(tfm); + if (rc) + return rc; + ctx->cipher_aes192_fb = NULL; + ctx->ahash_aead_aes192_fb = NULL; + if (!cp->ce_support.aes_key_192) { + ctx->cipher_aes192_fb = crypto_alloc_ablkcipher( + "cbc(aes)", 0, 0); + if (IS_ERR(ctx->cipher_aes192_fb)) { + ctx->cipher_aes192_fb = NULL; + } else { + ctx->ahash_aead_aes192_fb = crypto_alloc_ahash( + "hmac(sha1)", 0, 0); + if (IS_ERR(ctx->ahash_aead_aes192_fb)) { + ctx->ahash_aead_aes192_fb = NULL; + crypto_free_ablkcipher(ctx->cipher_aes192_fb); + ctx->cipher_aes192_fb = NULL; + } + } + } + ctx->auth_alg = QCE_HASH_SHA1_HMAC; + return 0; +} + +static int _qcrypto_cra_aead_aes_sha256_init(struct crypto_tfm *tfm) +{ + int rc; + struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_priv *cp = &qcrypto_dev; + + tfm->crt_aead.reqsize = sizeof(struct qcrypto_cipher_req_ctx); + rc = _qcrypto_cipher_cra_init(tfm); + if (rc) + return rc; + ctx->cipher_aes192_fb = NULL; + ctx->ahash_aead_aes192_fb = NULL; + if (!cp->ce_support.aes_key_192) { + ctx->cipher_aes192_fb = crypto_alloc_ablkcipher( + "cbc(aes)", 0, 0); + if (IS_ERR(ctx->cipher_aes192_fb)) { + ctx->cipher_aes192_fb = NULL; + } else { + ctx->ahash_aead_aes192_fb = crypto_alloc_ahash( + "hmac(sha256)", 0, 0); + if (IS_ERR(ctx->ahash_aead_aes192_fb)) { + ctx->ahash_aead_aes192_fb = NULL; + crypto_free_ablkcipher(ctx->cipher_aes192_fb); + ctx->cipher_aes192_fb = NULL; + } + } + } + ctx->auth_alg = QCE_HASH_SHA256_HMAC; + return 0; +} + static int _qcrypto_cra_aead_ccm_init(struct crypto_tfm *tfm) { int rc; @@ -866,9 +1052,9 @@ static void _qcrypto_cra_aes_ablkcipher_exit(struct crypto_tfm *tfm) struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm); _qcrypto_cra_ablkcipher_exit(tfm); - if (ctx->fallback.cipher_fb) - crypto_free_ablkcipher(ctx->fallback.cipher_fb); - ctx->fallback.cipher_fb = NULL; + if (ctx->cipher_aes192_fb) + crypto_free_ablkcipher(ctx->cipher_aes192_fb); + ctx->cipher_aes192_fb = NULL; } static void _qcrypto_cra_aead_exit(struct crypto_tfm *tfm) @@ -877,7 +1063,21 @@ static void _qcrypto_cra_aead_exit(struct crypto_tfm *tfm) if (!list_empty(&ctx->rsp_queue)) pr_err("_qcrypto__cra_aead_exit: requests still outstanding"); -}; +} + +static void _qcrypto_cra_aead_aes_exit(struct crypto_tfm *tfm) +{ + struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!list_empty(&ctx->rsp_queue)) + pr_err("_qcrypto__cra_aead_exit: requests still outstanding"); + if (ctx->cipher_aes192_fb) + crypto_free_ablkcipher(ctx->cipher_aes192_fb); + if (ctx->ahash_aead_aes192_fb) + crypto_free_ahash(ctx->ahash_aead_aes192_fb); + ctx->cipher_aes192_fb = NULL; + ctx->ahash_aead_aes192_fb = NULL; +} static int _disp_stats(int id) { @@ -886,6 +1086,7 @@ static int _disp_stats(int id) unsigned long flags; struct crypto_priv *cp = &qcrypto_dev; struct crypto_engine *pe; + int i; pstat = &_qcrypto_stat; len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1, @@ -1007,6 +1208,18 @@ static int _disp_stats(int id) len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1, " AHASH operation fail : %llu\n", pstat->ahash_op_fail); + len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1, + " resp start, resp stop, max rsp queue reorder-cnt : %u %u %u %u\n", + cp->resp_start, cp->resp_stop, + cp->max_resp_qlen, cp->max_reorder_cnt); + len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1, + " max queue legnth, no avail : %u %u\n", + cp->max_qlen, cp->no_avail); + len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1, + " work queue : %u %u %u\n", + cp->queue_work_eng3, + cp->queue_work_not_eng3, + cp->queue_work_not_eng3_nz); len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1, "\n"); spin_lock_irqsave(&cp->lock, flags); @@ -1014,8 +1227,9 @@ static int _disp_stats(int id) len += scnprintf( _debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1, - " Engine %4d Req : %llu\n", + " Engine %4d Req max %d : %llu\n", pe->unit, + pe->max_req_used, pe->total_req ); len += scnprintf( @@ -1025,8 +1239,17 @@ static int _disp_stats(int id) pe->unit, pe->err_req ); + qce_get_driver_stats(pe->qce); } spin_unlock_irqrestore(&cp->lock, flags); + + for (i = 0; i < MAX_SMP_CPU+1; i++) + if (cp->cpu_req[i]) + len += scnprintf( + _debug_read_buf + len, + DEBUG_MAX_RW_BUF - len - 1, + "CPU %d Issue Req : %d\n", + i, cp->cpu_req[i]); return len; } @@ -1036,18 +1259,29 @@ static void _qcrypto_remove_engine(struct crypto_engine *pengine) struct qcrypto_alg *q_alg; struct qcrypto_alg *n; unsigned long flags; + struct crypto_engine *pe; cp = pengine->pcp; spin_lock_irqsave(&cp->lock, flags); list_del(&pengine->elist); + if (pengine->first_engine) { + cp->first_engine = NULL; + pe = list_first_entry(&cp->engine_list, struct crypto_engine, + elist); + if (pe) { + pe->first_engine = true; + cp->first_engine = pe; + } + } if (cp->next_engine == pengine) cp->next_engine = NULL; + if (cp->scheduled_eng == pengine) + cp->scheduled_eng = NULL; spin_unlock_irqrestore(&cp->lock, flags); cp->total_units--; - tasklet_kill(&pengine->done_tasklet); cancel_work_sync(&pengine->bw_reaper_ws); cancel_work_sync(&pengine->bw_allocate_ws); del_timer_sync(&pengine->bw_reaper_timer); @@ -1056,6 +1290,8 @@ static void _qcrypto_remove_engine(struct crypto_engine *pengine) msm_bus_scale_unregister_client(pengine->bus_scale_handle); pengine->bus_scale_handle = 0; + kzfree(pengine->preq_pool); + if (cp->total_units) return; @@ -1115,10 +1351,10 @@ static int _qcrypto_setkey_aes_192_fallback(struct crypto_ablkcipher *cipher, int ret; ctx->enc_key_len = AES_KEYSIZE_192; - ctx->fallback.cipher_fb->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; - ctx->fallback.cipher_fb->base.crt_flags |= + ctx->cipher_aes192_fb->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + ctx->cipher_aes192_fb->base.crt_flags |= (cipher->base.crt_flags & CRYPTO_TFM_REQ_MASK); - ret = crypto_ablkcipher_setkey(ctx->fallback.cipher_fb, key, + ret = crypto_ablkcipher_setkey(ctx->cipher_aes192_fb, key, AES_KEYSIZE_192); if (ret) { tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; @@ -1139,7 +1375,7 @@ static int _qcrypto_setkey_aes(struct crypto_ablkcipher *cipher, const u8 *key, return 0; if ((len == AES_KEYSIZE_192) && (!cp->ce_support.aes_key_192) - && ctx->fallback.cipher_fb) + && ctx->cipher_aes192_fb) return _qcrypto_setkey_aes_192_fallback(cipher, key); if (_qcrypto_check_aes_keylen(cipher, cp, len)) { @@ -1248,14 +1484,80 @@ static int _qcrypto_setkey_3des(struct crypto_ablkcipher *cipher, const u8 *key, return 0; }; -static void _qcrypto_tfm_complete(struct crypto_priv *cp, u32 type, - void *tfm_ctx) +static void seq_response(struct work_struct *work) { + struct crypto_priv *cp = container_of(work, struct crypto_priv, + resp_work); + struct llist_node *list; + struct llist_node *rev = NULL; + struct crypto_engine *pengine; + unsigned long flags; + int total_unit; + +again: + list = llist_del_all(&cp->ordered_resp_list); + + if (!list) + goto end; + + while (list) { + struct llist_node *t = list; + list = llist_next(list); + + t->next = rev; + rev = t; + } + + while (rev) { + struct qcrypto_resp_ctx *arsp; + struct crypto_async_request *areq; + + arsp = container_of(rev, struct qcrypto_resp_ctx, llist); + rev = llist_next(rev); + + areq = arsp->async_req; + local_bh_disable(); + areq->complete(areq, arsp->res); + local_bh_enable(); + atomic_dec(&cp->resp_cnt); + } + + if (atomic_read(&cp->resp_cnt) < COMPLETION_CB_BACKLOG_LENGTH_START && + (cmpxchg(&cp->ce_req_proc_sts, STOPPED, IN_PROGRESS) + == STOPPED)) { + cp->resp_start++; + for (total_unit = cp->total_units; total_unit-- > 0;) { + spin_lock_irqsave(&cp->lock, flags); + pengine = _avail_eng(cp); + spin_unlock_irqrestore(&cp->lock, flags); + if (pengine) + _start_qcrypto_process(cp, pengine); + else + break; + } + } +end: + if (cmpxchg(&cp->sched_resp_workq_status, SCHEDULE_AGAIN, + IS_SCHEDULED) == SCHEDULE_AGAIN) + goto again; + else if (cmpxchg(&cp->sched_resp_workq_status, IS_SCHEDULED, + NOT_SCHEDULED) == SCHEDULE_AGAIN) + goto end; +} + +#define SCHEUDLE_RSP_QLEN_THRESHOLD 64 + +static void _qcrypto_tfm_complete(struct crypto_engine *pengine, u32 type, + void *tfm_ctx, + struct qcrypto_resp_ctx *cur_arsp, + int res) +{ + struct crypto_priv *cp = pengine->pcp; unsigned long flags; struct qcrypto_resp_ctx *arsp; struct list_head *plist; - struct crypto_async_request *areq; - bool pending_list; + unsigned int resp_qlen; + unsigned int cnt = 0; switch (type) { case CRYPTO_ALG_TYPE_AHASH: @@ -1267,66 +1569,108 @@ static void _qcrypto_tfm_complete(struct crypto_priv *cp, u32 type, plist = &((struct qcrypto_cipher_ctx *) tfm_ctx)->rsp_queue; break; } -again: + spin_lock_irqsave(&cp->lock, flags); - if (list_empty(plist)) { - arsp = NULL; /* nothing to do */ - pending_list = false; - } else { + + cur_arsp->res = res; + while (!list_empty(plist)) { arsp = list_first_entry(plist, - struct qcrypto_resp_ctx, list); + struct qcrypto_resp_ctx, list); if (arsp->res == -EINPROGRESS) - arsp = NULL; /* still in progress */ - else - list_del(&arsp->list); /* request is complete */ - if (list_empty(plist)) - pending_list = false; - else - pending_list = true; + break; + else { + list_del(&arsp->list); + llist_add(&arsp->llist, &cp->ordered_resp_list); + atomic_inc(&cp->resp_cnt); + cnt++; + } + } + resp_qlen = atomic_read(&cp->resp_cnt); + if (resp_qlen > cp->max_resp_qlen) + cp->max_resp_qlen = resp_qlen; + if (cnt > cp->max_reorder_cnt) + cp->max_reorder_cnt = cnt; + if ((resp_qlen >= COMPLETION_CB_BACKLOG_LENGTH_STOP) && + cmpxchg(&cp->ce_req_proc_sts, IN_PROGRESS, + STOPPED) == IN_PROGRESS) { + cp->resp_stop++; } + spin_unlock_irqrestore(&cp->lock, flags); - if (arsp) { - areq = arsp->async_req; - areq->complete(areq, arsp->res); - if (pending_list) - goto again; + +retry: + if (!llist_empty(&cp->ordered_resp_list)) { + unsigned int cpu; + + if (pengine->first_engine) { + cpu = WORK_CPU_UNBOUND; + cp->queue_work_eng3++; + } else { + cp->queue_work_not_eng3++; + cpu = cp->cpu_getting_irqs_frm_first_ce; + /* + * If source not the first engine, and there + * are outstanding requests going on first engine, + * skip scheduling of work queue to anticipate + * more may be coming. If the response queue + * length exceeds threshold, to avoid further + * delay, schedule work queue immediately. + */ + if (cp->first_engine && atomic_read( + &cp->first_engine->req_count)) { + if (resp_qlen < SCHEUDLE_RSP_QLEN_THRESHOLD) + return; + cp->queue_work_not_eng3_nz++; + } + } + if (cmpxchg(&cp->sched_resp_workq_status, NOT_SCHEDULED, + IS_SCHEDULED) == NOT_SCHEDULED) + queue_work_on(cpu, cp->resp_wq, &cp->resp_work); + else if (cmpxchg(&cp->sched_resp_workq_status, IS_SCHEDULED, + SCHEDULE_AGAIN) == NOT_SCHEDULED) + goto retry; } } -static void req_done(unsigned long data) +static void req_done(struct qcrypto_req_control *pqcrypto_req_control) { + struct crypto_engine *pengine; struct crypto_async_request *areq; - struct crypto_engine *pengine = (struct crypto_engine *)data; struct crypto_priv *cp; - unsigned long flags; struct qcrypto_resp_ctx *arsp; - int res; u32 type = 0; void *tfm_ctx = NULL; + unsigned int cpu; + int res; + pengine = pqcrypto_req_control->pce; cp = pengine->pcp; - spin_lock_irqsave(&cp->lock, flags); - areq = pengine->req; + areq = pqcrypto_req_control->req; + arsp = pqcrypto_req_control->arsp; + res = pqcrypto_req_control->res; + qcrypto_free_req_control(pengine, pqcrypto_req_control); - arsp = pengine->arsp; - res = pengine->res; - pengine->req = NULL; - pengine->arsp = NULL; if (areq) { type = crypto_tfm_alg_type(areq->tfm); tfm_ctx = crypto_tfm_ctx(areq->tfm); - arsp->res = res; } - spin_unlock_irqrestore(&cp->lock, flags); - _start_qcrypto_process(cp, pengine); + cpu = smp_processor_id(); + pengine->irq_cpu = cpu; + if (pengine->first_engine) { + if (cpu != cp->cpu_getting_irqs_frm_first_ce) + cp->cpu_getting_irqs_frm_first_ce = cpu; + } if (areq) - _qcrypto_tfm_complete(cp, type, tfm_ctx); + _qcrypto_tfm_complete(pengine, type, tfm_ctx, arsp, res); + if (ACCESS_ONCE(cp->ce_req_proc_sts) == IN_PROGRESS) + _start_qcrypto_process(cp, pengine); } static void _qce_ahash_complete(void *cookie, unsigned char *digest, unsigned char *authdata, int ret) { struct ahash_request *areq = (struct ahash_request *) cookie; + struct crypto_async_request *async_req; struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(areq->base.tfm); struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(areq); @@ -1335,17 +1679,27 @@ static void _qce_ahash_complete(void *cookie, unsigned char *digest, uint32_t diglen = crypto_ahash_digestsize(ahash); uint32_t *auth32 = (uint32_t *)authdata; struct crypto_engine *pengine; + struct qcrypto_req_control *pqcrypto_req_control; + async_req = &areq->base; pstat = &_qcrypto_stat; pengine = rctx->pengine; + pqcrypto_req_control = find_req_control_for_areq(pengine, + async_req); + if (pqcrypto_req_control == NULL) { + pr_err("async request not found\n"); + return; + } + #ifdef QCRYPTO_DEBUG dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %pK ret %d\n", areq, ret); #endif if (digest) { memcpy(rctx->digest, digest, diglen); - memcpy(areq->result, digest, diglen); + if (rctx->last_blk) + memcpy(areq->result, digest, diglen); } if (authdata) { rctx->byte_count[0] = auth32[0]; @@ -1360,34 +1714,43 @@ static void _qce_ahash_complete(void *cookie, unsigned char *digest, rctx->first_blk = 0; if (ret) { - pengine->res = -ENXIO; + pqcrypto_req_control->res = -ENXIO; pstat->ahash_op_fail++; } else { - pengine->res = 0; + pqcrypto_req_control->res = 0; pstat->ahash_op_success++; } if (cp->ce_support.aligned_only) { areq->src = rctx->orig_src; kfree(rctx->data); } - - tasklet_schedule(&pengine->done_tasklet); + req_done(pqcrypto_req_control); }; static void _qce_ablk_cipher_complete(void *cookie, unsigned char *icb, unsigned char *iv, int ret) { struct ablkcipher_request *areq = (struct ablkcipher_request *) cookie; + struct crypto_async_request *async_req; struct crypto_ablkcipher *ablk = crypto_ablkcipher_reqtfm(areq); struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(areq->base.tfm); struct crypto_priv *cp = ctx->cp; struct crypto_stat *pstat; struct qcrypto_cipher_req_ctx *rctx; struct crypto_engine *pengine; + struct qcrypto_req_control *pqcrypto_req_control; + async_req = &areq->base; pstat = &_qcrypto_stat; rctx = ablkcipher_request_ctx(areq); pengine = rctx->pengine; + pqcrypto_req_control = find_req_control_for_areq(pengine, + async_req); + if (pqcrypto_req_control == NULL) { + pr_err("async request not found\n"); + return; + } + #ifdef QCRYPTO_DEBUG dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %pK ret %d\n", areq, ret); @@ -1396,10 +1759,10 @@ static void _qce_ablk_cipher_complete(void *cookie, unsigned char *icb, memcpy(ctx->iv, iv, crypto_ablkcipher_ivsize(ablk)); if (ret) { - pengine->res = -ENXIO; + pqcrypto_req_control->res = -ENXIO; pstat->ablk_cipher_op_fail++; } else { - pengine->res = 0; + pqcrypto_req_control->res = 0; pstat->ablk_cipher_op_success++; } @@ -1420,8 +1783,7 @@ static void _qce_ablk_cipher_complete(void *cookie, unsigned char *icb, areq->nbytes); kzfree(rctx->data); } - - tasklet_schedule(&pengine->done_tasklet); + req_done(pqcrypto_req_control); }; @@ -1429,16 +1791,25 @@ static void _qce_aead_complete(void *cookie, unsigned char *icv, unsigned char *iv, int ret) { struct aead_request *areq = (struct aead_request *) cookie; + struct crypto_async_request *async_req; struct crypto_aead *aead = crypto_aead_reqtfm(areq); struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(areq->base.tfm); struct crypto_priv *cp = ctx->cp; struct qcrypto_cipher_req_ctx *rctx; struct crypto_stat *pstat; struct crypto_engine *pengine; + struct qcrypto_req_control *pqcrypto_req_control; + async_req = &areq->base; pstat = &_qcrypto_stat; rctx = aead_request_ctx(areq); pengine = rctx->pengine; + pqcrypto_req_control = find_req_control_for_areq(pengine, + async_req); + if (pqcrypto_req_control == NULL) { + pr_err("async request not found\n"); + return; + } if (rctx->mode == QCE_MODE_CCM) { if (cp->ce_support.aligned_only) { @@ -1534,9 +1905,8 @@ static void _qce_aead_complete(void *cookie, unsigned char *icv, else pstat->aead_op_success++; - pengine->res = ret; - - tasklet_schedule(&pengine->done_tasklet); + pqcrypto_req_control->res = ret; + req_done(pqcrypto_req_control); } static int aead_ccm_set_msg_len(u8 *block, unsigned int msglen, int csize) @@ -1628,8 +1998,9 @@ static int qcrypto_aead_ccm_format_adata(struct qce_req *qreq, uint32_t alen, } static int _qcrypto_process_ablkcipher(struct crypto_engine *pengine, - struct crypto_async_request *async_req) + struct qcrypto_req_control *pqcrypto_req_control) { + struct crypto_async_request *async_req; struct qce_req qreq; int ret; struct qcrypto_cipher_req_ctx *rctx; @@ -1637,6 +2008,7 @@ static int _qcrypto_process_ablkcipher(struct crypto_engine *pengine, struct ablkcipher_request *req; struct crypto_ablkcipher *tfm; + async_req = pqcrypto_req_control->req; req = container_of(async_req, struct ablkcipher_request, base); cipher_ctx = crypto_tfm_ctx(async_req->tfm); rctx = ablkcipher_request_ctx(req); @@ -1692,14 +2064,16 @@ static int _qcrypto_process_ablkcipher(struct crypto_engine *pengine, } static int _qcrypto_process_ahash(struct crypto_engine *pengine, - struct crypto_async_request *async_req) + struct qcrypto_req_control *pqcrypto_req_control) { + struct crypto_async_request *async_req; struct ahash_request *req; struct qce_sha_req sreq; struct qcrypto_sha_req_ctx *rctx; struct qcrypto_sha_ctx *sha_ctx; int ret = 0; + async_req = pqcrypto_req_control->req; req = container_of(async_req, struct ahash_request, base); rctx = ahash_request_ctx(req); @@ -1749,16 +2123,19 @@ static int _qcrypto_process_ahash(struct crypto_engine *pengine, } static int _qcrypto_process_aead(struct crypto_engine *pengine, - struct crypto_async_request *async_req) + struct qcrypto_req_control *pqcrypto_req_control) { + struct crypto_async_request *async_req; struct qce_req qreq; int ret = 0; struct qcrypto_cipher_req_ctx *rctx; struct qcrypto_cipher_ctx *cipher_ctx; - struct aead_request *req = container_of(async_req, - struct aead_request, base); - struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct aead_request *req; + struct crypto_aead *aead; + async_req = pqcrypto_req_control->req; + req = container_of(async_req, struct aead_request, base); + aead = crypto_aead_reqtfm(req); rctx = aead_request_ctx(req); rctx->pengine = pengine; cipher_ctx = crypto_tfm_ctx(async_req->tfm); @@ -1988,12 +2365,25 @@ static int _start_qcrypto_process(struct crypto_priv *cp, struct ahash_request *ahash_req; struct aead_request *aead_req; struct qcrypto_resp_ctx *arsp; + struct qcrypto_req_control *pqcrypto_req_control; + unsigned int cpu = MAX_SMP_CPU; + + if (ACCESS_ONCE(cp->ce_req_proc_sts) == STOPPED) + return 0; + + if (in_interrupt()) { + cpu = smp_processor_id(); + if (cpu >= MAX_SMP_CPU) + cpu = MAX_SMP_CPU - 1; + } else + cpu = MAX_SMP_CPU; pstat = &_qcrypto_stat; again: spin_lock_irqsave(&cp->lock, flags); - if (pengine->req) { + if (pengine->issue_req || + atomic_read(&pengine->req_count) >= (pengine->max_req)) { spin_unlock_irqrestore(&cp->lock, flags); return 0; } @@ -2020,6 +2410,12 @@ again: return 0; } } + pqcrypto_req_control = qcrypto_alloc_req_control(pengine); + if (pqcrypto_req_control == NULL) { + pr_err("Allocation of request failed\n"); + spin_unlock_irqrestore(&cp->lock, flags); + return 0; + } /* add associated rsp entry to tfm response queue */ type = crypto_tfm_alg_type(async_req->tfm); @@ -2042,7 +2438,7 @@ again: arsp = &cipher_rctx->rsp_entry; list_add_tail( &arsp->list, - &((struct qcrypto_sha_ctx *)tfm_ctx) + &((struct qcrypto_cipher_ctx *)tfm_ctx) ->rsp_queue); break; case CRYPTO_ALG_TYPE_AEAD: @@ -2053,18 +2449,23 @@ again: arsp = &cipher_rctx->rsp_entry; list_add_tail( &arsp->list, - &((struct qcrypto_sha_ctx *)tfm_ctx) + &((struct qcrypto_cipher_ctx *)tfm_ctx) ->rsp_queue); break; } arsp->res = -EINPROGRESS; arsp->async_req = async_req; - pengine->req = async_req; - pengine->arsp = arsp; + pqcrypto_req_control->pce = pengine; + pqcrypto_req_control->req = async_req; + pqcrypto_req_control->arsp = arsp; pengine->active_seq++; pengine->check_flag = true; + pengine->issue_req = true; + cp->cpu_req[cpu]++; + smp_mb(); /* make it visible */ + spin_unlock_irqrestore(&cp->lock, flags); if (backlog_eng) backlog_eng->complete(backlog_eng, -EINPROGRESS); @@ -2072,25 +2473,26 @@ again: backlog_cp->complete(backlog_cp, -EINPROGRESS); switch (type) { case CRYPTO_ALG_TYPE_ABLKCIPHER: - ret = _qcrypto_process_ablkcipher(pengine, async_req); + ret = _qcrypto_process_ablkcipher(pengine, + pqcrypto_req_control); break; case CRYPTO_ALG_TYPE_AHASH: - ret = _qcrypto_process_ahash(pengine, async_req); + ret = _qcrypto_process_ahash(pengine, pqcrypto_req_control); break; case CRYPTO_ALG_TYPE_AEAD: - ret = _qcrypto_process_aead(pengine, async_req); + ret = _qcrypto_process_aead(pengine, pqcrypto_req_control); break; default: ret = -EINVAL; }; + + pengine->issue_req = false; + smp_mb(); /* make it visible */ + pengine->total_req++; if (ret) { - arsp->res = ret; pengine->err_req++; - spin_lock_irqsave(&cp->lock, flags); - pengine->req = NULL; - pengine->arsp = NULL; - spin_unlock_irqrestore(&cp->lock, flags); + qcrypto_free_req_control(pengine, pqcrypto_req_control); if (type == CRYPTO_ALG_TYPE_ABLKCIPHER) pstat->ablk_cipher_op_fail++; @@ -2100,21 +2502,49 @@ again: else pstat->aead_op_fail++; - _qcrypto_tfm_complete(cp, type, tfm_ctx); + _qcrypto_tfm_complete(pengine, type, tfm_ctx, arsp, ret); goto again; }; return ret; } +static inline struct crypto_engine *_next_eng(struct crypto_priv *cp, + struct crypto_engine *p) +{ + + if (p == NULL || list_is_last(&p->elist, &cp->engine_list)) + p = list_first_entry(&cp->engine_list, struct crypto_engine, + elist); + else + p = list_entry(p->elist.next, struct crypto_engine, elist); + return p; +} static struct crypto_engine *_avail_eng(struct crypto_priv *cp) { - struct crypto_engine *pe = NULL; + /* call this function with spinlock set */ + struct crypto_engine *q = NULL; + struct crypto_engine *p = cp->scheduled_eng; + struct crypto_engine *q1; + int eng_cnt = cp->total_units; - list_for_each_entry(pe, &cp->engine_list, elist) { - if (pe->req == NULL) - return pe; + if (unlikely(list_empty(&cp->engine_list))) { + pr_err("%s: no valid ce to schedule\n", __func__); + return NULL; } - return NULL; + + p = _next_eng(cp, p); + q1 = p; + while (eng_cnt-- > 0) { + if (!p->issue_req && atomic_read(&p->req_count) < p->max_req) { + q = p; + break; + } + p = _next_eng(cp, p); + if (q1 == p) + break; + } + cp->scheduled_eng = q; + return q; } static int _qcrypto_queue_req(struct crypto_priv *cp, @@ -2131,6 +2561,8 @@ static int _qcrypto_queue_req(struct crypto_priv *cp, } else { ret = crypto_enqueue_request(&cp->req_queue, req); pengine = _avail_eng(cp); + if (cp->req_queue.qlen > cp->max_qlen) + cp->max_qlen = cp->req_queue.qlen; } if (pengine) { switch (pengine->bw_state) { @@ -2156,9 +2588,11 @@ static int _qcrypto_queue_req(struct crypto_priv *cp, pengine = NULL; break; } + } else { + cp->no_avail++; } spin_unlock_irqrestore(&cp->lock, flags); - if (pengine) + if (pengine && (ACCESS_ONCE(cp->ce_req_proc_sts) == IN_PROGRESS)) _start_qcrypto_process(cp, pengine); return ret; } @@ -2170,7 +2604,7 @@ static int _qcrypto_enc_aes_192_fallback(struct ablkcipher_request *req) struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); int err; - ablkcipher_request_set_tfm(req, ctx->fallback.cipher_fb); + ablkcipher_request_set_tfm(req, ctx->cipher_aes192_fb); err = crypto_ablkcipher_encrypt(req); ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm)); return err; @@ -2183,7 +2617,7 @@ static int _qcrypto_dec_aes_192_fallback(struct ablkcipher_request *req) struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); int err; - ablkcipher_request_set_tfm(req, ctx->fallback.cipher_fb); + ablkcipher_request_set_tfm(req, ctx->cipher_aes192_fb); err = crypto_ablkcipher_decrypt(req); ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm)); return err; @@ -2207,7 +2641,7 @@ static int _qcrypto_enc_aes_ecb(struct ablkcipher_request *req) if ((ctx->enc_key_len == AES_KEYSIZE_192) && (!cp->ce_support.aes_key_192) && - ctx->fallback.cipher_fb) + ctx->cipher_aes192_fb) return _qcrypto_enc_aes_192_fallback(req); rctx = ablkcipher_request_ctx(req); @@ -2237,7 +2671,7 @@ static int _qcrypto_enc_aes_cbc(struct ablkcipher_request *req) if ((ctx->enc_key_len == AES_KEYSIZE_192) && (!cp->ce_support.aes_key_192) && - ctx->fallback.cipher_fb) + ctx->cipher_aes192_fb) return _qcrypto_enc_aes_192_fallback(req); rctx = ablkcipher_request_ctx(req); @@ -2267,7 +2701,7 @@ static int _qcrypto_enc_aes_ctr(struct ablkcipher_request *req) if ((ctx->enc_key_len == AES_KEYSIZE_192) && (!cp->ce_support.aes_key_192) && - ctx->fallback.cipher_fb) + ctx->cipher_aes192_fb) return _qcrypto_enc_aes_192_fallback(req); rctx = ablkcipher_request_ctx(req); @@ -2451,7 +2885,7 @@ static int _qcrypto_dec_aes_ecb(struct ablkcipher_request *req) if ((ctx->enc_key_len == AES_KEYSIZE_192) && (!cp->ce_support.aes_key_192) && - ctx->fallback.cipher_fb) + ctx->cipher_aes192_fb) return _qcrypto_dec_aes_192_fallback(req); rctx = ablkcipher_request_ctx(req); @@ -2481,7 +2915,7 @@ static int _qcrypto_dec_aes_cbc(struct ablkcipher_request *req) if ((ctx->enc_key_len == AES_KEYSIZE_192) && (!cp->ce_support.aes_key_192) && - ctx->fallback.cipher_fb) + ctx->cipher_aes192_fb) return _qcrypto_dec_aes_192_fallback(req); rctx = ablkcipher_request_ctx(req); @@ -2511,7 +2945,7 @@ static int _qcrypto_dec_aes_ctr(struct ablkcipher_request *req) if ((ctx->enc_key_len == AES_KEYSIZE_192) && (!cp->ce_support.aes_key_192) && - ctx->fallback.cipher_fb) + ctx->cipher_aes192_fb) return _qcrypto_dec_aes_192_fallback(req); rctx = ablkcipher_request_ctx(req); @@ -2733,6 +3167,7 @@ static int _qcrypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(tfm); struct rtattr *rta = (struct rtattr *)key; struct crypto_authenc_key_param *param; + int ret; if (!RTA_OK(rta, keylen)) goto badkey; @@ -2758,6 +3193,20 @@ static int _qcrypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, memcpy(ctx->enc_key, key + ctx->auth_key_len, ctx->enc_key_len); memcpy(ctx->auth_key, key, ctx->auth_key_len); + if (ctx->enc_key_len == AES_KEYSIZE_192 && ctx->cipher_aes192_fb && + ctx->ahash_aead_aes192_fb) { + crypto_ahash_clear_flags(ctx->ahash_aead_aes192_fb, ~0); + ret = crypto_ahash_setkey(ctx->ahash_aead_aes192_fb, + ctx->auth_key, ctx->auth_key_len); + if (ret) + goto badkey; + crypto_ablkcipher_clear_flags(ctx->cipher_aes192_fb, ~0); + ret = crypto_ablkcipher_setkey(ctx->cipher_aes192_fb, + ctx->enc_key, ctx->enc_key_len); + if (ret) + goto badkey; + } + return 0; badkey: ctx->enc_key_len = 0; @@ -2807,6 +3256,253 @@ static int _qcrypto_aead_rfc4309_ccm_setkey(struct crypto_aead *aead, return ret; }; +static void _qcrypto_aead_aes_192_fb_a_cb(struct qcrypto_cipher_req_ctx *rctx, + int res) +{ + struct aead_request *req; + struct crypto_async_request *areq; + + req = rctx->aead_req; + areq = &req->base; + if (rctx->fb_aes_req) + ablkcipher_request_free(rctx->fb_aes_req); + if (rctx->fb_hash_req) + ahash_request_free(rctx->fb_hash_req); + rctx->fb_aes_req = NULL; + rctx->fb_hash_req = NULL; + kfree(rctx->fb_ahash_assoc_iv); + kfree(rctx->fb_aes_iv); + areq->complete(areq, res); +} + +static void _aead_aes_fb_stage2_ahash_complete( + struct crypto_async_request *base, int err) +{ + struct qcrypto_cipher_req_ctx *rctx; + struct aead_request *req; + struct qcrypto_cipher_ctx *ctx; + + rctx = base->data; + req = rctx->aead_req; + ctx = crypto_tfm_ctx(req->base.tfm); + /* copy icv */ + if (err == 0) + scatterwalk_map_and_copy(rctx->fb_ahash_digest, + req->dst, + req->cryptlen, + ctx->authsize, 1); + _qcrypto_aead_aes_192_fb_a_cb(rctx, err); +} + + +static int _start_aead_aes_fb_stage2_hmac(struct qcrypto_cipher_req_ctx *rctx) +{ + struct ahash_request *ahash_req; + + ahash_req = rctx->fb_hash_req; + ahash_request_set_callback(ahash_req, CRYPTO_TFM_REQ_MAY_BACKLOG, + _aead_aes_fb_stage2_ahash_complete, rctx); + + return crypto_ahash_digest(ahash_req); +} + +static void _aead_aes_fb_stage2_decrypt_complete( + struct crypto_async_request *base, int err) +{ + struct qcrypto_cipher_req_ctx *rctx; + + rctx = base->data; + _qcrypto_aead_aes_192_fb_a_cb(rctx, err); +} + +static int _start_aead_aes_fb_stage2_decrypt( + struct qcrypto_cipher_req_ctx *rctx) +{ + struct ablkcipher_request *aes_req; + + aes_req = rctx->fb_aes_req; + ablkcipher_request_set_callback(aes_req, CRYPTO_TFM_REQ_MAY_BACKLOG, + _aead_aes_fb_stage2_decrypt_complete, rctx); + return crypto_ablkcipher_decrypt(aes_req); +} + +static void _aead_aes_fb_stage1_ahash_complete( + struct crypto_async_request *base, int err) +{ + struct qcrypto_cipher_req_ctx *rctx; + struct aead_request *req; + struct qcrypto_cipher_ctx *ctx; + + rctx = base->data; + req = rctx->aead_req; + ctx = crypto_tfm_ctx(req->base.tfm); + + /* compare icv */ + if (err == 0) { + unsigned char tmp[ctx->authsize]; + + scatterwalk_map_and_copy(tmp, req->src, + req->cryptlen - ctx->authsize, ctx->authsize, 0); + if (memcmp(rctx->fb_ahash_digest, tmp, ctx->authsize) != 0) + err = -EBADMSG; + } + if (err) + _qcrypto_aead_aes_192_fb_a_cb(rctx, err); + else { + err = _start_aead_aes_fb_stage2_decrypt(rctx); + if (err != -EINPROGRESS && err != -EBUSY) + _qcrypto_aead_aes_192_fb_a_cb(rctx, err); + } +} + +static void _aead_aes_fb_stage1_encrypt_complete( + struct crypto_async_request *base, int err) +{ + struct qcrypto_cipher_req_ctx *rctx; + struct aead_request *req; + struct qcrypto_cipher_ctx *ctx; + + rctx = base->data; + req = rctx->aead_req; + ctx = crypto_tfm_ctx(req->base.tfm); + + memcpy(ctx->iv, rctx->fb_aes_iv, rctx->ivsize); + + if (err) { + _qcrypto_aead_aes_192_fb_a_cb(rctx, err); + return; + } + + err = _start_aead_aes_fb_stage2_hmac(rctx); + + /* copy icv */ + if (err == 0) { + scatterwalk_map_and_copy(rctx->fb_ahash_digest, + req->dst, + req->cryptlen, + ctx->authsize, 1); + } + if (err != -EINPROGRESS && err != -EBUSY) + _qcrypto_aead_aes_192_fb_a_cb(rctx, err); +} + +static int _qcrypto_aead_aes_192_fallback(struct aead_request *req, + bool is_encrypt) +{ + struct qcrypto_cipher_req_ctx *rctx = aead_request_ctx(req); + struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct crypto_aead *aead_tfm = crypto_aead_reqtfm(req); + struct ablkcipher_request *aes_req = NULL; + struct ahash_request *ahash_req = NULL; + int rc = -EINVAL; + int nbytes; + int num_sg; + + rctx->fb_ahash_assoc_iv = NULL; + rctx->fb_aes_iv = NULL; + aes_req = ablkcipher_request_alloc(ctx->cipher_aes192_fb, GFP_KERNEL); + if (!aes_req) + return -ENOMEM; + ahash_req = ahash_request_alloc(ctx->ahash_aead_aes192_fb, GFP_KERNEL); + if (!ahash_req) + goto ret; + rctx->fb_aes_req = aes_req; + rctx->fb_hash_req = ahash_req; + rctx->aead_req = req; + num_sg = qcrypto_count_sg(req->assoc, req->assoclen); + rctx->fb_ahash_assoc_iv = kzalloc(req->assoclen + + crypto_aead_ivsize(aead_tfm), GFP_ATOMIC); + if (!rctx->fb_ahash_assoc_iv) + goto ret; + if (req->assoclen) + qcrypto_sg_copy_to_buffer(req->assoc, num_sg, + rctx->fb_ahash_assoc_iv, req->assoclen); + memcpy(rctx->fb_ahash_assoc_iv + req->assoclen, + req->iv, crypto_aead_ivsize(aead_tfm)); + memset(rctx->fb_ahash_sg, 0, sizeof(rctx->fb_ahash_sg)); + sg_set_buf(&rctx->fb_ahash_sg[0], rctx->fb_ahash_assoc_iv, + req->assoclen + crypto_aead_ivsize(aead_tfm)); + sg_mark_end(&rctx->fb_ahash_sg[1]); + + nbytes = req->cryptlen; + if (is_encrypt) { + sg_chain(&rctx->fb_ahash_sg[0], 2, req->dst); + } else { + sg_chain(&rctx->fb_ahash_sg[0], 2, req->src); + nbytes -= ctx->authsize; + } + rctx->fb_ahash_length = nbytes + crypto_aead_ivsize(aead_tfm) + + req->assoclen; + rctx->fb_aes_src = req->src; + rctx->fb_aes_dst = req->dst; + rctx->fb_aes_cryptlen = nbytes; + rctx->ivsize = crypto_aead_ivsize(aead_tfm); + rctx->fb_aes_iv = kzalloc(rctx->ivsize, GFP_ATOMIC); + if (!rctx->fb_aes_iv) + goto ret; + memcpy(rctx->fb_aes_iv, req->iv, rctx->ivsize); + ablkcipher_request_set_crypt(aes_req, rctx->fb_aes_src, + rctx->fb_aes_dst, + rctx->fb_aes_cryptlen, rctx->fb_aes_iv); + ahash_request_set_crypt(ahash_req, &rctx->fb_ahash_sg[0], + rctx->fb_ahash_digest, + rctx->fb_ahash_length); + + if (is_encrypt) { + + ablkcipher_request_set_callback(aes_req, + CRYPTO_TFM_REQ_MAY_BACKLOG, + _aead_aes_fb_stage1_encrypt_complete, rctx); + + rc = crypto_ablkcipher_encrypt(aes_req); + if (rc == 0) { + memcpy(ctx->iv, rctx->fb_aes_iv, rctx->ivsize); + rc = _start_aead_aes_fb_stage2_hmac(rctx); + if (rc == 0) { + /* copy icv */ + scatterwalk_map_and_copy(rctx->fb_ahash_digest, + req->dst, + req->cryptlen, + ctx->authsize, 1); + } + } + if (rc == -EINPROGRESS || rc == -EBUSY) + return rc; + goto ret; + + } else { + ahash_request_set_callback(ahash_req, + CRYPTO_TFM_REQ_MAY_BACKLOG, + _aead_aes_fb_stage1_ahash_complete, rctx); + + rc = crypto_ahash_digest(ahash_req); + if (rc == 0) { + unsigned char tmp[ctx->authsize]; + + /* compare icv */ + scatterwalk_map_and_copy(tmp, + req->src, req->cryptlen - ctx->authsize, + ctx->authsize, 0); + if (memcmp(rctx->fb_ahash_digest, tmp, + ctx->authsize) != 0) + rc = -EBADMSG; + else + rc = _start_aead_aes_fb_stage2_decrypt(rctx); + } + if (rc == -EINPROGRESS || rc == -EBUSY) + return rc; + goto ret; + } +ret: + if (aes_req) + ablkcipher_request_free(aes_req); + if (ahash_req) + ahash_request_free(ahash_req); + kfree(rctx->fb_ahash_assoc_iv); + kfree(rctx->fb_aes_iv); + return rc; +} + static int _qcrypto_aead_encrypt_aes_cbc(struct aead_request *req) { struct qcrypto_cipher_req_ctx *rctx; @@ -2827,10 +3523,14 @@ static int _qcrypto_aead_encrypt_aes_cbc(struct aead_request *req) rctx->dir = QCE_ENCRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->iv; + rctx->aead_req = req; if (ctx->auth_alg == QCE_HASH_SHA1_HMAC) pstat->aead_sha1_aes_enc++; else pstat->aead_sha256_aes_enc++; + if (ctx->enc_key_len == AES_KEYSIZE_192 && ctx->cipher_aes192_fb && + ctx->ahash_aead_aes192_fb) + return _qcrypto_aead_aes_192_fallback(req, true); return _qcrypto_queue_req(cp, ctx->pengine, &req->base); } @@ -2853,11 +3553,16 @@ static int _qcrypto_aead_decrypt_aes_cbc(struct aead_request *req) rctx->dir = QCE_DECRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->iv; + rctx->aead_req = req; if (ctx->auth_alg == QCE_HASH_SHA1_HMAC) pstat->aead_sha1_aes_dec++; else pstat->aead_sha256_aes_dec++; + + if (ctx->enc_key_len == AES_KEYSIZE_192 && ctx->cipher_aes192_fb && + ctx->ahash_aead_aes192_fb) + return _qcrypto_aead_aes_192_fallback(req, false); return _qcrypto_queue_req(cp, ctx->pengine, &req->base); } @@ -2878,6 +3583,7 @@ static int _qcrypto_aead_givencrypt_aes_cbc(struct aead_givcrypt_request *req) rctx->dir = QCE_ENCRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->giv; /* generated iv */ + rctx->aead_req = areq; memcpy(req->giv, ctx->iv, crypto_aead_ivsize(authenc)); /* avoid consecutive packets going out with same IV */ @@ -2887,6 +3593,11 @@ static int _qcrypto_aead_givencrypt_aes_cbc(struct aead_givcrypt_request *req) pstat->aead_sha1_aes_enc++; else pstat->aead_sha256_aes_enc++; + if (ctx->enc_key_len == AES_KEYSIZE_192 && ctx->cipher_aes192_fb && + ctx->ahash_aead_aes192_fb) { + areq->iv = req->giv; + return _qcrypto_aead_aes_192_fallback(areq, true); + } return _qcrypto_queue_req(cp, ctx->pengine, &areq->base); } @@ -2905,6 +3616,7 @@ static int _qcrypto_aead_encrypt_des_cbc(struct aead_request *req) rctx->dir = QCE_ENCRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->iv; + rctx->aead_req = req; if (ctx->auth_alg == QCE_HASH_SHA1_HMAC) pstat->aead_sha1_des_enc++; @@ -2928,6 +3640,7 @@ static int _qcrypto_aead_decrypt_des_cbc(struct aead_request *req) rctx->dir = QCE_DECRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->iv; + rctx->aead_req = req; if (ctx->auth_alg == QCE_HASH_SHA1_HMAC) pstat->aead_sha1_des_dec++; @@ -2953,6 +3666,7 @@ static int _qcrypto_aead_givencrypt_des_cbc(struct aead_givcrypt_request *req) rctx->dir = QCE_ENCRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->giv; /* generated iv */ + rctx->aead_req = areq; memcpy(req->giv, ctx->iv, crypto_aead_ivsize(authenc)); /* avoid consecutive packets going out with same IV */ @@ -2979,6 +3693,7 @@ static int _qcrypto_aead_encrypt_3des_cbc(struct aead_request *req) rctx->dir = QCE_ENCRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->iv; + rctx->aead_req = req; if (ctx->auth_alg == QCE_HASH_SHA1_HMAC) pstat->aead_sha1_3des_enc++; @@ -3002,6 +3717,7 @@ static int _qcrypto_aead_decrypt_3des_cbc(struct aead_request *req) rctx->dir = QCE_DECRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->iv; + rctx->aead_req = req; if (ctx->auth_alg == QCE_HASH_SHA1_HMAC) pstat->aead_sha1_3des_dec++; @@ -3027,6 +3743,7 @@ static int _qcrypto_aead_givencrypt_3des_cbc(struct aead_givcrypt_request *req) rctx->dir = QCE_ENCRYPT; rctx->mode = QCE_MODE_CBC; rctx->iv = req->giv; /* generated iv */ + rctx->aead_req = areq; memcpy(req->giv, ctx->iv, crypto_aead_ivsize(authenc)); /* avoid consecutive packets going out with same IV */ @@ -3302,8 +4019,8 @@ static int _sha_update(struct ahash_request *req, uint32_t sha_block_size) break; len += sg_last->length; sg_last = scatterwalk_sg_next(sg_last); - if (sg_last == NULL) { - pr_err("qcrypto: _sha_update, sg = NULL\n"); + if (NULL == sg_last) { + pr_err("qcrypto.c: _sha_update, sg_last = NULL"); break; } } @@ -3330,7 +4047,7 @@ static int _sha_update(struct ahash_request *req, uint32_t sha_block_size) if (sg_last) sg_mark_end(sg_last); else - pr_err("qcrypto: _sha_update, sg = NULL\n"); + pr_err("qcrypto: _sha_update, sg_last= NULL"); memset(rctx->sg, 0, sizeof(rctx->sg)); sg_set_buf(&rctx->sg[0], staging, rctx->trailing_buf_len); @@ -3338,12 +4055,11 @@ static int _sha_update(struct ahash_request *req, uint32_t sha_block_size) sg_chain(rctx->sg, 2, req->src); req->src = rctx->sg; } - } else { + } else if (sg_last) sg_mark_end(sg_last); else - pr_err("qcrypto: _sha_update, sg = NULL\n"); - } + pr_err("qcrypto.c: _sha_update, sg_last = NULL"); req->nbytes = nbytes; rctx->trailing_buf_len = trailing_buf_len; @@ -3511,7 +4227,7 @@ static int _sha_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, ret = wait_for_completion_interruptible( &ahash_req_complete); - init_completion(&sha_ctx->ahash_req_complete); + reinit_completion(&sha_ctx->ahash_req_complete); } kzfree(in_buf); @@ -3707,7 +4423,7 @@ static int _sha_hmac_inner_hash(struct ahash_request *req, if (ret == -EINPROGRESS || ret == -EBUSY) { ret = wait_for_completion_interruptible(&sha_ctx->ahash_req_complete); - init_completion(&sha_ctx->ahash_req_complete); + reinit_completion(&sha_ctx->ahash_req_complete); } return ret; @@ -3797,23 +4513,6 @@ static int _qcrypto_prefix_alg_cra_name(char cra_name[], unsigned int size) return 0; } -/* - * Fill up fips_selftest_data structure - */ - -static void _qcrypto_fips_selftest_d(struct fips_selftest_data *selftest_d, - struct ce_hw_support *ce_support, - char *prefix) -{ - strlcpy(selftest_d->algo_prefix, prefix, CRYPTO_MAX_ALG_NAME); - selftest_d->prefix_ahash_algo = ce_support->use_sw_ahash_algo; - selftest_d->prefix_hmac_algo = ce_support->use_sw_hmac_algo; - selftest_d->prefix_aes_xts_algo = ce_support->use_sw_aes_xts_algo; - selftest_d->prefix_aes_cbc_ecb_ctr_algo = - ce_support->use_sw_aes_cbc_ecb_ctr_algo; - selftest_d->prefix_aead_algo = ce_support->use_sw_aead_algo; - selftest_d->ce_device = ce_support->ce_device; -} int qcrypto_cipher_set_device(struct ablkcipher_request *req, unsigned int dev) { @@ -4287,8 +4986,8 @@ static struct crypto_alg _qcrypto_aead_sha1_hmac_algos[] = { .cra_alignmask = 0, .cra_type = &crypto_aead_type, .cra_module = THIS_MODULE, - .cra_init = _qcrypto_cra_aead_sha1_init, - .cra_exit = _qcrypto_cra_aead_exit, + .cra_init = _qcrypto_cra_aead_aes_sha1_init, + .cra_exit = _qcrypto_cra_aead_aes_exit, .cra_u = { .aead = { .ivsize = AES_BLOCK_SIZE, @@ -4365,8 +5064,8 @@ static struct crypto_alg _qcrypto_aead_sha256_hmac_algos[] = { .cra_alignmask = 0, .cra_type = &crypto_aead_type, .cra_module = THIS_MODULE, - .cra_init = _qcrypto_cra_aead_sha256_init, - .cra_exit = _qcrypto_cra_aead_exit, + .cra_init = _qcrypto_cra_aead_aes_sha256_init, + .cra_exit = _qcrypto_cra_aead_aes_exit, .cra_u = { .aead = { .ivsize = AES_BLOCK_SIZE, @@ -4493,10 +5192,7 @@ static int _qcrypto_probe(struct platform_device *pdev) struct msm_ce_hw_support *platform_support; struct crypto_engine *pengine; unsigned long flags; - - /* For FIPS140-2 Power on self tests */ - struct fips_selftest_data selftest_d; - char prefix[10] = ""; + struct qcrypto_req_control *pqcrypto_req_control = NULL; pengine = kzalloc(sizeof(*pengine), GFP_KERNEL); if (!pengine) { @@ -4517,7 +5213,6 @@ static int _qcrypto_probe(struct platform_device *pdev) pengine->qce = handle; pengine->pcp = cp; pengine->pdev = pdev; - pengine->req = NULL; pengine->signature = 0xdeadbeef; init_timer(&(pengine->bw_reaper_timer)); @@ -4529,8 +5224,9 @@ static int _qcrypto_probe(struct platform_device *pdev) pengine->active_seq = 0; pengine->last_active_seq = 0; pengine->check_flag = false; + pengine->max_req_used = 0; + pengine->issue_req = false; - tasklet_init(&pengine->done_tasklet, req_done, (unsigned long)pengine); crypto_init_queue(&pengine->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH); mutex_lock(&cp->engine_lock); @@ -4538,12 +5234,23 @@ static int _qcrypto_probe(struct platform_device *pdev) pengine->unit = cp->total_units; spin_lock_irqsave(&cp->lock, flags); + pengine->first_engine = list_empty(&cp->engine_list); + if (pengine->first_engine) + cp->first_engine = pengine; list_add_tail(&pengine->elist, &cp->engine_list); cp->next_engine = pengine; spin_unlock_irqrestore(&cp->lock, flags); qce_hw_support(pengine->qce, &cp->ce_support); pengine->ce_hw_instance = cp->ce_support.ce_hw_instance; + pengine->max_req = cp->ce_support.max_request; + pqcrypto_req_control = kzalloc(sizeof(struct qcrypto_req_control) * + pengine->max_req, GFP_KERNEL); + if (pqcrypto_req_control == NULL) { + rc = -ENOMEM; + goto err; + } + qcrypto_init_req_control(pengine, pqcrypto_req_control); if (cp->ce_support.bam) { cp->platform_support.ce_shared = cp->ce_support.is_shared; cp->platform_support.shared_ce_resource = 0; @@ -4591,7 +5298,7 @@ static int _qcrypto_probe(struct platform_device *pdev) if (cp->total_units != 1) { mutex_unlock(&cp->engine_lock); - goto fips_selftest; + return 0; } /* register crypto cipher algorithms the device supports */ @@ -4882,33 +5589,6 @@ static int _qcrypto_probe(struct platform_device *pdev) mutex_unlock(&cp->engine_lock); -fips_selftest: - /* - * FIPS140-2 Known Answer Tests : - * IN case of any failure, do not Init the module - */ - is_fips_qcrypto_tests_done = false; - - if (g_fips140_status != FIPS140_STATUS_NA) { - - _qcrypto_prefix_alg_cra_name(prefix, 0); - _qcrypto_fips_selftest_d(&selftest_d, &cp->ce_support, prefix); - if (_fips_qcrypto_sha_selftest(&selftest_d) || - _fips_qcrypto_cipher_selftest(&selftest_d) || - _fips_qcrypto_aead_selftest(&selftest_d)) { - pr_err("qcrypto: FIPS140-2 Known Answer Tests : Failed\n"); - BUG_ON(1); - rc = -1; - goto err; - } else - pr_info("qcrypto: FIPS140-2 Known Answer Tests: Successful\n"); - if (g_fips140_status != FIPS140_STATUS_PASS) - g_fips140_status = FIPS140_STATUS_PASS_CRYPTO; - - } else - pr_info("qcrypto: FIPS140-2 Known Answer Tests: Skipped\n"); - - is_fips_qcrypto_tests_done = true; return 0; err: @@ -4924,7 +5604,8 @@ static int _qcrypto_engine_in_use(struct crypto_engine *pengine) { struct crypto_priv *cp = pengine->pcp; - if (pengine->req || pengine->req_queue.qlen || cp->req_queue.qlen) + if ((atomic_read(&pengine->req_count) > 0) || pengine->req_queue.qlen + || cp->req_queue.qlen) return 1; return 0; } @@ -5079,13 +5760,27 @@ static ssize_t _debug_stats_write(struct file *file, const char __user *buf, unsigned long flags; struct crypto_priv *cp = &qcrypto_dev; struct crypto_engine *pe; + int i; memset((char *)&_qcrypto_stat, 0, sizeof(struct crypto_stat)); spin_lock_irqsave(&cp->lock, flags); list_for_each_entry(pe, &cp->engine_list, elist) { pe->total_req = 0; pe->err_req = 0; + qce_clear_driver_stats(pe->qce); + pe->max_req_used = 0; } + cp->max_qlen = 0; + cp->resp_start = 0; + cp->resp_stop = 0; + cp->no_avail = 0; + cp->max_resp_qlen = 0; + cp->queue_work_eng3 = 0; + cp->queue_work_not_eng3 = 0; + cp->queue_work_not_eng3_nz = 0; + cp->max_reorder_cnt = 0; + for (i = 0; i < MAX_SMP_CPU + 1; i++) + cp->cpu_req[i] = 0; spin_unlock_irqrestore(&cp->lock, flags); return count; } @@ -5135,11 +5830,21 @@ static int __init _qcrypto_init(void) return rc; INIT_LIST_HEAD(&pcp->alg_list); INIT_LIST_HEAD(&pcp->engine_list); + init_llist_head(&pcp->ordered_resp_list); spin_lock_init(&pcp->lock); mutex_init(&pcp->engine_lock); + pcp->resp_wq = alloc_workqueue("qcrypto_seq_response_wq", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); + if (!pcp->resp_wq) { + pr_err("Error allocating workqueue\n"); + return -ENOMEM; + } + INIT_WORK(&pcp->resp_work, seq_response); pcp->total_units = 0; pcp->platform_support.bus_scale_table = NULL; pcp->next_engine = NULL; + pcp->scheduled_eng = NULL; + pcp->ce_req_proc_sts = IN_PROGRESS; crypto_init_queue(&pcp->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH); return platform_driver_register(&_qualcomm_crypto); } diff --git a/drivers/crypto/msm/qcryptoi.h b/drivers/crypto/msm/qcryptoi.h deleted file mode 100644 index fe89e99ddf0fbc140b2a0450c0d7e332509db3bc..0000000000000000000000000000000000000000 --- a/drivers/crypto/msm/qcryptoi.h +++ /dev/null @@ -1,72 +0,0 @@ -/* QTI Crypto driver - * - * Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __CRYPTO_MSM_QCRYPTOI_H -#define __CRYPTO_MSM_QCRYPTOI_H - -/* The structure to hold data - * that selftests require - */ -struct fips_selftest_data { - - char algo_prefix[10]; - unsigned int ce_device; - bool prefix_ahash_algo; - bool prefix_hmac_algo; - bool prefix_aes_xts_algo; - bool prefix_aes_cbc_ecb_ctr_algo; - bool prefix_aead_algo; -}; - -extern enum fips_status g_fips140_status; - -#ifdef CONFIG_FIPS_ENABLE -/* - * Sha/HMAC self tests - */ -int _fips_qcrypto_sha_selftest(struct fips_selftest_data *selftest_d); - -/* -* Cipher algorithm self tests -*/ -int _fips_qcrypto_cipher_selftest(struct fips_selftest_data *selftest_d); - -/* - * AEAD algorithm self tests - */ -int _fips_qcrypto_aead_selftest(struct fips_selftest_data *selftest_d); - -#else - -static inline -int _fips_qcrypto_sha_selftest(struct fips_selftest_data *selftest_d) -{ - return 0; -} - -static inline -int _fips_qcrypto_cipher_selftest(struct fips_selftest_data *selftest_d) -{ - return 0; -} - -static -inline int _fips_qcrypto_aead_selftest(struct fips_selftest_data *selftest_d) -{ - return 0; -} - -#endif /* CONFIG_FIPS_ENABLE*/ - -#endif /* __CRYPTO_MSM_QCRYPTOI_H */ diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index b5f7e6db24d42fa3bcc84662fb206bab7dcc7e19..e94857e56c70850f7d5b8bd4513f28a9b828b094 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -63,7 +63,7 @@ struct dcp { struct dcp_coherent_block *coh; struct completion completion[DCP_MAX_CHANS]; - struct mutex mutex[DCP_MAX_CHANS]; + spinlock_t lock[DCP_MAX_CHANS]; struct task_struct *thread[DCP_MAX_CHANS]; struct crypto_queue queue[DCP_MAX_CHANS]; }; @@ -349,13 +349,20 @@ static int dcp_chan_thread_aes(void *data) int ret; - do { - __set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&sdcp->mutex[chan]); + spin_lock(&sdcp->lock[chan]); backlog = crypto_get_backlog(&sdcp->queue[chan]); arq = crypto_dequeue_request(&sdcp->queue[chan]); - mutex_unlock(&sdcp->mutex[chan]); + spin_unlock(&sdcp->lock[chan]); + + if (!backlog && !arq) { + schedule(); + continue; + } + + set_current_state(TASK_RUNNING); if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -363,11 +370,8 @@ static int dcp_chan_thread_aes(void *data) if (arq) { ret = mxs_dcp_aes_block_crypt(arq); arq->complete(arq, ret); - continue; } - - schedule(); - } while (!kthread_should_stop()); + } return 0; } @@ -407,9 +411,9 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb) rctx->ecb = ecb; actx->chan = DCP_CHAN_CRYPTO; - mutex_lock(&sdcp->mutex[actx->chan]); + spin_lock(&sdcp->lock[actx->chan]); ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); - mutex_unlock(&sdcp->mutex[actx->chan]); + spin_unlock(&sdcp->lock[actx->chan]); wake_up_process(sdcp->thread[actx->chan]); @@ -645,13 +649,20 @@ static int dcp_chan_thread_sha(void *data) struct ahash_request *req; int ret, fini; - do { - __set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&sdcp->mutex[chan]); + spin_lock(&sdcp->lock[chan]); backlog = crypto_get_backlog(&sdcp->queue[chan]); arq = crypto_dequeue_request(&sdcp->queue[chan]); - mutex_unlock(&sdcp->mutex[chan]); + spin_unlock(&sdcp->lock[chan]); + + if (!backlog && !arq) { + schedule(); + continue; + } + + set_current_state(TASK_RUNNING); if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -663,12 +674,8 @@ static int dcp_chan_thread_sha(void *data) ret = dcp_sha_req_to_buf(arq); fini = rctx->fini; arq->complete(arq, ret); - if (!fini) - continue; } - - schedule(); - } while (!kthread_should_stop()); + } return 0; } @@ -726,9 +733,9 @@ static int dcp_sha_update_fx(struct ahash_request *req, int fini) rctx->init = 1; } - mutex_lock(&sdcp->mutex[actx->chan]); + spin_lock(&sdcp->lock[actx->chan]); ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); - mutex_unlock(&sdcp->mutex[actx->chan]); + spin_unlock(&sdcp->lock[actx->chan]); wake_up_process(sdcp->thread[actx->chan]); mutex_unlock(&actx->mutex); @@ -984,7 +991,7 @@ static int mxs_dcp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sdcp); for (i = 0; i < DCP_MAX_CHANS; i++) { - mutex_init(&sdcp->mutex[i]); + spin_lock_init(&sdcp->lock[i]); init_completion(&sdcp->completion[i]); crypto_init_queue(&sdcp->queue[i], 50); } diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index f8e3207fecb1c97b3c8fb6dca06b33e01d5f32d8..d62a148075bf8f00469352e96d41be96f4c3b18d 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1641,6 +1641,7 @@ static int queue_cache_init(void) CWQ_ENTRY_SIZE, 0, NULL); if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) { kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); + queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; return -ENOMEM; } return 0; @@ -1650,6 +1651,8 @@ static void queue_cache_destroy(void) { kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]); + queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; + queue_cache[HV_NCS_QTYPE_CWQ - 1] = NULL; } static int spu_queue_register(struct spu_queue *p, unsigned long q_type) diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index c178ed8c3908d3a92e55432aecb86e0e6e1501ee..2250db02619879c4c4de1dbe1f9ca1a9ec9b4417 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -266,6 +266,8 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, return; } + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) @@ -273,7 +275,7 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) - : "d"(control_word), "b"(key), "c"(count - initial)); + : "d"(control_word), "b"(key), "c"(count)); } static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, @@ -284,6 +286,8 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, if (count < cbc_fetch_blocks) return cbc_crypt(input, output, key, iv, control_word, count); + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) @@ -291,7 +295,7 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) - : "d" (control_word), "b" (key), "c" (count-initial)); + : "d" (control_word), "b" (key), "c" (count)); return iv; } diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 658fa533ced1b3e06a49bdddacd176126d0fe9a2..9c046904f001c1e6371bcd08a2ccfe9de3462e56 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -419,16 +419,21 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) uint32_t aes_control; int err; unsigned long flags; + u8 *iv; aes_control = SSS_AES_KEY_CHANGE_MODE; if (mode & FLAGS_AES_DECRYPT) aes_control |= SSS_AES_MODE_DECRYPT; - if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) + if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { aes_control |= SSS_AES_CHAIN_MODE_CBC; - else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) + iv = req->info; + } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { aes_control |= SSS_AES_CHAIN_MODE_CTR; - + iv = req->info; + } else { + iv = NULL; /* AES_ECB */ + } if (dev->ctx->keylen == AES_KEYSIZE_192) aes_control |= SSS_AES_KEY_SIZE_192; else if (dev->ctx->keylen == AES_KEYSIZE_256) @@ -458,7 +463,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) goto outdata_error; SSS_AES_WRITE(dev, AES_CONTROL, aes_control); - s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); + s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen); s5p_set_dma_indata(dev, req->src); s5p_set_dma_outdata(dev, req->dst); @@ -682,8 +687,9 @@ static int s5p_aes_probe(struct platform_device *pdev) dev_warn(dev, "feed control interrupt is not available.\n"); goto err_irq; } - err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt, - IRQF_SHARED, pdev->name, pdev); + err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL, + s5p_aes_interrupt, IRQF_ONESHOT, + pdev->name, pdev); if (err < 0) { dev_warn(dev, "feed control interrupt is not available.\n"); goto err_irq; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 00410b319b26d1ff6dc18adc23fd36972c99f968..9fa17913941c376724c8ec5fbfb1aa026edf2723 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1581,9 +1581,9 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, req_ctx->swinit = 0; } else { desc->ptr[1] = zero_entry; - /* Indicate next op is not the first. */ - req_ctx->first = 0; } + /* Indicate next op is not the first. */ + req_ctx->first = 0; /* HMAC key */ if (ctx->keylen) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 129cfb92874377966898001df3dbb27a1bfa23ba..43114114623adf7c3ffb354fc00fe2f8474f57f9 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -610,7 +610,7 @@ struct devfreq *devm_devfreq_add_device(struct device *dev, devfreq = devfreq_add_device(dev, profile, governor_name, data); if (IS_ERR(devfreq)) { devres_free(ptr); - return ERR_PTR(-ENOMEM); + return devfreq; } *ptr = devfreq; diff --git a/drivers/devfreq/governor_gpubw_mon.c b/drivers/devfreq/governor_gpubw_mon.c index e261bf5f9d31c281999e48f9e5e3e76d741ddda6..b0c1ec02c709b3ce3b2fcfa9bdd7e2d30d9473bc 100644 --- a/drivers/devfreq/governor_gpubw_mon.c +++ b/drivers/devfreq/governor_gpubw_mon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015,2020, The Linux Foundation. All rights reserved. * * 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 @@ -212,9 +212,11 @@ static int devfreq_gpubw_event_handler(struct devfreq *devfreq, case DEVFREQ_GOV_SUSPEND: { struct devfreq_msm_adreno_tz_data *priv = devfreq->data; - priv->bus.total_time = 0; - priv->bus.gpu_time = 0; - priv->bus.ram_time = 0; + if (priv) { + priv->bus.total_time = 0; + priv->bus.gpu_time = 0; + priv->bus.ram_time = 0; + } } break; default: diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c index ae2ab14e64b30e5edf9119569d379766eba24b94..a2a9726a68717cf488a5a1298c8cda96aa9b86ba 100644 --- a/drivers/dma/dma-jz4740.c +++ b/drivers/dma/dma-jz4740.c @@ -575,7 +575,7 @@ static int jz4740_dma_probe(struct platform_device *pdev) ret = dma_async_device_register(dd); if (ret) - return ret; + goto err_clk; irq = platform_get_irq(pdev, 0); ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev); @@ -588,6 +588,8 @@ static int jz4740_dma_probe(struct platform_device *pdev) err_unregister: dma_async_device_unregister(dd); +err_clk: + clk_disable_unprepare(dmadev->clk); return ret; } diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 24bfaf0b92ba1a87cd45b8dbb1bfdd1a60a2dc59..6433baf641cbd19be030e8800fa49653ab59dac1 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -976,12 +976,14 @@ static struct dmaengine_unmap_pool *__get_unmap_pool(int nr) switch (order) { case 0 ... 1: return &unmap_pool[0]; +#if IS_ENABLED(CONFIG_DMA_ENGINE_RAID) case 2 ... 4: return &unmap_pool[1]; case 5 ... 7: return &unmap_pool[2]; case 8: return &unmap_pool[3]; +#endif default: BUG(); return NULL; diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index a1f911aaf220e0b107c1009a74edfaca1ff06634..a95f46c2a98444da30ec2c2217f88953aed7108f 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -652,7 +652,7 @@ static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec, struct k3_dma_dev *d = ofdma->of_dma_data; unsigned int request = dma_spec->args[0]; - if (request > d->dma_requests) + if (request >= d->dma_requests) return NULL; return dma_get_slave_channel(&(d->chans[request].vc.chan)); diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 19a99743cf524670d5906400d286cc877bcf91d6..e57139d91f0063ddbb8b2853f7d453b7da9648f8 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1516,7 +1516,7 @@ static void pl330_dotask(unsigned long data) /* Returns 1 if state was updated, 0 otherwise */ static int pl330_update(struct pl330_dmac *pl330) { - struct dma_pl330_desc *descdone, *tmp; + struct dma_pl330_desc *descdone; unsigned long flags; void __iomem *regs; u32 val; @@ -1592,7 +1592,9 @@ static int pl330_update(struct pl330_dmac *pl330) } /* Now that we are in no hurry, do the callbacks */ - list_for_each_entry_safe(descdone, tmp, &pl330->req_done, rqd) { + while (!list_empty(&pl330->req_done)) { + descdone = list_first_entry(&pl330->req_done, + struct dma_pl330_desc, rqd); list_del(&descdone->rqd); spin_unlock_irqrestore(&pl330->lock, flags); dma_pl330_rqcb(descdone, PL330_ERR_NONE); diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 72e07e3cf718fb760c62cda09023b199857bcb13..16e0eb523439a8193df821056b68d3bd6a3a431f 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -227,7 +227,7 @@ #define NREC_RDWR(x) (((x)>>11) & 1) #define NREC_RANK(x) (((x)>>8) & 0x7) #define NRECMEMB 0xC0 -#define NREC_CAS(x) (((x)>>16) & 0xFFFFFF) +#define NREC_CAS(x) (((x)>>16) & 0xFFF) #define NREC_RAS(x) ((x) & 0x7FFF) #define NRECFGLOG 0xC4 #define NREEECFBDA 0xC8 @@ -371,7 +371,7 @@ struct i5000_error_info { /* These registers are input ONLY if there was a * Non-Recoverable Error */ u16 nrecmema; /* Non-Recoverable Mem log A */ - u16 nrecmemb; /* Non-Recoverable Mem log B */ + u32 nrecmemb; /* Non-Recoverable Mem log B */ }; @@ -407,7 +407,7 @@ static void i5000_get_error_info(struct mem_ctl_info *mci, NERR_FAT_FBD, &info->nerr_fat_fbd); pci_read_config_word(pvt->branchmap_werrors, NRECMEMA, &info->nrecmema); - pci_read_config_word(pvt->branchmap_werrors, + pci_read_config_dword(pvt->branchmap_werrors, NRECMEMB, &info->nrecmemb); /* Clear the error bits, by writing them back */ @@ -1293,7 +1293,7 @@ static int i5000_init_csrows(struct mem_ctl_info *mci) dimm->mtype = MEM_FB_DDR2; /* ask what device type on this row */ - if (MTR_DRAM_WIDTH(mtr)) + if (MTR_DRAM_WIDTH(mtr) == 8) dimm->dtype = DEV_X8; else dimm->dtype = DEV_X4; diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index 6ef6ad1ba16ef3351217074f2ba63316a07276e4..2ea2f32e608be9f916a038301cd90c0260a8d508 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -368,7 +368,7 @@ struct i5400_error_info { /* These registers are input ONLY if there was a Non-Rec Error */ u16 nrecmema; /* Non-Recoverable Mem log A */ - u16 nrecmemb; /* Non-Recoverable Mem log B */ + u32 nrecmemb; /* Non-Recoverable Mem log B */ }; @@ -458,7 +458,7 @@ static void i5400_get_error_info(struct mem_ctl_info *mci, NERR_FAT_FBD, &info->nerr_fat_fbd); pci_read_config_word(pvt->branchmap_werrors, NRECMEMA, &info->nrecmema); - pci_read_config_word(pvt->branchmap_werrors, + pci_read_config_dword(pvt->branchmap_werrors, NRECMEMB, &info->nrecmemb); /* Clear the error bits, by writing them back */ @@ -1207,13 +1207,14 @@ static int i5400_init_dimms(struct mem_ctl_info *mci) dimm->nr_pages = size_mb << 8; dimm->grain = 8; - dimm->dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4; + dimm->dtype = MTR_DRAM_WIDTH(mtr) == 8 ? + DEV_X8 : DEV_X4; dimm->mtype = MEM_FB_DDR2; /* * The eccc mechanism is SDDC (aka SECC), with * is similar to Chipkill. */ - dimm->edac_mode = MTR_DRAM_WIDTH(mtr) ? + dimm->edac_mode = MTR_DRAM_WIDTH(mtr) == 8 ? EDAC_S8ECD8ED : EDAC_S4ECD4ED; ndimms++; } diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index 542fad70e360d60f7c51c7db8f39ab9dc3de9038..f0e5a6aa23713aed678cdeb5c2f6ff97dadcfbcb 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c @@ -763,7 +763,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) /* Non-ECC RAM? */ printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); res = -ENODEV; - goto err2; + goto err; } edac_dbg(3, "init mci\n"); diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index 4bd10f94f0683a3c14e44f0fb8e5f41bb92ab83e..c0c80ae8c47c66adefb2325e9c0607b4ab8174c0 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -79,6 +79,7 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci) if (!pvt->inject) int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx)); else { + int_reg.u64 = 0; if (pvt->error_type == 1) int_reg.s.sec_err = 1; if (pvt->error_type == 2) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 6aa25a3aa2c73830088c558fea3f04d52fd5891f..42f6674855949220777e25b89123b456fd55c667 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1645,6 +1645,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, break; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA: pvt->pci_ta = pdev; + break; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS: pvt->pci_ras = pdev; break; diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index 230e1220ce48bc49ef24bd5683ca1c074e94202e..1cee9f4909db079a7fcafcf425a4caa4e6e1fc42 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -150,6 +150,11 @@ static int palmas_usb_probe(struct platform_device *pdev) struct palmas_usb *palmas_usb; int status; + if (!palmas) { + dev_err(&pdev->dev, "failed to get valid parent\n"); + return -EINVAL; + } + palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL); if (!palmas_usb) return -ENOMEM; diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f047d7c2b6436c113624946b402f8e8ab642c01b..437f5f0c0d934699411cbaa175c68b1b33c01929 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1137,7 +1137,13 @@ static int context_add_buffer(struct context *ctx) return -ENOMEM; offset = (void *)&desc->buffer - (void *)desc; - desc->buffer_size = PAGE_SIZE - offset; + /* + * Some controllers, like JMicron ones, always issue 0x20-byte DMA reads + * for descriptors, even 0x10-byte ones. This can cause page faults when + * an IOMMU is in use and the oversized read crosses a page boundary. + * Work around this by always leaving at least 0x10 bytes of padding. + */ + desc->buffer_size = PAGE_SIZE - offset - 0x10; desc->buffer_bus = bus_addr + offset; desc->used = 0; diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 29f93bf718e6a524377ed85dae8da7d60d25b8a3..d021f52e6e814939a4ab723d91f1fd292fb760ed 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -15,7 +15,7 @@ * of and an antecedent to, SMBIOS, which stands for System * Management BIOS. See further: http://www.dmtf.org/standards */ -static const char dmi_empty_string[] = " "; +static const char dmi_empty_string[] = ""; static u16 __initdata dmi_ver; /* @@ -36,25 +36,21 @@ static int dmi_memdev_nr; static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) { const u8 *bp = ((u8 *) dm) + dm->length; + const u8 *nsp; if (s) { - s--; - while (s > 0 && *bp) { + while (--s > 0 && *bp) bp += strlen(bp) + 1; - s--; - } - - if (*bp != 0) { - size_t len = strlen(bp)+1; - size_t cmp_len = len > 8 ? 8 : len; - if (!memcmp(bp, dmi_empty_string, cmp_len)) - return dmi_empty_string; + /* Strings containing only spaces are considered empty */ + nsp = bp; + while (*nsp == ' ') + nsp++; + if (*nsp != '\0') return bp; - } } - return ""; + return dmi_empty_string; } static const char * __init dmi_string(const struct dmi_header *dm, u8 s) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 49eb145043ff70a0964c3289c96c5b0f047f0c01..33489aec541a30988018760127ea0e630c30de09 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -99,8 +99,7 @@ static ssize_t systab_show(struct kobject *kobj, return str - buf; } -static struct kobj_attribute efi_attr_systab = - __ATTR(systab, 0400, systab_show, NULL); +static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400); #define EFI_FIELD(var) efi.var diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 06c3d420527df2ea5d833a978b343111d440356a..ff1f570d6b14b51471f7d0415d180382cfa2aaa6 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -24,9 +24,6 @@ KASAN_SANITIZE := n # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. KCOV_INSTRUMENT := n -# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. -KCOV_INSTRUMENT := n - lib-y := efi-stub-helper.o lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index 87b8e3b900d2195bc44ae471003db4ad610b7d77..1df70fd4787f742155b25ebfb0ac2fbba7c4ada3 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -67,11 +67,11 @@ static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, return map_attr->show(entry, buf); } -static struct map_attribute map_type_attr = __ATTR_RO(type); -static struct map_attribute map_phys_addr_attr = __ATTR_RO(phys_addr); -static struct map_attribute map_virt_addr_attr = __ATTR_RO(virt_addr); -static struct map_attribute map_num_pages_attr = __ATTR_RO(num_pages); -static struct map_attribute map_attribute_attr = __ATTR_RO(attribute); +static struct map_attribute map_type_attr = __ATTR_RO_MODE(type, 0400); +static struct map_attribute map_phys_addr_attr = __ATTR_RO_MODE(phys_addr, 0400); +static struct map_attribute map_virt_addr_attr = __ATTR_RO_MODE(virt_addr, 0400); +static struct map_attribute map_num_pages_attr = __ATTR_RO_MODE(num_pages, 0400); +static struct map_attribute map_attribute_attr = __ATTR_RO_MODE(attribute, 0400); /* * These are default attributes that are added for every memmap entry. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9d4a9a81c568399f41d17c75b6859d87ee9e616e..34aee7f42fc407da0f90a5cd8aa77c6c35007271 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -108,4 +108,3 @@ obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o obj-$(CONFIG_MSM_SMP2P) += gpio-msm-smp2p.o -obj-$(CONFIG_MSM_SMP2P_TEST) += gpio-msm-smp2p-test.o diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 3beed6ea8c6568fbd4d560e5dd2da8f6102ba167..348cde4252200c34d9a4139701f3a70067defa57 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -41,6 +41,8 @@ struct adp5588_gpio { uint8_t int_en[3]; uint8_t irq_mask[3]; uint8_t irq_stat[3]; + uint8_t int_input_en[3]; + uint8_t int_lvl_cached[3]; }; static int adp5588_gpio_read(struct i2c_client *client, u8 reg) @@ -177,12 +179,28 @@ static void adp5588_irq_bus_sync_unlock(struct irq_data *d) struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); int i; - for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) + for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) { + if (dev->int_input_en[i]) { + mutex_lock(&dev->lock); + dev->dir[i] &= ~dev->int_input_en[i]; + dev->int_input_en[i] = 0; + adp5588_gpio_write(dev->client, GPIO_DIR1 + i, + dev->dir[i]); + mutex_unlock(&dev->lock); + } + + if (dev->int_lvl_cached[i] != dev->int_lvl[i]) { + dev->int_lvl_cached[i] = dev->int_lvl[i]; + adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + i, + dev->int_lvl[i]); + } + if (dev->int_en[i] ^ dev->irq_mask[i]) { dev->int_en[i] = dev->irq_mask[i]; adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i, dev->int_en[i]); } + } mutex_unlock(&dev->irq_lock); } @@ -225,9 +243,7 @@ static int adp5588_irq_set_type(struct irq_data *d, unsigned int type) else return -EINVAL; - adp5588_gpio_direction_input(&dev->gpio_chip, gpio); - adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank, - dev->int_lvl[bank]); + dev->int_input_en[bank] |= bit; return 0; } diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index 0a5e9d3f308cb512761e916e4d578c7136489eb1..2978aa5ae2820d55e88deee12a9721716518415a 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -130,3 +130,7 @@ static int __init iop3xx_gpio_init(void) return platform_driver_register(&iop3xx_gpio_driver); } arch_initcall(iop3xx_gpio_init); + +MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors"); +MODULE_AUTHOR("Lennert Buytenhek "); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 5536108aa9db5c8e6a7aa5e0fbbecdfe4ae03c95..fe21734bbe5c4dad4d22297ce2a2630fe5f7bf20 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -495,9 +495,10 @@ err_irq_alloc_descs: chip = chip_save; err_gpiochip_add: + chip = chip_save; while (--i >= 0) { - chip--; gpiochip_remove(&chip->gpio); + chip++; } kfree(chip_save); diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 27319a8335e258cf12cb093c5c598523fbe307f3..345dc4d0851ef43bd73069679c3ec7fef8bfa073 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -160,6 +160,7 @@ enum { CFG_ALPHAM_GRA = 0x1 << 16, CFG_ALPHAM_CFG = 0x2 << 16, CFG_ALPHA_MASK = 0xff << 8, +#define CFG_ALPHA(x) ((x) << 8) CFG_PIXCMD_MASK = 0xff, }; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 5c22b380f8f3e48dd9c2f6d7d1346c2bfc740b48..f8a69ec6355026bc3ef3ed7003ece2930b9eaef5 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -27,6 +27,7 @@ struct armada_ovl_plane_properties { uint16_t contrast; uint16_t saturation; uint32_t colorkey_mode; + uint32_t colorkey_enable; }; struct armada_ovl_plane { @@ -62,11 +63,13 @@ armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE); spin_lock_irq(&dcrtc->irq_lock); - armada_updatel(prop->colorkey_mode | CFG_ALPHAM_GRA, - CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, - dcrtc->base + LCD_SPU_DMA_CTRL1); - - armada_updatel(ADV_GRACOLORKEY, 0, dcrtc->base + LCD_SPU_ADV_REG); + armada_updatel(prop->colorkey_mode, + CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, + dcrtc->base + LCD_SPU_DMA_CTRL1); + if (dcrtc->variant->has_spu_adv_reg) + armada_updatel(prop->colorkey_enable, + ADV_GRACOLORKEY | ADV_VIDCOLORKEY, + dcrtc->base + LCD_SPU_ADV_REG); spin_unlock_irq(&dcrtc->irq_lock); } @@ -339,8 +342,17 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, dplane->prop.colorkey_vb |= K2B(val); update_attr = true; } else if (property == priv->colorkey_mode_prop) { - dplane->prop.colorkey_mode &= ~CFG_CKMODE_MASK; - dplane->prop.colorkey_mode |= CFG_CKMODE(val); + if (val == CKMODE_DISABLE) { + dplane->prop.colorkey_mode = + CFG_CKMODE(CKMODE_DISABLE) | + CFG_ALPHAM_CFG | CFG_ALPHA(255); + dplane->prop.colorkey_enable = 0; + } else { + dplane->prop.colorkey_mode = + CFG_CKMODE(val) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + dplane->prop.colorkey_enable = ADV_GRACOLORKEY; + } update_attr = true; } else if (property == priv->brightness_prop) { dplane->prop.brightness = val - 256; @@ -469,7 +481,9 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->prop.colorkey_yr = 0xfefefe00; dplane->prop.colorkey_ug = 0x01010100; dplane->prop.colorkey_vb = 0x01010100; - dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB); + dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + dplane->prop.colorkey_enable = ADV_GRACOLORKEY; dplane->prop.brightness = 0; dplane->prop.contrast = 0x4000; dplane->prop.saturation = 0x4000; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 35709d90c0a6f9a475eed34d59d9e37c1c91314a..aa11ab6ad11e4409c1937849d27b83c83f4feaf0 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1799,6 +1799,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) return -EINVAL; } req_payload.num_slots = mgr->proposed_vcpis[i]->num_slots; + req_payload.vcpi = mgr->proposed_vcpis[i]->vcpi; } else { port = NULL; req_payload.num_slots = 0; @@ -1814,6 +1815,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) if (req_payload.num_slots) { drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload); mgr->payloads[i].num_slots = req_payload.num_slots; + mgr->payloads[i].vcpi = req_payload.vcpi; } else if (mgr->payloads[i].num_slots) { mgr->payloads[i].num_slots = 0; drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 7dd6728dd092e23af63516295be42331bcc1f3c8..ccc2044af8314d69fd1bdbceeadb757ca387e141 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -312,7 +312,7 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); - return ret; + goto err_debugfs; } ret = device_add(minor->kdev); diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 6b5625e6611975735a1bd4c218edd3cfa9ec5e69..88ceac091454eb92ffbdd81e84bd7db5dcd4d125 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -209,6 +209,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) return -ENOMEM; filp->private_data = priv; + filp->f_mode |= FMODE_UNSIGNED_OFFSET; priv->filp = filp; priv->uid = current_euid(); priv->pid = get_pid(task_pid(current)); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 8090989185b2bb2d06b4522a52b4a331f17b1ab1..4ddbc49125cd7ef1892b8bc1ed73349ab455b091 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1271,9 +1271,9 @@ void drm_vblank_put(struct drm_device *dev, unsigned int pipe) if (atomic_dec_and_test(&vblank->refcount)) { if (drm_vblank_offdelay == 0) return; - else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) + else if (drm_vblank_offdelay < 0) vblank_disable_fn((unsigned long)vblank); - else + else if (!dev->vblank_disable_immediate) mod_timer(&vblank->disable_timer, jiffies + ((drm_vblank_offdelay * HZ)/1000)); } @@ -1902,6 +1902,16 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) wake_up(&vblank->queue); drm_handle_vblank_events(dev, pipe); + /* With instant-off, we defer disabling the interrupt until after + * we finish processing the following vblank. The disable has to + * be last (after drm_handle_vblank_events) so that the timestamp + * is always accurate. + */ + if (dev->vblank_disable_immediate && + drm_vblank_offdelay > 0 && + !atomic_read(&vblank->refcount)) + vblank_disable_fn((unsigned long)vblank); + spin_unlock_irqrestore(&dev->event_lock, irqflags); return true; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 11b87d2a7913b60565481ca59dd23f01b8944550..ba69d1c72221a33ee4f2d2cffb2dd3cc2c7fb075 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -526,21 +526,25 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt) GSC_IN_CHROMA_ORDER_CRCB); break; case DRM_FORMAT_NV21: + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P); + break; case DRM_FORMAT_NV61: - cfg |= (GSC_IN_CHROMA_ORDER_CRCB | - GSC_IN_YUV420_2P); + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P); break; case DRM_FORMAT_YUV422: cfg |= GSC_IN_YUV422_3P; break; case DRM_FORMAT_YUV420: + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); + break; case DRM_FORMAT_YVU420: - cfg |= GSC_IN_YUV420_3P; + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P); break; case DRM_FORMAT_NV12: + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P); + break; case DRM_FORMAT_NV16: - cfg |= (GSC_IN_CHROMA_ORDER_CBCR | - GSC_IN_YUV420_2P); + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P); break; default: dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt); @@ -800,18 +804,25 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt) GSC_OUT_CHROMA_ORDER_CRCB); break; case DRM_FORMAT_NV21: - case DRM_FORMAT_NV61: cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P); break; + case DRM_FORMAT_NV61: + cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P); + break; case DRM_FORMAT_YUV422: + cfg |= GSC_OUT_YUV422_3P; + break; case DRM_FORMAT_YUV420: + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); + break; case DRM_FORMAT_YVU420: - cfg |= GSC_OUT_YUV420_3P; + cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P); break; case DRM_FORMAT_NV12: + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P); + break; case DRM_FORMAT_NV16: - cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | - GSC_OUT_YUV420_2P); + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P); break; default: dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt); diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h index 30496134a3d0720bcc649711bd8d2ef5d35cf47a..d7cbe53c4c01f440cf9c0aecec153dc3d4f3f912 100644 --- a/drivers/gpu/drm/exynos/regs-fimc.h +++ b/drivers/gpu/drm/exynos/regs-fimc.h @@ -569,7 +569,7 @@ #define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26) #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26) #define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26) -#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0)) +#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | (0xff << 0)) /* Real input DMA size register */ #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31) diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 9ad592707aafd18e147887cfd0b15fddb711e8fe..ade10966d6af7c69ee579100caa8361b8391c557 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h @@ -138,6 +138,7 @@ #define GSC_OUT_YUV420_3P (3 << 4) #define GSC_OUT_YUV422_1P (4 << 4) #define GSC_OUT_YUV422_2P (5 << 4) +#define GSC_OUT_YUV422_3P (6 << 4) #define GSC_OUT_YUV444 (7 << 4) #define GSC_OUT_TILE_TYPE_MASK (1 << 2) #define GSC_OUT_TILE_C_16x8 (0 << 2) diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 860dd2177ca15269bfedc7cf1ca2b4dafc3bddae..283570080d47cafd8c388fb2da723a1d39d5e4e7 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -252,7 +252,7 @@ extern int intelfb_remove(struct drm_device *dev, extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern int psb_intel_lvds_mode_valid(struct drm_connector *connector, +extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode); extern int psb_intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index 61e3a097a47811ce502b81b33282343095a1271b..ccd1b8bf0fd50d57415db3cd6a701078a6aecebd 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -343,7 +343,7 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) } } -int psb_intel_lvds_mode_valid(struct drm_connector *connector, +enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_psb_private *dev_priv = connector->dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index ce82f9c7df2460b049b279957a8db78965b4f49c..e5a56ccb10d694b4e7cf3cc0a5440c02c1e52fab 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -957,6 +957,13 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); + if (port == PORT_A && is_dvi) { + DRM_DEBUG_KMS("VBT claims port A supports DVI%s, ignoring\n", + is_hdmi ? "/HDMI" : ""); + is_dvi = false; + is_hdmi = false; + } + info->supports_dvi = is_dvi; info->supports_hdmi = is_hdmi; info->supports_dp = is_dp; diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index f3bee54c414f926bde876fa5df12319f7dc9907b..cb4313c68f71038e6ac431eb3a398751932f2308 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -440,7 +440,9 @@ static bool gmbus_is_index_read(struct i2c_msg *msgs, int i, int num) { return (i + 1 < num && - !(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 && + msgs[i].addr == msgs[i + 1].addr && + !(msgs[i].flags & I2C_M_RD) && + (msgs[i].len == 1 || msgs[i].len == 2) && (msgs[i + 1].flags & I2C_M_RD)); } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 7f39b8ad88ae2faaf3ff16949e2792a684997771..de6710fe3ff451b10296f83663868306e7d24e12 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -768,6 +768,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Radiant P845", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "P845"), + }, + }, { } /* terminating entry */ }; diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index b1a0f565617510d5797349004f1ee3dd63063042..44df959cbadb44ddf3859b13303971fdb2c3bf49 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -145,6 +145,8 @@ static int mga_vram_init(struct mga_device *mdev) } mem = pci_iomap(mdev->dev->pdev, 0, 0); + if (!mem) + return -ENOMEM; mdev->mc.vram_size = mga_probe_vram(mdev, mem); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index b8520aadbc0c82e258a25e9f2cbf253d75919c4d..5b2d57d129a8f80b05586345e1e4cf7a3b71c3cf 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018-2019, The Linux Foundation. All rights reserved. * * 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 @@ -123,6 +123,9 @@ static ssize_t debugfs_state_info_read(struct file *file, dsi_ctrl->clk_info.link_clks.pixel_clk_rate, dsi_ctrl->clk_info.link_clks.esc_clk_rate); + if (len > count) + len = count; + /* TODO: make sure that this does not exceed 4K */ if (copy_to_user(buff, buf, len)) { kfree(buf); @@ -162,6 +165,9 @@ static ssize_t debugfs_reg_dump_read(struct file *file, "Core clocks are not turned on, cannot read\n"); } + if (len > count) + len = count; + /* TODO: make sure that this does not exceed 4K */ if (copy_to_user(buff, buf, len)) { kfree(buf); @@ -484,7 +490,7 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev, } ctrl->hw.base = ptr; - pr_debug("[%s] map dsi_ctrl registers to %p\n", ctrl->name, + pr_debug("[%s] map dsi_ctrl registers to %pK\n", ctrl->name, ctrl->hw.base); ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name); @@ -494,7 +500,7 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev, } ctrl->hw.mmss_misc_base = ptr; - pr_debug("[%s] map mmss_misc registers to %p\n", ctrl->name, + pr_debug("[%s] map mmss_misc registers to %pK\n", ctrl->name, ctrl->hw.mmss_misc_base); return rc; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 7a8dd567bb1f177d7565421363215b62e8e34079..1af0a55f840fe82b06cdac15ff257ed57279a91d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -1469,7 +1469,7 @@ static int dsi_panel_parse_dba_config(struct dsi_panel *panel, "qcom,bridge-name", &len); if (!panel->dba_config.bridge_name || len <= 0) { SDE_ERROR( - "%s:%d Unable to read bridge_name, data=%p,len=%d\n", + "%s:%d Unable to read bridge_name, data=%pK,len=%d\n", __func__, __LINE__, panel->dba_config.bridge_name, len); rc = -EINVAL; goto error; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c index 1ccbbe7df57359428de447fb4427bdc3e338b1ae..f7a77336e691d4b9744419b9e36fc854b3aea3c0 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -93,7 +93,8 @@ static int dsi_phy_regmap_init(struct platform_device *pdev, phy->hw.base = ptr; - pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base); + pr_debug("[%s] map dsi_phy registers to %pK\n", + phy->name, phy->hw.base); return rc; } diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c index 0940e84b2821b6df619b901f4c25f2fbf9297828..253e022ffb09b702d735970b2724acd94b52063e 100644 --- a/drivers/gpu/drm/msm/edp/edp.c +++ b/drivers/gpu/drm/msm/edp/edp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -54,7 +54,7 @@ static struct msm_edp *edp_init(struct platform_device *pdev) ret = -ENOMEM; goto fail; } - DBG("eDP probed=%p", edp); + DBG("eDP probed=%pK", edp); edp->pdev = pdev; platform_set_drvdata(pdev, edp); diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index e4c1a259410c74678e03686c6717ba60abec4a68..5a0403e2e447a4702892b3a00f6f73eff4e9b39a 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -73,7 +73,12 @@ static ssize_t _sde_hdmi_debugfs_dump_info_read(struct file *file, if (!buf) return -ENOMEM; - len += snprintf(buf, SZ_4K, "name = %s\n", display->name); + len += snprintf(buf, SZ_1K, "name = %s\n", display->name); + + if (len > count) { + kfree(buf); + return -ENOMEM; + } if (copy_to_user(buff, buf, len)) { kfree(buf); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 62e3047e3f313fcc91b184210e9f7da8ea662efb..63a1de59c3a594706732c09475ea068f0df2f46d 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -2,7 +2,7 @@ * Copyright (C) 2013 Red Hat * Author: Rob Clark * - * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * 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 @@ -99,7 +99,8 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, } if (reglog) - printk(KERN_DEBUG "IO:region %s %p %08lx\n", dbgname, ptr, size); + pr_debug("IO:region %s %pK %08lx\n", + dbgname, ptr, size); return ptr; } @@ -107,7 +108,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, void msm_writel(u32 data, void __iomem *addr) { if (reglog) - printk(KERN_DEBUG "IO:W %p %08x\n", addr, data); + pr_debug("IO:W %pK %08x\n", addr, data); writel(data, addr); } @@ -115,7 +116,7 @@ u32 msm_readl(const void __iomem *addr) { u32 val = readl(addr); if (reglog) - printk(KERN_ERR "IO:R %p %08x\n", addr, val); + pr_debug("IO:R %pK %08x\n", addr, val); return val; } @@ -598,7 +599,7 @@ static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe) struct msm_kms *kms = priv->kms; if (!kms) return -ENXIO; - DBG("dev=%p, crtc=%u", dev, pipe); + DBG("dev=%pK crtc=%u", dev, pipe); return vblank_ctrl_queue_work(priv, pipe, true); } @@ -608,7 +609,7 @@ static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) struct msm_kms *kms = priv->kms; if (!kms) return; - DBG("dev=%p, crtc=%u", dev, pipe); + DBG("dev=%pK, crtc=%u", dev, pipe); vblank_ctrl_queue_work(priv, pipe, false); } diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index dca4de382581a5eedb18412df42d5b20ae27ac94..7b1a6246b268eebdec21f8fdaee9a20a165747d2 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -43,7 +43,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb) struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int i, n = drm_format_num_planes(fb->pixel_format); - DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); + DBG("destroy: FB ID: %d (%pK)", fb->base.id, fb); drm_framebuffer_cleanup(fb); @@ -178,7 +178,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, unsigned int hsub, vsub; bool is_modified = false; - DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", + DBG("create framebuffer: dev=%pK, mode_cmd=%pK (%dx%d@%4.4s)", dev, mode_cmd, mode_cmd->width, mode_cmd->height, (char *)&mode_cmd->pixel_format); @@ -261,7 +261,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, goto fail; } - DBG("create: FB ID: %d (%p)", fb->base.id, fb); + DBG("create: FB ID: %d (%pK)", fb->base.id, fb); return fb; diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index e49df634e3f21511fa45f64789f50b65bc1239b8..14cdd10f29f9a8e7c2bad01e7daceed31bed6437 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -146,7 +146,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, goto fail_unlock; } - DBG("fbi=%p, dev=%p", fbi, dev); + DBG("fbi=%pK, dev=%pK", fbi, dev); fbdev->fb = fb; helper->fb = fb; @@ -167,7 +167,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, fbi->fix.smem_start = paddr; fbi->fix.smem_len = fbdev->bo->size; - DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); + DBG("par=%pK, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 05ae5b7e4dc10c754b59784c3b3532cbba8ead9a..69bd4c53df65211b10c7251c9ed6a87c665d6618 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -290,7 +290,7 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) pfn = page_to_pfn(pages[pgoff]); - VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + VERB("Inserting %pK pfn %lx, pa %lx", vmf->virtual_address, pfn, pfn << PAGE_SHIFT); ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); @@ -399,7 +399,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, msm_obj->domain[id].sgt, IOMMU_READ | IOMMU_NOEXEC); if (ret) { - DRM_ERROR("Unable to map phy buf=%p\n", + DRM_ERROR("Unable to map phy buf=%pK\n", (void *)pa); return ret; } @@ -414,7 +414,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, msm_obj->domain[id].iova = sg_dma_address(msm_obj->domain[id].sgt->sgl); } - DRM_DEBUG("iova=%p\n", + DRM_DEBUG("iova=%pK\n", (void *)msm_obj->domain[id].iova); } else { WARN_ONCE(1, "physical address being used\n"); @@ -599,7 +599,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) uint64_t off = drm_vma_node_start(&obj->vma_node); WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %zu\n", + seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %pK %zu\n", msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', msm_obj->read_timestamp, msm_obj->write_timestamp, obj->name, obj->refcount.refcount.counter, diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index fd06bf826b2cee122fc30a519a73e55c11540dd2..b3e5827719ba3d77014c7e96e25080fd8b1ed189 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -1253,7 +1253,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, sde_crtc_install_properties(crtc); - SDE_DEBUG("%s: successfully initialized crtc=%p\n", + SDE_DEBUG("%s: successfully initialized crtc=%pK\n", sde_crtc->name, crtc); return crtc; } diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 629ca373665ca1881901c689f86d946a5e05fe68..1a5e0faf9e472a18a21cc5358c0ae9ed41df5438 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -133,7 +133,7 @@ struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 major, struct sde_mdss_cfg *cfg = NULL; if (!dev || !dev->dev) { - SDE_ERROR("dev=%p or dev->dev is NULL\n", dev); + SDE_ERROR("dev=%pK or dev->dev is NULL\n", dev); return NULL; } diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index cffdaad1de32a898b2b36de60bbcfa3a6dbc4809..c013fc135a972f9894e4edb0ecc8d63ec645cefb 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -1506,7 +1506,7 @@ u32 sde_plane_num_of_phy_pipe(struct drm_plane *plane) struct sde_plane *sde_plane = to_sde_plane(plane); if (!plane || !sde_plane) { - SDE_ERROR("plane=%p or sde_plane=%p is NULL\n", + SDE_ERROR("plane=%pK or sde_plane=%pK is NULL\n", plane, sde_plane); return 0; } diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 7841970de48d19e10bc23a0bde4a2388b05708f5..412f0282420f514fbb6045d035c3bbc075e95c73 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -288,7 +288,12 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait) msecs_to_jiffies(100))) { dev_err(dmm->dev, "timed out waiting for done\n"); ret = -ETIMEDOUT; + goto cleanup; } + + /* Check the engine status before continue */ + ret = wait_status(engine, DMM_PATSTATUS_READY | + DMM_PATSTATUS_VALID | DMM_PATSTATUS_DONE); } cleanup: @@ -359,11 +364,15 @@ int tiler_unpin(struct tiler_block *block) struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, uint16_t h, uint16_t align) { - struct tiler_block *block = kzalloc(sizeof(*block), GFP_KERNEL); + struct tiler_block *block; u32 min_align = 128; int ret; unsigned long flags; + block = kzalloc(sizeof(*block), GFP_KERNEL); + if (!block) + return ERR_PTR(-ENOMEM); + BUG_ON(!validfmt(fmt)); /* convert width/height to slots */ diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 7ed08fdc4c4285eff29f109ce67de4b79e970de2..393e5335e33b3e387a9f30ce2ec8624760021e2d 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -158,7 +158,7 @@ static void evict_entry(struct drm_gem_object *obj, size_t size = PAGE_SIZE * n; loff_t off = mmap_offset(obj) + (entry->obj_pgoff << PAGE_SHIFT); - const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE); if (m > 1) { int i; @@ -415,7 +415,7 @@ static int fault_2d(struct drm_gem_object *obj, * into account in some of the math, so figure out virtual stride * in pages */ - const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE); /* We don't use vmf->pgoff since that has the fake offset: */ pgoff = ((unsigned long)vmf->virtual_address - diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index b5217fe37f02742e87df986280fb69c2097bead9..0e46b6762cf04ca8b44f7d32b17a6ca1d1be352f 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -835,7 +835,7 @@ static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx) int ret, i; ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id)); - if (ret < ARRAY_SIZE(id) || id[0] == 0x00) { + if (ret < 0 || ret < ARRAY_SIZE(id) || id[0] == 0x00) { dev_err(ctx->dev, "read id failed\n"); ctx->error = -EIO; return; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index f97b73ec4713722ae3af5a05ba048ea95042e4e0..f418c002d3235bd94dc32e4a348d57deb3f73c8a 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -352,6 +352,7 @@ static int panel_simple_remove(struct device *dev) drm_panel_remove(&panel->base); panel_simple_disable(&panel->base); + panel_simple_unprepare(&panel->base); if (panel->ddc) put_device(&panel->ddc->dev); @@ -367,6 +368,7 @@ static void panel_simple_shutdown(struct device *dev) struct panel_simple *panel = dev_get_drvdata(dev); panel_simple_disable(&panel->base); + panel_simple_unprepare(&panel->base); } static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = { diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 30f00748ed37e7c406beed32ab3ac539ab86d120..7fa9151be6190984e143eb3f3338d27ac1949059 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -851,7 +851,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) return ret; } -static int radeon_lvds_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = radeon_best_single_encoder(connector); @@ -994,7 +994,7 @@ static int radeon_vga_get_modes(struct drm_connector *connector) return ret; } -static int radeon_vga_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1133,7 +1133,7 @@ static int radeon_tv_get_modes(struct drm_connector *connector) return 1; } -static int radeon_tv_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { if ((mode->hdisplay > 1024) || (mode->vdisplay > 768)) @@ -1464,7 +1464,7 @@ static void radeon_dvi_force(struct drm_connector *connector) radeon_connector->use_digital = true; } -static int radeon_dvi_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1761,7 +1761,7 @@ out: return ret; } -static int radeon_dp_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 3645b223aa3711e1f1a03e259d5f9a5b347bf034..446d990623069f08ffe01474403ea9ffc59bf6a9 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1374,6 +1374,12 @@ radeon_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOENT); } + /* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */ + if (obj->import_attach) { + DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n"); + return ERR_PTR(-EINVAL); + } + radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); if (radeon_fb == NULL) { drm_gem_object_unreference_unlocked(obj); diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 6edcb54850922a87535a3440a24d0e316977cf05..b35ebabd6a9f881b2d9d8acc47b0ac23893a2645 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -946,7 +946,7 @@ int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev, /* calc dclk divider with current vco freq */ dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk, pd_min, pd_even); - if (vclk_div > pd_max) + if (dclk_div > pd_max) break; /* vco is too big, it has to stop */ /* calc score with current vco freq */ diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 569417b38913cc22c610152a4be7d608ff5409b6..f09aa7e754003d0d513d8842f6eafabc709ccd7a 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -3042,6 +3042,16 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, max_sclk = 75000; max_mclk = 80000; } + } else if (rdev->family == CHIP_OLAND) { + if ((rdev->pdev->revision == 0xC7) || + (rdev->pdev->revision == 0x80) || + (rdev->pdev->revision == 0x81) || + (rdev->pdev->revision == 0x83) || + (rdev->pdev->revision == 0x87) || + (rdev->pdev->device == 0x6604) || + (rdev->pdev->device == 0x6605)) { + max_sclk = 75000; + } } /* Apply dpm quirks */ while (p && p->chip_device != 0) { @@ -5967,9 +5977,9 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev, { u32 lane_width; u32 new_lane_width = - (radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; u32 current_lane_width = - (radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; if (new_lane_width != current_lane_width) { radeon_set_pcie_lanes(rdev, new_lane_width); diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c index d56630c60039fead79ca37f1ed52b7614f9e8aee..117a2f52fb4eadbc1bc4715d7e0a4a728dbb4f18 100644 --- a/drivers/gpu/drm/sti/sti_vtg.c +++ b/drivers/gpu/drm/sti/sti_vtg.c @@ -346,6 +346,10 @@ static int vtg_probe(struct platform_device *pdev) return -ENOMEM; } vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); + if (!vtg->regs) { + DRM_ERROR("failed to remap I/O memory\n"); + return -ENOMEM; + } np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0); if (np) { diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 5d8dfe027b302e619fefaca59a88be5bc513613e..75d51ec98e0628b393919d9fb3b69de14ba2ae83 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -818,6 +818,8 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages) pr_info("Initializing pool allocator\n"); _manager = kzalloc(sizeof(*_manager), GFP_KERNEL); + if (!_manager) + return -ENOMEM; ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc"); diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 73e41a8613da338d0151a27efff9c73390645930..0c648efd9a584df61e1798c45f855490288a4bc0 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -256,10 +256,15 @@ static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long offset; unsigned long page, pos; - if (offset + size > info->fix.smem_len) + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + + offset = vma->vm_pgoff << PAGE_SHIFT; + + if (offset > info->fix.smem_len || size > info->fix.smem_len - offset) return -EINVAL; pos = (unsigned long)info->fix.smem_start + offset; @@ -336,7 +341,7 @@ static int udl_fb_open(struct fb_info *info, int user) struct fb_deferred_io *fbdefio; - fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); + fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); if (fbdefio) { fbdefio->delay = DL_DEFIO_WRITE_DELAY; diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 33dbfb2c47486ee3b7a88cc318d3e6230b4dc0f1..30bfeb1b25124f5921e61960d60910b2158857d3 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -141,18 +141,13 @@ static void udl_free_urb_list(struct drm_device *dev) struct list_head *node; struct urb_node *unode; struct urb *urb; - int ret; unsigned long flags; DRM_DEBUG("Waiting for completes and freeing all render urbs\n"); /* keep waiting and freeing, until we've got 'em all */ while (count--) { - - /* Getting interrupted means a leak, but ok at shutdown*/ - ret = down_interruptible(&udl->urbs.limit_sem); - if (ret) - break; + down(&udl->urbs.limit_sem); spin_lock_irqsave(&udl->urbs.lock, flags); @@ -176,17 +171,22 @@ static void udl_free_urb_list(struct drm_device *dev) static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) { struct udl_device *udl = dev->dev_private; - int i = 0; struct urb *urb; struct urb_node *unode; char *buf; + size_t wanted_size = count * size; spin_lock_init(&udl->urbs.lock); +retry: udl->urbs.size = size; INIT_LIST_HEAD(&udl->urbs.list); - while (i < count) { + sema_init(&udl->urbs.limit_sem, 0); + udl->urbs.count = 0; + udl->urbs.available = 0; + + while (udl->urbs.count * size < wanted_size) { unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL); if (!unode) break; @@ -202,11 +202,16 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) } unode->urb = urb; - buf = usb_alloc_coherent(udl->udev, MAX_TRANSFER, GFP_KERNEL, + buf = usb_alloc_coherent(udl->udev, size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { kfree(unode); usb_free_urb(urb); + if (size > PAGE_SIZE) { + size /= 2; + udl_free_urb_list(dev); + goto retry; + } break; } @@ -217,16 +222,14 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) list_add_tail(&unode->entry, &udl->urbs.list); - i++; + up(&udl->urbs.limit_sem); + udl->urbs.count++; + udl->urbs.available++; } - sema_init(&udl->urbs.limit_sem, i); - udl->urbs.count = i; - udl->urbs.available = i; - - DRM_DEBUG("allocated %d %d byte urbs\n", i, (int) size); + DRM_DEBUG("allocated %d %d byte urbs\n", udl->urbs.count, (int) size); - return i; + return udl->urbs.count; } struct urb *udl_get_urb(struct drm_device *dev) diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index f300eba95bb1bff32ad8e9be2a8250779ec255b6..1244cdf528599312d9596290b37077958fafa09a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -81,8 +81,10 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, return -ENOMEM; size = roundup(size, PAGE_SIZE); ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size); - if (ret != 0) + if (ret != 0) { + kfree(bo); return ret; + } bo->dumb = false; virtio_gpu_init_ttm_placement(bo, pinned); diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index f94558bcb3ce705d70587e0c4cb0d5b96e069829..7a1d32737bac66a8322e2c5f004737d90ca8198c 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -3,7 +3,7 @@ ccflags-y := -Iinclude/uapi/drm -Iinclude/drm -Idrivers/gpu/msm msm_kgsl_core-y = \ kgsl.o \ kgsl_trace.o \ - kgsl_drawobj.o \ + kgsl_cmdbatch.o \ kgsl_ioctl.o \ kgsl_sharedmem.o \ kgsl_pwrctrl.o \ @@ -27,21 +27,19 @@ msm_adreno-y += \ adreno_snapshot.o \ adreno_coresight.o \ adreno_trace.o \ + adreno_a3xx.o \ + adreno_a4xx.o \ + adreno_a5xx.o \ + adreno_a3xx_snapshot.o \ + adreno_a4xx_snapshot.o \ + adreno_a5xx_snapshot.o \ + adreno_a4xx_preempt.o \ + adreno_a5xx_preempt.o \ adreno_sysfs.o \ adreno.o \ adreno_cp_parser.o \ adreno_perfcounter.o -msm_adreno-$(CONFIG_ARCH_MSM8916) += adreno_a4xx.o adreno_a4xx_snapshot.o adreno_a4xx_preempt.o -msm_adreno-$(CONFIG_ARCH_MSM8917) += adreno_a3xx.o adreno_a3xx_snapshot.o -msm_adreno-$(CONFIG_ARCH_MSM8920) += adreno_a3xx.o adreno_a3xx_snapshot.o -msm_adreno-$(CONFIG_ARCH_MSM8937) += adreno_a5xx.o adreno_a5xx_snapshot.o adreno_a5xx_preempt.o -msm_adreno-$(CONFIG_ARCH_MSM8940) += adreno_a5xx.o adreno_a5xx_snapshot.o adreno_a5xx_preempt.o -msm_adreno-$(CONFIG_ARCH_MSM8953) += adreno_a5xx.o adreno_a5xx_snapshot.o adreno_a5xx_preempt.o -msm_adreno-$(CONFIG_ARCH_MSM8996) += adreno_a5xx.o adreno_a5xx_snapshot.o adreno_a5xx_preempt.o -msm_adreno-$(CONFIG_ARCH_MSMCOBALT) += adreno_a5xx.o adreno_a5xx_snapshot.o adreno_a5xx_preempt.o -msm_adreno-$(CONFIG_ARCH_SDM450) += adreno_a5xx.o adreno_a5xx_snapshot.o adreno_a5xx_preempt.o - msm_adreno-$(CONFIG_MSM_KGSL_IOMMU) += adreno_iommu.o msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o adreno_profile.o msm_adreno-$(CONFIG_COMPAT) += adreno_compat.o diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index a2d1da04b3e02f0092a7317ffdb29dec93392486..778c76f52d0bdf33e781250f635a8f1308579bba 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -14,7 +14,6 @@ #define ANY_ID (~0) static const struct adreno_gpu_core adreno_gpulist[] = { -#if defined(CONFIG_ARCH_MSM8917) | defined(CONFIG_ARCH_MSM8920) { .gpurev = ADRENO_REV_A306, .core = 3, @@ -51,8 +50,6 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .gmem_size = (SZ_64K + SZ_32K), .busy_mask = 0x7FFFFFFE, }, -#endif /* CONFIG_ARCH_MSM8917 | CONFIG_ARCH_MSM8920 */ -#ifdef CONFIG_ARCH_MSM8916 { .gpurev = ADRENO_REV_A405, .core = 4, @@ -136,8 +133,6 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .num_protected_regs = 0x18, .busy_mask = 0x7FFFFFFE, }, -#endif /* CONFIG_ARCH_MSM8916 */ -#if defined(CONFIG_ARCH_MSM8937) | defined(CONFIG_ARCH_MSM8940) | defined(CONFIG_ARCH_MSM8953) | defined(CONFIG_ARCH_MSM8996) | defined(CONFIG_ARCH_MSMCOBALT) | defined(CONFIG_ARCH_SDM450) { .gpurev = ADRENO_REV_A530, .core = 5, @@ -266,5 +261,4 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .gpmu_tsens = 0x000C000D, .max_power = 5448, }, -#endif /* CONFIG_ARCH_MSM8937 | CONFIG_ARCH_MSM8940 | CONFIG_ARCH_MSM8953 | CONFIG_ARCH_MSM8996 | CONFIG_ARCH_MSMCOBALT | CONFIG_ARCH_SDM450 */ }; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 57e9946c0b965af5abf5efa3363bdecc7174c158..c5ef65c1d71eff4289355b6374f1c8f28c90a3ad 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,6 @@ /* Include the master list of GPU cores that are supported */ #include "adreno-gpulist.h" -#include "adreno_dispatch.h" #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "adreno." @@ -57,7 +57,7 @@ MODULE_PARM_DESC(nopreempt, "Disable GPU preemption"); #define KGSL_LOG_LEVEL_DEFAULT 3 -static void adreno_pwr_on_work(struct work_struct *work); +static void adreno_input_work(struct work_struct *work); static unsigned int counter_delta(struct kgsl_device *device, unsigned int reg, unsigned int *counter); @@ -95,13 +95,13 @@ static struct adreno_device device_3d0 = { .ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY, .fast_hang_detect = 1, .long_ib_detect = 1, + .input_work = __WORK_INITIALIZER(device_3d0.input_work, + adreno_input_work), .pwrctrl_flag = BIT(ADRENO_SPTP_PC_CTRL) | BIT(ADRENO_PPD_CTRL) | BIT(ADRENO_LM_CTRL) | BIT(ADRENO_HWCG_CTRL), .profile.enabled = false, .active_list = LIST_HEAD_INIT(device_3d0.active_list), .active_list_lock = __SPIN_LOCK_UNLOCKED(device_3d0.active_list_lock), - .pwr_on_work = __WORK_INITIALIZER(device_3d0.pwr_on_work, - adreno_pwr_on_work), }; /* Ptr to array for the current set of fault detect registers */ @@ -123,6 +123,9 @@ static unsigned int adreno_ft_regs_default[] = { /* Nice level for the higher priority GPU start thread */ int adreno_wake_nice = -7; +/* Number of milliseconds to stay active active after a wake on touch */ +unsigned int adreno_wake_timeout = 100; + /** * adreno_readreg64() - Read a 64bit register by getting its offset from the * offset array defined in gpudev node @@ -351,17 +354,152 @@ void adreno_fault_detect_stop(struct adreno_device *adreno_dev) adreno_dev->fast_hang_detect = 0; } -static void adreno_pwr_on_work(struct work_struct *work) +/* + * A workqueue callback responsible for actually turning on the GPU after a + * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any + * active_count protection to avoid the need to maintain state. Either + * somebody will start using the GPU or the idle timer will fire and put the + * GPU back into slumber. + */ +static void adreno_input_work(struct work_struct *work) { - struct adreno_device *adreno_dev = - container_of(work, typeof(*adreno_dev), pwr_on_work); + struct adreno_device *adreno_dev = container_of(work, + struct adreno_device, input_work); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); mutex_lock(&device->mutex); + + device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; + + /* + * Don't schedule adreno_start in a high priority workqueue, we are + * already in a workqueue which should be sufficient + */ kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); + + /* + * When waking up from a touch event we want to stay active long enough + * for the user to send a draw command. The default idle timer timeout + * is shorter than we want so go ahead and push the idle timer out + * further for this special case + */ + mod_timer(&device->idle_timer, + jiffies + msecs_to_jiffies(adreno_wake_timeout)); mutex_unlock(&device->mutex); } +/* + * Process input events and schedule work if needed. At this point we are only + * interested in groking EV_ABS touchscreen events + */ +static void adreno_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + struct kgsl_device *device = handle->handler->private; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + /* Only consider EV_ABS (touch) events */ + if (type != EV_ABS) + return; + + /* + * Don't do anything if anything hasn't been rendered since we've been + * here before + */ + + if (device->flags & KGSL_FLAG_WAKE_ON_TOUCH) + return; + + /* + * If the device is in nap, kick the idle timer to make sure that we + * don't go into slumber before the first render. If the device is + * already in slumber schedule the wake. + */ + + if (device->state == KGSL_STATE_NAP) { + /* + * Set the wake on touch bit to keep from coming back here and + * keeping the device in nap without rendering + */ + + device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; + + mod_timer(&device->idle_timer, + jiffies + device->pwrctrl.interval_timeout); + } else if (device->state == KGSL_STATE_SLUMBER) { + schedule_work(&adreno_dev->input_work); + } +} + +#ifdef CONFIG_INPUT +static int adreno_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int ret; + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (handle == NULL) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = handler->name; + + ret = input_register_handle(handle); + if (ret) { + kfree(handle); + return ret; + } + + ret = input_open_device(handle); + if (ret) { + input_unregister_handle(handle); + kfree(handle); + } + + return ret; +} + +static void adreno_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} +#else +static int adreno_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + return 0; +} +static void adreno_input_disconnect(struct input_handle *handle) {} +#endif + +/* + * We are only interested in EV_ABS events so only register handlers for those + * input devices that have EV_ABS events + */ +static const struct input_device_id adreno_input_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_ABS) }, + /* assumption: MT_.._X & MT_.._Y are in the same long */ + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, + { }, +}; + +static struct input_handler adreno_input_handler = { + .event = adreno_input_event, + .connect = adreno_input_connect, + .disconnect = adreno_input_disconnect, + .name = "kgsl", + .id_table = adreno_input_ids, +}; + static int adreno_soft_reset(struct kgsl_device *device); /* @@ -642,6 +780,7 @@ static void adreno_of_get_initial_pwrlevel(struct adreno_device *adreno_dev, init_level = 1; pwr->active_pwrlevel = init_level; + pwr->default_pwrlevel = init_level; } static int adreno_of_get_legacy_pwrlevels(struct adreno_device *adreno_dev, @@ -744,17 +883,17 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev, /* get pm-qos-active-latency, set it to default if not found */ if (of_property_read_u32(node, "qcom,pm-qos-active-latency", &device->pwrctrl.pm_qos_active_latency)) - device->pwrctrl.pm_qos_active_latency = 1000; + device->pwrctrl.pm_qos_active_latency = 501; /* get pm-qos-cpu-mask-latency, set it to default if not found */ if (of_property_read_u32(node, "qcom,l2pc-cpu-mask-latency", &device->pwrctrl.pm_qos_cpu_mask_latency)) - device->pwrctrl.pm_qos_cpu_mask_latency = 1000; + device->pwrctrl.pm_qos_cpu_mask_latency = 501; /* get pm-qos-wakeup-latency, set it to default if not found */ if (of_property_read_u32(node, "qcom,pm-qos-wakeup-latency", &device->pwrctrl.pm_qos_wakeup_latency)) - device->pwrctrl.pm_qos_wakeup_latency = 100; + device->pwrctrl.pm_qos_wakeup_latency = 101; if (of_property_read_u32(node, "qcom,idle-timeout", &timeout)) timeout = 80; @@ -916,6 +1055,20 @@ static int adreno_probe(struct platform_device *pdev) /* Initialize coresight for the target */ adreno_coresight_init(adreno_dev); +#ifdef CONFIG_INPUT + if (!device->pwrctrl.input_disable) { + adreno_input_handler.private = device; + /* + * It isn't fatal if we cannot register the input handler. Sad, + * perhaps, but not fatal + */ + if (input_register_handler(&adreno_input_handler)) { + adreno_input_handler.private = NULL; + KGSL_DRV_ERR(device, + "Unable to register the input handler\n"); + } + } +#endif out: if (status) { adreno_ringbuffer_close(adreno_dev); @@ -930,8 +1083,8 @@ static void _adreno_free_memories(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - if (test_bit(ADRENO_DEVICE_DRAWOBJ_PROFILE, &adreno_dev->priv)) - kgsl_free_global(device, &adreno_dev->profile_buffer); + if (test_bit(ADRENO_DEVICE_CMDBATCH_PROFILE, &adreno_dev->priv)) + kgsl_free_global(device, &adreno_dev->cmdbatch_profile_buffer); /* Free local copies of firmware and other command streams */ kfree(adreno_dev->pfp_fw); @@ -965,6 +1118,10 @@ static int adreno_remove(struct platform_device *pdev) /* The memory is fading */ _adreno_free_memories(adreno_dev); +#ifdef CONFIG_INPUT + if (adreno_input_handler.private) + input_unregister_handler(&adreno_input_handler); +#endif adreno_sysfs_close(adreno_dev); adreno_coresight_remove(adreno_dev); @@ -1103,22 +1260,22 @@ static int adreno_init(struct kgsl_device *device) } /* - * Allocate a small chunk of memory for precise drawobj profiling for + * Allocate a small chunk of memory for precise cmdbatch profiling for * those targets that have the always on timer */ if (!adreno_is_a3xx(adreno_dev)) { int r = kgsl_allocate_global(device, - &adreno_dev->profile_buffer, PAGE_SIZE, + &adreno_dev->cmdbatch_profile_buffer, PAGE_SIZE, 0, 0, "alwayson"); - adreno_dev->profile_index = 0; + adreno_dev->cmdbatch_profile_index = 0; if (r == 0) { - set_bit(ADRENO_DEVICE_DRAWOBJ_PROFILE, + set_bit(ADRENO_DEVICE_CMDBATCH_PROFILE, &adreno_dev->priv); kgsl_sharedmem_set(device, - &adreno_dev->profile_buffer, 0, 0, + &adreno_dev->cmdbatch_profile_buffer, 0, 0, PAGE_SIZE); } @@ -2261,12 +2418,12 @@ int adreno_idle(struct kgsl_device *device) * adreno_drain() - Drain the dispatch queue * @device: Pointer to the KGSL device structure for the GPU * - * Drain the dispatcher of existing drawobjs. This halts + * Drain the dispatcher of existing command batches. This halts * additional commands from being issued until the gate is completed. */ static int adreno_drain(struct kgsl_device *device) { - reinit_completion(&device->halt_gate); + reinit_completion(&device->cmdbatch_gate); return 0; } @@ -2755,7 +2912,7 @@ static const struct kgsl_functable adreno_functable = { .getproperty_compat = adreno_getproperty_compat, .waittimestamp = adreno_waittimestamp, .readtimestamp = adreno_readtimestamp, - .queue_cmds = adreno_dispatcher_queue_cmds, + .issueibcmds = adreno_ringbuffer_issueibcmds, .ioctl = adreno_ioctl, .compat_ioctl = adreno_compat_ioctl, .power_stats = adreno_power_stats, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 1eb929ede538b17ba046463aa38f4ab7bd3e2b91..eaef1aa9c4005c1c4ef10aa00e43bcdcffcb5441 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -76,13 +76,13 @@ KGSL_CONTEXT_PREEMPT_STYLE_SHIFT) /* - * return the dispatcher drawqueue in which the given drawobj should + * return the dispatcher cmdqueue in which the given cmdbatch should * be submitted */ -#define ADRENO_DRAWOBJ_DISPATCH_DRAWQUEUE(c) \ +#define ADRENO_CMDBATCH_DISPATCH_CMDQUEUE(c) \ (&((ADRENO_CONTEXT(c->context))->rb->dispatch_q)) -#define ADRENO_DRAWOBJ_RB(c) \ +#define ADRENO_CMDBATCH_RB(c) \ ((ADRENO_CONTEXT(c->context))->rb) /* Adreno core features */ @@ -344,7 +344,7 @@ struct adreno_gpu_core { * @dispatcher: Container for adreno GPU dispatcher * @pwron_fixup: Command buffer to run a post-power collapse shader workaround * @pwron_fixup_dwords: Number of dwords in the command buffer - * @pwr_on_work: Work struct for turning on the GPU + * @input_work: Work struct for turning on the GPU after a touch event * @busy_data: Struct holding GPU VBIF busy stats * @ram_cycles_lo: Number of DDR clock cycles for the monitor session * @perfctr_pwr_lo: Number of cycles VBIF is stalled by DDR @@ -352,8 +352,8 @@ struct adreno_gpu_core { * @pending_irq_refcnt: Atomic variable to keep track of running IRQ handlers * @ctx_d_debugfs: Context debugfs node * @pwrctrl_flag: Flag to hold adreno specific power attributes - * @profile_buffer: Memdesc holding the drawobj profiling buffer - * @profile_index: Index to store the start/stop ticks in the profiling + * @cmdbatch_profile_buffer: Memdesc holding the cmdbatch profiling buffer + * @cmdbatch_profile_index: Index to store the start/stop ticks in the profiling * buffer * @sp_local_gpuaddr: Base GPU virtual address for SP local memory * @sp_pvt_gpuaddr: Base GPU virtual address for SP private memory @@ -401,7 +401,7 @@ struct adreno_device { struct adreno_dispatcher dispatcher; struct kgsl_memdesc pwron_fixup; unsigned int pwron_fixup_dwords; - struct work_struct pwr_on_work; + struct work_struct input_work; struct adreno_busy_data busy_data; unsigned int ram_cycles_lo; unsigned int starved_ram_lo; @@ -411,8 +411,8 @@ struct adreno_device { struct dentry *ctx_d_debugfs; unsigned long pwrctrl_flag; - struct kgsl_memdesc profile_buffer; - unsigned int profile_index; + struct kgsl_memdesc cmdbatch_profile_buffer; + unsigned int cmdbatch_profile_index; uint64_t sp_local_gpuaddr; uint64_t sp_pvt_gpuaddr; const struct firmware *lm_fw; @@ -448,7 +448,7 @@ struct adreno_device { * @ADRENO_DEVICE_STARTED - Set if the device start sequence is in progress * @ADRENO_DEVICE_FAULT - Set if the device is currently in fault (and shouldn't * send any more commands to the ringbuffer) - * @ADRENO_DEVICE_DRAWOBJ_PROFILE - Set if the device supports drawobj + * @ADRENO_DEVICE_CMDBATCH_PROFILE - Set if the device supports command batch * profiling via the ALWAYSON counter * @ADRENO_DEVICE_PREEMPTION - Turn on/off preemption * @ADRENO_DEVICE_SOFT_FAULT_DETECT - Set if soft fault detect is enabled @@ -466,7 +466,7 @@ enum adreno_device_flags { ADRENO_DEVICE_HANG_INTR = 4, ADRENO_DEVICE_STARTED = 5, ADRENO_DEVICE_FAULT = 6, - ADRENO_DEVICE_DRAWOBJ_PROFILE = 7, + ADRENO_DEVICE_CMDBATCH_PROFILE = 7, ADRENO_DEVICE_GPU_REGULATOR_ENABLED = 8, ADRENO_DEVICE_PREEMPTION = 9, ADRENO_DEVICE_SOFT_FAULT_DETECT = 10, @@ -476,22 +476,22 @@ enum adreno_device_flags { }; /** - * struct adreno_drawobj_profile_entry - a single drawobj entry in the + * struct adreno_cmdbatch_profile_entry - a single command batch entry in the * kernel profiling buffer - * @started: Number of GPU ticks at start of the drawobj - * @retired: Number of GPU ticks at the end of the drawobj + * @started: Number of GPU ticks at start of the command batch + * @retired: Number of GPU ticks at the end of the command batch */ -struct adreno_drawobj_profile_entry { +struct adreno_cmdbatch_profile_entry { uint64_t started; uint64_t retired; }; -#define ADRENO_DRAWOBJ_PROFILE_COUNT \ - (PAGE_SIZE / sizeof(struct adreno_drawobj_profile_entry)) +#define ADRENO_CMDBATCH_PROFILE_COUNT \ + (PAGE_SIZE / sizeof(struct adreno_cmdbatch_profile_entry)) -#define ADRENO_DRAWOBJ_PROFILE_OFFSET(_index, _member) \ - ((_index) * sizeof(struct adreno_drawobj_profile_entry) \ - + offsetof(struct adreno_drawobj_profile_entry, _member)) +#define ADRENO_CMDBATCH_PROFILE_OFFSET(_index, _member) \ + ((_index) * sizeof(struct adreno_cmdbatch_profile_entry) \ + + offsetof(struct adreno_cmdbatch_profile_entry, _member)) /** @@ -790,7 +790,7 @@ struct adreno_gpudev { * @KGSL_FT_REPLAY: Replay the faulting command * @KGSL_FT_SKIPIB: Skip the faulting indirect buffer * @KGSL_FT_SKIPFRAME: Skip the frame containing the faulting IB - * @KGSL_FT_DISABLE: Tells the dispatcher to disable FT for the command obj + * @KGSL_FT_DISABLE: Tells the dispatcher to disable FT for the command batch * @KGSL_FT_TEMP_DISABLE: Disables FT for all commands * @KGSL_FT_THROTTLE: Disable the context if it faults too often * @KGSL_FT_SKIPCMD: Skip the command containing the faulting IB @@ -807,7 +807,7 @@ enum kgsl_ft_policy_bits { /* KGSL_FT_MAX_BITS is used to calculate the mask */ KGSL_FT_MAX_BITS, /* Internal bits - set during GFT */ - /* Skip the PM dump on replayed command obj's */ + /* Skip the PM dump on replayed command batches */ KGSL_FT_SKIP_PMDUMP = 31, }; @@ -867,6 +867,7 @@ extern struct adreno_gpudev adreno_a4xx_gpudev; extern struct adreno_gpudev adreno_a5xx_gpudev; extern int adreno_wake_nice; +extern unsigned int adreno_wake_timeout; long adreno_ioctl(struct kgsl_device_private *dev_priv, unsigned int cmd, unsigned long arg); @@ -895,7 +896,7 @@ int adreno_reset(struct kgsl_device *device, int fault); void adreno_fault_skipcmd_detached(struct adreno_device *adreno_dev, struct adreno_context *drawctxt, - struct kgsl_drawobj *drawobj); + struct kgsl_cmdbatch *cmdbatch); int adreno_coresight_init(struct adreno_device *adreno_dev); diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index bcb1df07438978e26735a0623c45e6d62c7fff00..cc313d27ee074cc0314c1315e9a0796b3cd7c0e2 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -44,7 +44,7 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) if (reset_timer) rb->dispatch_q.expires = jiffies + - msecs_to_jiffies(adreno_drawobj_timeout); + msecs_to_jiffies(adreno_cmdbatch_timeout); spin_unlock_irqrestore(&rb->preempt_lock, flags); } diff --git a/drivers/gpu/msm/adreno_cp_parser.h b/drivers/gpu/msm/adreno_cp_parser.h index 78557ec6330f563d0f57cbe762d9a7117858498d..f4d6cd99226e1c3d1cfe9438f8dddbc21f992598 100644 --- a/drivers/gpu/msm/adreno_cp_parser.h +++ b/drivers/gpu/msm/adreno_cp_parser.h @@ -15,12 +15,8 @@ #include "adreno.h" -#if defined(CONFIG_ARCH_MSM8917) | defined(CONFIG_ARCH_MSM8920) extern const unsigned int a3xx_cp_addr_regs[]; -#endif -#ifdef CONFIG_ARCH_MSM8916 extern const unsigned int a4xx_cp_addr_regs[]; -#endif /* * struct adreno_ib_object - Structure containing information about an @@ -141,17 +137,12 @@ static inline int adreno_cp_parser_getreg(struct adreno_device *adreno_dev, if (reg_enum == ADRENO_CP_ADDR_MAX) return -EEXIST; -#if defined(CONFIG_ARCH_MSM8917) | defined(CONFIG_ARCH_MSM8920) if (adreno_is_a3xx(adreno_dev)) return a3xx_cp_addr_regs[reg_enum]; -#endif -#ifdef CONFIG_ARCH_MSM8916 - if (adreno_is_a4xx(adreno_dev)) + else if (adreno_is_a4xx(adreno_dev)) return a4xx_cp_addr_regs[reg_enum]; -#endif -#if defined(CONFIG_ARCH_MSM8937) | defined(CONFIG_ARCH_MSM8940) | defined(CONFIG_ARCH_MSM8953) | defined(CONFIG_ARCH_MSM8996) | defined(CONFIG_ARCH_MSMCOBALT) | defined(CONFIG_ARCH_SDM450) + else return -EEXIST; -#endif } /* @@ -171,17 +162,12 @@ static inline int adreno_cp_parser_regindex(struct adreno_device *adreno_dev, { int i; const unsigned int *regs; -#ifdef CONFIG_ARCH_MSM8916 if (adreno_is_a4xx(adreno_dev)) regs = a4xx_cp_addr_regs; -#endif -#if defined(CONFIG_ARCH_MSM8917) | defined(CONFIG_ARCH_MSM8920) - if (adreno_is_a3xx(adreno_dev)) + else if (adreno_is_a3xx(adreno_dev)) regs = a3xx_cp_addr_regs; -#endif -#if defined(CONFIG_ARCH_MSM8937) | defined(CONFIG_ARCH_MSM8940) | defined(CONFIG_ARCH_MSM8953) | defined(CONFIG_ARCH_MSM8996) | defined(CONFIG_ARCH_MSMCOBALT) | defined(CONFIG_ARCH_SDM450) + else return -EEXIST; -#endif for (i = start; i <= end && i < ADRENO_CP_ADDR_MAX; i++) if (regs[i] == offset) diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 2027ac66f73720d1bec5699a664e32823eb743bd..6b247603bc6a4ff06e02988d508a9981d200b742 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -129,7 +129,7 @@ typedef void (*reg_read_fill_t)(struct kgsl_device *device, int i, static void sync_event_print(struct seq_file *s, - struct kgsl_drawobj_sync_event *sync_event) + struct kgsl_cmdbatch_sync_event *sync_event) { unsigned long flags; @@ -142,7 +142,7 @@ static void sync_event_print(struct seq_file *s, case KGSL_CMD_SYNCPOINT_TYPE_FENCE: spin_lock_irqsave(&sync_event->handle_lock, flags); - seq_printf(s, "sync: [%pK] %s", sync_event->handle, + seq_printf(s, "sync: [%pk] %s", sync_event->handle, (sync_event->handle && sync_event->handle->fence) ? sync_event->handle->fence->name : "NULL"); @@ -159,12 +159,12 @@ struct flag_entry { const char *str; }; -static const struct flag_entry drawobj_flags[] = {KGSL_DRAWOBJ_FLAGS}; +static const struct flag_entry cmdbatch_flags[] = {KGSL_CMDBATCH_FLAGS}; -static const struct flag_entry cmdobj_priv[] = { - { CMDOBJ_SKIP, "skip"}, - { CMDOBJ_FORCE_PREAMBLE, "force_preamble"}, - { CMDOBJ_WFI, "wait_for_idle" }, +static const struct flag_entry cmdbatch_priv[] = { + { CMDBATCH_FLAG_SKIP, "skip"}, + { CMDBATCH_FLAG_FORCE_PREAMBLE, "force_preamble"}, + { CMDBATCH_FLAG_WFI, "wait_for_idle" }, }; static const struct flag_entry context_flags[] = {KGSL_CONTEXT_FLAGS}; @@ -206,54 +206,42 @@ static void print_flags(struct seq_file *s, const struct flag_entry *table, seq_puts(s, "None"); } -static void syncobj_print(struct seq_file *s, - struct kgsl_drawobj_sync *syncobj) +static void cmdbatch_print(struct seq_file *s, struct kgsl_cmdbatch *cmdbatch) { - struct kgsl_drawobj_sync_event *event; + struct kgsl_cmdbatch_sync_event *event; unsigned int i; - seq_puts(s, " syncobj "); + /* print fences first, since they block this cmdbatch */ - for (i = 0; i < syncobj->numsyncs; i++) { - event = &syncobj->synclist[i]; + for (i = 0; i < cmdbatch->numsyncs; i++) { + event = &cmdbatch->synclist[i]; - if (!kgsl_drawobj_event_pending(syncobj, i)) + if (!kgsl_cmdbatch_event_pending(cmdbatch, i)) continue; + /* + * Timestamp is 0 for KGSL_CONTEXT_SYNC, but print it anyways + * so that it is clear if the fence was a separate submit + * or part of an IB submit. + */ + seq_printf(s, "\t%d ", cmdbatch->timestamp); sync_event_print(s, event); seq_puts(s, "\n"); } -} -static void cmdobj_print(struct seq_file *s, - struct kgsl_drawobj_cmd *cmdobj) -{ - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); + /* if this flag is set, there won't be an IB */ + if (cmdbatch->flags & KGSL_CONTEXT_SYNC) + return; - if (drawobj->type == CMDOBJ_TYPE) - seq_puts(s, " cmdobj "); - else - seq_puts(s, " markerobj "); + seq_printf(s, "\t%d: ", cmdbatch->timestamp); - seq_printf(s, "\t %d ", drawobj->timestamp); + seq_puts(s, " flags: "); + print_flags(s, cmdbatch_flags, ARRAY_SIZE(cmdbatch_flags), + cmdbatch->flags); seq_puts(s, " priv: "); - print_flags(s, cmdobj_priv, ARRAY_SIZE(cmdobj_priv), - cmdobj->priv); -} - -static void drawobj_print(struct seq_file *s, - struct kgsl_drawobj *drawobj) -{ - if (drawobj->type == SYNCOBJ_TYPE) - syncobj_print(s, SYNCOBJ(drawobj)); - else if ((drawobj->type == CMDOBJ_TYPE) || - (drawobj->type == MARKEROBJ_TYPE)) - cmdobj_print(s, CMDOBJ(drawobj)); - - seq_puts(s, " flags: "); - print_flags(s, drawobj_flags, ARRAY_SIZE(drawobj_flags), - drawobj->flags); + print_flags(s, cmdbatch_priv, ARRAY_SIZE(cmdbatch_priv), + cmdbatch->priv); seq_puts(s, "\n"); } @@ -304,13 +292,13 @@ static int ctx_print(struct seq_file *s, void *unused) queued, consumed, retired, drawctxt->internal_timestamp); - seq_puts(s, "drawqueue:\n"); + seq_puts(s, "cmdqueue:\n"); spin_lock(&drawctxt->lock); - for (i = drawctxt->drawqueue_head; - i != drawctxt->drawqueue_tail; - i = DRAWQUEUE_NEXT(i, ADRENO_CONTEXT_DRAWQUEUE_SIZE)) - drawobj_print(s, drawctxt->drawqueue[i]); + for (i = drawctxt->cmdqueue_head; + i != drawctxt->cmdqueue_tail; + i = CMDQUEUE_NEXT(i, ADRENO_CONTEXT_CMDQUEUE_SIZE)) + cmdbatch_print(s, drawctxt->cmdqueue[i]); spin_unlock(&drawctxt->lock); seq_puts(s, "events:\n"); diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 7749e5ece4609187b70770418958e10f8e937112..381da0e3a26cd8d33ce7ad52ec5a1ac4fb727b56 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * 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 @@ -25,7 +25,7 @@ #include "adreno_trace.h" #include "kgsl_sharedmem.h" -#define DRAWQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s)) +#define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s)) /* Time in ms after which the dispatcher tries to schedule an unscheduled RB */ unsigned int adreno_dispatch_starvation_time = 2000; @@ -43,13 +43,13 @@ unsigned int adreno_dispatch_time_slice = 25; unsigned int adreno_disp_preempt_fair_sched; /* Number of commands that can be queued in a context before it sleeps */ -static unsigned int _context_drawqueue_size = 50; +static unsigned int _context_cmdqueue_size = 50; /* Number of milliseconds to wait for the context queue to clear */ static unsigned int _context_queue_wait = 10000; -/* Number of drawobjs sent at a time from a single context */ -static unsigned int _context_drawobj_burst = 5; +/* Number of command batches sent at a time from a single context */ +static unsigned int _context_cmdbatch_burst = 5; /* * GFT throttle parameters. If GFT recovered more than @@ -73,25 +73,24 @@ static unsigned int _dispatcher_q_inflight_hi = 15; static unsigned int _dispatcher_q_inflight_lo = 4; /* Command batch timeout (in milliseconds) */ -unsigned int adreno_drawobj_timeout = 2000; +unsigned int adreno_cmdbatch_timeout = 2000; /* Interval for reading and comparing fault detection registers */ static unsigned int _fault_timer_interval = 200; -#define DRAWQUEUE_RB(_drawqueue) \ +#define CMDQUEUE_RB(_cmdqueue) \ ((struct adreno_ringbuffer *) \ - container_of((_drawqueue),\ - struct adreno_ringbuffer, dispatch_q)) + container_of((_cmdqueue), struct adreno_ringbuffer, dispatch_q)) -#define DRAWQUEUE(_ringbuffer) (&(_ringbuffer)->dispatch_q) +#define CMDQUEUE(_ringbuffer) (&(_ringbuffer)->dispatch_q) -static int adreno_dispatch_retire_drawqueue(struct adreno_device *adreno_dev, - struct adreno_dispatcher_drawqueue *drawqueue); +static int adreno_dispatch_retire_cmdqueue(struct adreno_device *adreno_dev, + struct adreno_dispatcher_cmdqueue *cmdqueue); -static inline bool drawqueue_is_current( - struct adreno_dispatcher_drawqueue *drawqueue) +static inline bool cmdqueue_is_current( + struct adreno_dispatcher_cmdqueue *cmdqueue) { - struct adreno_ringbuffer *rb = DRAWQUEUE_RB(drawqueue); + struct adreno_ringbuffer *rb = CMDQUEUE_RB(cmdqueue); struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); return (adreno_dev->cur_rb == rb); @@ -115,8 +114,7 @@ static int __count_context(struct adreno_context *drawctxt, void *data) return time_after(jiffies, expires) ? 0 : 1; } -static int __count_drawqueue_context(struct adreno_context *drawctxt, - void *data) +static int __count_cmdqueue_context(struct adreno_context *drawctxt, void *data) { unsigned long expires = drawctxt->active_time + msecs_to_jiffies(100); @@ -124,7 +122,7 @@ static int __count_drawqueue_context(struct adreno_context *drawctxt, return 0; return (&drawctxt->rb->dispatch_q == - (struct adreno_dispatcher_drawqueue *) data) ? 1 : 0; + (struct adreno_dispatcher_cmdqueue *) data) ? 1 : 0; } static int _adreno_count_active_contexts(struct adreno_device *adreno_dev, @@ -144,7 +142,7 @@ static int _adreno_count_active_contexts(struct adreno_device *adreno_dev, } static void _track_context(struct adreno_device *adreno_dev, - struct adreno_dispatcher_drawqueue *drawqueue, + struct adreno_dispatcher_cmdqueue *cmdqueue, struct adreno_context *drawctxt) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -156,9 +154,9 @@ static void _track_context(struct adreno_device *adreno_dev, device->active_context_count = _adreno_count_active_contexts(adreno_dev, __count_context, NULL); - drawqueue->active_context_count = + cmdqueue->active_context_count = _adreno_count_active_contexts(adreno_dev, - __count_drawqueue_context, drawqueue); + __count_cmdqueue_context, cmdqueue); spin_unlock(&adreno_dev->active_list_lock); } @@ -171,9 +169,9 @@ static void _track_context(struct adreno_device *adreno_dev, */ static inline int -_drawqueue_inflight(struct adreno_dispatcher_drawqueue *drawqueue) +_cmdqueue_inflight(struct adreno_dispatcher_cmdqueue *cmdqueue) { - return (drawqueue->active_context_count > 1) + return (cmdqueue->active_context_count > 1) ? _dispatcher_q_inflight_lo : _dispatcher_q_inflight_hi; } @@ -277,20 +275,20 @@ static void start_fault_timer(struct adreno_device *adreno_dev) } /** - * _retire_timestamp() - Retire object without sending it - * to the hardware - * @drawobj: Pointer to the object to retire + * _retire_marker() - Retire a marker command batch without sending it to the + * hardware + * @cmdbatch: Pointer to the cmdbatch to retire * - * In some cases ibs can be retired by the software - * without going to the GPU. In those cases, update the - * memstore from the CPU, kick off the event engine to handle - * expired events and destroy the ib. + * In some cases marker commands can be retired by the software without going to + * the GPU. In those cases, update the memstore from the CPU, kick off the + * event engine to handle expired events and destroy the command batch. */ -static void _retire_timestamp(struct kgsl_drawobj *drawobj) +static void _retire_marker(struct kgsl_cmdbatch *cmdbatch) { - struct kgsl_context *context = drawobj->context; - struct adreno_context *drawctxt = ADRENO_CONTEXT(context); + struct kgsl_context *context = cmdbatch->context; + struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context); struct kgsl_device *device = context->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); /* * Write the start and end timestamp to the memstore to keep the @@ -298,11 +296,11 @@ static void _retire_timestamp(struct kgsl_drawobj *drawobj) */ kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), - drawobj->timestamp); + cmdbatch->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), - drawobj->timestamp); + cmdbatch->timestamp); /* Retire pending GPU events for the object */ @@ -313,13 +311,13 @@ static void _retire_timestamp(struct kgsl_drawobj *drawobj) * rptr scratch out address. At this point GPU clocks turned off. * So avoid reading GPU register directly for A3xx. */ - if (adreno_is_a3xx(ADRENO_DEVICE(device))) - trace_adreno_cmdbatch_retired(drawobj, -1, 0, 0, drawctxt->rb, - 0, 0); + if (adreno_is_a3xx(adreno_dev)) + trace_adreno_cmdbatch_retired(cmdbatch, -1, 0, 0, drawctxt->rb, + 0); else - trace_adreno_cmdbatch_retired(drawobj, -1, 0, 0, drawctxt->rb, - adreno_get_rptr(drawctxt->rb), 0); - kgsl_drawobj_destroy(drawobj); + trace_adreno_cmdbatch_retired(cmdbatch, -1, 0, 0, drawctxt->rb, + adreno_get_rptr(drawctxt->rb)); + kgsl_cmdbatch_destroy(cmdbatch); } static int _check_context_queue(struct adreno_context *drawctxt) @@ -336,7 +334,7 @@ static int _check_context_queue(struct adreno_context *drawctxt) if (kgsl_context_invalid(&drawctxt->base)) ret = 1; else - ret = drawctxt->queued < _context_drawqueue_size ? 1 : 0; + ret = drawctxt->queued < _context_cmdqueue_size ? 1 : 0; spin_unlock(&drawctxt->lock); @@ -347,151 +345,176 @@ static int _check_context_queue(struct adreno_context *drawctxt) * return true if this is a marker command and the dependent timestamp has * retired */ -static bool _marker_expired(struct kgsl_drawobj_cmd *markerobj) +static bool _marker_expired(struct kgsl_cmdbatch *cmdbatch) { - struct kgsl_drawobj *drawobj = DRAWOBJ(markerobj); - - return (drawobj->flags & KGSL_DRAWOBJ_MARKER) && - kgsl_check_timestamp(drawobj->device, drawobj->context, - markerobj->marker_timestamp); + return (cmdbatch->flags & KGSL_CMDBATCH_MARKER) && + kgsl_check_timestamp(cmdbatch->device, cmdbatch->context, + cmdbatch->marker_timestamp); } -static inline void _pop_drawobj(struct adreno_context *drawctxt) +static inline void _pop_cmdbatch(struct adreno_context *drawctxt) { - drawctxt->drawqueue_head = DRAWQUEUE_NEXT(drawctxt->drawqueue_head, - ADRENO_CONTEXT_DRAWQUEUE_SIZE); + drawctxt->cmdqueue_head = CMDQUEUE_NEXT(drawctxt->cmdqueue_head, + ADRENO_CONTEXT_CMDQUEUE_SIZE); drawctxt->queued--; } - -static int _retire_markerobj(struct kgsl_drawobj_cmd *cmdobj, - struct adreno_context *drawctxt) +/** + * Removes all expired marker and sync cmdbatches from + * the context queue when marker command and dependent + * timestamp are retired. This function is recursive. + * returns cmdbatch if context has command, NULL otherwise. + */ +static struct kgsl_cmdbatch *_expire_markers(struct adreno_context *drawctxt) { - if (_marker_expired(cmdobj)) { - _pop_drawobj(drawctxt); - _retire_timestamp(DRAWOBJ(cmdobj)); - return 0; - } + struct kgsl_cmdbatch *cmdbatch; - /* - * If the marker isn't expired but the SKIP bit - * is set then there are real commands following - * this one in the queue. This means that we - * need to dispatch the command so that we can - * keep the timestamp accounting correct. If - * skip isn't set then we block this queue - * until the dependent timestamp expires - */ - return test_bit(CMDOBJ_SKIP, &cmdobj->priv) ? 1 : -EAGAIN; -} + if (drawctxt->cmdqueue_head == drawctxt->cmdqueue_tail) + return NULL; -static int _retire_syncobj(struct kgsl_drawobj_sync *syncobj, - struct adreno_context *drawctxt) -{ - if (!kgsl_drawobj_events_pending(syncobj)) { - _pop_drawobj(drawctxt); - kgsl_drawobj_destroy(DRAWOBJ(syncobj)); - return 0; + cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; + + if (cmdbatch == NULL) + return NULL; + + /* Check to see if this is a marker we can skip over */ + if ((cmdbatch->flags & KGSL_CMDBATCH_MARKER) && + _marker_expired(cmdbatch)) { + _pop_cmdbatch(drawctxt); + _retire_marker(cmdbatch); + return _expire_markers(drawctxt); } - /* - * If we got here, there are pending events for sync object. - * Start the canary timer if it hasnt been started already. - */ - if (!syncobj->timeout_jiffies) { - syncobj->timeout_jiffies = jiffies + msecs_to_jiffies(5000); - mod_timer(&syncobj->timer, syncobj->timeout_jiffies); + if (cmdbatch->flags & KGSL_CMDBATCH_SYNC) { + if (!kgsl_cmdbatch_events_pending(cmdbatch)) { + _pop_cmdbatch(drawctxt); + kgsl_cmdbatch_destroy(cmdbatch); + return _expire_markers(drawctxt); + } } - return -EAGAIN; + return cmdbatch; } -/* - * Retires all expired marker and sync objs from the context - * queue and returns one of the below - * a) next drawobj that needs to be sent to ringbuffer - * b) -EAGAIN for syncobj with syncpoints pending. - * c) -EAGAIN for markerobj whose marker timestamp has not expired yet. - * c) NULL for no commands remaining in drawqueue. - */ -static struct kgsl_drawobj *_process_drawqueue_get_next_drawobj( - struct adreno_context *drawctxt) +static void expire_markers(struct adreno_context *drawctxt) { - struct kgsl_drawobj *drawobj; - unsigned int i = drawctxt->drawqueue_head; - int ret = 0; + spin_lock(&drawctxt->lock); + _expire_markers(drawctxt); + spin_unlock(&drawctxt->lock); +} - if (drawctxt->drawqueue_head == drawctxt->drawqueue_tail) - return NULL; +static struct kgsl_cmdbatch *_get_cmdbatch(struct adreno_context *drawctxt) +{ + struct kgsl_cmdbatch *cmdbatch; + bool pending = false; - for (i = drawctxt->drawqueue_head; i != drawctxt->drawqueue_tail; - i = DRAWQUEUE_NEXT(i, ADRENO_CONTEXT_DRAWQUEUE_SIZE)) { + cmdbatch = _expire_markers(drawctxt); - drawobj = drawctxt->drawqueue[i]; + if (cmdbatch == NULL) + return NULL; - if (drawobj == NULL) - return NULL; + /* + * If the marker isn't expired but the SKIP bit is set + * then there are real commands following this one in + * the queue. This means that we need to dispatch the + * command so that we can keep the timestamp accounting + * correct. If skip isn't set then we block this queue + * until the dependent timestamp expires + */ + if ((cmdbatch->flags & KGSL_CMDBATCH_MARKER) && + (!test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv))) + pending = true; - if (drawobj->type == CMDOBJ_TYPE) - return drawobj; - else if (drawobj->type == MARKEROBJ_TYPE) { - ret = _retire_markerobj(CMDOBJ(drawobj), drawctxt); - /* Special case where marker needs to be sent to GPU */ - if (ret == 1) - return drawobj; - } else if (drawobj->type == SYNCOBJ_TYPE) - ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt); + if (kgsl_cmdbatch_events_pending(cmdbatch)) + pending = true; - if (ret == -EAGAIN) - return ERR_PTR(-EAGAIN); + /* + * If changes are pending and the canary timer hasn't been + * started yet, start it + */ + if (pending) { + /* + * If syncpoints are pending start the canary timer if + * it hasn't already been started + */ + if (!cmdbatch->timeout_jiffies) { + cmdbatch->timeout_jiffies = + jiffies + msecs_to_jiffies(5000); + mod_timer(&cmdbatch->timer, cmdbatch->timeout_jiffies); + } - continue; + return ERR_PTR(-EAGAIN); } - return NULL; + _pop_cmdbatch(drawctxt); + return cmdbatch; +} + +/** + * adreno_dispatcher_get_cmdbatch() - Get a new command from a context queue + * @drawctxt: Pointer to the adreno draw context + * + * Dequeue a new command batch from the context list + */ +static struct kgsl_cmdbatch *adreno_dispatcher_get_cmdbatch( + struct adreno_context *drawctxt) +{ + struct kgsl_cmdbatch *cmdbatch; + + spin_lock(&drawctxt->lock); + cmdbatch = _get_cmdbatch(drawctxt); + spin_unlock(&drawctxt->lock); + + /* + * Delete the timer and wait for timer handler to finish executing + * on another core before queueing the buffer. We must do this + * without holding any spin lock that the timer handler might be using + */ + if (!IS_ERR_OR_NULL(cmdbatch)) + del_timer_sync(&cmdbatch->timer); + + return cmdbatch; } /** - * adreno_dispatcher_requeue_cmdobj() - Put a command back on the context + * adreno_dispatcher_requeue_cmdbatch() - Put a command back on the context * queue * @drawctxt: Pointer to the adreno draw context - * @cmdobj: Pointer to the KGSL command object to requeue + * @cmdbatch: Pointer to the KGSL cmdbatch to requeue * * Failure to submit a command to the ringbuffer isn't the fault of the command * being submitted so if a failure happens, push it back on the head of the the * context queue to be reconsidered again unless the context got detached. */ -static inline int adreno_dispatcher_requeue_cmdobj( - struct adreno_context *drawctxt, - struct kgsl_drawobj_cmd *cmdobj) +static inline int adreno_dispatcher_requeue_cmdbatch( + struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch) { unsigned int prev; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); spin_lock(&drawctxt->lock); if (kgsl_context_detached(&drawctxt->base) || kgsl_context_invalid(&drawctxt->base)) { spin_unlock(&drawctxt->lock); - /* get rid of this drawobj since the context is bad */ - kgsl_drawobj_destroy(drawobj); + /* get rid of this cmdbatch since the context is bad */ + kgsl_cmdbatch_destroy(cmdbatch); return -ENOENT; } - prev = drawctxt->drawqueue_head == 0 ? - (ADRENO_CONTEXT_DRAWQUEUE_SIZE - 1) : - (drawctxt->drawqueue_head - 1); + prev = drawctxt->cmdqueue_head == 0 ? + (ADRENO_CONTEXT_CMDQUEUE_SIZE - 1) : + (drawctxt->cmdqueue_head - 1); /* * The maximum queue size always needs to be one less then the size of - * the ringbuffer queue so there is "room" to put the drawobj back in + * the ringbuffer queue so there is "room" to put the cmdbatch back in */ - WARN_ON(prev == drawctxt->drawqueue_tail); + BUG_ON(prev == drawctxt->cmdqueue_tail); - drawctxt->drawqueue[prev] = drawobj; + drawctxt->cmdqueue[prev] = cmdbatch; drawctxt->queued++; /* Reset the command queue head to reflect the newly requeued change */ - drawctxt->drawqueue_head = prev; + drawctxt->cmdqueue_head = prev; spin_unlock(&drawctxt->lock); return 0; } @@ -526,22 +549,21 @@ static void dispatcher_queue_context(struct adreno_device *adreno_dev, } /** - * sendcmd() - Send a drawobj to the GPU hardware + * sendcmd() - Send a command batch to the GPU hardware * @dispatcher: Pointer to the adreno dispatcher struct - * @drawobj: Pointer to the KGSL drawobj being sent + * @cmdbatch: Pointer to the KGSL cmdbatch being sent * - * Send a KGSL drawobj to the GPU hardware + * Send a KGSL command batch to the GPU hardware */ static int sendcmd(struct adreno_device *adreno_dev, - struct kgsl_drawobj_cmd *cmdobj) + struct kgsl_cmdbatch *cmdbatch) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct adreno_context *drawctxt = ADRENO_CONTEXT(drawobj->context); - struct adreno_dispatcher_drawqueue *dispatch_q = - ADRENO_DRAWOBJ_DISPATCH_DRAWQUEUE(drawobj); + struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context); + struct adreno_dispatcher_cmdqueue *dispatch_q = + ADRENO_CMDBATCH_DISPATCH_CMDQUEUE(cmdbatch); struct adreno_submit_time time; uint64_t secs = 0; unsigned long nsecs = 0; @@ -570,15 +592,15 @@ static int sendcmd(struct adreno_device *adreno_dev, set_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv); } - if (test_bit(ADRENO_DEVICE_DRAWOBJ_PROFILE, &adreno_dev->priv)) { - set_bit(CMDOBJ_PROFILE, &cmdobj->priv); - cmdobj->profile_index = adreno_dev->profile_index; - adreno_dev->profile_index = - (adreno_dev->profile_index + 1) % - ADRENO_DRAWOBJ_PROFILE_COUNT; + if (test_bit(ADRENO_DEVICE_CMDBATCH_PROFILE, &adreno_dev->priv)) { + set_bit(CMDBATCH_FLAG_PROFILE, &cmdbatch->priv); + cmdbatch->profile_index = adreno_dev->cmdbatch_profile_index; + adreno_dev->cmdbatch_profile_index = + (adreno_dev->cmdbatch_profile_index + 1) % + ADRENO_CMDBATCH_PROFILE_COUNT; } - ret = adreno_ringbuffer_submitcmd(adreno_dev, cmdobj, &time); + ret = adreno_ringbuffer_submitcmd(adreno_dev, cmdbatch, &time); /* * On the first command, if the submission was successful, then read the @@ -631,17 +653,17 @@ static int sendcmd(struct adreno_device *adreno_dev, secs = time.ktime; nsecs = do_div(secs, 1000000000); - trace_adreno_cmdbatch_submitted(drawobj, (int) dispatcher->inflight, + trace_adreno_cmdbatch_submitted(cmdbatch, (int) dispatcher->inflight, time.ticks, (unsigned long) secs, nsecs / 1000, drawctxt->rb, adreno_get_rptr(drawctxt->rb)); mutex_unlock(&device->mutex); - cmdobj->submit_ticks = time.ticks; + cmdbatch->submit_ticks = time.ticks; - dispatch_q->cmd_q[dispatch_q->tail] = cmdobj; + dispatch_q->cmd_q[dispatch_q->tail] = cmdbatch; dispatch_q->tail = (dispatch_q->tail + 1) % - ADRENO_DISPATCH_DRAWQUEUE_SIZE; + ADRENO_DISPATCH_CMDQUEUE_SIZE; /* * For the first submission in any given command queue update the @@ -652,7 +674,7 @@ static int sendcmd(struct adreno_device *adreno_dev, if (dispatch_q->inflight == 1) dispatch_q->expires = jiffies + - msecs_to_jiffies(adreno_drawobj_timeout); + msecs_to_jiffies(adreno_cmdbatch_timeout); /* * If we believe ourselves to be current and preemption isn't a thing, @@ -660,7 +682,7 @@ static int sendcmd(struct adreno_device *adreno_dev, * thing and the timer will be set up in due time */ if (!adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) { - if (drawqueue_is_current(dispatch_q)) + if (cmdqueue_is_current(dispatch_q)) mod_timer(&dispatcher->timer, dispatch_q->expires); } @@ -686,70 +708,75 @@ static int sendcmd(struct adreno_device *adreno_dev, static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev, struct adreno_context *drawctxt) { - struct adreno_dispatcher_drawqueue *dispatch_q = + struct adreno_dispatcher_cmdqueue *dispatch_q = &(drawctxt->rb->dispatch_q); int count = 0; int ret = 0; - int inflight = _drawqueue_inflight(dispatch_q); + int inflight = _cmdqueue_inflight(dispatch_q); unsigned int timestamp; if (dispatch_q->inflight >= inflight) { - spin_lock(&drawctxt->lock); - _process_drawqueue_get_next_drawobj(drawctxt); - spin_unlock(&drawctxt->lock); + expire_markers(drawctxt); return -EBUSY; } /* - * Each context can send a specific number of drawobjs per cycle + * Each context can send a specific number of command batches per cycle */ - while ((count < _context_drawobj_burst) && + while ((count < _context_cmdbatch_burst) && (dispatch_q->inflight < inflight)) { - struct kgsl_drawobj *drawobj; - struct kgsl_drawobj_cmd *cmdobj; + struct kgsl_cmdbatch *cmdbatch; if (adreno_gpu_fault(adreno_dev) != 0) break; - spin_lock(&drawctxt->lock); - drawobj = _process_drawqueue_get_next_drawobj(drawctxt); + cmdbatch = adreno_dispatcher_get_cmdbatch(drawctxt); /* - * adreno_context_get_drawobj returns -EAGAIN if the current - * drawobj has pending sync points so no more to do here. + * adreno_context_get_cmdbatch returns -EAGAIN if the current + * cmdbatch has pending sync points so no more to do here. * When the sync points are satisfied then the context will get * reqeueued */ - if (IS_ERR_OR_NULL(drawobj)) { - if (IS_ERR(drawobj)) - ret = PTR_ERR(drawobj); - spin_unlock(&drawctxt->lock); + if (IS_ERR_OR_NULL(cmdbatch)) { + if (IS_ERR(cmdbatch)) + ret = PTR_ERR(cmdbatch); break; } - _pop_drawobj(drawctxt); - spin_unlock(&drawctxt->lock); - timestamp = drawobj->timestamp; - cmdobj = CMDOBJ(drawobj); - ret = sendcmd(adreno_dev, cmdobj); + /* + * If this is a synchronization submission then there are no + * commands to submit. Discard it and get the next item from + * the queue. Decrement count so this packet doesn't count + * against the burst for the context + */ + + if (cmdbatch->flags & KGSL_CMDBATCH_SYNC) { + kgsl_cmdbatch_destroy(cmdbatch); + continue; + } + + timestamp = cmdbatch->timestamp; + + ret = sendcmd(adreno_dev, cmdbatch); /* - * On error from sendcmd() try to requeue the cmdobj + * On error from sendcmd() try to requeue the command batch * unless we got back -ENOENT which means that the context has * been detached and there will be no more deliveries from here */ if (ret != 0) { - /* Destroy the cmdobj on -ENOENT */ + /* Destroy the cmdbatch on -ENOENT */ if (ret == -ENOENT) - kgsl_drawobj_destroy(drawobj); + kgsl_cmdbatch_destroy(cmdbatch); else { /* * If the requeue returns an error, return that * instead of whatever sendcmd() sent us */ - int r = adreno_dispatcher_requeue_cmdobj( - drawctxt, cmdobj); + int r = adreno_dispatcher_requeue_cmdbatch( + drawctxt, cmdbatch); if (r) ret = r; } @@ -903,100 +930,129 @@ static inline void _decrement_submit_now(struct kgsl_device *device) */ static void adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev) { - adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + spin_lock(&device->submit_lock); + /* If state transition to SLUMBER, schedule the work for later */ + if (device->slumber == true) { + spin_unlock(&device->submit_lock); + goto done; + } + device->submit_now++; + spin_unlock(&device->submit_lock); + + /* If the dispatcher is busy then schedule the work for later */ + if (!mutex_trylock(&dispatcher->mutex)) { + _decrement_submit_now(device); + goto done; + } + + _adreno_dispatcher_issuecmds(adreno_dev); + mutex_unlock(&dispatcher->mutex); + _decrement_submit_now(device); + return; +done: + adreno_dispatcher_schedule(device); } /** * get_timestamp() - Return the next timestamp for the context * @drawctxt - Pointer to an adreno draw context struct - * @drawobj - Pointer to a drawobj + * @cmdbatch - Pointer to a command batch * @timestamp - Pointer to a timestamp value possibly passed from the user - * @user_ts - user generated timestamp * * Assign a timestamp based on the settings of the draw context and the command * batch. */ static int get_timestamp(struct adreno_context *drawctxt, - struct kgsl_drawobj *drawobj, unsigned int *timestamp, - unsigned int user_ts) + struct kgsl_cmdbatch *cmdbatch, unsigned int *timestamp) { + /* Synchronization commands don't get a timestamp */ + if (cmdbatch->flags & KGSL_CMDBATCH_SYNC) { + *timestamp = 0; + return 0; + } if (drawctxt->base.flags & KGSL_CONTEXT_USER_GENERATED_TS) { /* * User specified timestamps need to be greater than the last * issued timestamp in the context */ - if (timestamp_cmp(drawctxt->timestamp, user_ts) >= 0) + if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) return -ERANGE; - drawctxt->timestamp = user_ts; + drawctxt->timestamp = *timestamp; } else drawctxt->timestamp++; *timestamp = drawctxt->timestamp; - drawobj->timestamp = *timestamp; return 0; } -static void _set_ft_policy(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, - struct kgsl_drawobj_cmd *cmdobj) +/** + * adreno_dispactcher_queue_cmd() - Queue a new command in the context + * @adreno_dev: Pointer to the adreno device struct + * @drawctxt: Pointer to the adreno draw context + * @cmdbatch: Pointer to the command batch being submitted + * @timestamp: Pointer to the requested timestamp + * + * Queue a command in the context - if there isn't any room in the queue, then + * block until there is + */ +int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev, + struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch, + uint32_t *timestamp) { - /* - * Set the fault tolerance policy for the command batch - assuming the - * context hasn't disabled FT use the current device policy - */ - if (drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE) - set_bit(KGSL_FT_DISABLE, &cmdobj->fault_policy); - /* - * Set the fault tolerance policy to FT_REPLAY - As context wants - * to invalidate it after a replay attempt fails. This doesn't - * require to execute the default FT policy. - */ - else if (drawctxt->base.flags & KGSL_CONTEXT_INVALIDATE_ON_FAULT) - set_bit(KGSL_FT_REPLAY, &cmdobj->fault_policy); - else - cmdobj->fault_policy = adreno_dev->ft_policy; -} + struct adreno_dispatcher_cmdqueue *dispatch_q = + ADRENO_CMDBATCH_DISPATCH_CMDQUEUE(cmdbatch); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + spin_lock(&drawctxt->lock); + + if (kgsl_context_detached(&drawctxt->base)) { + spin_unlock(&drawctxt->lock); + return -ENOENT; + } -static void _cmdobj_set_flags(struct adreno_context *drawctxt, - struct kgsl_drawobj_cmd *cmdobj) -{ /* * Force the preamble for this submission only - this is usually * requested by the dispatcher as part of fault recovery */ + if (test_and_clear_bit(ADRENO_CONTEXT_FORCE_PREAMBLE, &drawctxt->base.priv)) - set_bit(CMDOBJ_FORCE_PREAMBLE, &cmdobj->priv); + set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv); /* - * Force the premable if set from userspace in the context or - * command obj flags + * Force the premable if set from userspace in the context or cmdbatch + * flags */ + if ((drawctxt->base.flags & KGSL_CONTEXT_CTX_SWITCH) || - (cmdobj->base.flags & KGSL_DRAWOBJ_CTX_SWITCH)) - set_bit(CMDOBJ_FORCE_PREAMBLE, &cmdobj->priv); + (cmdbatch->flags & KGSL_CMDBATCH_CTX_SWITCH)) + set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv); - /* Skip this ib if IFH_NOP is enabled */ + /* Skip this cmdbatch commands if IFH_NOP is enabled */ if (drawctxt->base.flags & KGSL_CONTEXT_IFH_NOP) - set_bit(CMDOBJ_SKIP, &cmdobj->priv); + set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv); /* * If we are waiting for the end of frame and it hasn't appeared yet, - * then mark the command obj as skipped. It will still progress + * then mark the command batch as skipped. It will still progress * through the pipeline but it won't actually send any commands */ if (test_bit(ADRENO_CONTEXT_SKIP_EOF, &drawctxt->base.priv)) { - set_bit(CMDOBJ_SKIP, &cmdobj->priv); + set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv); /* - * If this command obj represents the EOF then clear the way + * If this command batch represents the EOF then clear the way * for the dispatcher to continue submitting */ - if (cmdobj->base.flags & KGSL_DRAWOBJ_END_OF_FRAME) { + if (cmdbatch->flags & KGSL_CMDBATCH_END_OF_FRAME) { clear_bit(ADRENO_CONTEXT_SKIP_EOF, &drawctxt->base.priv); @@ -1008,78 +1064,10 @@ static void _cmdobj_set_flags(struct adreno_context *drawctxt, &drawctxt->base.priv); } } -} - -static inline int _check_context_state(struct kgsl_context *context) -{ - if (kgsl_context_invalid(context)) - return -EDEADLK; - - if (kgsl_context_detached(context)) - return -ENOENT; - - return 0; -} - -static inline bool _verify_ib(struct kgsl_device_private *dev_priv, - struct kgsl_context *context, struct kgsl_memobj_node *ib) -{ - struct kgsl_device *device = dev_priv->device; - struct kgsl_process_private *private = dev_priv->process_priv; - - /* The maximum allowable size for an IB in the CP is 0xFFFFF dwords */ - if (ib->size == 0 || ((ib->size >> 2) > 0xFFFFF)) { - pr_context(device, context, "ctxt %d invalid ib size %lld\n", - context->id, ib->size); - return false; - } - - /* Make sure that the address is mapped */ - if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, ib->gpuaddr)) { - pr_context(device, context, "ctxt %d invalid ib gpuaddr %llX\n", - context->id, ib->gpuaddr); - return false; - } - - return true; -} - -static inline int _verify_cmdobj(struct kgsl_device_private *dev_priv, - struct kgsl_context *context, struct kgsl_drawobj *drawobj[], - uint32_t count) -{ - struct kgsl_device *device = dev_priv->device; - struct kgsl_memobj_node *ib; - unsigned int i; - - for (i = 0; i < count; i++) { - /* Verify the IBs before they get queued */ - if (drawobj[i]->type == CMDOBJ_TYPE) { - struct kgsl_drawobj_cmd *cmdobj = CMDOBJ(drawobj[i]); - - list_for_each_entry(ib, &cmdobj->cmdlist, node) - if (_verify_ib(dev_priv, - &ADRENO_CONTEXT(context)->base, ib) - == false) - return -EINVAL; - } - - /* A3XX does not have support for drawobj profiling */ - if (adreno_is_a3xx(ADRENO_DEVICE(device)) && - (drawobj[i]->flags & KGSL_DRAWOBJ_PROFILING)) - return -EOPNOTSUPP; - } - - return 0; -} - -static inline int _wait_for_room_in_context_queue( - struct adreno_context *drawctxt) -{ - int ret = 0; /* Wait for room in the context queue */ - while (drawctxt->queued >= _context_drawqueue_size) { + + while (drawctxt->queued >= _context_cmdqueue_size) { trace_adreno_drawctxt_sleep(drawctxt); spin_unlock(&drawctxt->lock); @@ -1090,210 +1078,105 @@ static inline int _wait_for_room_in_context_queue( spin_lock(&drawctxt->lock); trace_adreno_drawctxt_wake(drawctxt); - if (ret <= 0) + if (ret <= 0) { + spin_unlock(&drawctxt->lock); return (ret == 0) ? -ETIMEDOUT : (int) ret; + } } - - return 0; -} - -static unsigned int _check_context_state_to_queue_cmds( - struct adreno_context *drawctxt) -{ - int ret = _check_context_state(&drawctxt->base); - - if (ret) - return ret; - - ret = _wait_for_room_in_context_queue(drawctxt); - if (ret) - return ret; - /* * Account for the possiblity that the context got invalidated * while we were sleeping */ - return _check_context_state(&drawctxt->base); -} - -static void _queue_drawobj(struct adreno_context *drawctxt, - struct kgsl_drawobj *drawobj) -{ - /* Put the command into the queue */ - drawctxt->drawqueue[drawctxt->drawqueue_tail] = drawobj; - drawctxt->drawqueue_tail = (drawctxt->drawqueue_tail + 1) % - ADRENO_CONTEXT_DRAWQUEUE_SIZE; - drawctxt->queued++; - trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued); -} - -static int _queue_markerobj(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, struct kgsl_drawobj_cmd *markerobj, - uint32_t *timestamp, unsigned int user_ts) -{ - struct kgsl_drawobj *drawobj = DRAWOBJ(markerobj); - int ret; - - ret = get_timestamp(drawctxt, drawobj, timestamp, user_ts); - if (ret) - return ret; - /* - * See if we can fastpath this thing - if nothing is queued - * and nothing is inflight retire without bothering the GPU - */ - if (!drawctxt->queued && kgsl_check_timestamp(drawobj->device, - drawobj->context, drawctxt->queued_timestamp)) { - trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued); - _retire_timestamp(drawobj); - return 1; + if (kgsl_context_invalid(&drawctxt->base)) { + spin_unlock(&drawctxt->lock); + return -EDEADLK; + } + if (kgsl_context_detached(&drawctxt->base)) { + spin_unlock(&drawctxt->lock); + return -ENOENT; } - /* - * Remember the last queued timestamp - the marker will block - * until that timestamp is expired (unless another command - * comes along and forces the marker to execute) - */ - - markerobj->marker_timestamp = drawctxt->queued_timestamp; - drawctxt->queued_timestamp = *timestamp; - _set_ft_policy(adreno_dev, drawctxt, markerobj); - _cmdobj_set_flags(drawctxt, markerobj); - - _queue_drawobj(drawctxt, drawobj); - - return 0; -} - -static int _queue_cmdobj(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, struct kgsl_drawobj_cmd *cmdobj, - uint32_t *timestamp, unsigned int user_ts) -{ - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); - unsigned int j; - int ret; - - ret = get_timestamp(drawctxt, drawobj, timestamp, user_ts); - if (ret) + ret = get_timestamp(drawctxt, cmdbatch, timestamp); + if (ret) { + spin_unlock(&drawctxt->lock); return ret; - - /* - * If this is a real command then we need to force any markers - * queued before it to dispatch to keep time linear - set the - * skip bit so the commands get NOPed. - */ - j = drawctxt->drawqueue_head; - - while (j != drawctxt->drawqueue_tail) { - if (drawctxt->drawqueue[j]->type == MARKEROBJ_TYPE) { - struct kgsl_drawobj_cmd *markerobj = - CMDOBJ(drawctxt->drawqueue[j]); - set_bit(CMDOBJ_SKIP, &markerobj->priv); - } - - j = DRAWQUEUE_NEXT(j, ADRENO_CONTEXT_DRAWQUEUE_SIZE); } - drawctxt->queued_timestamp = *timestamp; - _set_ft_policy(adreno_dev, drawctxt, cmdobj); - _cmdobj_set_flags(drawctxt, cmdobj); + cmdbatch->timestamp = *timestamp; - _queue_drawobj(drawctxt, drawobj); + if (cmdbatch->flags & KGSL_CMDBATCH_MARKER) { - return 0; -} - -static void _queue_syncobj(struct adreno_context *drawctxt, - struct kgsl_drawobj_sync *syncobj, uint32_t *timestamp) -{ - struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); + /* + * See if we can fastpath this thing - if nothing is queued + * and nothing is inflight retire without bothering the GPU + */ - *timestamp = 0; - drawobj->timestamp = 0; + if (!drawctxt->queued && kgsl_check_timestamp(cmdbatch->device, + cmdbatch->context, drawctxt->queued_timestamp)) { + trace_adreno_cmdbatch_queued(cmdbatch, + drawctxt->queued); - _queue_drawobj(drawctxt, drawobj); -} + _retire_marker(cmdbatch); + spin_unlock(&drawctxt->lock); + return 0; + } -/** - * adreno_dispactcher_queue_drawobj() - Queue a new draw object in the context - * @dev_priv: Pointer to the device private struct - * @context: Pointer to the kgsl draw context - * @drawobj: Pointer to the array of drawobj's being submitted - * @count: Number of drawobj's being submitted - * @timestamp: Pointer to the requested timestamp - * - * Queue a command in the context - if there isn't any room in the queue, then - * block until there is - */ -int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, - struct kgsl_context *context, struct kgsl_drawobj *drawobj[], - uint32_t count, uint32_t *timestamp) + /* + * Remember the last queued timestamp - the marker will block + * until that timestamp is expired (unless another command + * comes along and forces the marker to execute) + */ -{ - struct kgsl_device *device = dev_priv->device; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_context *drawctxt = ADRENO_CONTEXT(context); - struct adreno_dispatcher_drawqueue *dispatch_q; - int ret; - unsigned int i, user_ts; + cmdbatch->marker_timestamp = drawctxt->queued_timestamp; + } - ret = _check_context_state(&drawctxt->base); - if (ret) - return ret; + /* SYNC commands have timestamp 0 and will get optimized out anyway */ + if (!(cmdbatch->flags & KGSL_CONTEXT_SYNC)) + drawctxt->queued_timestamp = *timestamp; - ret = _verify_cmdobj(dev_priv, context, drawobj, count); - if (ret) - return ret; + /* + * Set the fault tolerance policy for the command batch - assuming the + * context hasn't disabled FT use the current device policy + */ - /* wait for the suspend gate */ - wait_for_completion(&device->halt_gate); + if (drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE) + set_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy); + /* + * Set the fault tolerance policy to FT_REPLAY - As context wants + * to invalidate it after a replay attempt fails. This doesn't + * require to execute the default FT policy. + */ + else if (drawctxt->base.flags & KGSL_CONTEXT_INVALIDATE_ON_FAULT) + set_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy); + else + cmdbatch->fault_policy = adreno_dev->ft_policy; - spin_lock(&drawctxt->lock); + /* Put the command into the queue */ + drawctxt->cmdqueue[drawctxt->cmdqueue_tail] = cmdbatch; + drawctxt->cmdqueue_tail = (drawctxt->cmdqueue_tail + 1) % + ADRENO_CONTEXT_CMDQUEUE_SIZE; - ret = _check_context_state_to_queue_cmds(drawctxt); - if (ret) { - spin_unlock(&drawctxt->lock); - return ret; - } + /* + * If this is a real command then we need to force any markers queued + * before it to dispatch to keep time linear - set the skip bit so + * the commands get NOPed. + */ - user_ts = *timestamp; + if (!(cmdbatch->flags & KGSL_CMDBATCH_MARKER)) { + unsigned int i = drawctxt->cmdqueue_head; - for (i = 0; i < count; i++) { + while (i != drawctxt->cmdqueue_tail) { + if (drawctxt->cmdqueue[i]->flags & KGSL_CMDBATCH_MARKER) + set_bit(CMDBATCH_FLAG_SKIP, + &drawctxt->cmdqueue[i]->priv); - switch (drawobj[i]->type) { - case MARKEROBJ_TYPE: - ret = _queue_markerobj(adreno_dev, drawctxt, - CMDOBJ(drawobj[i]), - timestamp, user_ts); - if (ret == 1) { - spin_unlock(&drawctxt->lock); - goto done; - } else if (ret) { - spin_unlock(&drawctxt->lock); - return ret; - } - break; - case CMDOBJ_TYPE: - ret = _queue_cmdobj(adreno_dev, drawctxt, - CMDOBJ(drawobj[i]), - timestamp, user_ts); - if (ret) { - spin_unlock(&drawctxt->lock); - return ret; - } - break; - case SYNCOBJ_TYPE: - _queue_syncobj(drawctxt, SYNCOBJ(drawobj[i]), - timestamp); - break; - default: - spin_unlock(&drawctxt->lock); - return -EINVAL; + i = CMDQUEUE_NEXT(i, ADRENO_CONTEXT_CMDQUEUE_SIZE); } - } - dispatch_q = ADRENO_DRAWOBJ_DISPATCH_DRAWQUEUE(drawobj[0]); + drawctxt->queued++; + trace_adreno_cmdbatch_queued(cmdbatch, drawctxt->queued); _track_context(adreno_dev, dispatch_q, drawctxt); @@ -1315,11 +1198,8 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, * queue will try to schedule new commands anyway. */ - if (dispatch_q->inflight < _context_drawobj_burst) + if (dispatch_q->inflight < _context_cmdbatch_burst) adreno_dispatcher_issuecmds(adreno_dev); -done: - if (test_and_clear_bit(ADRENO_CONTEXT_FAULT, &context->priv)) - return -EPROTO; return 0; } @@ -1363,15 +1243,15 @@ static void mark_guilty_context(struct kgsl_device *device, unsigned int id) } /* - * If an IB inside of the drawobj has a gpuaddr that matches the base + * If an IB inside of the command batch has a gpuaddr that matches the base * passed in then zero the size which effectively skips it when it is submitted * in the ringbuffer. */ -static void _skip_ib(struct kgsl_drawobj_cmd *cmdobj, uint64_t base) +static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, uint64_t base) { struct kgsl_memobj_node *ib; - list_for_each_entry(ib, &cmdobj->cmdlist, node) { + list_for_each_entry(ib, &cmdbatch->cmdlist, node) { if (ib->gpuaddr == base) { ib->priv |= MEMOBJ_SKIP; if (base) @@ -1380,11 +1260,10 @@ static void _skip_ib(struct kgsl_drawobj_cmd *cmdobj, uint64_t base) } } -static void _skip_cmd(struct kgsl_drawobj_cmd *cmdobj, - struct kgsl_drawobj_cmd **replay, int count) +static void cmdbatch_skip_cmd(struct kgsl_cmdbatch *cmdbatch, + struct kgsl_cmdbatch **replay, int count) { - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); - struct adreno_context *drawctxt = ADRENO_CONTEXT(drawobj->context); + struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context); int i; /* @@ -1399,9 +1278,9 @@ static void _skip_cmd(struct kgsl_drawobj_cmd *cmdobj, * b) force preamble for next commandbatch */ for (i = 1; i < count; i++) { - if (DRAWOBJ(replay[i])->context->id == drawobj->context->id) { + if (replay[i]->context->id == cmdbatch->context->id) { replay[i]->fault_policy = replay[0]->fault_policy; - set_bit(CMDOBJ_FORCE_PREAMBLE, &replay[i]->priv); + set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv); set_bit(KGSL_FT_SKIPCMD, &replay[i]->fault_recovery); break; } @@ -1418,44 +1297,41 @@ static void _skip_cmd(struct kgsl_drawobj_cmd *cmdobj, drawctxt->fault_policy = replay[0]->fault_policy; } - /* set the flags to skip this cmdobj */ - set_bit(CMDOBJ_SKIP, &cmdobj->priv); - cmdobj->fault_recovery = 0; + /* set the flags to skip this cmdbatch */ + set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv); + cmdbatch->fault_recovery = 0; } -static void _skip_frame(struct kgsl_drawobj_cmd *cmdobj, - struct kgsl_drawobj_cmd **replay, int count) +static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch, + struct kgsl_cmdbatch **replay, int count) { - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); - struct adreno_context *drawctxt = ADRENO_CONTEXT(drawobj->context); + struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context); int skip = 1; int i; for (i = 0; i < count; i++) { - struct kgsl_drawobj *replay_obj = DRAWOBJ(replay[i]); - /* - * Only operate on drawobj's that belong to the + * Only operate on command batches that belong to the * faulting context */ - if (replay_obj->context->id != drawobj->context->id) + if (replay[i]->context->id != cmdbatch->context->id) continue; /* - * Skip all the drawobjs in this context until + * Skip all the command batches in this context until * the EOF flag is seen. If the EOF flag is seen then * force the preamble for the next command. */ if (skip) { - set_bit(CMDOBJ_SKIP, &replay[i]->priv); + set_bit(CMDBATCH_FLAG_SKIP, &replay[i]->priv); - if (replay_obj->flags & KGSL_DRAWOBJ_END_OF_FRAME) + if (replay[i]->flags & KGSL_CMDBATCH_END_OF_FRAME) skip = 0; } else { - set_bit(CMDOBJ_FORCE_PREAMBLE, &replay[i]->priv); + set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv); return; } } @@ -1477,28 +1353,26 @@ static void _skip_frame(struct kgsl_drawobj_cmd *cmdobj, set_bit(ADRENO_CONTEXT_FORCE_PREAMBLE, &drawctxt->base.priv); } -static void remove_invalidated_cmdobjs(struct kgsl_device *device, - struct kgsl_drawobj_cmd **replay, int count) +static void remove_invalidated_cmdbatches(struct kgsl_device *device, + struct kgsl_cmdbatch **replay, int count) { int i; for (i = 0; i < count; i++) { - struct kgsl_drawobj_cmd *cmdobj = replay[i]; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); - - if (cmdobj == NULL) + struct kgsl_cmdbatch *cmd = replay[i]; + if (cmd == NULL) continue; - if (kgsl_context_detached(drawobj->context) || - kgsl_context_invalid(drawobj->context)) { + if (kgsl_context_detached(cmd->context) || + kgsl_context_invalid(cmd->context)) { replay[i] = NULL; mutex_lock(&device->mutex); kgsl_cancel_events_timestamp(device, - &drawobj->context->events, drawobj->timestamp); + &cmd->context->events, cmd->timestamp); mutex_unlock(&device->mutex); - kgsl_drawobj_destroy(drawobj); + kgsl_cmdbatch_destroy(cmd); } } } @@ -1522,10 +1396,9 @@ static inline const char *_kgsl_context_comm(struct kgsl_context *context) static void adreno_fault_header(struct kgsl_device *device, - struct adreno_ringbuffer *rb, struct kgsl_drawobj_cmd *cmdobj) + struct adreno_ringbuffer *rb, struct kgsl_cmdbatch *cmdbatch) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); unsigned int status, rptr, wptr, ib1sz, ib2sz; uint64_t ib1base, ib2base; @@ -1539,22 +1412,23 @@ static void adreno_fault_header(struct kgsl_device *device, ADRENO_REG_CP_IB2_BASE_HI, &ib2base); adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ, &ib2sz); - if (drawobj != NULL) { + if (cmdbatch != NULL) { struct adreno_context *drawctxt = - ADRENO_CONTEXT(drawobj->context); + ADRENO_CONTEXT(cmdbatch->context); - trace_adreno_gpu_fault(drawobj->context->id, - drawobj->timestamp, + trace_adreno_gpu_fault(cmdbatch->context->id, + cmdbatch->timestamp, status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz, drawctxt->rb->id); - pr_fault(device, drawobj, - "gpu fault ctx %d ts %d status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n", - drawobj->context->id, drawobj->timestamp, status, + pr_fault(device, cmdbatch, + "gpu fault ctx %d ctx_type %s ts %d status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n", + cmdbatch->context->id, get_api_type_str(drawctxt->type), + cmdbatch->timestamp, status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz); if (rb != NULL) - pr_fault(device, drawobj, + pr_fault(device, cmdbatch, "gpu fault rb %d rb sw r/w %4.4x/%4.4x\n", rb->id, rptr, rb->wptr); } else { @@ -1573,34 +1447,33 @@ static void adreno_fault_header(struct kgsl_device *device, void adreno_fault_skipcmd_detached(struct adreno_device *adreno_dev, struct adreno_context *drawctxt, - struct kgsl_drawobj *drawobj) + struct kgsl_cmdbatch *cmdbatch) { if (test_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->base.priv) && kgsl_context_detached(&drawctxt->base)) { - pr_context(KGSL_DEVICE(adreno_dev), drawobj->context, - "gpu detached context %d\n", drawobj->context->id); + pr_context(KGSL_DEVICE(adreno_dev), cmdbatch->context, + "gpu detached context %d\n", cmdbatch->context->id); clear_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->base.priv); } } /** - * process_cmdobj_fault() - Process a cmdobj for fault policies - * @device: Device on which the cmdobj caused a fault - * @replay: List of cmdobj's that are to be replayed on the device. The - * first command in the replay list is the faulting command and the remaining - * cmdobj's in the list are commands that were submitted to the same queue + * process_cmdbatch_fault() - Process a cmdbatch for fault policies + * @device: Device on which the cmdbatch caused a fault + * @replay: List of cmdbatches that are to be replayed on the device. The + * faulting cmdbatch is the first command in the replay list and the remaining + * cmdbatches in the list are commands that were submitted to the same queue * as the faulting one. - * @count: Number of cmdobj's in replay + * @count: Number of cmdbatches in replay * @base: The IB1 base at the time of fault * @fault: The fault type */ -static void process_cmdobj_fault(struct kgsl_device *device, - struct kgsl_drawobj_cmd **replay, int count, +static void process_cmdbatch_fault(struct kgsl_device *device, + struct kgsl_cmdbatch **replay, int count, unsigned int base, int fault) { - struct kgsl_drawobj_cmd *cmdobj = replay[0]; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); + struct kgsl_cmdbatch *cmdbatch = replay[0]; int i; char *state = "failed"; @@ -1614,18 +1487,18 @@ static void process_cmdobj_fault(struct kgsl_device *device, * where 1st and 4th gpu hang are more than 3 seconds apart we * won't disable GFT and invalidate the context. */ - if (test_bit(KGSL_FT_THROTTLE, &cmdobj->fault_policy)) { - if (time_after(jiffies, (drawobj->context->fault_time + if (test_bit(KGSL_FT_THROTTLE, &cmdbatch->fault_policy)) { + if (time_after(jiffies, (cmdbatch->context->fault_time + msecs_to_jiffies(_fault_throttle_time)))) { - drawobj->context->fault_time = jiffies; - drawobj->context->fault_count = 1; + cmdbatch->context->fault_time = jiffies; + cmdbatch->context->fault_count = 1; } else { - drawobj->context->fault_count++; - if (drawobj->context->fault_count > + cmdbatch->context->fault_count++; + if (cmdbatch->context->fault_count > _fault_throttle_burst) { set_bit(KGSL_FT_DISABLE, - &cmdobj->fault_policy); - pr_context(device, drawobj->context, + &cmdbatch->fault_policy); + pr_context(device, cmdbatch->context, "gpu fault threshold exceeded %d faults in %d msecs\n", _fault_throttle_burst, _fault_throttle_time); @@ -1634,45 +1507,46 @@ static void process_cmdobj_fault(struct kgsl_device *device, } /* - * If FT is disabled for this cmdobj invalidate immediately + * If FT is disabled for this cmdbatch invalidate immediately */ - if (test_bit(KGSL_FT_DISABLE, &cmdobj->fault_policy) || - test_bit(KGSL_FT_TEMP_DISABLE, &cmdobj->fault_policy)) { + if (test_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy) || + test_bit(KGSL_FT_TEMP_DISABLE, &cmdbatch->fault_policy)) { state = "skipped"; - bitmap_zero(&cmdobj->fault_policy, BITS_PER_LONG); + bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG); } /* If the context is detached do not run FT on context */ - if (kgsl_context_detached(drawobj->context)) { + if (kgsl_context_detached(cmdbatch->context)) { state = "detached"; - bitmap_zero(&cmdobj->fault_policy, BITS_PER_LONG); + bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG); } /* - * Set a flag so we don't print another PM dump if the cmdobj fails + * Set a flag so we don't print another PM dump if the cmdbatch fails * again on replay */ - set_bit(KGSL_FT_SKIP_PMDUMP, &cmdobj->fault_policy); + set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy); /* * A hardware fault generally means something was deterministically - * wrong with the cmdobj - no point in trying to replay it + * wrong with the command batch - no point in trying to replay it * Clear the replay bit and move on to the next policy level */ if (fault & ADRENO_HARD_FAULT) - clear_bit(KGSL_FT_REPLAY, &(cmdobj->fault_policy)); + clear_bit(KGSL_FT_REPLAY, &(cmdbatch->fault_policy)); /* * A timeout fault means the IB timed out - clear the policy and * invalidate - this will clear the FT_SKIP_PMDUMP bit but that is okay - * because we won't see this cmdobj again + * because we won't see this cmdbatch again */ - if (fault & ADRENO_TIMEOUT_FAULT) - bitmap_zero(&cmdobj->fault_policy, BITS_PER_LONG); + if ((fault & ADRENO_TIMEOUT_FAULT) || + (fault & ADRENO_CTX_DETATCH_TIMEOUT_FAULT)) + bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG); /* * If the context had a GPU page fault then it is likely it would fault @@ -1680,84 +1554,83 @@ static void process_cmdobj_fault(struct kgsl_device *device, */ if (test_bit(KGSL_CONTEXT_PRIV_PAGEFAULT, - &drawobj->context->priv)) { + &cmdbatch->context->priv)) { /* we'll need to resume the mmu later... */ - clear_bit(KGSL_FT_REPLAY, &cmdobj->fault_policy); + clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy); clear_bit(KGSL_CONTEXT_PRIV_PAGEFAULT, - &drawobj->context->priv); + &cmdbatch->context->priv); } /* - * Execute the fault tolerance policy. Each cmdobj stores the + * Execute the fault tolerance policy. Each command batch stores the * current fault policy that was set when it was queued. * As the options are tried in descending priority * (REPLAY -> SKIPIBS -> SKIPFRAME -> NOTHING) the bits are cleared - * from the cmdobj policy so the next thing can be tried if the + * from the cmdbatch policy so the next thing can be tried if the * change comes around again */ - /* Replay the hanging cmdobj again */ - if (test_and_clear_bit(KGSL_FT_REPLAY, &cmdobj->fault_policy)) { - trace_adreno_cmdbatch_recovery(cmdobj, BIT(KGSL_FT_REPLAY)); - set_bit(KGSL_FT_REPLAY, &cmdobj->fault_recovery); + /* Replay the hanging command batch again */ + if (test_and_clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy)) { + trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_REPLAY)); + set_bit(KGSL_FT_REPLAY, &cmdbatch->fault_recovery); return; } /* * Skip the last IB1 that was played but replay everything else. - * Note that the last IB1 might not be in the "hung" cmdobj + * Note that the last IB1 might not be in the "hung" command batch * because the CP may have caused a page-fault while it was prefetching * the next IB1/IB2. walk all outstanding commands and zap the * supposedly bad IB1 where ever it lurks. */ - if (test_and_clear_bit(KGSL_FT_SKIPIB, &cmdobj->fault_policy)) { - trace_adreno_cmdbatch_recovery(cmdobj, BIT(KGSL_FT_SKIPIB)); - set_bit(KGSL_FT_SKIPIB, &cmdobj->fault_recovery); + if (test_and_clear_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_policy)) { + trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPIB)); + set_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_recovery); for (i = 0; i < count; i++) { if (replay[i] != NULL && - DRAWOBJ(replay[i])->context->id == - drawobj->context->id) - _skip_ib(replay[i], base); + replay[i]->context->id == cmdbatch->context->id) + cmdbatch_skip_ib(replay[i], base); } return; } - /* Skip the faulted cmdobj submission */ - if (test_and_clear_bit(KGSL_FT_SKIPCMD, &cmdobj->fault_policy)) { - trace_adreno_cmdbatch_recovery(cmdobj, BIT(KGSL_FT_SKIPCMD)); + /* Skip the faulted command batch submission */ + if (test_and_clear_bit(KGSL_FT_SKIPCMD, &cmdbatch->fault_policy)) { + trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPCMD)); - /* Skip faulting cmdobj */ - _skip_cmd(cmdobj, replay, count); + /* Skip faulting command batch */ + cmdbatch_skip_cmd(cmdbatch, replay, count); return; } - if (test_and_clear_bit(KGSL_FT_SKIPFRAME, &cmdobj->fault_policy)) { - trace_adreno_cmdbatch_recovery(cmdobj, + if (test_and_clear_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_policy)) { + trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPFRAME)); - set_bit(KGSL_FT_SKIPFRAME, &cmdobj->fault_recovery); + set_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_recovery); /* - * Skip all the pending cmdobj's for this context until + * Skip all the pending command batches for this context until * the EOF frame is seen */ - _skip_frame(cmdobj, replay, count); + cmdbatch_skip_frame(cmdbatch, replay, count); return; } /* If we get here then all the policies failed */ - pr_context(device, drawobj->context, "gpu %s ctx %d ts %d\n", - state, drawobj->context->id, drawobj->timestamp); + pr_context(device, cmdbatch->context, "gpu %s ctx %d ts %d\n", + state, cmdbatch->context->id, cmdbatch->timestamp); /* Mark the context as failed */ - mark_guilty_context(device, drawobj->context->id); + mark_guilty_context(device, cmdbatch->context->id); /* Invalidate the context */ - adreno_drawctxt_invalidate(device, drawobj->context); + adreno_drawctxt_invalidate(device, cmdbatch->context); } /** @@ -1769,12 +1642,12 @@ static void process_cmdobj_fault(struct kgsl_device *device, * @base: The IB1 base during the fault */ static void recover_dispatch_q(struct kgsl_device *device, - struct adreno_dispatcher_drawqueue *dispatch_q, + struct adreno_dispatcher_cmdqueue *dispatch_q, int fault, unsigned int base) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct kgsl_drawobj_cmd **replay; + struct kgsl_cmdbatch **replay = NULL; unsigned int ptr; int first = 0; int count = 0; @@ -1788,16 +1661,14 @@ static void recover_dispatch_q(struct kgsl_device *device, /* Recovery failed - mark everybody on this q guilty */ while (ptr != dispatch_q->tail) { - struct kgsl_drawobj_cmd *cmdobj = - dispatch_q->cmd_q[ptr]; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); + struct kgsl_context *context = + dispatch_q->cmd_q[ptr]->context; - mark_guilty_context(device, drawobj->context->id); - adreno_drawctxt_invalidate(device, drawobj->context); - kgsl_drawobj_destroy(drawobj); + mark_guilty_context(device, context->id); + adreno_drawctxt_invalidate(device, context); + kgsl_cmdbatch_destroy(dispatch_q->cmd_q[ptr]); - ptr = DRAWQUEUE_NEXT(ptr, - ADRENO_DISPATCH_DRAWQUEUE_SIZE); + ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE); } /* @@ -1809,22 +1680,22 @@ static void recover_dispatch_q(struct kgsl_device *device, goto replay; } - /* Copy the inflight cmdobj's into the temporary storage */ + /* Copy the inflight command batches into the temporary storage */ ptr = dispatch_q->head; while (ptr != dispatch_q->tail) { replay[count++] = dispatch_q->cmd_q[ptr]; - ptr = DRAWQUEUE_NEXT(ptr, ADRENO_DISPATCH_DRAWQUEUE_SIZE); + ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE); } if (fault && count) - process_cmdobj_fault(device, replay, + process_cmdbatch_fault(device, replay, count, base, fault); replay: dispatch_q->inflight = 0; dispatch_q->head = dispatch_q->tail = 0; - /* Remove any pending cmdobj's that have been invalidated */ - remove_invalidated_cmdobjs(device, replay, count); + /* Remove any pending command batches that have been invalidated */ + remove_invalidated_cmdbatches(device, replay, count); /* Replay the pending command buffers */ for (i = 0; i < count; i++) { @@ -1840,16 +1711,16 @@ replay: */ if (first == 0) { - set_bit(CMDOBJ_FORCE_PREAMBLE, &replay[i]->priv); + set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv); first = 1; } /* - * Force each cmdobj to wait for idle - this avoids weird + * Force each command batch to wait for idle - this avoids weird * CP parse issues */ - set_bit(CMDOBJ_WFI, &replay[i]->priv); + set_bit(CMDBATCH_FLAG_WFI, &replay[i]->priv); ret = sendcmd(adreno_dev, replay[i]); @@ -1859,18 +1730,15 @@ replay: */ if (ret) { - pr_context(device, replay[i]->base.context, + pr_context(device, replay[i]->context, "gpu reset failed ctx %d ts %d\n", - replay[i]->base.context->id, - replay[i]->base.timestamp); + replay[i]->context->id, replay[i]->timestamp); /* Mark this context as guilty (failed recovery) */ - mark_guilty_context(device, - replay[i]->base.context->id); + mark_guilty_context(device, replay[i]->context->id); - adreno_drawctxt_invalidate(device, - replay[i]->base.context); - remove_invalidated_cmdobjs(device, &replay[i], + adreno_drawctxt_invalidate(device, replay[i]->context); + remove_invalidated_cmdbatches(device, &replay[i], count - i); } } @@ -1882,38 +1750,36 @@ replay: } static void do_header_and_snapshot(struct kgsl_device *device, - struct adreno_ringbuffer *rb, struct kgsl_drawobj_cmd *cmdobj) + struct adreno_ringbuffer *rb, struct kgsl_cmdbatch *cmdbatch) { - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); - - /* Always dump the snapshot on a non-drawobj failure */ - if (cmdobj == NULL) { + /* Always dump the snapshot on a non-cmdbatch failure */ + if (cmdbatch == NULL) { adreno_fault_header(device, rb, NULL); kgsl_device_snapshot(device, NULL); return; } /* Skip everything if the PMDUMP flag is set */ - if (test_bit(KGSL_FT_SKIP_PMDUMP, &cmdobj->fault_policy)) + if (test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) return; /* Print the fault header */ - adreno_fault_header(device, rb, cmdobj); + adreno_fault_header(device, rb, cmdbatch); - if (!(drawobj->context->flags & KGSL_CONTEXT_NO_SNAPSHOT)) - kgsl_device_snapshot(device, drawobj->context); + if (!(cmdbatch->context->flags & KGSL_CONTEXT_NO_SNAPSHOT)) + kgsl_device_snapshot(device, cmdbatch->context); } static int dispatcher_do_fault(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct adreno_dispatcher_drawqueue *dispatch_q = NULL, *dispatch_q_temp; + struct adreno_dispatcher_cmdqueue *dispatch_q = NULL, *dispatch_q_temp; struct adreno_ringbuffer *rb; struct adreno_ringbuffer *hung_rb = NULL; unsigned int reg; uint64_t base; - struct kgsl_drawobj_cmd *cmdobj = NULL; + struct kgsl_cmdbatch *cmdbatch = NULL; int ret, i; int fault; int halt; @@ -1980,10 +1846,10 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg); } /* - * retire cmdobj's from all the dispatch_q's before starting recovery + * retire cmdbatches from all the dispatch_q's before starting recovery */ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - adreno_dispatch_retire_drawqueue(adreno_dev, + adreno_dispatch_retire_cmdqueue(adreno_dev, &(rb->dispatch_q)); /* Select the active dispatch_q */ if (base == rb->buffer_desc.gpuaddr) { @@ -2002,15 +1868,15 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) } } - if (dispatch_q && !adreno_drawqueue_is_empty(dispatch_q)) { - cmdobj = dispatch_q->cmd_q[dispatch_q->head]; - trace_adreno_cmdbatch_fault(cmdobj, fault); + if (dispatch_q && !adreno_cmdqueue_is_empty(dispatch_q)) { + cmdbatch = dispatch_q->cmd_q[dispatch_q->head]; + trace_adreno_cmdbatch_fault(cmdbatch, fault); } adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE, ADRENO_REG_CP_IB1_BASE_HI, &base); - do_header_and_snapshot(device, hung_rb, cmdobj); + do_header_and_snapshot(device, hung_rb, cmdbatch); /* Terminate the stalled transaction and resume the IOMMU */ if (fault & ADRENO_IOMMU_PAGE_FAULT) @@ -2064,24 +1930,23 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) return 1; } -static inline int drawobj_consumed(struct kgsl_drawobj *drawobj, +static inline int cmdbatch_consumed(struct kgsl_cmdbatch *cmdbatch, unsigned int consumed, unsigned int retired) { - return ((timestamp_cmp(drawobj->timestamp, consumed) >= 0) && - (timestamp_cmp(retired, drawobj->timestamp) < 0)); + return ((timestamp_cmp(cmdbatch->timestamp, consumed) >= 0) && + (timestamp_cmp(retired, cmdbatch->timestamp) < 0)); } static void _print_recovery(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj) + struct kgsl_cmdbatch *cmdbatch) { static struct { unsigned int mask; const char *str; } flags[] = { ADRENO_FT_TYPES }; - int i, nr = find_first_bit(&cmdobj->fault_recovery, BITS_PER_LONG); + int i, nr = find_first_bit(&cmdbatch->fault_recovery, BITS_PER_LONG); char *result = "unknown"; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); for (i = 0; i < ARRAY_SIZE(flags); i++) { if (flags[i].mask == BIT(nr)) { @@ -2090,41 +1955,40 @@ static void _print_recovery(struct kgsl_device *device, } } - pr_context(device, drawobj->context, + pr_context(device, cmdbatch->context, "gpu %s ctx %d ts %d policy %lX\n", - result, drawobj->context->id, drawobj->timestamp, - cmdobj->fault_recovery); + result, cmdbatch->context->id, cmdbatch->timestamp, + cmdbatch->fault_recovery); } -static void cmdobj_profile_ticks(struct adreno_device *adreno_dev, - struct kgsl_drawobj_cmd *cmdobj, uint64_t *start, uint64_t *retire) +static void cmdbatch_profile_ticks(struct adreno_device *adreno_dev, + struct kgsl_cmdbatch *cmdbatch, uint64_t *start, uint64_t *retire) { - void *ptr = adreno_dev->profile_buffer.hostptr; - struct adreno_drawobj_profile_entry *entry; + void *ptr = adreno_dev->cmdbatch_profile_buffer.hostptr; + struct adreno_cmdbatch_profile_entry *entry; - entry = (struct adreno_drawobj_profile_entry *) - (ptr + (cmdobj->profile_index * sizeof(*entry))); + entry = (struct adreno_cmdbatch_profile_entry *) + (ptr + (cmdbatch->profile_index * sizeof(*entry))); rmb(); *start = entry->started; *retire = entry->retired; } -static void retire_cmdobj(struct adreno_device *adreno_dev, - struct kgsl_drawobj_cmd *cmdobj) +static void retire_cmdbatch(struct adreno_device *adreno_dev, + struct kgsl_cmdbatch *cmdbatch) { struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); - struct adreno_context *drawctxt = ADRENO_CONTEXT(drawobj->context); + struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context); uint64_t start = 0, end = 0; - if (cmdobj->fault_recovery != 0) { - set_bit(ADRENO_CONTEXT_FAULT, &drawobj->context->priv); - _print_recovery(KGSL_DEVICE(adreno_dev), cmdobj); + if (cmdbatch->fault_recovery != 0) { + set_bit(ADRENO_CONTEXT_FAULT, &cmdbatch->context->priv); + _print_recovery(KGSL_DEVICE(adreno_dev), cmdbatch); } - if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) - cmdobj_profile_ticks(adreno_dev, cmdobj, &start, &end); + if (test_bit(CMDBATCH_FLAG_PROFILE, &cmdbatch->priv)) + cmdbatch_profile_ticks(adreno_dev, cmdbatch, &start, &end); /* * For A3xx we still get the rptr from the CP_RB_RPTR instead of @@ -2132,49 +1996,48 @@ static void retire_cmdobj(struct adreno_device *adreno_dev, * So avoid reading GPU register directly for A3xx. */ if (adreno_is_a3xx(adreno_dev)) - trace_adreno_cmdbatch_retired(drawobj, - (int) dispatcher->inflight, start, end, - ADRENO_DRAWOBJ_RB(drawobj), 0, cmdobj->fault_recovery); + trace_adreno_cmdbatch_retired(cmdbatch, + (int) dispatcher->inflight, start, end, + ADRENO_CMDBATCH_RB(cmdbatch), 0); else - trace_adreno_cmdbatch_retired(drawobj, - (int) dispatcher->inflight, start, end, - ADRENO_DRAWOBJ_RB(drawobj), - adreno_get_rptr(drawctxt->rb), cmdobj->fault_recovery); + trace_adreno_cmdbatch_retired(cmdbatch, + (int) dispatcher->inflight, start, end, + ADRENO_CMDBATCH_RB(cmdbatch), + adreno_get_rptr(drawctxt->rb)); drawctxt->submit_retire_ticks[drawctxt->ticks_index] = - end - cmdobj->submit_ticks; + end - cmdbatch->submit_ticks; drawctxt->ticks_index = (drawctxt->ticks_index + 1) % SUBMIT_RETIRE_TICKS_SIZE; - kgsl_drawobj_destroy(drawobj); + kgsl_cmdbatch_destroy(cmdbatch); } -static int adreno_dispatch_retire_drawqueue(struct adreno_device *adreno_dev, - struct adreno_dispatcher_drawqueue *drawqueue) +static int adreno_dispatch_retire_cmdqueue(struct adreno_device *adreno_dev, + struct adreno_dispatcher_cmdqueue *cmdqueue) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; int count = 0; - while (!adreno_drawqueue_is_empty(drawqueue)) { - struct kgsl_drawobj_cmd *cmdobj = - drawqueue->cmd_q[drawqueue->head]; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); + while (!adreno_cmdqueue_is_empty(cmdqueue)) { + struct kgsl_cmdbatch *cmdbatch = + cmdqueue->cmd_q[cmdqueue->head]; - if (!kgsl_check_timestamp(device, drawobj->context, - drawobj->timestamp)) + if (!kgsl_check_timestamp(device, cmdbatch->context, + cmdbatch->timestamp)) break; - retire_cmdobj(adreno_dev, cmdobj); + retire_cmdbatch(adreno_dev, cmdbatch); dispatcher->inflight--; - drawqueue->inflight--; + cmdqueue->inflight--; - drawqueue->cmd_q[drawqueue->head] = NULL; + cmdqueue->cmd_q[cmdqueue->head] = NULL; - drawqueue->head = DRAWQUEUE_NEXT(drawqueue->head, - ADRENO_DISPATCH_DRAWQUEUE_SIZE); + cmdqueue->head = CMDQUEUE_NEXT(cmdqueue->head, + ADRENO_DISPATCH_CMDQUEUE_SIZE); count++; } @@ -2183,14 +2046,13 @@ static int adreno_dispatch_retire_drawqueue(struct adreno_device *adreno_dev, } static void _adreno_dispatch_check_timeout(struct adreno_device *adreno_dev, - struct adreno_dispatcher_drawqueue *drawqueue) + struct adreno_dispatcher_cmdqueue *cmdqueue) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_drawobj *drawobj = - DRAWOBJ(drawqueue->cmd_q[drawqueue->head]); + struct kgsl_cmdbatch *cmdbatch = cmdqueue->cmd_q[cmdqueue->head]; /* Don't timeout if the timer hasn't expired yet (duh) */ - if (time_is_after_jiffies(drawqueue->expires)) + if (time_is_after_jiffies(cmdqueue->expires)) return; /* Don't timeout if the IB timeout is disabled globally */ @@ -2198,26 +2060,26 @@ static void _adreno_dispatch_check_timeout(struct adreno_device *adreno_dev, return; /* Don't time out if the context has disabled it */ - if (drawobj->context->flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE) + if (cmdbatch->context->flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE) return; - pr_context(device, drawobj->context, "gpu timeout ctx %d ts %d\n", - drawobj->context->id, drawobj->timestamp); + pr_context(device, cmdbatch->context, "gpu timeout ctx %d ts %d\n", + cmdbatch->context->id, cmdbatch->timestamp); adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT); } -static int adreno_dispatch_process_drawqueue(struct adreno_device *adreno_dev, - struct adreno_dispatcher_drawqueue *drawqueue) +static int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev, + struct adreno_dispatcher_cmdqueue *cmdqueue) { - int count = adreno_dispatch_retire_drawqueue(adreno_dev, drawqueue); + int count = adreno_dispatch_retire_cmdqueue(adreno_dev, cmdqueue); /* Nothing to do if there are no pending commands */ - if (adreno_drawqueue_is_empty(drawqueue)) + if (adreno_cmdqueue_is_empty(cmdqueue)) return count; - /* Don't update the drawqueue timeout if it isn't active */ - if (!drawqueue_is_current(drawqueue)) + /* Don't update the cmdqueue timeout if it isn't active */ + if (!cmdqueue_is_current(cmdqueue)) return count; /* @@ -2226,17 +2088,17 @@ static int adreno_dispatch_process_drawqueue(struct adreno_device *adreno_dev, */ if (count) { - drawqueue->expires = jiffies + - msecs_to_jiffies(adreno_drawobj_timeout); + cmdqueue->expires = jiffies + + msecs_to_jiffies(adreno_cmdbatch_timeout); return count; } /* * If we get here then 1) the ringbuffer is current and 2) we haven't * retired anything. Check to see if the timeout if valid for the - * current drawobj and fault if it has expired + * current cmdbatch and fault if it has expired */ - _adreno_dispatch_check_timeout(adreno_dev, drawqueue); + _adreno_dispatch_check_timeout(adreno_dev, cmdqueue); return 0; } @@ -2255,11 +2117,11 @@ static void _dispatcher_update_timers(struct adreno_device *adreno_dev) /* Check to see if we need to update the command timer */ if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) { - struct adreno_dispatcher_drawqueue *drawqueue = - DRAWQUEUE(adreno_dev->cur_rb); + struct adreno_dispatcher_cmdqueue *cmdqueue = + CMDQUEUE(adreno_dev->cur_rb); - if (!adreno_drawqueue_is_empty(drawqueue)) - mod_timer(&dispatcher->timer, drawqueue->expires); + if (!adreno_cmdqueue_is_empty(cmdqueue)) + mod_timer(&dispatcher->timer, cmdqueue->expires); } } @@ -2284,9 +2146,12 @@ static void _dispatcher_power_down(struct adreno_device *adreno_dev) mutex_unlock(&device->mutex); } -static void adreno_dispatcher_work(struct adreno_device *adreno_dev) +static void adreno_dispatcher_work(struct kthread_work *work) { - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + struct adreno_dispatcher *dispatcher = + container_of(work, struct adreno_dispatcher, work); + struct adreno_device *adreno_dev = + container_of(dispatcher, struct adreno_device, dispatcher); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); int count = 0; @@ -2296,14 +2161,14 @@ static void adreno_dispatcher_work(struct adreno_device *adreno_dev) /* * As long as there are inflight commands, process retired comamnds from - * all drawqueues + * all cmdqueues */ for (i = 0; i < adreno_dev->num_ringbuffers; i++) { - struct adreno_dispatcher_drawqueue *drawqueue = - DRAWQUEUE(&adreno_dev->ringbuffers[i]); + struct adreno_dispatcher_cmdqueue *cmdqueue = + CMDQUEUE(&adreno_dev->ringbuffers[i]); - count += adreno_dispatch_process_drawqueue(adreno_dev, - drawqueue); + count += adreno_dispatch_process_cmdqueue(adreno_dev, + cmdqueue); if (dispatcher->inflight == 0) break; } @@ -2336,39 +2201,12 @@ static void adreno_dispatcher_work(struct adreno_device *adreno_dev) mutex_unlock(&dispatcher->mutex); } -static int adreno_dispatcher_thread(void *data) -{ - static const struct sched_param sched_rt_prio = { - .sched_priority = 16 - }; - struct adreno_device *adreno_dev = data; - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - - sched_setscheduler_nocheck(current, SCHED_FIFO, &sched_rt_prio); - - while (1) { - bool should_stop; - - wait_event(dispatcher->cmd_waitq, - (should_stop = kthread_should_stop()) || - atomic_cmpxchg(&dispatcher->send_cmds, 1, 0)); - - if (should_stop) - break; - - adreno_dispatcher_work(adreno_dev); - } - - return 0; -} - void adreno_dispatcher_schedule(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - if (!atomic_cmpxchg(&dispatcher->send_cmds, 0, 1)) - wake_up(&dispatcher->cmd_waitq); + queue_kthread_work(&kgsl_driver.worker, &dispatcher->work); } /** @@ -2390,7 +2228,7 @@ void adreno_dispatcher_queue_context(struct kgsl_device *device, } /* - * This is called on a regular basis while cmdobj's are inflight. Fault + * This is called on a regular basis while command batches are inflight. Fault * detection registers are read and compared to the existing values - if they * changed then the GPU is still running. If they are the same between * subsequent calls then the GPU may have faulted @@ -2442,7 +2280,7 @@ static void adreno_dispatcher_timer(unsigned long data) */ void adreno_dispatcher_start(struct kgsl_device *device) { - complete_all(&device->halt_gate); + complete_all(&device->cmdbatch_gate); /* Schedule the work loop to get things going */ adreno_dispatcher_schedule(device); @@ -2488,20 +2326,18 @@ void adreno_dispatcher_close(struct adreno_device *adreno_dev) int i; struct adreno_ringbuffer *rb; - kthread_stop(dispatcher->thread); - mutex_lock(&dispatcher->mutex); del_timer_sync(&dispatcher->timer); del_timer_sync(&dispatcher->fault_timer); FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - struct adreno_dispatcher_drawqueue *dispatch_q = + struct adreno_dispatcher_cmdqueue *dispatch_q = &(rb->dispatch_q); - while (!adreno_drawqueue_is_empty(dispatch_q)) { - kgsl_drawobj_destroy( - DRAWOBJ(dispatch_q->cmd_q[dispatch_q->head])); + while (!adreno_cmdqueue_is_empty(dispatch_q)) { + kgsl_cmdbatch_destroy( + dispatch_q->cmd_q[dispatch_q->head]); dispatch_q->head = (dispatch_q->head + 1) - % ADRENO_DISPATCH_DRAWQUEUE_SIZE; + % ADRENO_DISPATCH_CMDQUEUE_SIZE; } } @@ -2560,23 +2396,23 @@ static ssize_t _show_uint(struct adreno_dispatcher *dispatcher, *((unsigned int *) attr->value)); } -static DISPATCHER_UINT_ATTR(inflight, 0644, ADRENO_DISPATCH_DRAWQUEUE_SIZE, +static DISPATCHER_UINT_ATTR(inflight, 0644, ADRENO_DISPATCH_CMDQUEUE_SIZE, _dispatcher_q_inflight_hi); static DISPATCHER_UINT_ATTR(inflight_low_latency, 0644, - ADRENO_DISPATCH_DRAWQUEUE_SIZE, _dispatcher_q_inflight_lo); + ADRENO_DISPATCH_CMDQUEUE_SIZE, _dispatcher_q_inflight_lo); /* * Our code that "puts back" a command from the context is much cleaner * if we are sure that there will always be enough room in the * ringbuffer so restrict the maximum size of the context queue to - * ADRENO_CONTEXT_DRAWQUEUE_SIZE - 1 + * ADRENO_CONTEXT_CMDQUEUE_SIZE - 1 */ -static DISPATCHER_UINT_ATTR(context_drawqueue_size, 0644, - ADRENO_CONTEXT_DRAWQUEUE_SIZE - 1, _context_drawqueue_size); +static DISPATCHER_UINT_ATTR(context_cmdqueue_size, 0644, + ADRENO_CONTEXT_CMDQUEUE_SIZE - 1, _context_cmdqueue_size); static DISPATCHER_UINT_ATTR(context_burst_count, 0644, 0, - _context_drawobj_burst); -static DISPATCHER_UINT_ATTR(drawobj_timeout, 0644, 0, - adreno_drawobj_timeout); + _context_cmdbatch_burst); +static DISPATCHER_UINT_ATTR(cmdbatch_timeout, 0644, 0, + adreno_cmdbatch_timeout); static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait); static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0, _fault_timer_interval); @@ -2594,9 +2430,9 @@ static DISPATCHER_UINT_ATTR(dispatch_starvation_time, 0644, 0, static struct attribute *dispatcher_attrs[] = { &dispatcher_attr_inflight.attr, &dispatcher_attr_inflight_low_latency.attr, - &dispatcher_attr_context_drawqueue_size.attr, + &dispatcher_attr_context_cmdqueue_size.attr, &dispatcher_attr_context_burst_count.attr, - &dispatcher_attr_drawobj_timeout.attr, + &dispatcher_attr_cmdbatch_timeout.attr, &dispatcher_attr_context_queue_wait.attr, &dispatcher_attr_fault_detect_interval.attr, &dispatcher_attr_fault_throttle_time.attr, @@ -2666,19 +2502,14 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer, (unsigned long) adreno_dev); + init_kthread_work(&dispatcher->work, adreno_dispatcher_work); + init_completion(&dispatcher->idle_gate); complete_all(&dispatcher->idle_gate); plist_head_init(&dispatcher->pending); spin_lock_init(&dispatcher->plist_lock); - init_waitqueue_head(&dispatcher->cmd_waitq); - dispatcher->send_cmds = (atomic_t)ATOMIC_INIT(0); - dispatcher->thread = kthread_run(adreno_dispatcher_thread, adreno_dev, - "adreno_dispatch"); - if (IS_ERR(dispatcher->thread)) - return PTR_ERR(dispatcher->thread); - ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher, &device->dev->kobj, "dispatch"); diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h index 0f50d2fdcfa67a286f9b07ae5a4cc65a2da266c9..d23f8175a18f03a054a2bc99a9798861bcc0713f 100644 --- a/drivers/gpu/msm/adreno_dispatch.h +++ b/drivers/gpu/msm/adreno_dispatch.h @@ -15,7 +15,7 @@ #define ____ADRENO_DISPATCHER_H extern unsigned int adreno_disp_preempt_fair_sched; -extern unsigned int adreno_drawobj_timeout; +extern unsigned int adreno_cmdbatch_timeout; extern unsigned int adreno_dispatch_starvation_time; extern unsigned int adreno_dispatch_time_slice; @@ -44,21 +44,21 @@ enum adreno_dispatcher_starve_timer_states { * sizes that can be chosen at runtime */ -#define ADRENO_DISPATCH_DRAWQUEUE_SIZE 128 +#define ADRENO_DISPATCH_CMDQUEUE_SIZE 128 -#define DRAWQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s)) +#define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s)) /** - * struct adreno_dispatcher_drawqueue - List of commands for a RB level - * @cmd_q: List of command obj's submitted to dispatcher + * struct adreno_dispatcher_cmdqueue - List of commands for a RB level + * @cmd_q: List of command batches submitted to dispatcher * @inflight: Number of commands inflight in this q * @head: Head pointer to the q * @tail: Queues tail pointer - * @active_context_count: Number of active contexts seen in this rb drawqueue - * @expires: The jiffies value at which this drawqueue has run too long + * @active_context_count: Number of active contexts seen in this rb cmdqueue + * @expires: The jiffies value at which this cmdqueue has run too long */ -struct adreno_dispatcher_drawqueue { - struct kgsl_drawobj_cmd *cmd_q[ADRENO_DISPATCH_DRAWQUEUE_SIZE]; +struct adreno_dispatcher_cmdqueue { + struct kgsl_cmdbatch *cmd_q[ADRENO_DISPATCH_CMDQUEUE_SIZE]; unsigned int inflight; unsigned int head; unsigned int tail; @@ -70,19 +70,17 @@ struct adreno_dispatcher_drawqueue { * struct adreno_dispatcher - container for the adreno GPU dispatcher * @mutex: Mutex to protect the structure * @state: Current state of the dispatcher (active or paused) - * @timer: Timer to monitor the progress of the drawobjs - * @inflight: Number of drawobj operations pending in the ringbuffer + * @timer: Timer to monitor the progress of the command batches + * @inflight: Number of command batch operations pending in the ringbuffer * @fault: Non-zero if a fault was detected. - * @pending: Priority list of contexts waiting to submit drawobjs + * @pending: Priority list of contexts waiting to submit command batches * @plist_lock: Spin lock to protect the pending queue + * @work: work_struct to put the dispatcher in a work queue * @kobj: kobject for the dispatcher directory in the device sysfs node * @idle_gate: Gate to wait on for dispatcher to idle * @disp_preempt_fair_sched: If set then dispatcher will try to be fair to * starving RB's by scheduling them in and enforcing a minimum time slice * for every RB that is scheduled to run on the device - * @thread: Kthread for the command dispatcher - * @cmd_waitq: Waitqueue for the command dispatcher - * @send_cmds: Atomic boolean indicating that commands should be dispatched */ struct adreno_dispatcher { struct mutex mutex; @@ -93,12 +91,10 @@ struct adreno_dispatcher { atomic_t fault; struct plist_head pending; spinlock_t plist_lock; + struct kthread_work work; struct kobject kobj; struct completion idle_gate; unsigned int disp_preempt_fair_sched; - struct task_struct *thread; - wait_queue_head_t cmd_waitq; - atomic_t send_cmds; }; enum adreno_dispatcher_flags { @@ -114,9 +110,9 @@ void adreno_dispatcher_irq_fault(struct adreno_device *adreno_dev); void adreno_dispatcher_stop(struct adreno_device *adreno_dev); void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device); -int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, - struct kgsl_context *context, struct kgsl_drawobj *drawobj[], - uint32_t count, uint32_t *timestamp); +int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev, + struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch, + uint32_t *timestamp); void adreno_dispatcher_schedule(struct kgsl_device *device); void adreno_dispatcher_pause(struct adreno_device *adreno_dev); @@ -125,11 +121,11 @@ void adreno_dispatcher_queue_context(struct kgsl_device *device, void adreno_dispatcher_preempt_callback(struct adreno_device *adreno_dev, int bit); void adreno_preempt_process_dispatch_queue(struct adreno_device *adreno_dev, - struct adreno_dispatcher_drawqueue *dispatch_q); + struct adreno_dispatcher_cmdqueue *dispatch_q); -static inline bool adreno_drawqueue_is_empty( - struct adreno_dispatcher_drawqueue *drawqueue) +static inline bool adreno_cmdqueue_is_empty( + struct adreno_dispatcher_cmdqueue *cmdqueue) { - return (drawqueue != NULL && drawqueue->head == drawqueue->tail); + return (cmdqueue != NULL && cmdqueue->head == cmdqueue->tail); } #endif /* __ADRENO_DISPATCHER_H */ diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index 2128abff95fff455a5d83ba5f3bb543baf404793..13ef0f51e4aed0cc3a1161360a27a6fc52623109 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -59,14 +59,14 @@ void adreno_drawctxt_dump(struct kgsl_device *device, kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED, &retire); /* - * We may have kgsl sync obj timer running, which also uses same + * We may have cmdbatch timer running, which also uses same * lock, take a lock with software interrupt disabled (bh) * to avoid spin lock recursion. * * Use Spin trylock because dispatcher can acquire drawctxt->lock * if context is pending and the fence it is waiting on just got * signalled. Dispatcher acquires drawctxt->lock and tries to - * delete the sync obj timer using del_timer_sync(). + * delete the cmdbatch timer using del_timer_sync(). * del_timer_sync() waits till timer and its pending handlers * are deleted. But if the timer expires at the same time, * timer handler could be waiting on drawctxt->lock leading to a @@ -83,27 +83,23 @@ void adreno_drawctxt_dump(struct kgsl_device *device, context->id, queue, drawctxt->submitted_timestamp, start, retire); - if (drawctxt->drawqueue_head != drawctxt->drawqueue_tail) { - struct kgsl_drawobj *drawobj = - drawctxt->drawqueue[drawctxt->drawqueue_head]; + if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { + struct kgsl_cmdbatch *cmdbatch = + drawctxt->cmdqueue[drawctxt->cmdqueue_head]; - if (test_bit(ADRENO_CONTEXT_FENCE_LOG, &context->priv)) { + if (test_bit(CMDBATCH_FLAG_FENCE_LOG, &cmdbatch->priv)) { dev_err(device->dev, " possible deadlock. Context %d might be blocked for itself\n", context->id); goto stats; } - if (drawobj->type == SYNCOBJ_TYPE) { - struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj); - - if (kgsl_drawobj_events_pending(syncobj)) { - dev_err(device->dev, - " context[%d] (ts=%d) Active sync points:\n", - context->id, drawobj->timestamp); + if (kgsl_cmdbatch_events_pending(cmdbatch)) { + dev_err(device->dev, + " context[%d] (ts=%d) Active sync points:\n", + context->id, cmdbatch->timestamp); - kgsl_dump_syncpoints(device, syncobj); - } + kgsl_dump_syncpoints(device, cmdbatch); } } @@ -235,19 +231,19 @@ done: return ret; } -static int drawctxt_detach_drawobjs(struct adreno_context *drawctxt, - struct kgsl_drawobj **list) +static int drawctxt_detach_cmdbatches(struct adreno_context *drawctxt, + struct kgsl_cmdbatch **list) { int count = 0; - while (drawctxt->drawqueue_head != drawctxt->drawqueue_tail) { - struct kgsl_drawobj *drawobj = - drawctxt->drawqueue[drawctxt->drawqueue_head]; + while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { + struct kgsl_cmdbatch *cmdbatch = + drawctxt->cmdqueue[drawctxt->cmdqueue_head]; - drawctxt->drawqueue_head = (drawctxt->drawqueue_head + 1) % - ADRENO_CONTEXT_DRAWQUEUE_SIZE; + drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) % + ADRENO_CONTEXT_CMDQUEUE_SIZE; - list[count++] = drawobj; + list[count++] = cmdbatch; } return count; @@ -265,7 +261,7 @@ void adreno_drawctxt_invalidate(struct kgsl_device *device, struct kgsl_context *context) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); - struct kgsl_drawobj *list[ADRENO_CONTEXT_DRAWQUEUE_SIZE]; + struct kgsl_cmdbatch *list[ADRENO_CONTEXT_CMDQUEUE_SIZE]; int i, count; trace_adreno_drawctxt_invalidate(drawctxt); @@ -286,13 +282,13 @@ void adreno_drawctxt_invalidate(struct kgsl_device *device, drawctxt->timestamp); /* Get rid of commands still waiting in the queue */ - count = drawctxt_detach_drawobjs(drawctxt, list); + count = drawctxt_detach_cmdbatches(drawctxt, list); spin_unlock(&drawctxt->lock); for (i = 0; i < count; i++) { kgsl_cancel_events_timestamp(device, &context->events, list[i]->timestamp); - kgsl_drawobj_destroy(list[i]); + kgsl_cmdbatch_destroy(list[i]); } /* Make sure all pending events are processed or cancelled */ @@ -462,7 +458,7 @@ void adreno_drawctxt_detach(struct kgsl_context *context) struct adreno_context *drawctxt; struct adreno_ringbuffer *rb; int ret, count, i; - struct kgsl_drawobj *list[ADRENO_CONTEXT_DRAWQUEUE_SIZE]; + struct kgsl_cmdbatch *list[ADRENO_CONTEXT_CMDQUEUE_SIZE]; if (context == NULL) return; @@ -477,7 +473,7 @@ void adreno_drawctxt_detach(struct kgsl_context *context) spin_unlock(&adreno_dev->active_list_lock); spin_lock(&drawctxt->lock); - count = drawctxt_detach_drawobjs(drawctxt, list); + count = drawctxt_detach_cmdbatches(drawctxt, list); spin_unlock(&drawctxt->lock); for (i = 0; i < count; i++) { @@ -487,7 +483,7 @@ void adreno_drawctxt_detach(struct kgsl_context *context) * detached status here. */ adreno_fault_skipcmd_detached(adreno_dev, drawctxt, list[i]); - kgsl_drawobj_destroy(list[i]); + kgsl_cmdbatch_destroy(list[i]); } /* diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h index 07108eaf502f339004931d92c3aef7ec32585f72..8ca10ee351070b6ccf6d285cc8bf8884180400b5 100644 --- a/drivers/gpu/msm/adreno_drawctxt.h +++ b/drivers/gpu/msm/adreno_drawctxt.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. * * 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 @@ -18,7 +18,7 @@ struct adreno_context_type { const char *str; }; -#define ADRENO_CONTEXT_DRAWQUEUE_SIZE 128 +#define ADRENO_CONTEXT_CMDQUEUE_SIZE 128 #define SUBMIT_RETIRE_TICKS_SIZE 7 struct kgsl_device; @@ -32,22 +32,21 @@ struct kgsl_context; * @internal_timestamp: Global timestamp of the last issued command * NOTE: guarded by device->mutex, not drawctxt->mutex! * @type: Context type (GL, CL, RS) - * @mutex: Mutex to protect the drawqueue - * @drawqueue: Queue of drawobjs waiting to be dispatched for this - * context - * @drawqueue_head: Head of the drawqueue queue - * @drawqueue_tail: Tail of the drawqueue queue + * @mutex: Mutex to protect the cmdqueue + * @cmdqueue: Queue of command batches waiting to be dispatched for this context + * @cmdqueue_head: Head of the cmdqueue queue + * @cmdqueue_tail: Tail of the cmdqueue queue * @pending: Priority list node for the dispatcher list of pending contexts * @wq: Workqueue structure for contexts to sleep pending room in the queue * @waiting: Workqueue structure for contexts waiting for a timestamp or event * @timeout: Workqueue structure for contexts waiting to invalidate - * @queued: Number of commands queued in the drawqueue - * @fault_policy: GFT fault policy set in _skip_cmd(); + * @queued: Number of commands queued in the cmdqueue + * @fault_policy: GFT fault policy set in cmdbatch_skip_cmd(); * @debug_root: debugfs entry for this context. * @queued_timestamp: The last timestamp that was queued on this context * @rb: The ringbuffer in which this context submits commands. * @submitted_timestamp: The last timestamp that was submitted for this context - * @submit_retire_ticks: Array to hold command obj execution times from submit + * @submit_retire_ticks: Array to hold cmdbatch execution times from submit * to retire * @ticks_index: The index into submit_retire_ticks[] where the new delta will * be written. @@ -62,9 +61,9 @@ struct adreno_context { spinlock_t lock; /* Dispatcher */ - struct kgsl_drawobj *drawqueue[ADRENO_CONTEXT_DRAWQUEUE_SIZE]; - unsigned int drawqueue_head; - unsigned int drawqueue_tail; + struct kgsl_cmdbatch *cmdqueue[ADRENO_CONTEXT_CMDQUEUE_SIZE]; + unsigned int cmdqueue_head; + unsigned int cmdqueue_tail; struct plist_node pending; wait_queue_head_t wq; @@ -95,9 +94,8 @@ struct adreno_context { * @ADRENO_CONTEXT_SKIP_EOF - Context skip IBs until the next end of frame * marker. * @ADRENO_CONTEXT_FORCE_PREAMBLE - Force the preamble for the next submission. - * @ADRENO_CONTEXT_SKIP_CMD - Context's drawobj's skipped during + * @ADRENO_CONTEXT_SKIP_CMD - Context's command batch is skipped during fault tolerance. - * @ADRENO_CONTEXT_FENCE_LOG - Dump fences on this context. */ enum adreno_context_priv { ADRENO_CONTEXT_FAULT = KGSL_CONTEXT_PRIV_DEVICE_SPECIFIC, @@ -106,7 +104,6 @@ enum adreno_context_priv { ADRENO_CONTEXT_SKIP_EOF, ADRENO_CONTEXT_FORCE_PREAMBLE, ADRENO_CONTEXT_SKIP_CMD, - ADRENO_CONTEXT_FENCE_LOG, }; /* Flags for adreno_drawctxt_switch() */ @@ -138,4 +135,16 @@ void adreno_drawctxt_invalidate(struct kgsl_device *device, void adreno_drawctxt_dump(struct kgsl_device *device, struct kgsl_context *context); +static struct adreno_context_type ctxt_type_table[] = {KGSL_CONTEXT_TYPES}; + +static inline const char *get_api_type_str(unsigned int type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ctxt_type_table); i++) { + if (ctxt_type_table[i].type == type) + return ctxt_type_table[i].str; + } + return "UNKNOWN"; +} #endif /* __ADRENO_DRAWCTXT_H */ diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c index d8af520b2fe60c5c0287211064d08ad4db7d615d..cbd847cfa4e0cd072791421250ac65772db971d8 100644 --- a/drivers/gpu/msm/adreno_profile.c +++ b/drivers/gpu/msm/adreno_profile.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 2018 The Linux Foundation. All rights reserved. * * 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,18 +78,6 @@ #define SIZE_PIPE_ENTRY(cnt) (50 + (cnt) * 62) #define SIZE_LOG_ENTRY(cnt) (6 + (cnt) * 5) -static struct adreno_context_type ctxt_type_table[] = {KGSL_CONTEXT_TYPES}; - -static const char *get_api_type_str(unsigned int type) -{ - int i; - for (i = 0; i < ARRAY_SIZE(ctxt_type_table) - 1; i++) { - if (ctxt_type_table[i].type == type) - return ctxt_type_table[i].str; - } - return "UNKNOWN"; -} - static inline uint _ib_start(struct adreno_device *adreno_dev, unsigned int *cmds) { diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 18c15c36c610e17f61101dd0c6c2d602deaf177b..7fc6969240f994ff2289745150cb505e21f575cf 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017,2019, The Linux Foundation. All rights reserved. * * 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 @@ -265,6 +265,11 @@ static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev, PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED, "pagetable_desc"); if (ret) return ret; + + /* allocate a chunk of memory to create user profiling IB1s */ + kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &rb->profile_desc, + PAGE_SIZE, KGSL_MEMFLAGS_GPUREADONLY, 0, "profile_desc"); + return kgsl_allocate_global(KGSL_DEVICE(adreno_dev), &rb->buffer_desc, KGSL_RB_SIZE, KGSL_MEMFLAGS_GPUREADONLY, 0, "ringbuffer"); @@ -278,7 +283,7 @@ int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) if (!adreno_is_a3xx(adreno_dev)) { status = kgsl_allocate_global(device, &device->scratch, - PAGE_SIZE, 0, 0, "scratch"); + PAGE_SIZE, 0, KGSL_MEMDESC_RANDOM, "scratch"); if (status != 0) return status; } @@ -309,7 +314,7 @@ static void _adreno_ringbuffer_close(struct adreno_device *adreno_dev, kgsl_free_global(device, &rb->pagetable_desc); kgsl_free_global(device, &rb->preemption_desc); - + kgsl_free_global(device, &rb->profile_desc); kgsl_free_global(device, &rb->buffer_desc); kgsl_del_event_group(&rb->events); memset(rb, 0, sizeof(struct adreno_ringbuffer)); @@ -703,17 +708,96 @@ adreno_ringbuffer_issuecmds(struct adreno_ringbuffer *rb, sizedwords, 0, NULL); } +/** + * _ringbuffer_verify_ib() - Check if an IB's size is within a permitted limit + * @device: The kgsl device pointer + * @ibdesc: Pointer to the IB descriptor + */ +static inline bool _ringbuffer_verify_ib(struct kgsl_device_private *dev_priv, + struct kgsl_context *context, struct kgsl_memobj_node *ib) +{ + struct kgsl_device *device = dev_priv->device; + struct kgsl_process_private *private = dev_priv->process_priv; + + /* The maximum allowable size for an IB in the CP is 0xFFFFF dwords */ + if (ib->size == 0 || ((ib->size >> 2) > 0xFFFFF)) { + pr_context(device, context, "ctxt %d invalid ib size %lld\n", + context->id, ib->size); + return false; + } + + /* Make sure that the address is mapped */ + if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, ib->gpuaddr)) { + pr_context(device, context, "ctxt %d invalid ib gpuaddr %llX\n", + context->id, ib->gpuaddr); + return false; + } + + return true; +} + +int +adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, + struct kgsl_context *context, + struct kgsl_cmdbatch *cmdbatch, + uint32_t *timestamp) +{ + struct kgsl_device *device = dev_priv->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_context *drawctxt = ADRENO_CONTEXT(context); + struct kgsl_memobj_node *ib; + int ret; + + if (kgsl_context_invalid(context)) + return -EDEADLK; + + /* Verify the IBs before they get queued */ + list_for_each_entry(ib, &cmdbatch->cmdlist, node) + if (_ringbuffer_verify_ib(dev_priv, context, ib) == false) + return -EINVAL; + + /* wait for the suspend gate */ + wait_for_completion(&device->cmdbatch_gate); + + /* + * Clear the wake on touch bit to indicate an IB has been + * submitted since the last time we set it. But only clear + * it when we have rendering commands. + */ + if (!(cmdbatch->flags & KGSL_CMDBATCH_MARKER) + && !(cmdbatch->flags & KGSL_CMDBATCH_SYNC)) + device->flags &= ~KGSL_FLAG_WAKE_ON_TOUCH; + + /* A3XX does not have support for command batch profiling */ + if (adreno_is_a3xx(adreno_dev) && + (cmdbatch->flags & KGSL_CMDBATCH_PROFILING)) + return -EOPNOTSUPP; + + /* Queue the command in the ringbuffer */ + ret = adreno_dispatcher_queue_cmd(adreno_dev, drawctxt, cmdbatch, + timestamp); + + /* + * Return -EPROTO if the device has faulted since the last time we + * checked - userspace uses this to perform post-fault activities + */ + if (!ret && test_and_clear_bit(ADRENO_CONTEXT_FAULT, &context->priv)) + ret = -EPROTO; + + return ret; +} + static void adreno_ringbuffer_set_constraint(struct kgsl_device *device, - struct kgsl_drawobj *drawobj) + struct kgsl_cmdbatch *cmdbatch) { - struct kgsl_context *context = drawobj->context; + struct kgsl_context *context = cmdbatch->context; /* * Check if the context has a constraint and constraint flags are * set. */ if (context->pwr_constraint.type && ((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) || - (drawobj->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) + (cmdbatch->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) kgsl_pwrctrl_set_constraint(device, &context->pwr_constraint, context->id); } @@ -743,42 +827,69 @@ static inline int _get_alwayson_counter(struct adreno_device *adreno_dev, return (unsigned int)(p - cmds); } +/* This is the maximum possible size for 64 bit targets */ +#define PROFILE_IB_DWORDS 4 +#define PROFILE_IB_SLOTS (PAGE_SIZE / (PROFILE_IB_DWORDS << 2)) + +static int set_user_profiling(struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb, u32 *cmds, u64 gpuaddr) +{ + int dwords, index = 0; + u64 ib_gpuaddr; + u32 *ib; + + if (!rb->profile_desc.hostptr) + return 0; + + ib = ((u32 *) rb->profile_desc.hostptr) + + (rb->profile_index * PROFILE_IB_DWORDS); + ib_gpuaddr = rb->profile_desc.gpuaddr + + (rb->profile_index * (PROFILE_IB_DWORDS << 2)); + + dwords = _get_alwayson_counter(adreno_dev, ib, gpuaddr); + + /* Make an indirect buffer for the request */ + cmds[index++] = cp_mem_packet(adreno_dev, CP_INDIRECT_BUFFER_PFE, 2, 1); + index += cp_gpuaddr(adreno_dev, &cmds[index], ib_gpuaddr); + cmds[index++] = dwords; + + rb->profile_index = (rb->profile_index + 1) % PROFILE_IB_SLOTS; + + return index; +} + /* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, - struct kgsl_drawobj_cmd *cmdobj, - struct adreno_submit_time *time) + struct kgsl_cmdbatch *cmdbatch, struct adreno_submit_time *time) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); struct kgsl_memobj_node *ib; unsigned int numibs = 0; unsigned int *link; - unsigned int link_onstack[SZ_256]; - bool use_onstack_link; unsigned int *cmds; struct kgsl_context *context; struct adreno_context *drawctxt; bool use_preamble = true; - bool user_profiling = false; - bool kernel_profiling = false; + bool cmdbatch_user_profiling = false; + bool cmdbatch_kernel_profiling = false; int flags = KGSL_CMD_FLAGS_NONE; int ret; struct adreno_ringbuffer *rb; - struct kgsl_drawobj_profiling_buffer *profile_buffer = NULL; + struct kgsl_cmdbatch_profiling_buffer *profile_buffer = NULL; unsigned int dwords = 0; struct adreno_submit_time local; - struct kgsl_mem_entry *entry = cmdobj->profiling_buf_entry; + struct kgsl_mem_entry *entry = cmdbatch->profiling_buf_entry; if (entry) profile_buffer = kgsl_gpuaddr_to_vaddr(&entry->memdesc, - cmdobj->profiling_buffer_gpuaddr); + cmdbatch->profiling_buffer_gpuaddr); - context = drawobj->context; + context = cmdbatch->context; drawctxt = ADRENO_CONTEXT(context); /* Get the total IBs in the list */ - list_for_each_entry(ib, &cmdobj->cmdlist, node) + list_for_each_entry(ib, &cmdbatch->cmdlist, node) numibs++; rb = drawctxt->rb; @@ -795,14 +906,14 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, * c) force preamble for commandbatch */ if (test_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->base.priv) && - (!test_bit(CMDOBJ_SKIP, &cmdobj->priv))) { + (!test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv))) { - set_bit(KGSL_FT_SKIPCMD, &cmdobj->fault_recovery); - cmdobj->fault_policy = drawctxt->fault_policy; - set_bit(CMDOBJ_FORCE_PREAMBLE, &cmdobj->priv); + set_bit(KGSL_FT_SKIPCMD, &cmdbatch->fault_recovery); + cmdbatch->fault_policy = drawctxt->fault_policy; + set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv); /* if context is detached print fault recovery */ - adreno_fault_skipcmd_detached(adreno_dev, drawctxt, drawobj); + adreno_fault_skipcmd_detached(adreno_dev, drawctxt, cmdbatch); /* clear the drawctxt flags */ clear_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->base.priv); @@ -814,7 +925,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, if a context switch hasn't occured */ if ((drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE) && - !test_bit(CMDOBJ_FORCE_PREAMBLE, &cmdobj->priv) && + !test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) && (rb->drawctxt_active == drawctxt)) use_preamble = false; @@ -824,7 +935,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, * the accounting sane. Set start_index and numibs to 0 to just * generate the start and end markers and skip everything else */ - if (test_bit(CMDOBJ_SKIP, &cmdobj->priv)) { + if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) { use_preamble = false; numibs = 0; } @@ -841,17 +952,15 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, /* Each IB takes up 30 dwords in worst case */ dwords += (numibs * 30); - if (drawobj->flags & KGSL_DRAWOBJ_PROFILING && + if (cmdbatch->flags & KGSL_CMDBATCH_PROFILING && !adreno_is_a3xx(adreno_dev) && profile_buffer) { - user_profiling = true; - dwords += 6; + cmdbatch_user_profiling = true; /* - * REG_TO_MEM packet on A5xx needs another ordinal. - * Add 2 more dwords since we do profiling before and after. + * User side profiling uses two IB1s, one before with 4 dwords + * per INDIRECT_BUFFER_PFE call */ - if (adreno_is_a5xx(adreno_dev)) - dwords += 2; + dwords += 8; /* * we want to use an adreno_submit_time struct to get the @@ -864,8 +973,8 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, time = &local; } - if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) { - kernel_profiling = true; + if (test_bit(CMDBATCH_FLAG_PROFILE, &cmdbatch->priv)) { + cmdbatch_kernel_profiling = true; dwords += 6; if (adreno_is_a5xx(adreno_dev)) dwords += 2; @@ -875,15 +984,10 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, adreno_is_preemption_enabled(adreno_dev)) dwords += 8; - use_onstack_link = dwords <= ARRAY_SIZE(link_onstack); - if (use_onstack_link) { - link = link_onstack; - } else { - link = kmalloc(sizeof(unsigned int) * dwords, GFP_KERNEL); - if (!link) { - ret = -ENOMEM; - goto done; - } + link = kzalloc(sizeof(unsigned int) * dwords, GFP_KERNEL); + if (!link) { + ret = -ENOMEM; + goto done; } cmds = link; @@ -891,26 +995,26 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, *cmds++ = cp_packet(adreno_dev, CP_NOP, 1); *cmds++ = KGSL_START_OF_IB_IDENTIFIER; - if (kernel_profiling) { + if (cmdbatch_kernel_profiling) { cmds += _get_alwayson_counter(adreno_dev, cmds, - adreno_dev->profile_buffer.gpuaddr + - ADRENO_DRAWOBJ_PROFILE_OFFSET(cmdobj->profile_index, + adreno_dev->cmdbatch_profile_buffer.gpuaddr + + ADRENO_CMDBATCH_PROFILE_OFFSET(cmdbatch->profile_index, started)); } /* - * Add cmds to read the GPU ticks at the start of command obj and - * write it into the appropriate command obj profiling buffer offset + * Add IB1 to read the GPU ticks at the start of the cmdbatch and + * write it into the appropriate cmdbatch profiling buffer offset */ - if (user_profiling) { - cmds += _get_alwayson_counter(adreno_dev, cmds, - cmdobj->profiling_buffer_gpuaddr + - offsetof(struct kgsl_drawobj_profiling_buffer, + if (cmdbatch_user_profiling) { + cmds += set_user_profiling(adreno_dev, rb, cmds, + cmdbatch->profiling_buffer_gpuaddr + + offsetof(struct kgsl_cmdbatch_profiling_buffer, gpu_ticks_submitted)); } if (numibs) { - list_for_each_entry(ib, &cmdobj->cmdlist, node) { + list_for_each_entry(ib, &cmdbatch->cmdlist, node) { /* * Skip 0 sized IBs - these are presumed to have been * removed from consideration by the FT policy @@ -934,21 +1038,21 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, adreno_is_preemption_enabled(adreno_dev)) cmds += gpudev->preemption_yield_enable(cmds); - if (kernel_profiling) { + if (cmdbatch_kernel_profiling) { cmds += _get_alwayson_counter(adreno_dev, cmds, - adreno_dev->profile_buffer.gpuaddr + - ADRENO_DRAWOBJ_PROFILE_OFFSET(cmdobj->profile_index, + adreno_dev->cmdbatch_profile_buffer.gpuaddr + + ADRENO_CMDBATCH_PROFILE_OFFSET(cmdbatch->profile_index, retired)); } /* - * Add cmds to read the GPU ticks at the end of command obj and - * write it into the appropriate command obj profiling buffer offset + * Add IB1 to read the GPU ticks at the end of the cmdbatch and + * write it into the appropriate cmdbatch profiling buffer offset */ - if (user_profiling) { - cmds += _get_alwayson_counter(adreno_dev, cmds, - cmdobj->profiling_buffer_gpuaddr + - offsetof(struct kgsl_drawobj_profiling_buffer, + if (cmdbatch_user_profiling) { + cmds += set_user_profiling(adreno_dev, rb, cmds, + cmdbatch->profiling_buffer_gpuaddr + + offsetof(struct kgsl_cmdbatch_profiling_buffer, gpu_ticks_retired)); } @@ -974,7 +1078,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, goto done; } - if (test_bit(CMDOBJ_WFI, &cmdobj->priv)) + if (test_bit(CMDBATCH_FLAG_WFI, &cmdbatch->priv)) flags = KGSL_CMD_FLAGS_WFI; /* @@ -987,27 +1091,27 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, flags |= KGSL_CMD_FLAGS_PWRON_FIXUP; /* Set the constraints before adding to ringbuffer */ - adreno_ringbuffer_set_constraint(device, drawobj); + adreno_ringbuffer_set_constraint(device, cmdbatch); /* CFF stuff executed only if CFF is enabled */ - kgsl_cffdump_capture_ib_desc(device, context, cmdobj); + kgsl_cffdump_capture_ib_desc(device, context, cmdbatch); ret = adreno_ringbuffer_addcmds(rb, flags, &link[0], (cmds - link), - drawobj->timestamp, time); + cmdbatch->timestamp, time); if (!ret) { set_bit(KGSL_CONTEXT_PRIV_SUBMITTED, &context->priv); - cmdobj->global_ts = drawctxt->internal_timestamp; + cmdbatch->global_ts = drawctxt->internal_timestamp; /* Put the timevalues in the profiling buffer */ - if (user_profiling) { + if (cmdbatch_user_profiling) { /* * Return kernel clock time to the the client * if requested */ - if (drawobj->flags & KGSL_DRAWOBJ_PROFILING_KTIME) { + if (cmdbatch->flags & KGSL_CMDBATCH_PROFILING_KTIME) { uint64_t secs = time->ktime; profile_buffer->wall_clock_ns = @@ -1032,11 +1136,11 @@ done: kgsl_memdesc_unmap(&entry->memdesc); - trace_kgsl_issueibcmds(device, context->id, numibs, drawobj->timestamp, - drawobj->flags, ret, drawctxt->type); + trace_kgsl_issueibcmds(device, context->id, cmdbatch, + numibs, cmdbatch->timestamp, + cmdbatch->flags, ret, drawctxt->type); - if (!use_onstack_link) - kfree(link); + kfree(link); return ret; } diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index 63374af1e3f7762014a24a5a25be9206a270d09d..9a43c5da0af9939334c70ec6bc40f6abeb47a606 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2016,2019, The Linux Foundation. All rights reserved. * * 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 @@ -119,7 +119,7 @@ struct adreno_ringbuffer { struct adreno_context *drawctxt_active; struct kgsl_memdesc preemption_desc; struct kgsl_memdesc pagetable_desc; - struct adreno_dispatcher_drawqueue dispatch_q; + struct adreno_dispatcher_cmdqueue dispatch_q; wait_queue_head_t ts_expire_waitq; unsigned int wptr_preempt_end; unsigned int gpr11; @@ -127,6 +127,18 @@ struct adreno_ringbuffer { unsigned long sched_timer; enum adreno_dispatcher_starve_timer_states starve_timer_state; spinlock_t preempt_lock; + /** + * @profile_desc: global memory to construct IB1s to do user side + * profiling + */ + struct kgsl_memdesc profile_desc; + /** + * @profile_index: Pointer to the next "slot" in profile_desc for a user + * profiling IB1. This allows for PAGE_SIZE / 16 = 256 simultaneous + * commands per ringbuffer with user profiling enabled + * enough. + */ + u32 profile_index; }; /* Returns the current ringbuffer */ @@ -136,11 +148,11 @@ int cp_secure_mode(struct adreno_device *adreno_dev, uint *cmds, int set); int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, struct kgsl_context *context, - struct kgsl_drawobj *drawobj, + struct kgsl_cmdbatch *cmdbatch, uint32_t *timestamp); int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, - struct kgsl_drawobj_cmd *cmdobj, + struct kgsl_cmdbatch *cmdbatch, struct adreno_submit_time *time); int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt); diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index 4e6a4a466cc9b97991fc42fc3caf7d3189c6a029..eda28ab15aec77779ffda50be36e226592177f6a 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * 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 @@ -70,6 +70,19 @@ void kgsl_snapshot_push_object(struct kgsl_process_private *process, for (index = 0; index < objbufptr; index++) { if (objbuf[index].gpuaddr == gpuaddr && objbuf[index].entry->priv == process) { + /* + * Check if newly requested size is within the + * allocated range or not, otherwise continue + * with previous size. + */ + if (!kgsl_gpuaddr_in_memdesc( + &objbuf[index].entry->memdesc, + gpuaddr, dwords << 2)) { + KGSL_CORE_ERR( + "snapshot: IB 0x%016llx size is not within the memdesc range\n", + gpuaddr); + return; + } objbuf[index].size = max_t(uint64_t, objbuf[index].size, diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index f99db56855fa64b4750d9452e1ae8e0501c6ce77..f9d16222177c02e829d7ddbc814a55223a576eee 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -309,6 +309,7 @@ static ADRENO_SYSFS_BOOL(ft_long_ib_detect); static ADRENO_SYSFS_BOOL(ft_hang_intr_status); static DEVICE_INT_ATTR(wake_nice, 0644, adreno_wake_nice); +static DEVICE_INT_ATTR(wake_timeout, 0644, adreno_wake_timeout); static ADRENO_SYSFS_BOOL(sptp_pc); static ADRENO_SYSFS_BOOL(lm); @@ -323,6 +324,7 @@ static const struct device_attribute *_attr_list[] = { &adreno_attr_ft_long_ib_detect.attr, &adreno_attr_ft_hang_intr_status.attr, &dev_attr_wake_nice.attr, + &dev_attr_wake_timeout.attr, &adreno_attr_sptp_pc.attr, &adreno_attr_lm.attr, &adreno_attr_preemption.attr, diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h index 74c4c4e6e1fac942b102663e497cce1bb9d86bf9..a33a386dfa5840d8d44e91e3d284f842f42e4ba6 100644 --- a/drivers/gpu/msm/adreno_trace.h +++ b/drivers/gpu/msm/adreno_trace.h @@ -27,8 +27,8 @@ #include "adreno_a5xx.h" TRACE_EVENT(adreno_cmdbatch_queued, - TP_PROTO(struct kgsl_drawobj *drawobj, unsigned int queued), - TP_ARGS(drawobj, queued), + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int queued), + TP_ARGS(cmdbatch, queued), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, timestamp) @@ -37,26 +37,26 @@ TRACE_EVENT(adreno_cmdbatch_queued, __field(unsigned int, prio) ), TP_fast_assign( - __entry->id = drawobj->context->id; - __entry->timestamp = drawobj->timestamp; + __entry->id = cmdbatch->context->id; + __entry->timestamp = cmdbatch->timestamp; __entry->queued = queued; - __entry->flags = drawobj->flags; - __entry->prio = drawobj->context->priority; + __entry->flags = cmdbatch->flags; + __entry->prio = cmdbatch->context->priority; ), TP_printk( "ctx=%u ctx_prio=%u ts=%u queued=%u flags=%s", __entry->id, __entry->prio, __entry->timestamp, __entry->queued, __entry->flags ? __print_flags(__entry->flags, "|", - KGSL_DRAWOBJ_FLAGS) : "none" + KGSL_CMDBATCH_FLAGS) : "none" ) ); TRACE_EVENT(adreno_cmdbatch_submitted, - TP_PROTO(struct kgsl_drawobj *drawobj, int inflight, uint64_t ticks, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight, uint64_t ticks, unsigned long secs, unsigned long usecs, struct adreno_ringbuffer *rb, unsigned int rptr), - TP_ARGS(drawobj, inflight, ticks, secs, usecs, rb, rptr), + TP_ARGS(cmdbatch, inflight, ticks, secs, usecs, rb, rptr), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, timestamp) @@ -72,14 +72,14 @@ TRACE_EVENT(adreno_cmdbatch_submitted, __field(int, q_inflight) ), TP_fast_assign( - __entry->id = drawobj->context->id; - __entry->timestamp = drawobj->timestamp; + __entry->id = cmdbatch->context->id; + __entry->timestamp = cmdbatch->timestamp; __entry->inflight = inflight; - __entry->flags = drawobj->flags; + __entry->flags = cmdbatch->flags; __entry->ticks = ticks; __entry->secs = secs; __entry->usecs = usecs; - __entry->prio = drawobj->context->priority; + __entry->prio = cmdbatch->context->priority; __entry->rb_id = rb->id; __entry->rptr = rptr; __entry->wptr = rb->wptr; @@ -90,7 +90,7 @@ TRACE_EVENT(adreno_cmdbatch_submitted, __entry->id, __entry->prio, __entry->timestamp, __entry->inflight, __entry->flags ? __print_flags(__entry->flags, "|", - KGSL_DRAWOBJ_FLAGS) : "none", + KGSL_CMDBATCH_FLAGS) : "none", __entry->ticks, __entry->secs, __entry->usecs, __entry->rb_id, __entry->rptr, __entry->wptr, __entry->q_inflight @@ -98,11 +98,10 @@ TRACE_EVENT(adreno_cmdbatch_submitted, ); TRACE_EVENT(adreno_cmdbatch_retired, - TP_PROTO(struct kgsl_drawobj *drawobj, int inflight, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight, uint64_t start, uint64_t retire, - struct adreno_ringbuffer *rb, unsigned int rptr, - unsigned long fault_recovery), - TP_ARGS(drawobj, inflight, start, retire, rb, rptr, fault_recovery), + struct adreno_ringbuffer *rb, unsigned int rptr), + TP_ARGS(cmdbatch, inflight, start, retire, rb, rptr), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, timestamp) @@ -116,17 +115,16 @@ TRACE_EVENT(adreno_cmdbatch_retired, __field(unsigned int, rptr) __field(unsigned int, wptr) __field(int, q_inflight) - __field(unsigned long, fault_recovery) ), TP_fast_assign( - __entry->id = drawobj->context->id; - __entry->timestamp = drawobj->timestamp; + __entry->id = cmdbatch->context->id; + __entry->timestamp = cmdbatch->timestamp; __entry->inflight = inflight; - __entry->recovery = fault_recovery; - __entry->flags = drawobj->flags; + __entry->recovery = cmdbatch->fault_recovery; + __entry->flags = cmdbatch->flags; __entry->start = start; __entry->retire = retire; - __entry->prio = drawobj->context->priority; + __entry->prio = cmdbatch->context->priority; __entry->rb_id = rb->id; __entry->rptr = rptr; __entry->wptr = rb->wptr; @@ -140,7 +138,7 @@ TRACE_EVENT(adreno_cmdbatch_retired, __print_flags(__entry->recovery, "|", ADRENO_FT_TYPES) : "none", __entry->flags ? __print_flags(__entry->flags, "|", - KGSL_DRAWOBJ_FLAGS) : "none", + KGSL_CMDBATCH_FLAGS) : "none", __entry->start, __entry->retire, __entry->rb_id, __entry->rptr, __entry->wptr, @@ -172,16 +170,16 @@ TRACE_EVENT(adreno_cmdbatch_sync, ); TRACE_EVENT(adreno_cmdbatch_fault, - TP_PROTO(struct kgsl_drawobj_cmd *cmdobj, unsigned int fault), - TP_ARGS(cmdobj, fault), + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int fault), + TP_ARGS(cmdbatch, fault), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, timestamp) __field(unsigned int, fault) ), TP_fast_assign( - __entry->id = cmdobj->base.context->id; - __entry->timestamp = cmdobj->base.timestamp; + __entry->id = cmdbatch->context->id; + __entry->timestamp = cmdbatch->timestamp; __entry->fault = fault; ), TP_printk( @@ -196,16 +194,16 @@ TRACE_EVENT(adreno_cmdbatch_fault, ); TRACE_EVENT(adreno_cmdbatch_recovery, - TP_PROTO(struct kgsl_drawobj_cmd *cmdobj, unsigned int action), - TP_ARGS(cmdobj, action), + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int action), + TP_ARGS(cmdbatch, action), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, timestamp) __field(unsigned int, action) ), TP_fast_assign( - __entry->id = cmdobj->base.context->id; - __entry->timestamp = cmdobj->base.timestamp; + __entry->id = cmdbatch->context->id; + __entry->timestamp = cmdbatch->timestamp; __entry->action = action; ), TP_printk( diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 28120b89795608c579a91f4d243331a99c078c58..f9eb9bedb3df0330441ff7f521f7a50d1d15c9cc 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * 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,7 +36,7 @@ #include "kgsl_cffdump.h" #include "kgsl_log.h" #include "kgsl_sharedmem.h" -#include "kgsl_drawobj.h" +#include "kgsl_cmdbatch.h" #include "kgsl_device.h" #include "kgsl_trace.h" #include "kgsl_sync.h" @@ -318,7 +318,7 @@ kgsl_mem_entry_destroy(struct kref *kref) entry->memdesc.sgt->nents, i) { page = sg_page(sg); for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) - set_page_dirty(nth_page(page, j)); + set_page_dirty_lock(nth_page(page, j)); } } @@ -442,6 +442,10 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) type = kgsl_memdesc_usermem_type(&entry->memdesc); entry->priv->stats[type].cur -= entry->memdesc.size; + + if (type != KGSL_MEM_ENTRY_ION) + entry->priv->gpumem_mapped -= entry->memdesc.mapsize; + spin_unlock(&entry->priv->mem_lock); kgsl_mmu_put_gpuaddr(&entry->memdesc); @@ -513,6 +517,23 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, struct kgsl_device *device = dev_priv->device; char name[64]; int ret = 0, id; + struct kgsl_process_private *proc_priv = dev_priv->process_priv; + + /* + * Read and increment the context count under lock to make sure + * no process goes beyond the specified context limit. + */ + spin_lock(&proc_priv->ctxt_count_lock); + if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) { + KGSL_DRV_ERR_RATELIMIT(device, + "Per process context limit reached for pid %u", + dev_priv->process_priv->pid); + spin_unlock(&proc_priv->ctxt_count_lock); + return -ENOSPC; + } + + atomic_inc(&proc_priv->ctxt_count); + spin_unlock(&proc_priv->ctxt_count_lock); id = _kgsl_get_context_id(device); if (id == -ENOSPC) { @@ -531,7 +552,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, KGSL_DRV_INFO(device, "cannot have more than %zu contexts due to memstore limitation\n", KGSL_MEMSTORE_MAX); - + atomic_dec(&proc_priv->ctxt_count); return id; } @@ -562,6 +583,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, out: if (ret) { + atomic_dec(&proc_priv->ctxt_count); write_lock(&device->context_lock); idr_remove(&dev_priv->device->context_idr, id); write_unlock(&device->context_lock); @@ -645,6 +667,7 @@ kgsl_context_destroy(struct kref *kref) device->pwrctrl.constraint.type = KGSL_CONSTRAINT_NONE; } + atomic_dec(&context->proc_priv->ctxt_count); idr_remove(&device->context_idr, context->id); context->id = KGSL_CONTEXT_INVALID; } @@ -879,6 +902,7 @@ static struct kgsl_process_private *kgsl_process_private_new( spin_lock_init(&private->mem_lock); spin_lock_init(&private->syncsource_lock); + spin_lock_init(&private->ctxt_count_lock); idr_init(&private->mem_idr); idr_init(&private->syncsource_idr); @@ -1350,6 +1374,45 @@ long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, kgsl_context_put(context); break; } + case KGSL_PROP_SECURE_BUFFER_ALIGNMENT: + { + unsigned int align; + + if (param->sizebytes != sizeof(unsigned int)) { + result = -EINVAL; + break; + } + /* + * XPUv2 impose the constraint of 1MB memory alignment, + * on the other hand Hypervisor does not have such + * constraints. So driver should fulfill such + * requirements when allocating secure memory. + */ + align = MMU_FEATURE(&dev_priv->device->mmu, + KGSL_MMU_HYP_SECURE_ALLOC) ? PAGE_SIZE : SZ_1M; + + if (copy_to_user(param->value, &align, sizeof(align))) + result = -EFAULT; + + break; + } + case KGSL_PROP_SECURE_CTXT_SUPPORT: + { + unsigned int secure_ctxt; + + if (param->sizebytes != sizeof(unsigned int)) { + result = -EINVAL; + break; + } + + secure_ctxt = dev_priv->device->mmu.secured ? 1 : 0; + + if (copy_to_user(param->value, &secure_ctxt, + sizeof(secure_ctxt))) + result = -EFAULT; + + break; + } default: if (is_compat_task()) result = dev_priv->device->ftbl->getproperty_compat( @@ -1423,17 +1486,11 @@ long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, struct kgsl_ringbuffer_issueibcmds *param = data; struct kgsl_device *device = dev_priv->device; struct kgsl_context *context; - struct kgsl_drawobj *drawobj; - struct kgsl_drawobj_cmd *cmdobj; + struct kgsl_cmdbatch *cmdbatch = NULL; long result = -EINVAL; /* The legacy functions don't support synchronization commands */ - if ((param->flags & (KGSL_DRAWOBJ_SYNC | KGSL_DRAWOBJ_MARKER))) - return -EINVAL; - - /* Sanity check the number of IBs */ - if (param->flags & KGSL_DRAWOBJ_SUBMIT_IB_LIST && - (param->numibs == 0 || param->numibs > KGSL_MAX_NUMIBS)) + if ((param->flags & (KGSL_CMDBATCH_SYNC | KGSL_CMDBATCH_MARKER))) return -EINVAL; /* Get the context */ @@ -1441,20 +1498,23 @@ long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, if (context == NULL) return -EINVAL; - cmdobj = kgsl_drawobj_cmd_create(device, context, param->flags, - CMDOBJ_TYPE); - if (IS_ERR(cmdobj)) { - kgsl_context_put(context); - return PTR_ERR(cmdobj); + /* Create a command batch */ + cmdbatch = kgsl_cmdbatch_create(device, context, param->flags); + if (IS_ERR(cmdbatch)) { + result = PTR_ERR(cmdbatch); + goto done; } - drawobj = DRAWOBJ(cmdobj); - - if (param->flags & KGSL_DRAWOBJ_SUBMIT_IB_LIST) - result = kgsl_drawobj_cmd_add_ibdesc_list(device, cmdobj, + if (param->flags & KGSL_CMDBATCH_SUBMIT_IB_LIST) { + /* Sanity check the number of IBs */ + if (param->numibs == 0 || param->numibs > KGSL_MAX_NUMIBS) { + result = -EINVAL; + goto done; + } + result = kgsl_cmdbatch_add_ibdesc_list(device, cmdbatch, (void __user *) param->ibdesc_addr, param->numibs); - else { + } else { struct kgsl_ibdesc ibdesc; /* Ultra legacy path */ @@ -1462,119 +1522,83 @@ long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, ibdesc.sizedwords = param->numibs; ibdesc.ctrl = 0; - result = kgsl_drawobj_cmd_add_ibdesc(device, cmdobj, &ibdesc); + result = kgsl_cmdbatch_add_ibdesc(device, cmdbatch, &ibdesc); } - if (result == 0) - result = dev_priv->device->ftbl->queue_cmds(dev_priv, context, - &drawobj, 1, ¶m->timestamp); + if (result) + goto done; + + result = dev_priv->device->ftbl->issueibcmds(dev_priv, context, + cmdbatch, ¶m->timestamp); +done: /* * -EPROTO is a "success" error - it just tells the user that the * context had previously faulted */ if (result && result != -EPROTO) - kgsl_drawobj_destroy(drawobj); + kgsl_cmdbatch_destroy(cmdbatch); kgsl_context_put(context); return result; } -/* Returns 0 on failure. Returns command type(s) on success */ -static unsigned int _process_command_input(struct kgsl_device *device, - unsigned int flags, unsigned int numcmds, - unsigned int numobjs, unsigned int numsyncs) -{ - if (numcmds > KGSL_MAX_NUMIBS || - numobjs > KGSL_MAX_NUMIBS || - numsyncs > KGSL_MAX_SYNCPOINTS) - return 0; - - /* - * The SYNC bit is supposed to identify a dummy sync object - * so warn the user if they specified any IBs with it. - * A MARKER command can either have IBs or not but if the - * command has 0 IBs it is automatically assumed to be a marker. - */ - - /* If they specify the flag, go with what they say */ - if (flags & KGSL_DRAWOBJ_MARKER) - return MARKEROBJ_TYPE; - else if (flags & KGSL_DRAWOBJ_SYNC) - return SYNCOBJ_TYPE; - - /* If not, deduce what they meant */ - if (numsyncs && numcmds) - return SYNCOBJ_TYPE | CMDOBJ_TYPE; - else if (numsyncs) - return SYNCOBJ_TYPE; - else if (numcmds) - return CMDOBJ_TYPE; - else if (numcmds == 0) - return MARKEROBJ_TYPE; - - return 0; -} - long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { struct kgsl_submit_commands *param = data; struct kgsl_device *device = dev_priv->device; struct kgsl_context *context; - struct kgsl_drawobj *drawobj[2]; - unsigned int type; - long result; - unsigned int i = 0; + struct kgsl_cmdbatch *cmdbatch = NULL; + long result = -EINVAL; + + /* + * The SYNC bit is supposed to identify a dummy sync object so warn the + * user if they specified any IBs with it. A MARKER command can either + * have IBs or not but if the command has 0 IBs it is automatically + * assumed to be a marker. If none of the above make sure that the user + * specified a sane number of IBs + */ + + if ((param->flags & KGSL_CMDBATCH_SYNC) && param->numcmds) + KGSL_DEV_ERR_ONCE(device, + "Commands specified with the SYNC flag. They will be ignored\n"); + else if (param->numcmds > KGSL_MAX_NUMIBS) + return -EINVAL; + else if (!(param->flags & KGSL_CMDBATCH_SYNC) && param->numcmds == 0) + param->flags |= KGSL_CMDBATCH_MARKER; - type = _process_command_input(device, param->flags, param->numcmds, 0, - param->numsyncs); - if (!type) + /* Make sure that we don't have too many syncpoints */ + if (param->numsyncs > KGSL_MAX_SYNCPOINTS) return -EINVAL; context = kgsl_context_get_owner(dev_priv, param->context_id); if (context == NULL) return -EINVAL; - if (type & SYNCOBJ_TYPE) { - struct kgsl_drawobj_sync *syncobj = - kgsl_drawobj_sync_create(device, context); - if (IS_ERR(syncobj)) { - result = PTR_ERR(syncobj); - goto done; - } - - drawobj[i++] = DRAWOBJ(syncobj); - - result = kgsl_drawobj_sync_add_syncpoints(device, syncobj, - param->synclist, param->numsyncs); - if (result) - goto done; + /* Create a command batch */ + cmdbatch = kgsl_cmdbatch_create(device, context, param->flags); + if (IS_ERR(cmdbatch)) { + result = PTR_ERR(cmdbatch); + goto done; } - if (type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)) { - struct kgsl_drawobj_cmd *cmdobj = - kgsl_drawobj_cmd_create(device, - context, param->flags, type); - if (IS_ERR(cmdobj)) { - result = PTR_ERR(cmdobj); - goto done; - } - - drawobj[i++] = DRAWOBJ(cmdobj); + result = kgsl_cmdbatch_add_ibdesc_list(device, cmdbatch, + param->cmdlist, param->numcmds); + if (result) + goto done; - result = kgsl_drawobj_cmd_add_ibdesc_list(device, cmdobj, - param->cmdlist, param->numcmds); - if (result) - goto done; + result = kgsl_cmdbatch_add_syncpoints(device, cmdbatch, + param->synclist, param->numsyncs); + if (result) + goto done; - /* If no profiling buffer was specified, clear the flag */ - if (cmdobj->profiling_buf_entry == NULL) - DRAWOBJ(cmdobj)->flags &= ~KGSL_DRAWOBJ_PROFILING; - } + /* If no profiling buffer was specified, clear the flag */ + if (cmdbatch->profiling_buf_entry == NULL) + cmdbatch->flags &= ~KGSL_CMDBATCH_PROFILING; - result = device->ftbl->queue_cmds(dev_priv, context, drawobj, - i, ¶m->timestamp); + result = dev_priv->device->ftbl->issueibcmds(dev_priv, context, + cmdbatch, ¶m->timestamp); done: /* @@ -1582,8 +1606,7 @@ done: * context had previously faulted */ if (result && result != -EPROTO) - while (i--) - kgsl_drawobj_destroy(drawobj[i]); + kgsl_cmdbatch_destroy(cmdbatch); kgsl_context_put(context); return result; @@ -1595,69 +1618,63 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv, struct kgsl_gpu_command *param = data; struct kgsl_device *device = dev_priv->device; struct kgsl_context *context; - struct kgsl_drawobj *drawobj[2]; - unsigned int type; - long result; - unsigned int i = 0; + struct kgsl_cmdbatch *cmdbatch = NULL; - type = _process_command_input(device, param->flags, param->numcmds, - param->numobjs, param->numsyncs); - if (!type) + long result = -EINVAL; + + /* + * The SYNC bit is supposed to identify a dummy sync object so warn the + * user if they specified any IBs with it. A MARKER command can either + * have IBs or not but if the command has 0 IBs it is automatically + * assumed to be a marker. If none of the above make sure that the user + * specified a sane number of IBs + */ + if ((param->flags & KGSL_CMDBATCH_SYNC) && param->numcmds) + KGSL_DEV_ERR_ONCE(device, + "Commands specified with the SYNC flag. They will be ignored\n"); + else if (!(param->flags & KGSL_CMDBATCH_SYNC) && param->numcmds == 0) + param->flags |= KGSL_CMDBATCH_MARKER; + + /* Make sure that the memobj and syncpoint count isn't too big */ + if (param->numcmds > KGSL_MAX_NUMIBS || + param->numobjs > KGSL_MAX_NUMIBS || + param->numsyncs > KGSL_MAX_SYNCPOINTS) return -EINVAL; context = kgsl_context_get_owner(dev_priv, param->context_id); if (context == NULL) return -EINVAL; - if (type & SYNCOBJ_TYPE) { - struct kgsl_drawobj_sync *syncobj = - kgsl_drawobj_sync_create(device, context); - - if (IS_ERR(syncobj)) { - result = PTR_ERR(syncobj); - goto done; - } - - drawobj[i++] = DRAWOBJ(syncobj); - - result = kgsl_drawobj_sync_add_synclist(device, syncobj, - to_user_ptr(param->synclist), - param->syncsize, param->numsyncs); - if (result) - goto done; + cmdbatch = kgsl_cmdbatch_create(device, context, param->flags); + if (IS_ERR(cmdbatch)) { + result = PTR_ERR(cmdbatch); + goto done; } - if (type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)) { - struct kgsl_drawobj_cmd *cmdobj = - kgsl_drawobj_cmd_create(device, - context, param->flags, type); - - if (IS_ERR(cmdobj)) { - result = PTR_ERR(cmdobj); - goto done; - } - - drawobj[i++] = DRAWOBJ(cmdobj); + result = kgsl_cmdbatch_add_cmdlist(device, cmdbatch, + to_user_ptr(param->cmdlist), + param->cmdsize, param->numcmds); + if (result) + goto done; - result = kgsl_drawobj_cmd_add_cmdlist(device, cmdobj, - to_user_ptr(param->cmdlist), - param->cmdsize, param->numcmds); - if (result) - goto done; + result = kgsl_cmdbatch_add_memlist(device, cmdbatch, + to_user_ptr(param->objlist), + param->objsize, param->numobjs); + if (result) + goto done; - result = kgsl_drawobj_cmd_add_memlist(device, cmdobj, - to_user_ptr(param->objlist), - param->objsize, param->numobjs); - if (result) - goto done; + result = kgsl_cmdbatch_add_synclist(device, cmdbatch, + to_user_ptr(param->synclist), + param->syncsize, param->numsyncs); + if (result) + goto done; - /* If no profiling buffer was specified, clear the flag */ - if (cmdobj->profiling_buf_entry == NULL) - DRAWOBJ(cmdobj)->flags &= ~KGSL_DRAWOBJ_PROFILING; - } + /* If no profiling buffer was specified, clear the flag */ + if (cmdbatch->profiling_buf_entry == NULL) + cmdbatch->flags &= ~KGSL_CMDBATCH_PROFILING; - result = device->ftbl->queue_cmds(dev_priv, context, drawobj, - i, ¶m->timestamp); + result = dev_priv->device->ftbl->issueibcmds(dev_priv, context, + cmdbatch, ¶m->timestamp); done: /* @@ -1665,9 +1682,7 @@ done: * context had previously faulted */ if (result && result != -EPROTO) - while (i--) - kgsl_drawobj_destroy(drawobj[i]); - + kgsl_cmdbatch_destroy(cmdbatch); kgsl_context_put(context); return result; @@ -3380,13 +3395,18 @@ static int kgsl_gpumem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct kgsl_mem_entry *entry = vma->vm_private_data; + int ret; if (!entry) return VM_FAULT_SIGBUS; if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault) return VM_FAULT_SIGBUS; - return entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf); + ret = entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf); + if ((ret == 0) || (ret == VM_FAULT_NOPAGE)) + entry->priv->gpumem_mapped += PAGE_SIZE; + + return ret; } static void @@ -4092,7 +4112,7 @@ static void kgsl_core_exit(void) kgsl_driver.class = NULL; } - kgsl_drawobj_exit(); + kgsl_cmdbatch_exit(); kgsl_memfree_exit(); unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX); @@ -4101,7 +4121,7 @@ static void kgsl_core_exit(void) static int __init kgsl_core_init(void) { int result = 0; - struct sched_param param = { .sched_priority = 16 }; + struct sched_param param = { .sched_priority = 2 }; /* alloc major and minor device numbers */ result = alloc_chrdev_region(&kgsl_driver.major, 0, KGSL_DEVICE_MAX, @@ -4182,7 +4202,7 @@ static int __init kgsl_core_init(void) kgsl_events_init(); - result = kgsl_drawobj_init(); + result = kgsl_cmdbatch_init(); if (result) goto err; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index c3f4eb4de6fc98ec3fed1d59030bcfe408635113..37a78a439c652a4ab6817ae477221d5addfed876 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * 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 @@ -29,25 +29,6 @@ #include #include -/* - * --- kgsl drawobj flags --- - * These flags are same as --- drawobj flags --- - * but renamed to reflect that cmdbatch is renamed to drawobj. - */ -#define KGSL_DRAWOBJ_MEMLIST KGSL_CMDBATCH_MEMLIST -#define KGSL_DRAWOBJ_MARKER KGSL_CMDBATCH_MARKER -#define KGSL_DRAWOBJ_SUBMIT_IB_LIST KGSL_CMDBATCH_SUBMIT_IB_LIST -#define KGSL_DRAWOBJ_CTX_SWITCH KGSL_CMDBATCH_CTX_SWITCH -#define KGSL_DRAWOBJ_PROFILING KGSL_CMDBATCH_PROFILING -#define KGSL_DRAWOBJ_PROFILING_KTIME KGSL_CMDBATCH_PROFILING_KTIME -#define KGSL_DRAWOBJ_END_OF_FRAME KGSL_CMDBATCH_END_OF_FRAME -#define KGSL_DRAWOBJ_SYNC KGSL_CMDBATCH_SYNC -#define KGSL_DRAWOBJ_PWR_CONSTRAINT KGSL_CMDBATCH_PWR_CONSTRAINT -#define KGSL_DRAWOBJ_SPARSE KGSL_CMDBATCH_SPARSE - -#define kgsl_drawobj_profiling_buffer kgsl_cmdbatch_profiling_buffer - - /* The number of memstore arrays limits the number of contexts allowed. * If more contexts are needed, update multiple for MEMSTORE_SIZE */ @@ -56,6 +37,7 @@ #define KGSL_PRIORITY_MAX_RB_LEVELS 4 #define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \ sizeof(struct kgsl_devmemstore) - 1 - KGSL_PRIORITY_MAX_RB_LEVELS) +#define KGSL_MAX_CONTEXTS_PER_PROC 200 #define MEMSTORE_RB_OFFSET(rb, field) \ KGSL_MEMSTORE_OFFSET(((rb)->id + KGSL_MEMSTORE_MAX), field) @@ -187,6 +169,8 @@ struct kgsl_memdesc_ops { #define KGSL_MEMDESC_TZ_LOCKED BIT(7) /* The memdesc is allocated through contiguous memory */ #define KGSL_MEMDESC_CONTIG BIT(8) +/* For global buffers, randomly assign an address from the region */ +#define KGSL_MEMDESC_RANDOM BIT(9) /** * struct kgsl_memdesc - GPU memory object descriptor diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c index 3337570477f942e1ccd7bc1b92af956b5c61661c..8e783f8ce017ebd86a6261f061bb39a87d3a95a8 100644 --- a/drivers/gpu/msm/kgsl_cffdump.c +++ b/drivers/gpu/msm/kgsl_cffdump.c @@ -705,7 +705,7 @@ static int kgsl_cffdump_capture_adreno_ib_cff(struct kgsl_device *device, */ int kgsl_cffdump_capture_ib_desc(struct kgsl_device *device, struct kgsl_context *context, - struct kgsl_drawobj_cmd *cmdobj) + struct kgsl_cmdbatch *cmdbatch) { int ret = 0; struct kgsl_memobj_node *ib; @@ -713,7 +713,7 @@ int kgsl_cffdump_capture_ib_desc(struct kgsl_device *device, if (!device->cff_dump_enable) return 0; /* Dump CFF for IB and all objects in it */ - list_for_each_entry(ib, &cmdobj->cmdlist, node) { + list_for_each_entry(ib, &cmdbatch->cmdlist, node) { ret = kgsl_cffdump_capture_adreno_ib_cff( device, context->proc_priv, ib->gpuaddr, ib->size >> 2); diff --git a/drivers/gpu/msm/kgsl_cffdump.h b/drivers/gpu/msm/kgsl_cffdump.h index d2b4156d66c3f53440628825e7caf201829a46c5..5eb04e7ea5000148a3342a98a025d52bfbc3986e 100644 --- a/drivers/gpu/msm/kgsl_cffdump.h +++ b/drivers/gpu/msm/kgsl_cffdump.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011,2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2011,2013-2015, The Linux Foundation. All rights reserved. * * 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 @@ -58,7 +58,7 @@ int kgsl_cff_dump_enable_set(void *data, u64 val); int kgsl_cff_dump_enable_get(void *data, u64 *val); int kgsl_cffdump_capture_ib_desc(struct kgsl_device *device, struct kgsl_context *context, - struct kgsl_drawobj_cmd *cmdobj); + struct kgsl_cmdbatch *cmdbatch); void kgsl_cffdump_printline(int id, uint opcode, uint op1, uint op2, uint op3, uint op4, uint op5); @@ -164,7 +164,7 @@ static inline void kgsl_cffdump_user_event(struct kgsl_device *device, static inline int kgsl_cffdump_capture_ib_desc(struct kgsl_device *device, struct kgsl_context *context, - struct kgsl_drawobj_cmd *cmdobj) + struct kgsl_cmdbatch *cmdbatch) { return 0; } diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_cmdbatch.c similarity index 51% rename from drivers/gpu/msm/kgsl_drawobj.c rename to drivers/gpu/msm/kgsl_cmdbatch.c index 300db48c1b1f1190054df10afd329bde4b0d4ec9..da546891c849cbb77eddebdbd65cb8202b313cae 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_cmdbatch.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017,2019, The Linux Foundation. All rights reserved. * * 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 @@ -11,17 +11,17 @@ */ /* - * KGSL drawobj management - * A drawobj is a single submission from userland. The drawobj + * KGSL command batch management + * A command batch is a single submission from userland. The cmdbatch * encapsulates everything about the submission : command buffers, flags and * sync points. * * Sync points are events that need to expire before the - * drawobj can be queued to the hardware. All synpoints are contained in an - * array of kgsl_drawobj_sync_event structs in the drawobj. There can be + * cmdbatch can be queued to the hardware. All synpoints are contained in an + * array of kgsl_cmdbatch_sync_event structs in the command batch. There can be * multiple types of events both internal ones (GPU events) and external * triggers. As the events expire bits are cleared in a pending bitmap stored - * in the drawobj. The GPU will submit the command as soon as the bitmap + * in the command batch. The GPU will submit the command as soon as the bitmap * goes to zero indicating no more pending events. */ @@ -31,7 +31,7 @@ #include "kgsl.h" #include "kgsl_device.h" -#include "kgsl_drawobj.h" +#include "kgsl_cmdbatch.h" #include "kgsl_sync.h" #include "kgsl_trace.h" #include "kgsl_compat.h" @@ -42,44 +42,27 @@ */ static struct kmem_cache *memobjs_cache; -static void drawobj_destroy_object(struct kref *kref) -{ - struct kgsl_drawobj *drawobj = container_of(kref, - struct kgsl_drawobj, refcount); - struct kgsl_drawobj_sync *syncobj; - - kgsl_context_put(drawobj->context); - - switch (drawobj->type) { - case SYNCOBJ_TYPE: - syncobj = SYNCOBJ(drawobj); - kfree(syncobj->synclist); - kfree(syncobj); - break; - case CMDOBJ_TYPE: - case MARKEROBJ_TYPE: - kfree(CMDOBJ(drawobj)); - break; - } -} - -static inline void drawobj_put(struct kgsl_drawobj *drawobj) +/** + * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object + * @cmdbatch: Pointer to the command batch object + */ +static inline void kgsl_cmdbatch_put(struct kgsl_cmdbatch *cmdbatch) { - if (drawobj) - kref_put(&drawobj->refcount, drawobj_destroy_object); + if (cmdbatch) + kref_put(&cmdbatch->refcount, kgsl_cmdbatch_destroy_object); } void kgsl_dump_syncpoints(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj) + struct kgsl_cmdbatch *cmdbatch) { - struct kgsl_drawobj_sync_event *event; + struct kgsl_cmdbatch_sync_event *event; unsigned int i; unsigned long flags; - for (i = 0; i < syncobj->numsyncs; i++) { - event = &syncobj->synclist[i]; + for (i = 0; i < cmdbatch->numsyncs; i++) { + event = &cmdbatch->synclist[i]; - if (!kgsl_drawobj_event_pending(syncobj, i)) + if (!kgsl_cmdbatch_event_pending(cmdbatch, i)) continue; switch (event->type) { @@ -112,34 +95,33 @@ void kgsl_dump_syncpoints(struct kgsl_device *device, } } -static void syncobj_timer(unsigned long data) +static void _kgsl_cmdbatch_timer(unsigned long data) { struct kgsl_device *device; - struct kgsl_drawobj_sync *syncobj = (struct kgsl_drawobj_sync *) data; - struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); - struct kgsl_drawobj_sync_event *event; + struct kgsl_cmdbatch *cmdbatch = (struct kgsl_cmdbatch *) data; + struct kgsl_cmdbatch_sync_event *event; unsigned int i; unsigned long flags; - if (syncobj == NULL || drawobj->context == NULL) + if (cmdbatch == NULL || cmdbatch->context == NULL) return; - device = drawobj->context->device; + device = cmdbatch->context->device; dev_err(device->dev, "kgsl: possible gpu syncpoint deadlock for context %d timestamp %d\n", - drawobj->context->id, drawobj->timestamp); + cmdbatch->context->id, cmdbatch->timestamp); - set_bit(ADRENO_CONTEXT_FENCE_LOG, &drawobj->context->priv); - kgsl_context_dump(drawobj->context); - clear_bit(ADRENO_CONTEXT_FENCE_LOG, &drawobj->context->priv); + set_bit(CMDBATCH_FLAG_FENCE_LOG, &cmdbatch->priv); + kgsl_context_dump(cmdbatch->context); + clear_bit(CMDBATCH_FLAG_FENCE_LOG, &cmdbatch->priv); dev_err(device->dev, " pending events:\n"); - for (i = 0; i < syncobj->numsyncs; i++) { - event = &syncobj->synclist[i]; + for (i = 0; i < cmdbatch->numsyncs; i++) { + event = &cmdbatch->synclist[i]; - if (!kgsl_drawobj_event_pending(syncobj, i)) + if (!kgsl_cmdbatch_event_pending(cmdbatch, i)) continue; switch (event->type) { @@ -165,52 +147,79 @@ static void syncobj_timer(unsigned long data) dev_err(device->dev, "--gpu syncpoint deadlock print end--\n"); } +/** + * kgsl_cmdbatch_destroy_object() - Destroy a cmdbatch object + * @kref: Pointer to the kref structure for this object + * + * Actually destroy a command batch object. Called from kgsl_cmdbatch_put + */ +void kgsl_cmdbatch_destroy_object(struct kref *kref) +{ + struct kgsl_cmdbatch *cmdbatch = container_of(kref, + struct kgsl_cmdbatch, refcount); + + kgsl_context_put(cmdbatch->context); + + kfree(cmdbatch->synclist); + kfree(cmdbatch); +} +EXPORT_SYMBOL(kgsl_cmdbatch_destroy_object); + /* * a generic function to retire a pending sync event and (possibly) * kick the dispatcher + * Returns false if the event was already marked for cancellation in another + * thread. This function should return true if this thread is responsible for + * freeing up the memory, and the event will not be cancelled. */ -static void drawobj_sync_expire(struct kgsl_device *device, - struct kgsl_drawobj_sync_event *event) +static bool kgsl_cmdbatch_sync_expire(struct kgsl_device *device, + struct kgsl_cmdbatch_sync_event *event) { - struct kgsl_drawobj_sync *syncobj = event->syncobj; /* * Clear the event from the pending mask - if it is already clear, then * leave without doing anything useful */ - if (!test_and_clear_bit(event->id, &syncobj->pending)) - return; + if (!test_and_clear_bit(event->id, &event->cmdbatch->pending)) + return false; /* * If no more pending events, delete the timer and schedule the command * for dispatch */ - if (!kgsl_drawobj_events_pending(event->syncobj)) { - del_timer_sync(&syncobj->timer); + if (!kgsl_cmdbatch_events_pending(event->cmdbatch)) { + del_timer_sync(&event->cmdbatch->timer); if (device->ftbl->drawctxt_sched) device->ftbl->drawctxt_sched(device, - event->syncobj->base.context); + event->cmdbatch->context); } + return true; } /* * This function is called by the GPU event when the sync event timestamp * expires */ -static void drawobj_sync_func(struct kgsl_device *device, +static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, struct kgsl_event_group *group, void *priv, int result) { - struct kgsl_drawobj_sync_event *event = priv; + struct kgsl_cmdbatch_sync_event *event = priv; - trace_syncpoint_timestamp_expire(event->syncobj, + trace_syncpoint_timestamp_expire(event->cmdbatch, event->context, event->timestamp); - drawobj_sync_expire(device, event); - kgsl_context_put(event->context); - drawobj_put(&event->syncobj->base); + /* + * Put down the context ref count only if + * this thread successfully clears the pending bit mask. + */ + + if (kgsl_cmdbatch_sync_expire(device, event)) + kgsl_context_put(event->context); + + kgsl_cmdbatch_put(event->cmdbatch); } -static inline void memobj_list_free(struct list_head *list) +static inline void _free_memobj_list(struct list_head *list) { struct kgsl_memobj_node *mem, *tmpmem; @@ -221,38 +230,50 @@ static inline void memobj_list_free(struct list_head *list) } } -static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) +/** + * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure + * @cmdbatch: Pointer to the command batch object to destroy + * + * Start the process of destroying a command batch. Cancel any pending events + * and decrement the refcount. Asynchronous events can still signal after + * kgsl_cmdbatch_destroy has returned. + */ +void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch) { - struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj); - unsigned long pending, flags; unsigned int i; + unsigned long flags; - /* Zap the canary timer */ - del_timer_sync(&syncobj->timer); + if (IS_ERR_OR_NULL(cmdbatch)) + return; - /* - * Copy off the pending list and clear all pending events - this will - * render any subsequent asynchronous callback harmless - */ - bitmap_copy(&pending, &syncobj->pending, KGSL_MAX_SYNCPOINTS); - bitmap_zero(&syncobj->pending, KGSL_MAX_SYNCPOINTS); + /* Zap the canary timer */ + del_timer_sync(&cmdbatch->timer); /* * Clear all pending events - this will render any subsequent async * callbacks harmless */ - for (i = 0; i < syncobj->numsyncs; i++) { - struct kgsl_drawobj_sync_event *event = &syncobj->synclist[i]; - /* Don't do anything if the event has already expired */ - if (!test_bit(i, &pending)) + for (i = 0; i < cmdbatch->numsyncs; i++) { + struct kgsl_cmdbatch_sync_event *event = &cmdbatch->synclist[i]; + + /* Don't do anything if the event has already expired. + * If this thread clears the pending bit mask then it is + * responsible for doing context put. + */ + if (!test_and_clear_bit(i, &cmdbatch->pending)) continue; switch (event->type) { case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP: - kgsl_cancel_event(drawobj->device, + kgsl_cancel_event(cmdbatch->device, &event->context->events, event->timestamp, - drawobj_sync_func, event); + kgsl_cmdbatch_sync_func, event); + /* + * Do context put here to make sure the context is alive + * till this thread cancels kgsl event. + */ + kgsl_context_put(event->context); break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: spin_lock_irqsave(&event->handle_lock, flags); @@ -261,7 +282,7 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) event->handle = NULL; spin_unlock_irqrestore( &event->handle_lock, flags); - drawobj_put(drawobj); + kgsl_cmdbatch_put(cmdbatch); } else { spin_unlock_irqrestore( &event->handle_lock, flags); @@ -271,66 +292,43 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) } /* - * If we cancelled an event, there's a good chance that the context is - * on a dispatcher queue, so schedule to get it removed. - */ - if (!bitmap_empty(&pending, KGSL_MAX_SYNCPOINTS) && - drawobj->device->ftbl->drawctxt_sched) - drawobj->device->ftbl->drawctxt_sched(drawobj->device, - drawobj->context); - -} - -static void drawobj_destroy_cmd(struct kgsl_drawobj *drawobj) -{ - struct kgsl_drawobj_cmd *cmdobj = CMDOBJ(drawobj); - - /* - * Release the refcount on the mem entry associated with the - * ib profiling buffer + * Release the the refcount on the mem entry associated with the + * cmdbatch profiling buffer */ - if (cmdobj->base.flags & KGSL_DRAWOBJ_PROFILING) - kgsl_mem_entry_put(cmdobj->profiling_buf_entry); + if (cmdbatch->flags & KGSL_CMDBATCH_PROFILING) + kgsl_mem_entry_put(cmdbatch->profiling_buf_entry); /* Destroy the cmdlist we created */ - memobj_list_free(&cmdobj->cmdlist); + _free_memobj_list(&cmdbatch->cmdlist); /* Destroy the memlist we created */ - memobj_list_free(&cmdobj->memlist); -} + _free_memobj_list(&cmdbatch->memlist); -/** - * kgsl_drawobj_destroy() - Destroy a kgsl object structure - * @obj: Pointer to the kgsl object to destroy - * - * Start the process of destroying a command batch. Cancel any pending events - * and decrement the refcount. Asynchronous events can still signal after - * kgsl_drawobj_destroy has returned. + /* + * If we cancelled an event, there's a good chance that the context is + * on a dispatcher queue, so schedule to get it removed. */ -void kgsl_drawobj_destroy(struct kgsl_drawobj *drawobj) -{ - if (!drawobj) - return; - - if (drawobj->type & SYNCOBJ_TYPE) - drawobj_destroy_sync(drawobj); - else if (drawobj->type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)) - drawobj_destroy_cmd(drawobj); - else - return; + if (!bitmap_empty(&cmdbatch->pending, KGSL_MAX_SYNCPOINTS) && + cmdbatch->device->ftbl->drawctxt_sched) + cmdbatch->device->ftbl->drawctxt_sched(cmdbatch->device, + cmdbatch->context); - drawobj_put(drawobj); + kgsl_cmdbatch_put(cmdbatch); } -EXPORT_SYMBOL(kgsl_drawobj_destroy); +EXPORT_SYMBOL(kgsl_cmdbatch_destroy); -static void drawobj_sync_fence_func(void *priv) +/* + * A callback that gets registered with kgsl_sync_fence_async_wait and is fired + * when a fence is expired + */ +static void kgsl_cmdbatch_sync_fence_func(void *priv) { unsigned long flags; - struct kgsl_drawobj_sync_event *event = priv; + struct kgsl_cmdbatch_sync_event *event = priv; - drawobj_sync_expire(event->device, event); + kgsl_cmdbatch_sync_expire(event->device, event); - trace_syncpoint_fence_expire(event->syncobj, + trace_syncpoint_fence_expire(event->cmdbatch, event->handle ? event->handle->name : "unknown"); spin_lock_irqsave(&event->handle_lock, flags); @@ -343,22 +341,21 @@ static void drawobj_sync_fence_func(void *priv) spin_unlock_irqrestore(&event->handle_lock, flags); - drawobj_put(&event->syncobj->base); + kgsl_cmdbatch_put(event->cmdbatch); } -/* drawobj_add_sync_fence() - Add a new sync fence syncpoint +/* kgsl_cmdbatch_add_sync_fence() - Add a new sync fence syncpoint * @device: KGSL device - * @syncobj: KGSL sync obj to add the sync point to - * @priv: Private structure passed by the user + * @cmdbatch: KGSL cmdbatch to add the sync point to + * @priv: Private sructure passed by the user * - * Add a new fence sync syncpoint to the sync obj. + * Add a new fence sync syncpoint to the cmdbatch. */ -static int drawobj_add_sync_fence(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void *priv) +static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void *priv) { struct kgsl_cmd_syncpoint_fence *sync = priv; - struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); - struct kgsl_drawobj_sync_event *event; + struct kgsl_cmdbatch_sync_event *event; struct sync_fence *fence = NULL; unsigned int id; unsigned long flags; @@ -368,27 +365,27 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, if (fence == NULL) return -EINVAL; - kref_get(&drawobj->refcount); + kref_get(&cmdbatch->refcount); - id = syncobj->numsyncs++; + id = cmdbatch->numsyncs++; - event = &syncobj->synclist[id]; + event = &cmdbatch->synclist[id]; event->id = id; event->type = KGSL_CMD_SYNCPOINT_TYPE_FENCE; - event->syncobj = syncobj; + event->cmdbatch = cmdbatch; event->device = device; event->context = NULL; spin_lock_init(&event->handle_lock); - set_bit(event->id, &syncobj->pending); + set_bit(event->id, &cmdbatch->pending); - trace_syncpoint_fence(syncobj, fence->name); + trace_syncpoint_fence(cmdbatch, fence->name); spin_lock_irqsave(&event->handle_lock, flags); event->handle = kgsl_sync_fence_async_wait(sync->fd, - drawobj_sync_fence_func, event); + kgsl_cmdbatch_sync_fence_func, event); if (IS_ERR_OR_NULL(event->handle)) { ret = PTR_ERR(event->handle); @@ -396,15 +393,15 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, event->handle = NULL; spin_unlock_irqrestore(&event->handle_lock, flags); - clear_bit(event->id, &syncobj->pending); + clear_bit(event->id, &cmdbatch->pending); + kgsl_cmdbatch_put(cmdbatch); - drawobj_put(drawobj); /* - * Print a syncpoint_fence_expire trace if - * the fence is already signaled or there is - * a failure in registering the fence waiter. - */ - trace_syncpoint_fence_expire(syncobj, (ret < 0) ? + * Print a syncpoint_fence_expire trace if + * fence is already signaled or there is + * a failure in registering the fence waiter. + */ + trace_syncpoint_fence_expire(cmdbatch, (ret < 0) ? "error" : fence->name); } else { spin_unlock_irqrestore(&event->handle_lock, flags); @@ -414,21 +411,20 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, return ret; } -/* drawobj_add_sync_timestamp() - Add a new sync point for a sync obj +/* kgsl_cmdbatch_add_sync_timestamp() - Add a new sync point for a cmdbatch * @device: KGSL device - * @syncobj: KGSL sync obj to add the sync point to - * @priv: Private structure passed by the user + * @cmdbatch: KGSL cmdbatch to add the sync point to + * @priv: Private sructure passed by the user * - * Add a new sync point timestamp event to the sync obj. + * Add a new sync point timestamp event to the cmdbatch. */ -static int drawobj_add_sync_timestamp(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void *priv) +static int kgsl_cmdbatch_add_sync_timestamp(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void *priv) { struct kgsl_cmd_syncpoint_timestamp *sync = priv; - struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); - struct kgsl_context *context = kgsl_context_get(device, + struct kgsl_context *context = kgsl_context_get(cmdbatch->device, sync->context_id); - struct kgsl_drawobj_sync_event *event; + struct kgsl_cmdbatch_sync_event *event; int ret = -EINVAL; unsigned int id; @@ -442,9 +438,8 @@ static int drawobj_add_sync_timestamp(struct kgsl_device *device, * create a sync point on a future timestamp. */ - if (context == drawobj->context) { + if (context == cmdbatch->context) { unsigned int queued; - kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED, &queued); @@ -456,29 +451,29 @@ static int drawobj_add_sync_timestamp(struct kgsl_device *device, } } - kref_get(&drawobj->refcount); + kref_get(&cmdbatch->refcount); - id = syncobj->numsyncs++; + id = cmdbatch->numsyncs++; - event = &syncobj->synclist[id]; + event = &cmdbatch->synclist[id]; event->id = id; event->type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP; - event->syncobj = syncobj; + event->cmdbatch = cmdbatch; event->context = context; event->timestamp = sync->timestamp; event->device = device; - set_bit(event->id, &syncobj->pending); + set_bit(event->id, &cmdbatch->pending); ret = kgsl_add_event(device, &context->events, sync->timestamp, - drawobj_sync_func, event); + kgsl_cmdbatch_sync_func, event); if (ret) { - clear_bit(event->id, &syncobj->pending); - drawobj_put(drawobj); + clear_bit(event->id, &cmdbatch->pending); + kgsl_cmdbatch_put(cmdbatch); } else { - trace_syncpoint_timestamp(syncobj, context, sync->timestamp); + trace_syncpoint_timestamp(cmdbatch, context, sync->timestamp); } done: @@ -489,46 +484,43 @@ done: } /** - * kgsl_drawobj_sync_add_sync() - Add a sync point to a command - * batch + * kgsl_cmdbatch_add_sync() - Add a sync point to a command batch * @device: Pointer to the KGSL device struct for the GPU - * @syncobj: Pointer to the sync obj + * @cmdbatch: Pointer to the cmdbatch * @sync: Pointer to the user-specified struct defining the syncpoint * - * Create a new sync point in the sync obj based on the - * user specified parameters + * Create a new sync point in the cmdbatch based on the user specified + * parameters */ -int kgsl_drawobj_sync_add_sync(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, +int kgsl_cmdbatch_add_sync(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, struct kgsl_cmd_syncpoint *sync) { void *priv; int ret, psize; - struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); - int (*func)(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, + int (*func)(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch, void *priv); switch (sync->type) { case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP: psize = sizeof(struct kgsl_cmd_syncpoint_timestamp); - func = drawobj_add_sync_timestamp; + func = kgsl_cmdbatch_add_sync_timestamp; break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: psize = sizeof(struct kgsl_cmd_syncpoint_fence); - func = drawobj_add_sync_fence; + func = kgsl_cmdbatch_add_sync_fence; break; default: KGSL_DRV_ERR(device, "bad syncpoint type ctxt %d type 0x%x size %zu\n", - drawobj->context->id, sync->type, sync->size); + cmdbatch->context->id, sync->type, sync->size); return -EINVAL; } if (sync->size != psize) { KGSL_DRV_ERR(device, "bad syncpoint size ctxt %d type 0x%x size %zu\n", - drawobj->context->id, sync->type, sync->size); + cmdbatch->context->id, sync->type, sync->size); return -EINVAL; } @@ -541,32 +533,30 @@ int kgsl_drawobj_sync_add_sync(struct kgsl_device *device, return -EFAULT; } - ret = func(device, syncobj, priv); + ret = func(device, cmdbatch, priv); kfree(priv); return ret; } static void add_profiling_buffer(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, - uint64_t gpuaddr, uint64_t size, + struct kgsl_cmdbatch *cmdbatch, uint64_t gpuaddr, uint64_t size, unsigned int id, uint64_t offset) { struct kgsl_mem_entry *entry; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); - if (!(drawobj->flags & KGSL_DRAWOBJ_PROFILING)) + if (!(cmdbatch->flags & KGSL_CMDBATCH_PROFILING)) return; /* Only the first buffer entry counts - ignore the rest */ - if (cmdobj->profiling_buf_entry != NULL) + if (cmdbatch->profiling_buf_entry != NULL) return; if (id != 0) - entry = kgsl_sharedmem_find_id(drawobj->context->proc_priv, + entry = kgsl_sharedmem_find_id(cmdbatch->context->proc_priv, id); else - entry = kgsl_sharedmem_find(drawobj->context->proc_priv, + entry = kgsl_sharedmem_find(cmdbatch->context->proc_priv, gpuaddr); if (entry != NULL) { @@ -579,50 +569,62 @@ static void add_profiling_buffer(struct kgsl_device *device, if (entry == NULL) { KGSL_DRV_ERR(device, "ignore bad profile buffer ctxt %d id %d offset %lld gpuaddr %llx size %lld\n", - drawobj->context->id, id, offset, gpuaddr, size); + cmdbatch->context->id, id, offset, gpuaddr, size); return; } - cmdobj->profiling_buf_entry = entry; + if (!id) { + cmdbatch->profiling_buffer_gpuaddr = gpuaddr; + } else { + u64 off = + offset + sizeof(struct kgsl_cmdbatch_profiling_buffer); - if (id != 0) - cmdobj->profiling_buffer_gpuaddr = + /* + * Make sure there is enough room in the object to store the + * entire profiling buffer object + */ + if (off < offset || off >= entry->memdesc.size) { + dev_err(device->dev, + "ignore invalid profile offset ctxt %d id %d offset %lld gpuaddr %llx size %lld\n", + cmdbatch->context->id, id, offset, gpuaddr, size); + kgsl_mem_entry_put(entry); + return; + } + + cmdbatch->profiling_buffer_gpuaddr = entry->memdesc.gpuaddr + offset; - else - cmdobj->profiling_buffer_gpuaddr = gpuaddr; + } + cmdbatch->profiling_buf_entry = entry; } /** - * kgsl_drawobj_cmd_add_ibdesc() - Add a legacy ibdesc to a command - * batch - * @cmdobj: Pointer to the ib + * kgsl_cmdbatch_add_ibdesc() - Add a legacy ibdesc to a command batch + * @cmdbatch: Pointer to the cmdbatch * @ibdesc: Pointer to the user-specified struct defining the memory or IB * - * Create a new memory entry in the ib based on the - * user specified parameters + * Create a new memory entry in the cmdbatch based on the user specified + * parameters */ -int kgsl_drawobj_cmd_add_ibdesc(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, struct kgsl_ibdesc *ibdesc) +int kgsl_cmdbatch_add_ibdesc(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, struct kgsl_ibdesc *ibdesc) { uint64_t gpuaddr = (uint64_t) ibdesc->gpuaddr; uint64_t size = (uint64_t) ibdesc->sizedwords << 2; struct kgsl_memobj_node *mem; - struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); /* sanitize the ibdesc ctrl flags */ ibdesc->ctrl &= KGSL_IBDESC_MEMLIST | KGSL_IBDESC_PROFILING_BUFFER; - if (drawobj->flags & KGSL_DRAWOBJ_MEMLIST && + if (cmdbatch->flags & KGSL_CMDBATCH_MEMLIST && ibdesc->ctrl & KGSL_IBDESC_MEMLIST) { if (ibdesc->ctrl & KGSL_IBDESC_PROFILING_BUFFER) { - add_profiling_buffer(device, cmdobj, + add_profiling_buffer(device, cmdbatch, gpuaddr, size, 0, 0); return 0; } } - /* Ignore if SYNC or MARKER is specified */ - if (drawobj->type & (SYNCOBJ_TYPE | MARKEROBJ_TYPE)) + if (cmdbatch->flags & (KGSL_CMDBATCH_SYNC | KGSL_CMDBATCH_MARKER)) return 0; mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL); @@ -636,121 +638,74 @@ int kgsl_drawobj_cmd_add_ibdesc(struct kgsl_device *device, mem->offset = 0; mem->flags = 0; - if (drawobj->flags & KGSL_DRAWOBJ_MEMLIST && - ibdesc->ctrl & KGSL_IBDESC_MEMLIST) + if (cmdbatch->flags & KGSL_CMDBATCH_MEMLIST && + ibdesc->ctrl & KGSL_IBDESC_MEMLIST) { /* add to the memlist */ - list_add_tail(&mem->node, &cmdobj->memlist); - else { + list_add_tail(&mem->node, &cmdbatch->memlist); + } else { /* set the preamble flag if directed to */ - if (drawobj->context->flags & KGSL_CONTEXT_PREAMBLE && - list_empty(&cmdobj->cmdlist)) + if (cmdbatch->context->flags & KGSL_CONTEXT_PREAMBLE && + list_empty(&cmdbatch->cmdlist)) mem->flags = KGSL_CMDLIST_CTXTSWITCH_PREAMBLE; /* add to the cmd list */ - list_add_tail(&mem->node, &cmdobj->cmdlist); + list_add_tail(&mem->node, &cmdbatch->cmdlist); } return 0; } -static inline int drawobj_init(struct kgsl_device *device, - struct kgsl_context *context, struct kgsl_drawobj *drawobj, - unsigned int type) -{ - /* - * Increase the reference count on the context so it doesn't disappear - * during the lifetime of this object - */ - if (!_kgsl_context_get(context)) - return -ENOENT; - - kref_init(&drawobj->refcount); - - drawobj->device = device; - drawobj->context = context; - drawobj->type = type; - - return 0; -} - -/** - * kgsl_drawobj_sync_create() - Create a new sync obj - * structure - * @device: Pointer to a KGSL device struct - * @context: Pointer to a KGSL context struct - * - * Allocate an new kgsl_drawobj_sync structure - */ -struct kgsl_drawobj_sync *kgsl_drawobj_sync_create(struct kgsl_device *device, - struct kgsl_context *context) -{ - struct kgsl_drawobj_sync *syncobj = kzalloc(sizeof(*syncobj), - GFP_KERNEL); - if (syncobj == NULL) - return ERR_PTR(-ENOMEM); - - if (drawobj_init(device, context, DRAWOBJ(syncobj), SYNCOBJ_TYPE)) { - kfree(syncobj); - return ERR_PTR(-ENOENT); - } - - /* Add a timer to help debug sync deadlocks */ - setup_timer(&syncobj->timer, syncobj_timer, (unsigned long) syncobj); - - return syncobj; -} - /** - * kgsl_drawobj_cmd_create() - Create a new command obj - * structure + * kgsl_cmdbatch_create() - Create a new cmdbatch structure * @device: Pointer to a KGSL device struct * @context: Pointer to a KGSL context struct - * @flags: Flags for the command obj - * @type: type of cmdobj MARKER/CMD + * @flags: Flags for the cmdbatch * - * Allocate a new kgsl_drawobj_cmd structure + * Allocate an new cmdbatch structure */ -struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device, - struct kgsl_context *context, unsigned int flags, - unsigned int type) +struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, + struct kgsl_context *context, unsigned int flags) { - struct kgsl_drawobj_cmd *cmdobj = kzalloc(sizeof(*cmdobj), GFP_KERNEL); - struct kgsl_drawobj *drawobj; - - if (cmdobj == NULL) + struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL); + if (cmdbatch == NULL) return ERR_PTR(-ENOMEM); - type &= CMDOBJ_TYPE | MARKEROBJ_TYPE; - if (type == 0) { - kfree(cmdobj); - return ERR_PTR(-EINVAL); - } - - drawobj = DRAWOBJ(cmdobj); + /* + * Increase the reference count on the context so it doesn't disappear + * during the lifetime of this command batch + */ - if (drawobj_init(device, context, drawobj, type)) { - kfree(cmdobj); + if (!_kgsl_context_get(context)) { + kfree(cmdbatch); return ERR_PTR(-ENOENT); } - /* sanitize our flags for drawobj's */ - drawobj->flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH - | KGSL_DRAWOBJ_MARKER - | KGSL_DRAWOBJ_END_OF_FRAME - | KGSL_DRAWOBJ_PWR_CONSTRAINT - | KGSL_DRAWOBJ_MEMLIST - | KGSL_DRAWOBJ_PROFILING - | KGSL_DRAWOBJ_PROFILING_KTIME); + kref_init(&cmdbatch->refcount); + INIT_LIST_HEAD(&cmdbatch->cmdlist); + INIT_LIST_HEAD(&cmdbatch->memlist); + + cmdbatch->device = device; + cmdbatch->context = context; + /* sanitize our flags for cmdbatches */ + cmdbatch->flags = flags & (KGSL_CMDBATCH_CTX_SWITCH + | KGSL_CMDBATCH_MARKER + | KGSL_CMDBATCH_END_OF_FRAME + | KGSL_CMDBATCH_SYNC + | KGSL_CMDBATCH_PWR_CONSTRAINT + | KGSL_CMDBATCH_MEMLIST + | KGSL_CMDBATCH_PROFILING + | KGSL_CMDBATCH_PROFILING_KTIME); - INIT_LIST_HEAD(&cmdobj->cmdlist); - INIT_LIST_HEAD(&cmdobj->memlist); + /* Add a timer to help debug sync deadlocks */ + setup_timer(&cmdbatch->timer, _kgsl_cmdbatch_timer, + (unsigned long) cmdbatch); - return cmdobj; + return cmdbatch; } #ifdef CONFIG_COMPAT static int add_ibdesc_list_compat(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, int count) + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count) { int i, ret = 0; struct kgsl_ibdesc_compat ibdesc32; @@ -768,7 +723,7 @@ static int add_ibdesc_list_compat(struct kgsl_device *device, ibdesc.sizedwords = (size_t) ibdesc32.sizedwords; ibdesc.ctrl = (unsigned int) ibdesc32.ctrl; - ret = kgsl_drawobj_cmd_add_ibdesc(device, cmdobj, &ibdesc); + ret = kgsl_cmdbatch_add_ibdesc(device, cmdbatch, &ibdesc); if (ret) break; @@ -779,7 +734,7 @@ static int add_ibdesc_list_compat(struct kgsl_device *device, } static int add_syncpoints_compat(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void __user *ptr, int count) + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count) { struct kgsl_cmd_syncpoint_compat sync32; struct kgsl_cmd_syncpoint sync; @@ -797,7 +752,7 @@ static int add_syncpoints_compat(struct kgsl_device *device, sync.priv = compat_ptr(sync32.priv); sync.size = (size_t) sync32.size; - ret = kgsl_drawobj_sync_add_sync(device, syncobj, &sync); + ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync); if (ret) break; @@ -808,54 +763,26 @@ static int add_syncpoints_compat(struct kgsl_device *device, } #else static int add_ibdesc_list_compat(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, int count) + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count) { return -EINVAL; } static int add_syncpoints_compat(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void __user *ptr, int count) + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count) { return -EINVAL; } #endif -/* Returns: - * -EINVAL: Bad data - * 0: All data fields are empty (nothing to do) - * 1: All list information is valid - */ -static int _verify_input_list(unsigned int count, void __user *ptr, - unsigned int size) -{ - /* Return early if nothing going on */ - if (count == 0 && ptr == NULL && size == 0) - return 0; - - /* Sanity check inputs */ - if (count == 0 || ptr == NULL || size == 0) - return -EINVAL; - - return 1; -} - -int kgsl_drawobj_cmd_add_ibdesc_list(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, int count) +int kgsl_cmdbatch_add_ibdesc_list(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count) { struct kgsl_ibdesc ibdesc; - struct kgsl_drawobj *baseobj = DRAWOBJ(cmdobj); int i, ret; - /* Ignore everything if this is a MARKER */ - if (baseobj->type & MARKEROBJ_TYPE) - return 0; - - ret = _verify_input_list(count, ptr, sizeof(ibdesc)); - if (ret <= 0) - return -EINVAL; - if (is_compat_task()) - return add_ibdesc_list_compat(device, cmdobj, ptr, count); + return add_ibdesc_list_compat(device, cmdbatch, ptr, count); for (i = 0; i < count; i++) { memset(&ibdesc, 0, sizeof(ibdesc)); @@ -863,7 +790,7 @@ int kgsl_drawobj_cmd_add_ibdesc_list(struct kgsl_device *device, if (copy_from_user(&ibdesc, ptr, sizeof(ibdesc))) return -EFAULT; - ret = kgsl_drawobj_cmd_add_ibdesc(device, cmdobj, &ibdesc); + ret = kgsl_cmdbatch_add_ibdesc(device, cmdbatch, &ibdesc); if (ret) return ret; @@ -873,8 +800,8 @@ int kgsl_drawobj_cmd_add_ibdesc_list(struct kgsl_device *device, return 0; } -int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void __user *ptr, int count) +int kgsl_cmdbatch_add_syncpoints(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count) { struct kgsl_cmd_syncpoint sync; int i, ret; @@ -882,14 +809,17 @@ int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device, if (count == 0) return 0; - syncobj->synclist = kcalloc(count, - sizeof(struct kgsl_drawobj_sync_event), GFP_KERNEL); + if (count > KGSL_MAX_SYNCPOINTS) + return -EINVAL; + + cmdbatch->synclist = kcalloc(count, + sizeof(struct kgsl_cmdbatch_sync_event), GFP_KERNEL); - if (syncobj->synclist == NULL) + if (cmdbatch->synclist == NULL) return -ENOMEM; if (is_compat_task()) - return add_syncpoints_compat(device, syncobj, ptr, count); + return add_syncpoints_compat(device, cmdbatch, ptr, count); for (i = 0; i < count; i++) { memset(&sync, 0, sizeof(sync)); @@ -897,7 +827,7 @@ int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device, if (copy_from_user(&sync, ptr, sizeof(sync))) return -EFAULT; - ret = kgsl_drawobj_sync_add_sync(device, syncobj, &sync); + ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync); if (ret) return ret; @@ -907,7 +837,7 @@ int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device, return 0; } -static int drawobj_add_object(struct list_head *head, +static int kgsl_cmdbatch_add_object(struct list_head *head, struct kgsl_command_object *obj) { struct kgsl_memobj_node *mem; @@ -932,22 +862,24 @@ static int drawobj_add_object(struct list_head *head, KGSL_CMDLIST_CTXTSWITCH_PREAMBLE | \ KGSL_CMDLIST_IB_PREAMBLE) -/* This can only accept MARKEROBJ_TYPE and CMDOBJ_TYPE */ -int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, +int kgsl_cmdbatch_add_cmdlist(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, unsigned int size, unsigned int count) { struct kgsl_command_object obj; - struct kgsl_drawobj *baseobj = DRAWOBJ(cmdobj); - int i, ret; + int i, ret = 0; - /* Ignore everything if this is a MARKER */ - if (baseobj->type & MARKEROBJ_TYPE) + /* Return early if nothing going on */ + if (count == 0 && ptr == NULL && size == 0) return 0; - ret = _verify_input_list(count, ptr, size); - if (ret <= 0) - return ret; + /* Sanity check inputs */ + if (count == 0 || ptr == NULL || size == 0) + return -EINVAL; + + /* Ignore all if SYNC or MARKER is specified */ + if (cmdbatch->flags & (KGSL_CMDBATCH_SYNC | KGSL_CMDBATCH_MARKER)) + return 0; for (i = 0; i < count; i++) { memset(&obj, 0, sizeof(obj)); @@ -960,12 +892,12 @@ int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device, if (!(obj.flags & CMDLIST_FLAGS)) { KGSL_DRV_ERR(device, "invalid cmdobj ctxt %d flags %d id %d offset %lld addr %lld size %lld\n", - baseobj->context->id, obj.flags, obj.id, + cmdbatch->context->id, obj.flags, obj.id, obj.offset, obj.gpuaddr, obj.size); return -EINVAL; } - ret = drawobj_add_object(&cmdobj->cmdlist, &obj); + ret = kgsl_cmdbatch_add_object(&cmdbatch->cmdlist, &obj); if (ret) return ret; @@ -975,21 +907,20 @@ int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device, return 0; } -int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, +int kgsl_cmdbatch_add_memlist(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, unsigned int size, unsigned int count) { struct kgsl_command_object obj; - struct kgsl_drawobj *baseobj = DRAWOBJ(cmdobj); - int i, ret; + int i, ret = 0; - /* Ignore everything if this is a MARKER */ - if (baseobj->type & MARKEROBJ_TYPE) + /* Return early if nothing going on */ + if (count == 0 && ptr == NULL && size == 0) return 0; - ret = _verify_input_list(count, ptr, size); - if (ret <= 0) - return ret; + /* Sanity check inputs */ + if (count == 0 || ptr == NULL || size == 0) + return -EINVAL; for (i = 0; i < count; i++) { memset(&obj, 0, sizeof(obj)); @@ -1001,16 +932,17 @@ int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device, if (!(obj.flags & KGSL_OBJLIST_MEMOBJ)) { KGSL_DRV_ERR(device, "invalid memobj ctxt %d flags %d id %d offset %lld addr %lld size %lld\n", - DRAWOBJ(cmdobj)->context->id, obj.flags, - obj.id, obj.offset, obj.gpuaddr, obj.size); + cmdbatch->context->id, obj.flags, obj.id, + obj.offset, obj.gpuaddr, obj.size); return -EINVAL; } if (obj.flags & KGSL_OBJLIST_PROFILE) - add_profiling_buffer(device, cmdobj, obj.gpuaddr, + add_profiling_buffer(device, cmdbatch, obj.gpuaddr, obj.size, obj.id, obj.offset); else { - ret = drawobj_add_object(&cmdobj->memlist, &obj); + ret = kgsl_cmdbatch_add_object(&cmdbatch->memlist, + &obj); if (ret) return ret; } @@ -1021,23 +953,29 @@ int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device, return 0; } -int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void __user *ptr, +int kgsl_cmdbatch_add_synclist(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, unsigned int size, unsigned int count) { struct kgsl_command_syncpoint syncpoint; struct kgsl_cmd_syncpoint sync; - int i, ret; + int i, ret = 0; + + /* Return early if nothing going on */ + if (count == 0 && ptr == NULL && size == 0) + return 0; + + /* Sanity check inputs */ + if (count == 0 || ptr == NULL || size == 0) + return -EINVAL; - /* If creating a sync and the data is not there or wrong then error */ - ret = _verify_input_list(count, ptr, size); - if (ret <= 0) + if (count > KGSL_MAX_SYNCPOINTS) return -EINVAL; - syncobj->synclist = kcalloc(count, - sizeof(struct kgsl_drawobj_sync_event), GFP_KERNEL); + cmdbatch->synclist = kcalloc(count, + sizeof(struct kgsl_cmdbatch_sync_event), GFP_KERNEL); - if (syncobj->synclist == NULL) + if (cmdbatch->synclist == NULL) return -ENOMEM; for (i = 0; i < count; i++) { @@ -1051,7 +989,7 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device, sync.priv = to_user_ptr(syncpoint.priv); sync.size = syncpoint.size; - ret = kgsl_drawobj_sync_add_sync(device, syncobj, &sync); + ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync); if (ret) return ret; @@ -1061,13 +999,13 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device, return 0; } -void kgsl_drawobj_exit(void) +void kgsl_cmdbatch_exit(void) { if (memobjs_cache != NULL) kmem_cache_destroy(memobjs_cache); } -int kgsl_drawobj_init(void) +int kgsl_cmdbatch_init(void) { memobjs_cache = KMEM_CACHE(kgsl_memobj_node, 0); if (memobjs_cache == NULL) { diff --git a/drivers/gpu/msm/kgsl_cmdbatch.h b/drivers/gpu/msm/kgsl_cmdbatch.h new file mode 100644 index 0000000000000000000000000000000000000000..b37f432f3e7d10b0f92ec0528beb768a2c917a5b --- /dev/null +++ b/drivers/gpu/msm/kgsl_cmdbatch.h @@ -0,0 +1,170 @@ +/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. + * + * 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. + */ + +#ifndef __KGSL_CMDBATCH_H +#define __KGSL_CMDBATCH_H + +#define KGSL_CMDBATCH_FLAGS \ + { KGSL_CMDBATCH_MARKER, "MARKER" }, \ + { KGSL_CMDBATCH_CTX_SWITCH, "CTX_SWITCH" }, \ + { KGSL_CMDBATCH_SYNC, "SYNC" }, \ + { KGSL_CMDBATCH_END_OF_FRAME, "EOF" }, \ + { KGSL_CMDBATCH_PWR_CONSTRAINT, "PWR_CONSTRAINT" }, \ + { KGSL_CMDBATCH_SUBMIT_IB_LIST, "IB_LIST" } + +/** + * struct kgsl_cmdbatch - KGSl command descriptor + * @device: KGSL GPU device that the command was created for + * @context: KGSL context that created the command + * @timestamp: Timestamp assigned to the command + * @flags: flags + * @priv: Internal flags + * @fault_policy: Internal policy describing how to handle this command in case + * of a fault + * @fault_recovery: recovery actions actually tried for this batch + * @refcount: kref structure to maintain the reference count + * @cmdlist: List of IBs to issue + * @memlist: List of all memory used in this command batch + * @synclist: Array of context/timestamp tuples to wait for before issuing + * @numsyncs: Number of sync entries in the array + * @pending: Bitmask of sync events that are active + * @timer: a timer used to track possible sync timeouts for this cmdbatch + * @marker_timestamp: For markers, the timestamp of the last "real" command that + * was queued + * @profiling_buf_entry: Mem entry containing the profiling buffer + * @profiling_buffer_gpuaddr: GPU virt address of the profile buffer added here + * for easy access + * @profile_index: Index to store the start/stop ticks in the kernel profiling + * buffer + * @submit_ticks: Variable to hold ticks at the time of cmdbatch submit. + * @global_ts: The ringbuffer timestamp corresponding to this cmdbatch + * @timeout_jiffies: For a syncpoint cmdbatch the jiffies at which the + * timer will expire + * This structure defines an atomic batch of command buffers issued from + * userspace. + */ +struct kgsl_cmdbatch { + struct kgsl_device *device; + struct kgsl_context *context; + uint32_t timestamp; + uint32_t flags; + unsigned long priv; + unsigned long fault_policy; + unsigned long fault_recovery; + struct kref refcount; + struct list_head cmdlist; + struct list_head memlist; + struct kgsl_cmdbatch_sync_event *synclist; + unsigned int numsyncs; + unsigned long pending; + struct timer_list timer; + unsigned int marker_timestamp; + struct kgsl_mem_entry *profiling_buf_entry; + uint64_t profiling_buffer_gpuaddr; + unsigned int profile_index; + uint64_t submit_ticks; + unsigned int global_ts; + unsigned long timeout_jiffies; +}; + +/** + * struct kgsl_cmdbatch_sync_event + * @id: identifer (positiion within the pending bitmap) + * @type: Syncpoint type + * @cmdbatch: Pointer to the cmdbatch that owns the sync event + * @context: Pointer to the KGSL context that owns the cmdbatch + * @timestamp: Pending timestamp for the event + * @handle: Pointer to a sync fence handle + * @handle_lock: Spin lock to protect handle + * @device: Pointer to the KGSL device + */ +struct kgsl_cmdbatch_sync_event { + unsigned int id; + int type; + struct kgsl_cmdbatch *cmdbatch; + struct kgsl_context *context; + unsigned int timestamp; + struct kgsl_sync_fence_waiter *handle; + spinlock_t handle_lock; + struct kgsl_device *device; +}; + +/** + * enum kgsl_cmdbatch_priv - Internal cmdbatch flags + * @CMDBATCH_FLAG_SKIP - skip the entire command batch + * @CMDBATCH_FLAG_FORCE_PREAMBLE - Force the preamble on for the cmdbatch + * @CMDBATCH_FLAG_WFI - Force wait-for-idle for the submission + * @CMDBATCH_FLAG_PROFILE - store the start / retire ticks for the command batch + * in the profiling buffer + * @CMDBATCH_FLAG_FENCE_LOG - Set if the cmdbatch is dumping fence logs via the + * cmdbatch timer - this is used to avoid recursion + */ + +enum kgsl_cmdbatch_priv { + CMDBATCH_FLAG_SKIP = 0, + CMDBATCH_FLAG_FORCE_PREAMBLE, + CMDBATCH_FLAG_WFI, + CMDBATCH_FLAG_PROFILE, + CMDBATCH_FLAG_FENCE_LOG, +}; + + +int kgsl_cmdbatch_add_memobj(struct kgsl_cmdbatch *cmdbatch, + struct kgsl_ibdesc *ibdesc); + +int kgsl_cmdbatch_add_sync(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, + struct kgsl_cmd_syncpoint *sync); + +struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, + struct kgsl_context *context, unsigned int flags); +int kgsl_cmdbatch_add_ibdesc(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, struct kgsl_ibdesc *ibdesc); +int kgsl_cmdbatch_add_ibdesc_list(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count); +int kgsl_cmdbatch_add_syncpoints(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, int count); +int kgsl_cmdbatch_add_cmdlist(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, + unsigned int size, unsigned int count); +int kgsl_cmdbatch_add_memlist(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, + unsigned int size, unsigned int count); +int kgsl_cmdbatch_add_synclist(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch, void __user *ptr, + unsigned int size, unsigned int count); + +int kgsl_cmdbatch_init(void); +void kgsl_cmdbatch_exit(void); + +void kgsl_dump_syncpoints(struct kgsl_device *device, + struct kgsl_cmdbatch *cmdbatch); + +void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch); + +void kgsl_cmdbatch_destroy_object(struct kref *kref); + +static inline bool kgsl_cmdbatch_events_pending(struct kgsl_cmdbatch *cmdbatch) +{ + return !bitmap_empty(&cmdbatch->pending, KGSL_MAX_SYNCPOINTS); +} + +static inline bool kgsl_cmdbatch_event_pending(struct kgsl_cmdbatch *cmdbatch, + unsigned int bit) +{ + if (bit >= KGSL_MAX_SYNCPOINTS) + return false; + + return test_bit(bit, &cmdbatch->pending); +} + +#endif /* __KGSL_CMDBATCH_H */ diff --git a/drivers/gpu/msm/kgsl_compat.h b/drivers/gpu/msm/kgsl_compat.h index 7681d74fb108e1449b94eaa9ab7acc5043d4524e..ca1685e5fcf5b620100cbb88733554fd2ec4ce4f 100644 --- a/drivers/gpu/msm/kgsl_compat.h +++ b/drivers/gpu/msm/kgsl_compat.h @@ -236,8 +236,8 @@ static inline compat_size_t sizet_to_compat(size_t size) return (compat_size_t)size; } -int kgsl_drawobj_create_compat(struct kgsl_device *device, unsigned int flags, - struct kgsl_drawobj *drawobj, void __user *cmdlist, +int kgsl_cmdbatch_create_compat(struct kgsl_device *device, unsigned int flags, + struct kgsl_cmdbatch *cmdbatch, void __user *cmdlist, unsigned int numcmds, void __user *synclist, unsigned int numsyncs); @@ -245,8 +245,8 @@ long kgsl_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); #else -static inline int kgsl_drawobj_create_compat(struct kgsl_device *device, - unsigned int flags, struct kgsl_drawobj *drawobj, +static inline int kgsl_cmdbatch_create_compat(struct kgsl_device *device, + unsigned int flags, struct kgsl_cmdbatch *cmdbatch, void __user *cmdlist, unsigned int numcmds, void __user *synclist, unsigned int numsyncs) { diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index d98ea10a6d654a9394111d3363f1e92d40a973ed..cf8a41b7af26069472313e433c2d9577363b0572 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. * * 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 @@ -25,7 +25,7 @@ #include "kgsl_pwrscale.h" #include "kgsl_snapshot.h" #include "kgsl_sharedmem.h" -#include "kgsl_drawobj.h" +#include "kgsl_cmdbatch.h" #include @@ -63,6 +63,8 @@ enum kgsl_event_results { KGSL_EVENT_CANCELLED = 2, }; +#define KGSL_FLAG_WAKE_ON_TOUCH BIT(0) + /* * "list" of event types for ftrace symbolic magic */ @@ -88,7 +90,8 @@ enum kgsl_event_results { { KGSL_CONTEXT_TYPE_GL, "GL" }, \ { KGSL_CONTEXT_TYPE_CL, "CL" }, \ { KGSL_CONTEXT_TYPE_C2D, "C2D" }, \ - { KGSL_CONTEXT_TYPE_RS, "RS" } + { KGSL_CONTEXT_TYPE_RS, "RS" }, \ + { KGSL_CONTEXT_TYPE_VK, "VK" } #define KGSL_CONTEXT_ID(_context) \ ((_context != NULL) ? (_context)->id : KGSL_MEMSTORE_GLOBAL) @@ -130,9 +133,9 @@ struct kgsl_functable { unsigned int msecs); int (*readtimestamp) (struct kgsl_device *device, void *priv, enum kgsl_timestamp_type type, unsigned int *timestamp); - int (*queue_cmds)(struct kgsl_device_private *dev_priv, - struct kgsl_context *context, struct kgsl_drawobj *drawobj[], - uint32_t count, uint32_t *timestamp); + int (*issueibcmds) (struct kgsl_device_private *dev_priv, + struct kgsl_context *context, struct kgsl_cmdbatch *cmdbatch, + uint32_t *timestamps); void (*power_stats)(struct kgsl_device *device, struct kgsl_power_stats *stats); unsigned int (*gpuid)(struct kgsl_device *device, unsigned int *chipid); @@ -188,7 +191,7 @@ long kgsl_ioctl_helper(struct file *filep, unsigned int cmd, unsigned long arg, /** * struct kgsl_memobj_node - Memory object descriptor - * @node: Local list node for the object + * @node: Local list node for the cmdbatch * @id: GPU memory ID for the object * offset: Offset within the object * @gpuaddr: GPU address for the object @@ -237,7 +240,7 @@ struct kgsl_device { struct kgsl_mmu mmu; struct completion hwaccess_gate; - struct completion halt_gate; + struct completion cmdbatch_gate; const struct kgsl_functable *ftbl; struct work_struct idle_check_ws; struct timer_list idle_timer; @@ -303,7 +306,7 @@ struct kgsl_device { #define KGSL_DEVICE_COMMON_INIT(_dev) \ .hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\ - .halt_gate = COMPLETION_INITIALIZER((_dev).halt_gate),\ + .cmdbatch_gate = COMPLETION_INITIALIZER((_dev).cmdbatch_gate),\ .idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\ kgsl_idle_check),\ .context_idr = IDR_INIT((_dev).context_idr),\ @@ -402,9 +405,12 @@ struct kgsl_context { * @kobj: Pointer to a kobj for the sysfs directory for this process * @debug_root: Pointer to the debugfs root for this process * @stats: Memory allocation statistics for this process + * @gpumem_mapped: KGSL memory mapped in the process address space * @syncsource_idr: sync sources created by this process * @syncsource_lock: Spinlock to protect the syncsource idr * @fd_count: Counter for the number of FDs for this process + * @ctxt_count: Count for the number of contexts for this process + * @ctxt_count_lock: Spinlock to protect ctxt_count */ struct kgsl_process_private { unsigned long priv; @@ -421,9 +427,12 @@ struct kgsl_process_private { uint64_t cur; uint64_t max; } stats[KGSL_MEM_ENTRY_MAX]; + uint64_t gpumem_mapped; struct idr syncsource_idr; spinlock_t syncsource_lock; int fd_count; + atomic_t ctxt_count; + spinlock_t ctxt_count_lock; }; /** diff --git a/drivers/gpu/msm/kgsl_drawobj.h b/drivers/gpu/msm/kgsl_drawobj.h deleted file mode 100644 index bbff5781d81ba3b0ef27f680c11efe5d98d0a30e..0000000000000000000000000000000000000000 --- a/drivers/gpu/msm/kgsl_drawobj.h +++ /dev/null @@ -1,200 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __KGSL_DRAWOBJ_H -#define __KGSL_DRAWOBJ_H - -#define DRAWOBJ(obj) (&obj->base) -#define SYNCOBJ(obj) \ - container_of(obj, struct kgsl_drawobj_sync, base) -#define CMDOBJ(obj) \ - container_of(obj, struct kgsl_drawobj_cmd, base) - -#define CMDOBJ_TYPE BIT(0) -#define MARKEROBJ_TYPE BIT(1) -#define SYNCOBJ_TYPE BIT(2) - -/** - * struct kgsl_drawobj - KGSL drawobj descriptor - * @device: KGSL GPU device that the command was created for - * @context: KGSL context that created the command - * @type: Object type - * @timestamp: Timestamp assigned to the command - * @flags: flags - * @refcount: kref structure to maintain the reference count - */ -struct kgsl_drawobj { - struct kgsl_device *device; - struct kgsl_context *context; - uint32_t type; - uint32_t timestamp; - unsigned long flags; - struct kref refcount; -}; - -/** - * struct kgsl_drawobj_cmd - KGSL command obj, This covers marker - * cmds also since markers are special form of cmds that do not - * need their cmds to be executed. - * @base: Base kgsl_drawobj - * @priv: Internal flags - * @global_ts: The ringbuffer timestamp corresponding to this - * command obj - * @fault_policy: Internal policy describing how to handle this command in case - * of a fault - * @fault_recovery: recovery actions actually tried for this batch - * be hung - * @refcount: kref structure to maintain the reference count - * @cmdlist: List of IBs to issue - * @memlist: List of all memory used in this command batch - * @marker_timestamp: For markers, the timestamp of the last "real" command that - * was queued - * @profiling_buf_entry: Mem entry containing the profiling buffer - * @profiling_buffer_gpuaddr: GPU virt address of the profile buffer added here - * for easy access - * @profile_index: Index to store the start/stop ticks in the kernel profiling - * buffer - * @submit_ticks: Variable to hold ticks at the time of - * command obj submit. - - */ -struct kgsl_drawobj_cmd { - struct kgsl_drawobj base; - unsigned long priv; - unsigned int global_ts; - unsigned long fault_policy; - unsigned long fault_recovery; - struct list_head cmdlist; - struct list_head memlist; - unsigned int marker_timestamp; - struct kgsl_mem_entry *profiling_buf_entry; - uint64_t profiling_buffer_gpuaddr; - unsigned int profile_index; - uint64_t submit_ticks; -}; - -/** - * struct kgsl_drawobj_sync - KGSL sync object - * @base: Base kgsl_drawobj, this needs to be the first entry - * @synclist: Array of context/timestamp tuples to wait for before issuing - * @numsyncs: Number of sync entries in the array - * @pending: Bitmask of sync events that are active - * @timer: a timer used to track possible sync timeouts for this - * sync obj - * @timeout_jiffies: For a sync obj the jiffies at - * which the timer will expire - */ -struct kgsl_drawobj_sync { - struct kgsl_drawobj base; - struct kgsl_drawobj_sync_event *synclist; - unsigned int numsyncs; - unsigned long pending; - struct timer_list timer; - unsigned long timeout_jiffies; -}; - -/** - * struct kgsl_drawobj_sync_event - * @id: identifer (positiion within the pending bitmap) - * @type: Syncpoint type - * @syncobj: Pointer to the syncobj that owns the sync event - * @context: KGSL context for whose timestamp we want to - * register this event - * @timestamp: Pending timestamp for the event - * @handle: Pointer to a sync fence handle - * @handle_lock: Spin lock to protect handle - * @device: Pointer to the KGSL device - */ -struct kgsl_drawobj_sync_event { - unsigned int id; - int type; - struct kgsl_drawobj_sync *syncobj; - struct kgsl_context *context; - unsigned int timestamp; - struct kgsl_sync_fence_waiter *handle; - spinlock_t handle_lock; - struct kgsl_device *device; -}; - -#define KGSL_DRAWOBJ_FLAGS \ - { KGSL_DRAWOBJ_MARKER, "MARKER" }, \ - { KGSL_DRAWOBJ_CTX_SWITCH, "CTX_SWITCH" }, \ - { KGSL_DRAWOBJ_SYNC, "SYNC" }, \ - { KGSL_DRAWOBJ_END_OF_FRAME, "EOF" }, \ - { KGSL_DRAWOBJ_PWR_CONSTRAINT, "PWR_CONSTRAINT" }, \ - { KGSL_DRAWOBJ_SUBMIT_IB_LIST, "IB_LIST" } - -/** - * enum kgsl_drawobj_cmd_priv - Internal command obj flags - * @CMDOBJ_SKIP - skip the entire command obj - * @CMDOBJ_FORCE_PREAMBLE - Force the preamble on for - * command obj - * @CMDOBJ_WFI - Force wait-for-idle for the submission - * @CMDOBJ_PROFILE - store the start / retire ticks for - * the command obj in the profiling buffer - */ -enum kgsl_drawobj_cmd_priv { - CMDOBJ_SKIP = 0, - CMDOBJ_FORCE_PREAMBLE, - CMDOBJ_WFI, - CMDOBJ_PROFILE, -}; - -struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device, - struct kgsl_context *context, unsigned int flags, - unsigned int type); -int kgsl_drawobj_cmd_add_ibdesc(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, struct kgsl_ibdesc *ibdesc); -int kgsl_drawobj_cmd_add_ibdesc_list(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, int count); -int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, - unsigned int size, unsigned int count); -int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device, - struct kgsl_drawobj_cmd *cmdobj, void __user *ptr, - unsigned int size, unsigned int count); - -struct kgsl_drawobj_sync *kgsl_drawobj_sync_create(struct kgsl_device *device, - struct kgsl_context *context); -int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void __user *ptr, - int count); -int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, void __user *ptr, - unsigned int size, unsigned int count); -int kgsl_drawobj_sync_add_sync(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj, - struct kgsl_cmd_syncpoint *sync); - -int kgsl_drawobj_init(void); -void kgsl_drawobj_exit(void); - -void kgsl_dump_syncpoints(struct kgsl_device *device, - struct kgsl_drawobj_sync *syncobj); - -void kgsl_drawobj_destroy(struct kgsl_drawobj *drawobj); - -static inline bool kgsl_drawobj_events_pending( - struct kgsl_drawobj_sync *syncobj) -{ - return !bitmap_empty(&syncobj->pending, KGSL_MAX_SYNCPOINTS); -} - -static inline bool kgsl_drawobj_event_pending( - struct kgsl_drawobj_sync *syncobj, unsigned int bit) -{ - if (bit >= KGSL_MAX_SYNCPOINTS) - return false; - - return test_bit(bit, &syncobj->pending); -} -#endif /* __KGSL_DRAWOBJ_H */ diff --git a/drivers/gpu/msm/kgsl_ioctl.c b/drivers/gpu/msm/kgsl_ioctl.c index 51c98a541af4c2e1bb60d0c2852d819d0dc775be..0802e94f56ad1179326141d3c7bbdfc992b614f7 100644 --- a/drivers/gpu/msm/kgsl_ioctl.c +++ b/drivers/gpu/msm/kgsl_ioctl.c @@ -17,7 +17,6 @@ #include #include "kgsl_device.h" #include "kgsl_sync.h" -#include "adreno.h" static const struct kgsl_ioctl kgsl_ioctl_funcs[] = { KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY, @@ -154,12 +153,8 @@ long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct kgsl_device_private *dev_priv = filep->private_data; struct kgsl_device *device = dev_priv->device; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); long ret; - if (cmd == IOCTL_KGSL_GPU_COMMAND) - kgsl_schedule_work(&adreno_dev->pwr_on_work); - ret = kgsl_ioctl_helper(filep, cmd, arg, kgsl_ioctl_funcs, ARRAY_SIZE(kgsl_ioctl_funcs)); diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 2fe1fdc0baa0ea927d37b35c5ef8403889a091ca..c3879e94813cad4459b719d9c74dc0cf5fa0c276 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * 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 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -84,15 +85,8 @@ static struct kmem_cache *addr_entry_cache; * * Here we define an array and a simple allocator to keep track of the currently * active global entries. Each entry is assigned a unique address inside of a - * MMU implementation specific "global" region. The addresses are assigned - * sequentially and never re-used to avoid having to go back and reprogram - * existing pagetables. The entire list of active entries are mapped and - * unmapped into every new pagetable as it is created and destroyed. - * - * Because there are relatively few entries and they are defined at boot time we - * don't need to go over the top to define a dynamic allocation scheme. It will - * be less wasteful to pick a static number with a little bit of growth - * potential. + * MMU implementation specific "global" region. We use a simple bitmap based + * allocator for the region to allow for both fixed and dynamic addressing. */ #define GLOBAL_PT_ENTRIES 32 @@ -102,10 +96,12 @@ struct global_pt_entry { char name[32]; }; +#define GLOBAL_MAP_PAGES (KGSL_IOMMU_GLOBAL_MEM_SIZE >> PAGE_SHIFT) + static struct global_pt_entry global_pt_entries[GLOBAL_PT_ENTRIES]; static struct kgsl_memdesc *kgsl_global_secure_pt_entry; +static DECLARE_BITMAP(global_map, GLOBAL_MAP_PAGES); static int global_pt_count; -uint64_t global_pt_alloc; static struct kgsl_memdesc gpu_qdss_desc; void kgsl_print_global_pt_entries(struct seq_file *s) @@ -181,6 +177,12 @@ static void kgsl_iommu_remove_global(struct kgsl_mmu *mmu, for (i = 0; i < global_pt_count; i++) { if (global_pt_entries[i].memdesc == memdesc) { + u64 offset = memdesc->gpuaddr - + KGSL_IOMMU_GLOBAL_MEM_BASE(mmu); + + bitmap_clear(global_map, offset >> PAGE_SHIFT, + kgsl_memdesc_footprint(memdesc) >> PAGE_SHIFT); + memdesc->gpuaddr = 0; memdesc->priv &= ~KGSL_MEMDESC_GLOBAL; global_pt_entries[i].memdesc = NULL; @@ -192,15 +194,43 @@ static void kgsl_iommu_remove_global(struct kgsl_mmu *mmu, static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, struct kgsl_memdesc *memdesc, const char *name) { + u32 bit, start = 0; + u64 size = kgsl_memdesc_footprint(memdesc); + if (memdesc->gpuaddr != 0) return; - BUG_ON(global_pt_count >= GLOBAL_PT_ENTRIES); - BUG_ON((global_pt_alloc + memdesc->size) >= KGSL_IOMMU_GLOBAL_MEM_SIZE); + if (WARN_ON(global_pt_count >= GLOBAL_PT_ENTRIES)) + return; + + if (WARN_ON(size > KGSL_IOMMU_GLOBAL_MEM_SIZE)) + return; + + if (memdesc->priv & KGSL_MEMDESC_RANDOM) { + u32 range = GLOBAL_MAP_PAGES - (size >> PAGE_SHIFT); + + start = get_random_int() % range; + } + + while (start >= 0) { + bit = bitmap_find_next_zero_area(global_map, GLOBAL_MAP_PAGES, + start, size >> PAGE_SHIFT, 0); + + if (bit < GLOBAL_MAP_PAGES) + break; + + start--; + } + + if (WARN_ON(start < 0)) + return; + + memdesc->gpuaddr = + KGSL_IOMMU_GLOBAL_MEM_BASE(mmu) + (bit << PAGE_SHIFT); + + bitmap_set(global_map, bit, size >> PAGE_SHIFT); - memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu) + global_pt_alloc; memdesc->priv |= KGSL_MEMDESC_GLOBAL; - global_pt_alloc += memdesc->size; global_pt_entries[global_pt_count].memdesc = memdesc; strlcpy(global_pt_entries[global_pt_count].name, name, @@ -813,11 +843,21 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr); if (!no_page_fault_log && __ratelimit(&_rs)) { + const char *api_str; + + if (context != NULL) { + struct adreno_context *drawctxt = + ADRENO_CONTEXT(context); + + api_str = get_api_type_str(drawctxt->type); + } else + api_str = "UNKNOWN"; + KGSL_MEM_CRIT(ctx->kgsldev, "GPU PAGE FAULT: addr = %lX pid= %d\n", addr, ptname); KGSL_MEM_CRIT(ctx->kgsldev, - "context=%s TTBR0=0x%llx CIDR=0x%x (%s %s fault)\n", - ctx->name, ptbase, contextidr, + "context=%s ctx_type=%s TTBR0=0x%llx CIDR=0x%x (%s %s fault)\n", + ctx->name, api_str, ptbase, contextidr, write ? "write" : "read", fault_type); /* Don't print the debug if this is a permissions fault */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index dcd243227bb8ac2cb18617862361b137260040ce..43f5c6ac7966bc8e4b996b8d89ba31cb6ec9c3e5 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved. * * 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 @@ -62,7 +62,7 @@ static const char * const clocks[] = { "rbcpr_clk" }; -static unsigned int ib_votes[KGSL_MAX_BUSLEVELS]; +static unsigned long ib_votes[KGSL_MAX_BUSLEVELS]; static int last_vote_buslevel; static int max_vote_buslevel; @@ -120,7 +120,7 @@ static void _record_pwrevent(struct kgsl_device *device, /** * kgsl_get_bw() - Return latest msm bus IB vote */ -static unsigned int kgsl_get_bw(void) +static unsigned long kgsl_get_bw(void) { return ib_votes[last_vote_buslevel]; } @@ -133,8 +133,9 @@ static unsigned int kgsl_get_bw(void) static void _ab_buslevel_update(struct kgsl_pwrctrl *pwr, unsigned long *ab) { - unsigned int ib = ib_votes[last_vote_buslevel]; - unsigned int max_bw = ib_votes[max_vote_buslevel]; + unsigned long ib = ib_votes[last_vote_buslevel]; + unsigned long max_bw = ib_votes[max_vote_buslevel]; + if (!ab) return; if (ib == 0) @@ -161,7 +162,8 @@ static void _ab_buslevel_update(struct kgsl_pwrctrl *pwr, * constraint if one exists. */ static unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level, - struct kgsl_pwr_constraint *pwrc) + struct kgsl_pwr_constraint *pwrc, + int popp) { unsigned int max_pwrlevel = max_t(unsigned int, pwr->thermal_pwrlevel, pwr->max_pwrlevel); @@ -184,6 +186,9 @@ static unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level, break; } + if (popp && (max_pwrlevel < pwr->active_pwrlevel)) + max_pwrlevel = pwr->active_pwrlevel; + if (level < max_pwrlevel) return max_pwrlevel; if (level > min_pwrlevel) @@ -330,7 +335,8 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, * Adjust the power level if required by thermal, max/min, * constraints, etc */ - new_level = _adjust_pwrlevel(pwr, new_level, &pwr->constraint); + new_level = _adjust_pwrlevel(pwr, new_level, &pwr->constraint, + device->pwrscale.popp_level); /* * If thermal cycling is required and the new level hits the @@ -437,7 +443,7 @@ void kgsl_pwrctrl_set_constraint(struct kgsl_device *device, if (device == NULL || pwrc == NULL) return; constraint = _adjust_pwrlevel(&device->pwrctrl, - device->pwrctrl.active_pwrlevel, pwrc); + device->pwrctrl.active_pwrlevel, pwrc, 0); pwrc_old = &device->pwrctrl.constraint; /* @@ -793,19 +799,12 @@ static ssize_t kgsl_pwrctrl_gpuclk_show(struct device *dev, struct device_attribute *attr, char *buf) { - unsigned long freq; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; if (device == NULL) return 0; pwr = &device->pwrctrl; - - if (device->state == KGSL_STATE_SLUMBER) - freq = pwr->pwrlevels[pwr->num_pwrlevels - 1].gpu_freq; - else - freq = kgsl_pwrctrl_active_freq(pwr); - - return snprintf(buf, PAGE_SIZE, "%lu\n", freq); + return snprintf(buf, PAGE_SIZE, "%ld\n", kgsl_pwrctrl_active_freq(pwr)); } static ssize_t __timer_store(struct device *dev, struct device_attribute *attr, @@ -1146,6 +1145,87 @@ static ssize_t kgsl_pwrctrl_bus_split_store(struct device *dev, return count; } +static ssize_t kgsl_pwrctrl_default_pwrlevel_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + if (device == NULL) + return 0; + return snprintf(buf, PAGE_SIZE, "%d\n", + device->pwrctrl.default_pwrlevel); +} + +static ssize_t kgsl_pwrctrl_default_pwrlevel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + struct kgsl_pwrctrl *pwr; + struct kgsl_pwrscale *pwrscale; + int ret; + unsigned int level = 0; + + if (device == NULL) + return 0; + + pwr = &device->pwrctrl; + pwrscale = &device->pwrscale; + + ret = kgsl_sysfs_store(buf, &level); + if (ret) + return ret; + + if (level > pwr->num_pwrlevels - 2) + goto done; + + mutex_lock(&device->mutex); + pwr->default_pwrlevel = level; + pwrscale->gpu_profile.profile.initial_freq + = pwr->pwrlevels[level].gpu_freq; + + mutex_unlock(&device->mutex); +done: + return count; +} + + +static ssize_t kgsl_popp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + struct kgsl_device *device = kgsl_device_from_dev(dev); + int ret; + + if (device == NULL) + return 0; + + ret = kgsl_sysfs_store(buf, &val); + if (ret) + return ret; + + mutex_lock(&device->mutex); + if (val) + set_bit(POPP_ON, &device->pwrscale.popp_state); + else + clear_bit(POPP_ON, &device->pwrscale.popp_state); + mutex_unlock(&device->mutex); + + return count; +} + +static ssize_t kgsl_popp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + if (device == NULL) + return 0; + return snprintf(buf, PAGE_SIZE, "%d\n", + test_bit(POPP_ON, &device->pwrscale.popp_state)); +} + static ssize_t kgsl_pwrctrl_pwrscale_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1423,6 +1503,10 @@ static DEVICE_ATTR(force_rail_on, 0644, static DEVICE_ATTR(bus_split, 0644, kgsl_pwrctrl_bus_split_show, kgsl_pwrctrl_bus_split_store); +static DEVICE_ATTR(default_pwrlevel, 0644, + kgsl_pwrctrl_default_pwrlevel_show, + kgsl_pwrctrl_default_pwrlevel_store); +static DEVICE_ATTR(popp, 0644, kgsl_popp_show, kgsl_popp_store); static DEVICE_ATTR(force_non_retention_on, 0644, kgsl_pwrctrl_force_non_retention_on_show, kgsl_pwrctrl_force_non_retention_on_store); @@ -1460,6 +1544,8 @@ static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_force_rail_on, &dev_attr_force_non_retention_on, &dev_attr_bus_split, + &dev_attr_default_pwrlevel, + &dev_attr_popp, &dev_attr_pwrscale, &dev_attr_gpu_model, &dev_attr_gpu_busy_percentage, @@ -1993,7 +2079,7 @@ static int kgsl_pwrctrl_clk_set_rate(struct clk *grp_clk, unsigned int freq, int kgsl_pwrctrl_init(struct kgsl_device *device) { - int i, k, m, n = 0, result; + int i, k, m, n = 0, result, freq; struct platform_device *pdev = device->pdev; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct device_node *ocmem_bus_node; @@ -2057,7 +2143,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->wakeup_maxpwrlevel = 0; for (i = 0; i < pwr->num_pwrlevels; i++) { - unsigned int freq = pwr->pwrlevels[i].gpu_freq; + freq = pwr->pwrlevels[i].gpu_freq; if (freq > 0) freq = clk_round_rate(pwr->grp_clks[0], freq); @@ -2068,13 +2154,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1].gpu_freq, clocks[0]); -#if 0 - if (pwr->grp_clks[6] != NULL) + freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ); + if (freq > 0) kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[6], - clk_round_rate(pwr->grp_clks[6], - KGSL_RBBMTIMER_CLK_FREQ), - clocks[6]); -#endif + freq, clocks[6]); result = get_regulators(device); if (result) @@ -2360,8 +2443,10 @@ static int kgsl_pwrctrl_enable(struct kgsl_device *device) if (pwr->wakeup_maxpwrlevel) { level = pwr->max_pwrlevel; pwr->wakeup_maxpwrlevel = 0; + } else if (kgsl_popp_check(device)) { + level = pwr->active_pwrlevel; } else { - level = pwr->num_pwrlevels - 1; + level = pwr->default_pwrlevel; } kgsl_pwrctrl_pwrlevel_change(device, level); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 2a506448cf49c3c53184c97b3ab0c2ff3ccdde10..38e554d4f8c501c1055917cfc9c87aa2c8ecdea8 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -128,6 +128,7 @@ struct kgsl_regulator { * @active_pwrlevel - The currently active power level * @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 @@ -183,6 +184,7 @@ struct kgsl_pwrctrl { unsigned int active_pwrlevel; unsigned int previous_pwrlevel; unsigned int thermal_pwrlevel; + unsigned int default_pwrlevel; unsigned int restrict_pwrlevel; unsigned int wakeup_maxpwrlevel; unsigned int max_pwrlevel; diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 82ad175e1c76a0dfd163dd83112d810435508f13..da79ad1cd0ad0b687ad53bc8210d5837dadec466 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -19,6 +19,24 @@ #include "kgsl_device.h" #include "kgsl_trace.h" +/* + * "SLEEP" is generic counting both NAP & SLUMBER + * PERIODS generally won't exceed 9 for the relavent 150msec + * window, but can be significantly smaller and still POPP + * pushable in cases where SLUMBER is involved. Hence the + * additional reliance on PERCENT to make sure a reasonable + * amount of down-time actually exists. + */ +#define MIN_SLEEP_PERIODS 3 +#define MIN_SLEEP_PERCENT 5 + +static struct kgsl_popp popp_param[POPP_MAX] = { + {0, 0}, + {-5, 20}, + {-5, 0}, + {0, 0}, +}; + static void do_devfreq_suspend(struct work_struct *work); static void do_devfreq_resume(struct work_struct *work); static void do_devfreq_notify(struct work_struct *work); @@ -38,11 +56,15 @@ static struct devfreq_dev_status last_status = { .private_data = &last_xstats }; */ void kgsl_pwrscale_sleep(struct kgsl_device *device) { + struct kgsl_pwrscale *psc = &device->pwrscale; BUG_ON(!mutex_is_locked(&device->mutex)); if (!device->pwrscale.enabled) return; device->pwrscale.on_time = 0; + psc->popp_level = 0; + clear_bit(POPP_PUSH, &device->pwrscale.popp_state); + /* to call devfreq_suspend_device() from a kernel thread */ queue_work(device->pwrscale.devfreq_wq, &device->pwrscale.devfreq_suspend_ws); @@ -115,6 +137,17 @@ void kgsl_pwrscale_update_stats(struct kgsl_device *device) if (device->state == KGSL_STATE_ACTIVE) { struct kgsl_power_stats stats; device->ftbl->power_stats(device, &stats); + if (psc->popp_level) { + u64 x = stats.busy_time; + u64 y = stats.ram_time; + do_div(x, 100); + do_div(y, 100); + x *= popp_param[psc->popp_level].gpu_x; + y *= popp_param[psc->popp_level].ddr_y; + trace_kgsl_popp_mod(device, x, y); + stats.busy_time += x; + stats.ram_time += y; + } device->pwrscale.accum_stats.busy_time += stats.busy_time; device->pwrscale.accum_stats.ram_time += stats.ram_time; device->pwrscale.accum_stats.ram_wait += stats.ram_wait; @@ -195,7 +228,7 @@ void kgsl_pwrscale_enable(struct kgsl_device *device) * run at default level; */ kgsl_pwrctrl_pwrlevel_change(device, - device->pwrctrl.num_pwrlevels - 1); + device->pwrctrl.default_pwrlevel); device->pwrscale.enabled = false; } } @@ -216,6 +249,193 @@ static int _thermal_adjust(struct kgsl_pwrctrl *pwr, int level) return level; } +/* + * Use various metrics including level stability, NAP intervals, and + * overall GPU freq / DDR freq combination to decide if POPP should + * be activated. + */ +static bool popp_stable(struct kgsl_device *device) +{ + s64 t; + s64 nap_time = 0; + s64 go_time = 0; + int i, index; + int nap = 0; + s64 percent_nap = 0; + struct kgsl_pwr_event *e; + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct kgsl_pwrscale *psc = &device->pwrscale; + + if (!test_bit(POPP_ON, &psc->popp_state)) + return false; + + /* If already pushed or running naturally at min don't push further */ + if (test_bit(POPP_PUSH, &psc->popp_state)) + return false; + if (!psc->popp_level && + (pwr->active_pwrlevel == pwr->min_pwrlevel)) + return false; + if (psc->history[KGSL_PWREVENT_STATE].events == NULL) + return false; + + t = ktime_to_ms(ktime_get()); + /* Check for recent NAP statistics: NAPping regularly and well? */ + if (pwr->active_pwrlevel == 0) { + index = psc->history[KGSL_PWREVENT_STATE].index; + i = index > 0 ? (index - 1) : + (psc->history[KGSL_PWREVENT_STATE].size - 1); + while (i != index) { + e = &psc->history[KGSL_PWREVENT_STATE].events[i]; + if (e->data == KGSL_STATE_NAP || + e->data == KGSL_STATE_SLUMBER) { + if (ktime_to_ms(e->start) + STABLE_TIME > t) { + nap++; + nap_time += e->duration; + } + } else if (e->data == KGSL_STATE_ACTIVE) { + if (ktime_to_ms(e->start) + STABLE_TIME > t) + go_time += e->duration; + } + if (i == 0) + i = psc->history[KGSL_PWREVENT_STATE].size - 1; + else + i--; + } + if (nap_time && go_time) { + percent_nap = 100 * nap_time; + do_div(percent_nap, nap_time + go_time); + } + trace_kgsl_popp_nap(device, (int)nap_time / 1000, nap, + percent_nap); + /* If running high at turbo, don't push */ + if (nap < MIN_SLEEP_PERIODS || percent_nap < MIN_SLEEP_PERCENT) + return false; + } + + /* Finally check that there hasn't been a recent change */ + if ((device->pwrscale.freq_change_time + STABLE_TIME) < t) { + device->pwrscale.freq_change_time = t; + return true; + } + return false; +} + +bool kgsl_popp_check(struct kgsl_device *device) +{ + int i; + struct kgsl_pwrscale *psc = &device->pwrscale; + struct kgsl_pwr_event *e; + + if (!test_bit(POPP_ON, &psc->popp_state)) + return false; + if (!test_bit(POPP_PUSH, &psc->popp_state)) + return false; + if (psc->history[KGSL_PWREVENT_STATE].events == NULL) { + clear_bit(POPP_PUSH, &psc->popp_state); + return false; + } + + e = &psc->history[KGSL_PWREVENT_STATE]. + events[psc->history[KGSL_PWREVENT_STATE].index]; + if (e->data == KGSL_STATE_SLUMBER) + e->duration = ktime_us_delta(ktime_get(), e->start); + + /* If there's been a long SLUMBER in recent history, clear the _PUSH */ + for (i = 0; i < psc->history[KGSL_PWREVENT_STATE].size; i++) { + e = &psc->history[KGSL_PWREVENT_STATE].events[i]; + if ((e->data == KGSL_STATE_SLUMBER) && + (e->duration > POPP_RESET_TIME)) { + clear_bit(POPP_PUSH, &psc->popp_state); + return false; + } + } + return true; +} + +/* + * The GPU has been running at the current frequency for a while. Attempt + * to lower the frequency for boarderline cases. + */ +static void popp_trans1(struct kgsl_device *device) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwr->active_pwrlevel]; + struct kgsl_pwrscale *psc = &device->pwrscale; + int old_level = psc->popp_level; + + switch (old_level) { + case 0: + psc->popp_level = 2; + /* If the current level has a high default bus don't push it */ + if (pl->bus_freq == pl->bus_max) + pwr->bus_mod = 1; + kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel + 1); + break; + case 1: + case 2: + psc->popp_level++; + break; + case 3: + set_bit(POPP_PUSH, &psc->popp_state); + psc->popp_level = 0; + break; + case POPP_MAX: + default: + psc->popp_level = 0; + break; + } + + trace_kgsl_popp_level(device, old_level, psc->popp_level); +} + +/* + * The GPU DCVS algorithm recommends a level change. Apply any + * POPP restrictions and update the level accordingly + */ +static int popp_trans2(struct kgsl_device *device, int level) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct kgsl_pwrscale *psc = &device->pwrscale; + int old_level = psc->popp_level; + + if (!test_bit(POPP_ON, &psc->popp_state)) + return level; + + clear_bit(POPP_PUSH, &psc->popp_state); + /* If the governor recommends going down, do it! */ + if (pwr->active_pwrlevel < level) { + psc->popp_level = 0; + trace_kgsl_popp_level(device, old_level, psc->popp_level); + return level; + } + + switch (psc->popp_level) { + case 0: + /* If the feature isn't engaged, go up immediately */ + break; + case 1: + /* Turn off mitigation, and go up a level */ + psc->popp_level = 0; + break; + case 2: + case 3: + /* Try a more aggressive mitigation */ + psc->popp_level--; + level++; + /* Update the stable timestamp */ + device->pwrscale.freq_change_time = ktime_to_ms(ktime_get()); + break; + case POPP_MAX: + default: + psc->popp_level = 0; + break; + } + + trace_kgsl_popp_level(device, old_level, psc->popp_level); + + return level; +} + /* * kgsl_devfreq_target - devfreq_dev_profile.target callback * @dev: see devfreq.h @@ -268,11 +488,13 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) if (pwr->thermal_cycle == CYCLE_ACTIVE) level = _thermal_adjust(pwr, i); else - level = i; + level = popp_trans2(device, i); break; } if (level != pwr->active_pwrlevel) kgsl_pwrctrl_pwrlevel_change(device, level); + } else if (popp_stable(device)) { + popp_trans1(device); } *freq = kgsl_pwrctrl_active_freq(pwr); @@ -555,7 +777,7 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) srcu_init_notifier_head(&pwrscale->nh); profile->initial_freq = - pwr->pwrlevels[pwr->num_pwrlevels - 1].gpu_freq; + pwr->pwrlevels[pwr->default_pwrlevel].gpu_freq; /* Let's start with 10 ms and tune in later */ profile->polling_ms = 10; diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h index 0922592c9e0850b7e943f5d57eeffe3a6ca06465..0756a4490f22af7d0052b5127b843fb355b9c9ec 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.h +++ b/drivers/gpu/msm/kgsl_pwrscale.h @@ -25,7 +25,8 @@ #define KGSL_PWREVENT_STATE 0 #define KGSL_PWREVENT_GPU_FREQ 1 #define KGSL_PWREVENT_BUS_FREQ 2 -#define KGSL_PWREVENT_MAX 3 +#define KGSL_PWREVENT_POPP 3 +#define KGSL_PWREVENT_MAX 4 /** * Amount of time running at a level to be considered @@ -33,6 +34,21 @@ */ #define STABLE_TIME 150 +/* Amount of idle time needed to re-set stability in usec */ +#define POPP_RESET_TIME 1000000 + +/* Number of POPP levels */ +#define POPP_MAX 4 + +/* POPP state bits */ +#define POPP_ON BIT(0) +#define POPP_PUSH BIT(1) + +struct kgsl_popp { + int gpu_x; + int ddr_y; +}; + struct kgsl_power_stats { u64 busy_time; u64 ram_time; @@ -63,7 +79,7 @@ struct kgsl_pwr_history { * @enabled - Whether or not power scaling is enabled * @time - Last submitted sample timestamp * @on_time - Timestamp when gpu busy begins - * @freq_change_time - Timestamp of last freq change + * @freq_change_time - Timestamp of last freq change or popp update * @nh - Notifier for the partner devfreq bus device * @devfreq_wq - Main devfreq workqueue * @devfreq_suspend_ws - Pass device suspension to devfreq @@ -72,6 +88,8 @@ struct kgsl_pwr_history { * @next_governor_call - Timestamp after which the governor may be notified of * a new sample * @history - History of power events with timestamps and durations + * @popp_level - Current level of POPP mitigation + * @popp_state - Control state for POPP, on/off, recently pushed, etc */ struct kgsl_pwrscale { struct devfreq *devfreqptr; @@ -91,6 +109,8 @@ struct kgsl_pwrscale { struct work_struct devfreq_notify_ws; ktime_t next_governor_call; struct kgsl_pwr_history history[KGSL_PWREVENT_MAX]; + int popp_level; + unsigned long popp_state; }; int kgsl_pwrscale_init(struct device *dev, const char *governor); @@ -113,6 +133,9 @@ int kgsl_busmon_target(struct device *dev, unsigned long *freq, u32 flags); int kgsl_busmon_get_dev_status(struct device *, struct devfreq_dev_status *); int kgsl_busmon_get_cur_freq(struct device *dev, unsigned long *freq); +bool kgsl_popp_check(struct kgsl_device *device); + + #define KGSL_PWRSCALE_INIT(_priv_data) { \ .enabled = true, \ .gpu_profile = { \ @@ -132,5 +155,6 @@ int kgsl_busmon_get_cur_freq(struct device *dev, unsigned long *freq); .history[KGSL_PWREVENT_STATE].size = 20, \ .history[KGSL_PWREVENT_GPU_FREQ].size = 3, \ .history[KGSL_PWREVENT_BUS_FREQ].size = 5, \ + .history[KGSL_PWREVENT_POPP].size = 5, \ } #endif diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 7e96127a092aac2504eb02f2da772b15b8b09884..f6e3f0ab786727c998614d5768a2d166bef4a260 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -98,6 +98,75 @@ struct mem_entry_stats { static void kgsl_cma_unlock_secure(struct kgsl_memdesc *memdesc); +static ssize_t +imported_mem_show(struct kgsl_process_private *priv, + int type, char *buf) +{ + struct kgsl_mem_entry *entry; + uint64_t imported_mem = 0; + int id = 0; + + spin_lock(&priv->mem_lock); + for (entry = idr_get_next(&priv->mem_idr, &id); entry; + id++, entry = idr_get_next(&priv->mem_idr, &id)) { + + int egl_surface_count = 0, egl_image_count = 0; + struct kgsl_memdesc *m; + + if (kgsl_mem_entry_get(entry) == 0) + continue; + spin_unlock(&priv->mem_lock); + + m = &entry->memdesc; + if (kgsl_memdesc_usermem_type(m) == KGSL_MEM_ENTRY_ION) { + kgsl_get_egl_counts(entry, &egl_surface_count, + &egl_image_count); + + if (kgsl_memdesc_get_memtype(m) == + KGSL_MEMTYPE_EGL_SURFACE) + imported_mem += m->size; + else if (egl_surface_count == 0) { + uint64_t size = m->size; + + do_div(size, (egl_image_count ? + egl_image_count : 1)); + imported_mem += size; + } + } + + kgsl_mem_entry_put(entry); + spin_lock(&priv->mem_lock); + } + spin_unlock(&priv->mem_lock); + + return scnprintf(buf, PAGE_SIZE, "%llu\n", imported_mem); +} + +static ssize_t +gpumem_mapped_show(struct kgsl_process_private *priv, + int type, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%llu\n", + priv->gpumem_mapped); +} + +static ssize_t +gpumem_unmapped_show(struct kgsl_process_private *priv, int type, char *buf) +{ + if (priv->gpumem_mapped > priv->stats[type].cur) + return -EIO; + + return scnprintf(buf, PAGE_SIZE, "%llu\n", + priv->stats[type].cur - priv->gpumem_mapped); +} + +static struct kgsl_mem_entry_attribute debug_memstats[] = { + __MEM_ENTRY_ATTR(0, imported_mem, imported_mem_show), + __MEM_ENTRY_ATTR(0, gpumem_mapped, gpumem_mapped_show), + __MEM_ENTRY_ATTR(KGSL_MEM_ENTRY_KERNEL, gpumem_unmapped, + gpumem_unmapped_show), +}; + /** * Show the current amount of memory allocated for the given memtype */ @@ -220,7 +289,13 @@ void kgsl_process_init_sysfs(struct kgsl_device *device, &mem_stats[i].max_attr.attr)) WARN(1, "Couldn't create sysfs file '%s'\n", mem_stats[i].max_attr.attr.name); + } + for (i = 0; i < ARRAY_SIZE(debug_memstats); i++) { + if (sysfs_create_file(&private->kobj, + &debug_memstats[i].attr)) + WARN(1, "Couldn't create sysfs file '%s'\n", + debug_memstats[i].attr.name); } } diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index 9f25ed685846d69e49b06fad5a26840edaf96607..dab7852e77b217a63d2dc8d0a7e208eae6885a7a 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -157,6 +157,7 @@ int kgsl_add_fence_event(struct kgsl_device *device, struct sync_pt *pt; struct sync_fence *fence = NULL; int ret = -EINVAL; + char fence_name[sizeof(fence->name)] = {}; unsigned int cur; priv.fence_fd = -1; @@ -178,8 +179,13 @@ int kgsl_add_fence_event(struct kgsl_device *device, ret = -ENOMEM; goto out; } + snprintf(fence_name, sizeof(fence_name), + "%s-pid-%d-ctx-%d-ts-%u", + device->name, current->group_leader->pid, + context_id, timestamp); - fence = sync_fence_create("", pt); + + fence = sync_fence_create(fence_name, pt); if (fence == NULL) { /* only destroy pt when not added to fence */ kgsl_sync_pt_destroy(pt); diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h index 0375bbb53f05373be37b87a7876af9b174ff0aef..8988dc12839f7c65de068643de1e7f1c9d9dec8c 100644 --- a/drivers/gpu/msm/kgsl_trace.h +++ b/drivers/gpu/msm/kgsl_trace.h @@ -36,13 +36,14 @@ TRACE_EVENT(kgsl_issueibcmds, TP_PROTO(struct kgsl_device *device, int drawctxt_id, + struct kgsl_cmdbatch *cmdbatch, unsigned int numibs, int timestamp, int flags, int result, unsigned int type), - TP_ARGS(device, drawctxt_id, numibs, timestamp, + TP_ARGS(device, drawctxt_id, cmdbatch, numibs, timestamp, flags, result, type), TP_STRUCT__entry( @@ -73,7 +74,7 @@ TRACE_EVENT(kgsl_issueibcmds, __entry->numibs, __entry->timestamp, __entry->flags ? __print_flags(__entry->flags, "|", - KGSL_DRAWOBJ_FLAGS) : "None", + KGSL_CMDBATCH_FLAGS) : "None", __entry->result, __print_symbolic(__entry->drawctxt_type, KGSL_CONTEXT_TYPES) ) @@ -878,6 +879,78 @@ TRACE_EVENT(kgsl_regwrite, ) ); +TRACE_EVENT(kgsl_popp_level, + + TP_PROTO(struct kgsl_device *device, int level1, int level2), + + TP_ARGS(device, level1, level2), + + TP_STRUCT__entry( + __string(device_name, device->name) + __field(int, level1) + __field(int, level2) + ), + + TP_fast_assign( + __assign_str(device_name, device->name); + __entry->level1 = level1; + __entry->level2 = level2; + ), + + TP_printk( + "d_name=%s old level=%d new level=%d", + __get_str(device_name), __entry->level1, __entry->level2) +); + +TRACE_EVENT(kgsl_popp_mod, + + TP_PROTO(struct kgsl_device *device, int x, int y), + + TP_ARGS(device, x, y), + + TP_STRUCT__entry( + __string(device_name, device->name) + __field(int, x) + __field(int, y) + ), + + TP_fast_assign( + __assign_str(device_name, device->name); + __entry->x = x; + __entry->y = y; + ), + + TP_printk( + "d_name=%s GPU busy mod=%d bus busy mod=%d", + __get_str(device_name), __entry->x, __entry->y) +); + +TRACE_EVENT(kgsl_popp_nap, + + TP_PROTO(struct kgsl_device *device, int t, int nap, int percent), + + TP_ARGS(device, t, nap, percent), + + TP_STRUCT__entry( + __string(device_name, device->name) + __field(int, t) + __field(int, nap) + __field(int, percent) + ), + + TP_fast_assign( + __assign_str(device_name, device->name); + __entry->t = t; + __entry->nap = nap; + __entry->percent = percent; + ), + + TP_printk( + "d_name=%s nap time=%d number of naps=%d percentage=%d", + __get_str(device_name), __entry->t, __entry->nap, + __entry->percent) +); + TRACE_EVENT(kgsl_register_event, TP_PROTO(unsigned int id, unsigned int timestamp, void *func), TP_ARGS(id, timestamp, func), @@ -960,62 +1033,59 @@ TRACE_EVENT(kgsl_pagetable_destroy, ); DECLARE_EVENT_CLASS(syncpoint_timestamp_template, - TP_PROTO(struct kgsl_drawobj_sync *syncobj, - struct kgsl_context *context, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, struct kgsl_context *context, unsigned int timestamp), - TP_ARGS(syncobj, context, timestamp), + TP_ARGS(cmdbatch, context, timestamp), TP_STRUCT__entry( - __field(unsigned int, syncobj_context_id) + __field(unsigned int, cmdbatch_context_id) __field(unsigned int, context_id) __field(unsigned int, timestamp) ), TP_fast_assign( - __entry->syncobj_context_id = syncobj->base.context->id; + __entry->cmdbatch_context_id = cmdbatch->context->id; __entry->context_id = context->id; __entry->timestamp = timestamp; ), TP_printk("ctx=%d sync ctx=%d ts=%d", - __entry->syncobj_context_id, __entry->context_id, + __entry->cmdbatch_context_id, __entry->context_id, __entry->timestamp) ); DEFINE_EVENT(syncpoint_timestamp_template, syncpoint_timestamp, - TP_PROTO(struct kgsl_drawobj_sync *syncobj, - struct kgsl_context *context, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, struct kgsl_context *context, unsigned int timestamp), - TP_ARGS(syncobj, context, timestamp) + TP_ARGS(cmdbatch, context, timestamp) ); DEFINE_EVENT(syncpoint_timestamp_template, syncpoint_timestamp_expire, - TP_PROTO(struct kgsl_drawobj_sync *syncobj, - struct kgsl_context *context, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, struct kgsl_context *context, unsigned int timestamp), - TP_ARGS(syncobj, context, timestamp) + TP_ARGS(cmdbatch, context, timestamp) ); DECLARE_EVENT_CLASS(syncpoint_fence_template, - TP_PROTO(struct kgsl_drawobj_sync *syncobj, char *name), - TP_ARGS(syncobj, name), + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, char *name), + TP_ARGS(cmdbatch, name), TP_STRUCT__entry( __string(fence_name, name) - __field(unsigned int, syncobj_context_id) + __field(unsigned int, cmdbatch_context_id) ), TP_fast_assign( - __entry->syncobj_context_id = syncobj->base.context->id; + __entry->cmdbatch_context_id = cmdbatch->context->id; __assign_str(fence_name, name); ), TP_printk("ctx=%d fence=%s", - __entry->syncobj_context_id, __get_str(fence_name)) + __entry->cmdbatch_context_id, __get_str(fence_name)) ); DEFINE_EVENT(syncpoint_fence_template, syncpoint_fence, - TP_PROTO(struct kgsl_drawobj_sync *syncobj, char *name), - TP_ARGS(syncobj, name) + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, char *name), + TP_ARGS(cmdbatch, name) ); DEFINE_EVENT(syncpoint_fence_template, syncpoint_fence_expire, - TP_PROTO(struct kgsl_drawobj_sync *syncobj, char *name), - TP_ARGS(syncobj, name) + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, char *name), + TP_ARGS(cmdbatch, name) ); TRACE_EVENT(kgsl_msg, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 7985385e650d83c1e55ea80ae126ccb49f6054f2..16ed53c127c80ab6e39e82959fc3a9fd2a726993 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1936,6 +1936,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, @@ -1978,6 +1981,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) }, { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 8bf61d295ffd7efd638e1f14570508e9c8498f50..7192fa1d2786c109d17f7a7a2f414ef726a05f98 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1150,6 +1150,8 @@ copy_rest: goto out; if (list->tail > list->head) { len = list->tail - list->head; + if (len > count) + len = count; if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1159,6 +1161,8 @@ copy_rest: list->head += len; } else { len = HID_DEBUG_BUFSIZE - list->head; + if (len > count) + len = count; if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1166,7 +1170,9 @@ copy_rest: } list->head = 0; ret += len; - goto copy_rest; + count -= len; + if (count > 0) + goto copy_rest; } } diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c index 0cd4f72162394b5652fc529681cfbc8774b50a36..5eea6fe0d7bd8181082599a4ed0f05eda3268d5c 100644 --- a/drivers/hid/hid-elo.c +++ b/drivers/hid/hid-elo.c @@ -42,6 +42,12 @@ static int elo_input_configured(struct hid_device *hdev, { struct input_dev *input = hidinput->input; + /* + * ELO devices have one Button usage in GenDesk field, which makes + * hid-input map it to BTN_LEFT; that confuses userspace, which then + * considers the device to be a mouse/touchpad instead of touchscreen. + */ + clear_bit(BTN_LEFT, input->keybit); set_bit(BTN_TOUCH, input->keybit); set_bit(ABS_PRESSURE, input->absbit); input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 213f616e7a1f6e9be77ad9f77cbf447b08b39f23..cf3d4944fc12353c34a065a32f8a22e05273d893 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -846,6 +846,8 @@ #define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 #define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 +#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc +#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE 0x0ba0 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000 @@ -1000,6 +1002,7 @@ #define USB_VENDOR_ID_XIN_MO 0x16c0 #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1 +#define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1 #define USB_VENDOR_ID_XIROKU 0x1477 #define USB_DEVICE_ID_XIROKU_SPX 0x1006 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 8319b9a417f04a2643d78b6a231e853fabb39334..0a9ee88bdc7bdeba75827992cc1c4ca436f09eda 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1090,18 +1090,26 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct /* * Ignore out-of-range values as per HID specification, - * section 5.10 and 6.2.25. + * section 5.10 and 6.2.25, when NULL state bit is present. + * When it's not, clamp the value to match Microsoft's input + * driver as mentioned in "Required HID usages for digitizers": + * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp * * The logical_minimum < logical_maximum check is done so that we * don't unintentionally discard values sent by devices which * don't specify logical min and max. */ if ((field->flags & HID_MAIN_ITEM_VARIABLE) && - (field->logical_minimum < field->logical_maximum) && - (value < field->logical_minimum || - value > field->logical_maximum)) { - dbg_hid("Ignoring out-of-range value %x\n", value); - return; + (field->logical_minimum < field->logical_maximum)) { + if (field->flags & HID_MAIN_ITEM_NULL_STATE && + (value < field->logical_minimum || + value > field->logical_maximum)) { + dbg_hid("Ignoring out-of-range value %x\n", value); + return; + } + value = clamp(value, + field->logical_minimum, + field->logical_maximum); } /* diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 756d1ef9bd991d9f77df5835f0cb1f44391493ed..6124fd6e04d1a7787ac2ab941f3888fcf35de0bf 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -955,6 +955,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = sysfs_create_group(&hdev->dev.kobj, &ntrig_attribute_group); + if (ret) + hid_err(hdev, "cannot create sysfs group\n"); return 0; err_free: diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 966047711fbfc91038912382d0303291c937070e..1073c0d1fae596d306b92abd0b7ebb76f5af9cbd 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c @@ -37,6 +37,8 @@ static uint kovaplus_convert_event_cpi(uint value) static void kovaplus_profile_activated(struct kovaplus_device *kovaplus, uint new_profile_index) { + if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings)) + return; kovaplus->actual_profile = new_profile_index; kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level; kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x; diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 8a4c1a10fa62416d82b745bd96e6c8b324830221..e9af6dd6ddb5b1710b4c98e982cc79337f64f12e 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -2049,6 +2049,12 @@ static const struct hid_device_id sony_devices[] = { .driver_data = DUALSHOCK4_CONTROLLER_USB }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER), .driver_data = DUALSHOCK4_CONTROLLER_BT }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), + .driver_data = DUALSHOCK4_CONTROLLER_USB }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), + .driver_data = DUALSHOCK4_CONTROLLER_BT }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE), + .driver_data = DUALSHOCK4_CONTROLLER_USB }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); diff --git a/drivers/hid/hid-xinmo.c b/drivers/hid/hid-xinmo.c index 7df5227a7e61d6ff79acd62cb009e29ffa4b79d8..9ad7731d2e10dad45268b55fbcf9dfc025570682 100644 --- a/drivers/hid/hid-xinmo.c +++ b/drivers/hid/hid-xinmo.c @@ -46,6 +46,7 @@ static int xinmo_event(struct hid_device *hdev, struct hid_field *field, static const struct hid_device_id xinmo_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) }, { } }; diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 9c2d7c23f2966f43953626b82d03cf62bca0c8ba..c0c4df1987259b7486f12a5cd3f6c64a7bfba342 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -197,6 +197,11 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t int ret = 0, len; unsigned char report_number; + if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { + ret = -ENODEV; + goto out; + } + dev = hidraw_table[minor]->hid; if (!dev->ll_driver->raw_request) { diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index fdcce357f39553050d7e5704cb115a287fee6b91..8463f83e037fb26599625bdddb0b1dd766c0018f 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -136,10 +136,10 @@ struct i2c_hid { * register of the HID * descriptor. */ unsigned int bufsize; /* i2c buffer size */ - char *inbuf; /* Input buffer */ - char *rawbuf; /* Raw Input buffer */ - char *cmdbuf; /* Command buffer */ - char *argsbuf; /* Command arguments buffer */ + u8 *inbuf; /* Input buffer */ + u8 *rawbuf; /* Raw Input buffer */ + u8 *cmdbuf; /* Command buffer */ + u8 *argsbuf; /* Command arguments buffer */ unsigned long flags; /* device flags */ @@ -373,7 +373,8 @@ static int i2c_hid_hwreset(struct i2c_client *client) static void i2c_hid_get_input(struct i2c_hid *ihid) { - int ret, ret_size; + int ret; + u32 ret_size; int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); if (size > ihid->bufsize) @@ -398,7 +399,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) return; } - if (ret_size > size) { + if ((ret_size > size) || (ret_size < 2)) { dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", __func__, size, ret_size); return; @@ -526,7 +527,8 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size) { /* the worst case is computed from the set_report command with a * reportID > 15 and the maximum report length */ - int args_len = sizeof(__u8) + /* optional ReportID byte */ + int args_len = sizeof(__u8) + /* ReportID */ + sizeof(__u8) + /* optional ReportID byte */ sizeof(__u16) + /* data register */ sizeof(__u16) + /* size of the report */ report_size; /* report */ @@ -979,6 +981,14 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); + /* Make sure there is something at this address */ + ret = i2c_smbus_read_byte(client); + if (ret < 0) { + dev_dbg(&client->dev, "nothing at this address: %d\n", ret); + ret = -ENXIO; + goto err_pm; + } + ret = i2c_hid_fetch_hid_descriptor(ihid); if (ret < 0) goto err_pm; diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c index e5c7a969f28b902f4e9664add9bb14e5a5a7e3b6..0cb78f30696b06342e001b5d307ad2ab78263f47 100644 --- a/drivers/hsi/clients/ssi_protocol.c +++ b/drivers/hsi/clients/ssi_protocol.c @@ -976,7 +976,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; /* Pad to 32-bits - FIXME: Revisit*/ if ((skb->len & 3) && skb_pad(skb, 4 - (skb->len & 3))) - goto drop; + goto inc_dropped; /* * Modem sends Phonet messages over SSI with its own endianess... @@ -1028,8 +1028,9 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) drop2: hsi_free_msg(msg); drop: - dev->stats.tx_dropped++; dev_kfree_skb(skb); +inc_dropped: + dev->stats.tx_dropped++; return 0; } diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 3cefd1aeb24f4a6c73f4bffd64fe7fc5b1edea18..9c262d95533150f6fd23fae6d9aeef9126ce607a 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -274,14 +274,18 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn) return clamp_val(reg, 0, 1023) & (0xff << 2); } -static u16 adt7475_read_word(struct i2c_client *client, int reg) +static int adt7475_read_word(struct i2c_client *client, int reg) { - u16 val; + int val1, val2; - val = i2c_smbus_read_byte_data(client, reg); - val |= (i2c_smbus_read_byte_data(client, reg + 1) << 8); + val1 = i2c_smbus_read_byte_data(client, reg); + if (val1 < 0) + return val1; + val2 = i2c_smbus_read_byte_data(client, reg + 1); + if (val2 < 0) + return val2; - return val; + return val1 | (val2 << 8); } static void adt7475_write_word(struct i2c_client *client, int reg, u16 val) diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index cccef87963e050afb99181d63d3ed5dcf401d5a1..975c43d446f8593d0e701efeaf8da133717cff74 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -646,6 +646,9 @@ static int atk_read_value(struct atk_sensor_data *sensor, u64 *value) else err = atk_read_value_new(sensor, value); + if (err) + return err; + sensor->is_valid = true; sensor->last_updated = jiffies; sensor->cached_value = *value; diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index dee93ec87d02a2c3c2f343ed6e2caeb0f7b35384..84e0994aafdd2ad96c3129e763149d525270d231 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -208,11 +208,13 @@ static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL); -#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4) -#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255) +#define VDD_FROM_REG(val) DIV_ROUND_CLOSEST((val) * 95, 4) +#define VDD_CLAMP(val) clamp_val(val, 0, 255 * 95 / 4) +#define VDD_TO_REG(val) DIV_ROUND_CLOSEST(VDD_CLAMP(val) * 4, 95) -#define IN_FROM_REG(val) ((val) * 19) -#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255) +#define IN_FROM_REG(val) ((val) * 19) +#define IN_CLAMP(val) clamp_val(val, 0, 255 * 19) +#define IN_TO_REG(val) DIV_ROUND_CLOSEST(IN_CLAMP(val), 19) static ssize_t get_in_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -349,8 +351,13 @@ static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR, #define DIV_FROM_REG(val) (1 << (val)) #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div)))) -#define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \ - clamp_val((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)) + +#define FAN_BASE(div) (480000 >> (div)) +#define FAN_CLAMP(val, div) clamp_val(val, FAN_BASE(div) / 255, \ + FAN_BASE(div)) +#define FAN_TO_REG(val, div) ((val) == 0 ? 0 : \ + DIV_ROUND_CLOSEST(480000, \ + FAN_CLAMP(val, div) << (div))) static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -513,9 +520,9 @@ static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR, get_fan_off, set_fan_off); -#define TEMP_FROM_REG(val) (((val) - 130) * 1000) -#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \ - (val) - 500 : (val) + 500) / 1000) + 130), 0, 255) +#define TEMP_FROM_REG(val) (((val) - 130) * 1000) +#define TEMP_CLAMP(val) clamp_val(val, -130000, 125000) +#define TEMP_TO_REG(val) (DIV_ROUND_CLOSEST(TEMP_CLAMP(val), 1000) + 130) static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 3aa958b5d45d5b42f1e0c69d6d18f57f3f3bf376..8097a5878e91e3828def5f714a49ac7da8bb052e 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -1286,7 +1286,7 @@ static void nct6775_update_pwm(struct device *dev) duty_is_dc = data->REG_PWM_MODE[i] && (nct6775_read_value(data, data->REG_PWM_MODE[i]) & data->PWM_MODE_MASK[i]); - data->pwm_mode[i] = duty_is_dc; + data->pwm_mode[i] = !duty_is_dc; fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]); for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) { @@ -2145,7 +2145,7 @@ show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); - return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]); + return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]); } static ssize_t @@ -2166,9 +2166,9 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, if (val > 1) return -EINVAL; - /* Setting DC mode is not supported for all chips/channels */ + /* Setting DC mode (0) is not supported for all chips/channels */ if (data->REG_PWM_MODE[nr] == 0) { - if (val) + if (!val) return -EINVAL; return count; } @@ -2177,7 +2177,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, data->pwm_mode[nr] = val; reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]); reg &= ~data->PWM_MODE_MASK[nr]; - if (val) + if (!val) reg |= data->PWM_MODE_MASK[nr]; nct6775_write_value(data, data->REG_PWM_MODE[nr], reg); mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 60aad9570f016987d82acd6d7f6104e94de3c12c..4876129c83376f331b2cc4cbe1284f1a954aad1d 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -67,7 +67,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) const struct adm1275_data *data = to_adm1275_data(info); int ret = 0; - if (page) + if (page > 0) return -ENXIO; switch (reg) { @@ -144,7 +144,7 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, { int ret; - if (page) + if (page > 0) return -ENXIO; switch (reg) { diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index f04454a42fdd2ec68395535ae3553e86e849bc3e..893df4dffae4207a15140e6321adae7a50021233 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -44,7 +44,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg) { int ret; - if (page) + if (page > 0) return -ENXIO; switch (reg) { diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 291d11fe93e792f50eab32bff2ce0783d97a75d8..6f3fabb5350f05a0a138af422ce985d683762649 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -443,8 +444,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data, static long pmbus_reg2data_direct(struct pmbus_data *data, struct pmbus_sensor *sensor) { - long val = (s16) sensor->data; - long m, b, R; + s64 b, val = (s16)sensor->data; + s32 m, R; m = data->info->m[sensor->class]; b = data->info->b[sensor->class]; @@ -472,11 +473,12 @@ static long pmbus_reg2data_direct(struct pmbus_data *data, R--; } while (R < 0) { - val = DIV_ROUND_CLOSEST(val, 10); + val = div_s64(val + 5LL, 10L); /* round closest */ R++; } - return (val - b) / m; + val = div_s64(val - b, m); + return clamp_val(val, LONG_MIN, LONG_MAX); } /* @@ -588,7 +590,8 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, static u16 pmbus_data2reg_direct(struct pmbus_data *data, struct pmbus_sensor *sensor, long val) { - long m, b, R; + s64 b, val64 = val; + s32 m, R; m = data->info->m[sensor->class]; b = data->info->b[sensor->class]; @@ -605,18 +608,18 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data, R -= 3; /* Adjust R and b for data in milli-units */ b *= 1000; } - val = val * m + b; + val64 = val64 * m + b; while (R > 0) { - val *= 10; + val64 *= 10; R--; } while (R < 0) { - val = DIV_ROUND_CLOSEST(val, 10); + val64 = div_s64(val64 + 5LL, 10L); /* round closest */ R++; } - return val; + return (u16)clamp_val(val64, S16_MIN, S16_MAX); } static u16 pmbus_data2reg_vid(struct pmbus_data *data, diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 35ec24aa1e56397115251ead6d843cad5874db4a..beab499d182ca6089f8665db73c6d097179abae4 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -339,12 +339,15 @@ static int ismt_process_desc(const struct ismt_desc *desc, data->word = dma_buffer[0] | (dma_buffer[1] << 8); break; case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: if (desc->rxbytes != dma_buffer[0] + 1) return -EMSGSIZE; memcpy(data->block, dma_buffer, desc->rxbytes); break; + case I2C_SMBUS_I2C_BLOCK_DATA: + memcpy(&data->block[1], dma_buffer, desc->rxbytes); + data->block[0] = desc->rxbytes; + break; } return 0; } @@ -584,7 +587,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, /* unmap the data buffer */ if (dma_size != 0) - dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction); + dma_unmap_single(dev, dma_addr, dma_size, dma_direction); if (unlikely(!ret)) { dev_err(dev, "completion wait timed out\n"); diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index f6783e71af4f8339048228e7911c5b8c3cb66556..f3e22b19efbf4f2a4fd2307436e75dffc1c9a8bd 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * 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 @@ -2139,8 +2139,12 @@ static bool i2c_msm_xfer_next_buf(struct i2c_msm_ctrl *ctrl) { struct i2c_msm_xfer_buf *cur_buf = &ctrl->xfer.cur_buf; struct i2c_msg *cur_msg = ctrl->xfer.msgs + cur_buf->msg_idx; - int bc_rem = cur_msg->len - cur_buf->end_idx; + int bc_rem = 0; + if (!cur_msg) + return false; + + bc_rem = cur_msg->len - cur_buf->end_idx; if (cur_buf->is_init && cur_buf->end_idx && bc_rem) { /* not the first buffer in a message */ @@ -2314,9 +2318,11 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) struct i2c_msm_ctrl *ctrl = i2c_get_adapdata(adap); struct i2c_msm_xfer *xfer = &ctrl->xfer; - if (IS_ERR_OR_NULL(msgs)) { - dev_err(ctrl->dev, " error on msgs Accessing invalid pointer location\n"); - return PTR_ERR(msgs); + if (IS_ERR_OR_NULL(msgs) || num < 1) { + dev_err(ctrl->dev, + "Error due to invalid message pointer or num of messages = %d\n", + num); + return -EINVAL; } /* if system is suspended just bail out */ diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 2f64273d3f2bba63c8f930e66fad83fdf5750551..fcf26f681f4e76ef4f3e42b34cf80ab36a0ac85f 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -783,12 +783,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, */ if (of_device_is_compatible(np, "marvell,mv78230-i2c")) { drv_data->offload_enabled = true; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) { drv_data->offload_enabled = false; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 177834e2d84101283ad0afd288e75703e5d4aa12..27315d85ef89de566d55bb27fc82e9d8e46c0805 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -592,10 +592,10 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap, * TODO: We could potentially loop and retry in the case * of MSP_TWI_XFER_TIMEOUT. */ - return -1; + return -EIO; } - return 0; + return num; } static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index af3b3d032a9f4c044b96f44d9113e1ca64161bab..43e88e3c1d275ae9dde4fef9d0ffb63638c41413 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -80,6 +80,7 @@ #define ICIER_TEIE 0x40 #define ICIER_RIE 0x20 #define ICIER_NAKIE 0x10 +#define ICIER_SPIE 0x08 #define ICSR2_NACKF 0x10 @@ -216,11 +217,14 @@ static irqreturn_t riic_tend_isr(int irq, void *data) return IRQ_NONE; } - if (riic->is_last || riic->err) + if (riic->is_last || riic->err) { + riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER); writeb(ICCR2_SP, riic->base + RIIC_ICCR2); - - writeb(0, riic->base + RIIC_ICIER); - complete(&riic->msg_done); + } else { + /* Transfer is complete, but do not send STOP */ + riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER); + complete(&riic->msg_done); + } return IRQ_HANDLED; } @@ -240,13 +244,13 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) if (riic->bytes_left == 1) { /* STOP must come before we set ACKBT! */ - if (riic->is_last) + if (riic->is_last) { + riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER); writeb(ICCR2_SP, riic->base + RIIC_ICCR2); + } riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3); - writeb(0, riic->base + RIIC_ICIER); - complete(&riic->msg_done); } else { riic_clear_set_bit(riic, ICMR3_ACKBT, 0, RIIC_ICMR3); } @@ -259,6 +263,21 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t riic_stop_isr(int irq, void *data) +{ + struct riic_dev *riic = data; + + /* read back registers to confirm writes have fully propagated */ + writeb(0, riic->base + RIIC_ICSR2); + readb(riic->base + RIIC_ICSR2); + writeb(0, riic->base + RIIC_ICIER); + readb(riic->base + RIIC_ICIER); + + complete(&riic->msg_done); + + return IRQ_HANDLED; +} + static u32 riic_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; @@ -326,6 +345,7 @@ static struct riic_irq_desc riic_irqs[] = { { .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" }, { .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" }, { .res_num = 2, .isr = riic_tdre_isr, .name = "riic-tdre" }, + { .res_num = 3, .isr = riic_stop_isr, .name = "riic-stop" }, { .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" }, }; diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 942b2d6428f3d268e7de4f5f6aa35ab0faafb942..efefcfa24a4c07a891cecb38b7da499079dc865c 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -18,6 +18,9 @@ #define ACPI_SMBUS_HC_CLASS "smbus" #define ACPI_SMBUS_HC_DEVICE_NAME "cmi" +/* SMBUS HID definition as supported by Microsoft Windows */ +#define ACPI_SMBUS_MS_HID "SMB0001" + ACPI_MODULE_NAME("smbus_cmi"); struct smbus_methods_t { @@ -51,6 +54,7 @@ static const struct smbus_methods_t ibm_smbus_methods = { static const struct acpi_device_id acpi_smbus_cmi_ids[] = { {"SMBUS01", (kernel_ulong_t)&smbus_methods}, {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, + {ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods}, {"", 0} }; MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 7533fa34d73711191c55ddf091a3f79831bd919b..d5f600c75aafb25207b99cb423fa7637056a10ff 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -341,7 +341,7 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs, } mutex_unlock(&vb->lock); } - return 0; + return num; error: mutex_unlock(&vb->lock); return error; diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index cc65ea0b818fe5cbf6c1c1c17c79304ba085e0aa..2490f80a2d98b79da1c0ea4417bf2833ca50231c 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -500,6 +500,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) { u8 rx_watermark; struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; + unsigned long flags; /* Clear and enable Rx full interrupt. */ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK); @@ -515,6 +516,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) rx_watermark = IIC_RX_FIFO_DEPTH; xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1); + local_irq_save(flags); if (!(msg->flags & I2C_M_NOSTART)) /* write the address */ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, @@ -525,6 +527,8 @@ static void xiic_start_recv(struct xiic_i2c *i2c) xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0)); + local_irq_restore(flags); + if (i2c->nmsgs == 1) /* very last, enable bus not busy as well */ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 0b510bafd90e2904d989d4f8ce06b89f50ea1f76..99cb9fa2d135f67c254a7981a1814ada397cab76 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1593,6 +1593,8 @@ static int idecd_open(struct block_device *bdev, fmode_t mode) struct cdrom_info *info; int rc = -ENXIO; + check_disk_change(bdev); + mutex_lock(&ide_cd_mutex); info = ide_cd_get(bdev->bd_disk); if (!info) diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 4dddeabdfbb02acdd847a79c6a567e8b0e5673b1..555cb74fbd49714fe547a8500f3020d2f9261f21 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -257,7 +257,7 @@ static int ad7793_setup(struct iio_dev *indio_dev, unsigned int vref_mv) { struct ad7793_state *st = iio_priv(indio_dev); - int i, ret = -1; + int i, ret; unsigned long long scale_uv; u32 id; @@ -266,7 +266,7 @@ static int ad7793_setup(struct iio_dev *indio_dev, return ret; /* reset the serial interface */ - ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret)); + ret = ad_sd_reset(&st->sd, 32); if (ret < 0) goto out; usleep_range(500, 2000); /* Wait for at least 500us */ diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index d10bd0c97233fa2351954e8bc6fdcd0b299e61dd..22c4c17cd9969486fe1ef80b68eaa99e51c43032 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -177,6 +177,34 @@ out: } EXPORT_SYMBOL_GPL(ad_sd_read_reg); +/** + * ad_sd_reset() - Reset the serial interface + * + * @sigma_delta: The sigma delta device + * @reset_length: Number of SCLKs with DIN = 1 + * + * Returns 0 on success, an error code otherwise. + **/ +int ad_sd_reset(struct ad_sigma_delta *sigma_delta, + unsigned int reset_length) +{ + uint8_t *buf; + unsigned int size; + int ret; + + size = DIV_ROUND_UP(reset_length, 8); + buf = kcalloc(size, sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memset(buf, 0xff, size); + ret = spi_write(sigma_delta->spi, buf, size); + kfree(buf); + + return ret; +} +EXPORT_SYMBOL_GPL(ad_sd_reset); + static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, unsigned int mode, unsigned int channel) { diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 28a086e48776255b3ba8889111dbb73203b5005e..662c930fb1c30d79e0bdec63d75efa54d2c018dc 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -180,6 +180,7 @@ static int mcp320x_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mcp320x_info; + spi_set_drvdata(spi, indio_dev); chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data]; indio_dev->channels = chip_info->channels; diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index ce93bd8e3f68b82fec81b31f8f1885b908ef0b45..a483747cdc9b91def9f6315109b9bca6342232c2 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1223,7 +1223,7 @@ static int xadc_probe(struct platform_device *pdev) ret = xadc->ops->setup(pdev, indio_dev, irq); if (ret) - goto err_free_samplerate_trigger; + goto err_clk_disable_unprepare; ret = request_threaded_irq(irq, xadc->ops->interrupt_handler, xadc->ops->threaded_interrupt_handler, @@ -1284,6 +1284,8 @@ static int xadc_probe(struct platform_device *pdev) err_free_irq: free_irq(irq, indio_dev); +err_clk_disable_unprepare: + clk_disable_unprepare(xadc->clk); err_free_samplerate_trigger: if (xadc->ops->flags & XADC_FLAGS_BUFFERED) iio_trigger_free(xadc->samplerate_trigger); @@ -1293,8 +1295,6 @@ err_free_convst_trigger: err_triggered_buffer_cleanup: if (xadc->ops->flags & XADC_FLAGS_BUFFERED) iio_triggered_buffer_cleanup(indio_dev); -err_clk_disable_unprepare: - clk_disable_unprepare(xadc->clk); err_device_free: kfree(indio_dev->channels); diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index 7c5245d9f99ccc82abee8d7eb9fdb5e14e0b3102..4cffd8fc5caecf414a82eab379cb06f5afa1d836 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -507,7 +507,7 @@ static ssize_t ad9523_store(struct device *dev, return ret; if (!state) - return 0; + return len; mutex_lock(&indio_dev->mlock); switch ((u32)this_attr->address) { @@ -641,7 +641,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev, code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) / AD9523_CLK_DIST_DIV_REV(ret); *val = code / 1000000; - *val2 = (code % 1000000) * 10; + *val2 = code % 1000000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 26069c7c2580834e05875daec67e66ea18f283b4..e2d882673542930d118c3db84d0d5c0b7868ca42 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -28,7 +28,10 @@ config ADIS16480 source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/inv_icm20689/Kconfig" source "drivers/iio/imu/bmi160/Kconfig" +source "drivers/iio/imu/inv_mpu/Kconfig" source "drivers/iio/imu/inv_mpu9250/Kconfig" +source "drivers/iio/imu/inv_icm20602/Kconfig" +source "drivers/iio/imu/st_asm330lhh/Kconfig" endmenu diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 8924e442973d71b918934490f04a096b7982bbe9..e265c37dd115cebaf827965a0489260cd53bfed2 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -15,5 +15,8 @@ obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-y += inv_mpu6050/ obj-y += inv_icm20689/ +obj-y += inv_icm20602/ obj-y += bmi160/ +obj-y += inv_mpu/ obj-y += inv_mpu9250/ +obj-y += st_asm330lhh/ diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index f53e9a803a0e1ec1589a5b0ad25d7aa1f8d54e70..93b99bd93738fab6cf2e9c2f8f0d14bf752bb31d 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -47,6 +47,10 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (adis->trig == NULL) return -ENOMEM; + adis->trig->dev.parent = &adis->spi->dev; + adis->trig->ops = &adis_trigger_ops; + iio_trigger_set_drvdata(adis->trig, adis); + ret = request_irq(adis->spi->irq, &iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING, @@ -55,9 +59,6 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (ret) goto error_free_trig; - adis->trig->dev.parent = &adis->spi->dev; - adis->trig->ops = &adis_trigger_ops; - iio_trigger_set_drvdata(adis->trig, adis); ret = iio_trigger_register(adis->trig); indio_dev->trig = iio_trigger_get(adis->trig); diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index efa60c4b34e4ed6996b341edd185032fad9798b0..d031ce69729e7d4a29fed7cac9bdb7083087f969 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -1113,7 +1113,6 @@ static int bmi160_report_accel_data(struct iio_dev *indio_dev, int header, struct bmi160_accel_t acc, u64 t) { u8 buf_16[IIO_AORGBUFFER] = {0}; - struct iio_buffer *ring = indio_dev->buffer; memcpy(buf_16, &acc, sizeof(acc)); memcpy(buf_16+8, &t, sizeof(t)); #ifdef BMI160_DEBUG @@ -1122,8 +1121,12 @@ static int bmi160_report_accel_data(struct iio_dev *indio_dev, ACC_FIFO_HEAD, acc.x, acc.y, acc.z, t); #endif + store_acc_boot_sample(acc.x, acc.y, acc.z); - ring->access->store_to(indio_dev->buffer, buf_16); + mutex_lock(&indio_dev->mlock); + iio_push_to_buffers(indio_dev, buf_16); + mutex_unlock(&indio_dev->mlock); + return 0; } @@ -1131,7 +1134,6 @@ static int bmi160_report_gyro_data(struct iio_dev *indio_dev, int header, struct bmi160_gyro_t gyro, u64 t) { u8 buf_16[IIO_AORGBUFFER] = {0}; - struct iio_buffer *ring = indio_dev->buffer; memcpy(buf_16, &gyro, sizeof(gyro)); memcpy(buf_16+8, &t, sizeof(t)); #ifdef BMI160_DEBUG @@ -1140,9 +1142,12 @@ static int bmi160_report_gyro_data(struct iio_dev *indio_dev, GYRO_FIFO_HEAD, gyro.x, gyro.y, gyro.z, t); #endif - /*iio_push_to_buffers(indio_dev, buf_16);*/ + store_gyro_boot_sample(gyro.x, gyro.y, gyro.z); - ring->access->store_to(indio_dev->buffer, buf_16); + mutex_lock(&indio_dev->mlock); + iio_push_to_buffers(indio_dev, buf_16); + mutex_unlock(&indio_dev->mlock); + return 0; } diff --git a/drivers/iio/imu/bmi160/bmi160_ring.c b/drivers/iio/imu/bmi160/bmi160_ring.c index 3489a9c256e9b41f5dc009cd7aaba46af90e0155..13db7bb8188bf123e3c24884835710dd8289b7ed 100644 --- a/drivers/iio/imu/bmi160/bmi160_ring.c +++ b/drivers/iio/imu/bmi160/bmi160_ring.c @@ -26,8 +26,6 @@ static int bmi160_buffer_preenable(struct iio_dev *indio_dev) static const struct iio_buffer_setup_ops bmi_buffer_setup_ops = { .preenable = &bmi160_buffer_preenable, - .postenable = &iio_triggered_buffer_postenable, - .predisable = &iio_triggered_buffer_predisable, }; int bmi_allocate_ring(struct iio_dev *indio_dev) @@ -40,11 +38,11 @@ int bmi_allocate_ring(struct iio_dev *indio_dev) err = -ENOMEM; goto error_ret; } - indio_dev->buffer = ring; + iio_device_attach_buffer(indio_dev, ring); /*setup ring buffer*/ ring->scan_timestamp = true; indio_dev->setup_ops = &bmi_buffer_setup_ops; - /*indio_dev->modes |= INDIO_BUFFER_TRIGGERED;*/ + indio_dev->modes |= INDIO_BUFFER_HARDWARE; err = iio_buffer_register(indio_dev, indio_dev->channels, indio_dev->num_channels); if (err) { diff --git a/drivers/iio/imu/inv_icm20602/Kconfig b/drivers/iio/imu/inv_icm20602/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..fa8868915fba812e980891b97dc81c3ab962c3b4 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/Kconfig @@ -0,0 +1,14 @@ +# +# inv-icm20602 drivers for Invensense MPU devices and combos +# +config INV_ICM20602_IIO + tristate "Invensense ICM20602 devices" + depends on I2C && SYSFS + select IIO_BUFFER + select IIO_BUFFER_CB + select IIO_TRIGGERED_BUFFER + help + This driver supports the Invensense ICM20602 devices. + It is a gyroscope/accelerometer combo device. + This driver can be built as a module. The module will be called + inv-icm20602. diff --git a/drivers/iio/imu/inv_icm20602/Makefile b/drivers/iio/imu/inv_icm20602/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d60c10ac178e190cbf878e8d0d7ba8d5dfe212f5 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Invensense icm20602 device. +# + +obj-$(CONFIG_INV_ICM20602_IIO) += inv-icm20602.o +inv-icm20602-objs := inv_icm20602_core.o inv_icm20602_ring.o inv_icm20602_trigger.o inv_icm20602_bsp.o diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c new file mode 100644 index 0000000000000000000000000000000000000000..e7640e989513a3b2505f94704437584239ac1824 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c @@ -0,0 +1,939 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_icm20602_bsp.h" +#include "inv_icm20602_iio.h" + +#define icm20602_init_reg_addr(head, tail, reg_map) { \ + enum inv_icm20602_reg_addr i;\ + for (i = head; i <= tail; i++) {\ + reg_map->address = i;\ + reg_map->reg_u.reg = 0x0;\ + reg_map++;\ + } \ +} + +#define icm20602_write_reg_simple(st, register) \ + icm20602_write_reg(st, \ + register.address, \ + register.reg_u.reg) + +static struct inv_icm20602_reg_map reg_set_20602; + +int icm20602_init_reg_map(void) +{ + struct struct_XG_OFFS_TC_H *reg_map = &(reg_set_20602.XG_OFFS_TC_H); + + icm20602_init_reg_addr(ADDR_XG_OFFS_TC_H, + ADDR_XG_OFFS_TC_L, reg_map); + + icm20602_init_reg_addr(ADDR_YG_OFFS_TC_H, + ADDR_YG_OFFS_TC_L, reg_map); + + icm20602_init_reg_addr(ADDR_ZG_OFFS_TC_H, + ADDR_ZG_OFFS_TC_L, reg_map); + + icm20602_init_reg_addr(ADDR_SELF_TEST_X_ACCEL, + ADDR_SELF_TEST_Z_ACCEL, reg_map); + + icm20602_init_reg_addr(ADDR_XG_OFFS_USRH, + ADDR_LP_MODE_CFG, reg_map); + + icm20602_init_reg_addr(ADDR_ACCEL_WOM_X_THR, + ADDR_FIFO_EN, reg_map); + + icm20602_init_reg_addr(ADDR_FSYNC_INT, + ADDR_GYRO_ZOUT_L, reg_map); + + icm20602_init_reg_addr(ADDR_SELF_TEST_X_GYRO, + ADDR_SELF_TEST_Z_GYRO, reg_map); + + icm20602_init_reg_addr(ADDR_FIFO_WM_TH1, + ADDR_FIFO_WM_TH2, reg_map); + + icm20602_init_reg_addr(ADDR_SIGNAL_PATH_RESET, + ADDR_PWR_MGMT_2, reg_map); + + icm20602_init_reg_addr(ADDR_I2C_IF, + ADDR_I2C_IF, reg_map); + + icm20602_init_reg_addr(ADDR_FIFO_COUNTH, + ADDR_XA_OFFSET_L, reg_map); + + icm20602_init_reg_addr(ADDR_YA_OFFSET_H, + ADDR_YA_OFFSET_L, reg_map); + + icm20602_init_reg_addr(ADDR_ZA_OFFSET_H, + ADDR_ZA_OFFSET_L, reg_map); + + return MPU_SUCCESS; +} + +#define W_FLG 0 +#define R_FLG 1 +int icm20602_bulk_read(struct inv_icm20602_state *st, + int reg, char *buf, int size) +{ + int result = MPU_SUCCESS; + char tx_buf[2] = {0x0, 0x0}; + int tmp_size = size; + int tmp_buf = buf; + struct i2c_msg msg[2]; + + if (!st || !buf) + return -MPU_FAIL; + + if (st->interface == ICM20602_SPI) { + tx_buf[0] = ICM20602_READ_REG(reg); + result = spi_write_then_read(st->spi, &tx_buf[0], + 1, tmp_buf, size); + if (result) { + dev_dbgerr("mpu read reg %u failed, rc %d\n", + reg, result); + result = -MPU_READ_FAIL; + } + } else { + result = size; + while (tmp_size > 0) { +#ifdef ICM20602_I2C_SMBUS + result += i2c_smbus_read_i2c_block_data(st->client, + reg, (tmp_size < 32)?tmp_size:32, tmp_buf); + tmp_size -= 32; + tmp_buf += tmp_size; +#else + tx_buf[0] = reg; + msg[0].addr = st->client->addr; + msg[0].flags = W_FLG; + msg[0].len = 1; + msg[0].buf = tx_buf; + + msg[1].addr = st->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = (tmp_size < 32)?tmp_size:32; + msg[1].buf = tmp_buf; + i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg)); + tmp_size -= 32; + tmp_buf += tmp_size; +#endif + } + } + + return result; +} + +static int icm20602_write_reg(struct inv_icm20602_state *st, + uint8_t reg, uint8_t val) +{ + int result = MPU_SUCCESS; + char txbuf[2] = {0x0, 0x0}; + struct i2c_msg msg[1]; + + if (st->interface == ICM20602_SPI) { + txbuf[0] = ICM20602_WRITE_REG(reg); + txbuf[1] = val; + result = spi_write_then_read(st->spi, &txbuf[0], 2, NULL, 0); + if (result) { + dev_dbgerr("mpu write reg %u failed, rc %d\n", + reg, val); + result = -MPU_READ_FAIL; + } + } else if (st->interface == ICM20602_I2C) { +#ifdef ICM20602_I2C_SMBUS + result = i2c_smbus_write_i2c_block_data(st->client, + reg, 1, &val); +#else + txbuf[0] = reg; + txbuf[1] = val; + msg[0].addr = st->client->addr; + msg[0].flags = I2C_M_IGNORE_NAK; + msg[0].len = 2; + msg[0].buf = txbuf; + + i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg)); +#endif + } + + return result; +} + +static int icm20602_read_reg(struct inv_icm20602_state *st, + uint8_t reg, uint8_t *val) +{ + int result = MPU_SUCCESS; + char txbuf[1] = {0x0}; + char rxbuf[1] = {0x0}; + struct i2c_msg msg[2]; + + if (st->interface == ICM20602_SPI) { + txbuf[0] = ICM20602_READ_REG(reg); + result = spi_write_then_read(st->spi, + &txbuf[0], 1, rxbuf, 1); + if (result) { + dev_dbgerr("mpu read reg %u failed, rc %d\n", + reg, result); + result = -MPU_READ_FAIL; + } + } else if (st->interface == ICM20602_I2C) { +#ifdef ICM20602_I2C_SMBUS + result = i2c_smbus_read_i2c_block_data(st->client, + reg, 1, rxbuf); + if (result != 1) { + dev_dbgerr("mpu read reg %u failed, rc %d\n", + reg, result); + result = -MPU_READ_FAIL; + } +#else + txbuf[0] = reg; + msg[0].addr = st->client->addr; + msg[0].flags = W_FLG; + msg[0].len = 1; + msg[0].buf = txbuf; + + msg[1].addr = st->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = rxbuf; + + i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg)); +#endif + } + *val = rxbuf[0]; + + return result; +} + +#define combine_8_to_16(upper, lower) ((upper << 8) | lower) + +int icm20602_read_raw(struct inv_icm20602_state *st, + struct struct_icm20602_real_data *real_data, u8 type) +{ + struct struct_icm20602_raw_data raw_data; + + if (type & ACCEL != 0) { + icm20602_read_reg(st, + reg_set_20602.ACCEL_XOUT_H.address, + &raw_data.ACCEL_XOUT_H); + icm20602_read_reg(st, + reg_set_20602.ACCEL_XOUT_L.address, + &raw_data.ACCEL_XOUT_L); + real_data->ACCEL_XOUT = + combine_8_to_16(raw_data.ACCEL_XOUT_H, + raw_data.ACCEL_XOUT_L); + + icm20602_read_reg(st, + reg_set_20602.ACCEL_YOUT_H.address, + &raw_data.ACCEL_YOUT_H); + icm20602_read_reg(st, + reg_set_20602.ACCEL_YOUT_L.address, + &raw_data.ACCEL_YOUT_L); + real_data->ACCEL_YOUT = + combine_8_to_16(raw_data.ACCEL_YOUT_H, + raw_data.ACCEL_YOUT_L); + + icm20602_read_reg(st, + reg_set_20602.ACCEL_ZOUT_H.address, + &raw_data.ACCEL_ZOUT_H); + icm20602_read_reg(st, + reg_set_20602.ACCEL_ZOUT_L.address, + &raw_data.ACCEL_ZOUT_L); + real_data->ACCEL_ZOUT = + combine_8_to_16(raw_data.ACCEL_ZOUT_H, + raw_data.ACCEL_ZOUT_L); + } + + if (type & GYRO != 0) { + icm20602_read_reg(st, + reg_set_20602.GYRO_XOUT_H.address, + &raw_data.GYRO_XOUT_H); + icm20602_read_reg(st, + reg_set_20602.GYRO_XOUT_L.address, + &raw_data.GYRO_XOUT_L); + real_data->GYRO_XOUT = + combine_8_to_16(raw_data.GYRO_XOUT_H, + raw_data.GYRO_XOUT_L); + + icm20602_read_reg(st, + reg_set_20602.GYRO_YOUT_H.address, + &raw_data.GYRO_YOUT_H); + icm20602_read_reg(st, + reg_set_20602.GYRO_YOUT_L.address, + &raw_data.GYRO_YOUT_L); + real_data->GYRO_YOUT = + combine_8_to_16(raw_data.GYRO_YOUT_H, + raw_data.GYRO_YOUT_L); + + icm20602_read_reg(st, + reg_set_20602.GYRO_ZOUT_H.address, + &raw_data.GYRO_ZOUT_H); + icm20602_read_reg(st, + reg_set_20602.GYRO_ZOUT_L.address, + &raw_data.GYRO_ZOUT_L); + real_data->GYRO_ZOUT = + combine_8_to_16(raw_data.GYRO_ZOUT_H, + raw_data.GYRO_ZOUT_L); + } + + return MPU_SUCCESS; +} + +int icm20602_read_fifo(struct inv_icm20602_state *st, + void *buf, const int size) +{ + return icm20602_bulk_read(st, + reg_set_20602.FIFO_R_W.address, buf, size); +} + +int icm20602_start_fifo(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + + config = st->config; + + /* enable fifo */ + if (config->fifo_enabled) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x1; + if (icm20602_write_reg_simple(st, + reg_set_20602.USER_CTRL)) { + dev_dbgerr("icm20602 start fifo failed\n"); + return -MPU_FAIL; + } + + /* enable interrupt, need to test */ + reg_set_20602.INT_ENABLE.reg_u.REG.FIFO_OFLOW_EN = 0x1; + reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0; + if (icm20602_write_reg_simple(st, + reg_set_20602.INT_ENABLE)) { + dev_dbgerr("icm20602 set FIFO_OFLOW_EN failed\n"); + return -MPU_FAIL; + } + } + + return MPU_SUCCESS; +} + +static int icm20602_stop_fifo(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + + config = st->config; + /* disable fifo */ + if (config->fifo_enabled) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x0; + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1; + if (icm20602_write_reg_simple(st, + reg_set_20602.USER_CTRL)) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + dev_dbgerr("icm20602 stop fifo failed\n"); + return -MPU_FAIL; + } + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + } + + return MPU_SUCCESS; +} + +static int icm20602_config_waterlevel(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + u8 val = 0; + + config = st->config; + if (config->fifo_enabled != true) + return MPU_SUCCESS; + /* config waterlevel as the fps need */ + config->gyro_accel_sample_rate); + config->fifo_waterlevel = (config->user_fps_in_ms / + (1000 / config->gyro_accel_sample_rate)) + *ICM20602_PACKAGE_SIZE; + + if (config->fifo_waterlevel > 1023 || + config->fifo_waterlevel/50 > + (1023-config->fifo_waterlevel)/ICM20602_PACKAGE_SIZE) { + dev_dbgerr("set fifo_waterlevel failed %d\n", + config->fifo_waterlevel); + return MPU_FAIL; + } + reg_set_20602.FIFO_WM_TH1.reg_u.reg = + (config->fifo_waterlevel & 0xff00) >> 8; + reg_set_20602.FIFO_WM_TH2.reg_u.reg = + (config->fifo_waterlevel & 0x00ff); + + icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH1); + icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH2); + icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH1.address, &val); + icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH2.address, &val); + + return MPU_SUCCESS; +} + +static int icm20602_read_ST_code(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + int result = 0; + + config = st->config; + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_ACCEL.address, + &(config->acc_self_test.X)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_ACCEL.address, + &(config->acc_self_test.Y)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_ACCEL.address, + &(config->acc_self_test.Z)); + + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_GYRO.address, + &(config->gyro_self_test.X)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_GYRO.address, + &(config->gyro_self_test.Y)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_GYRO.address, + &(config->gyro_self_test.Z)); + + return result; +} + +static int icm20602_set_self_test(struct inv_icm20602_state *st) +{ + uint8_t raw_data[6] = {0, 0, 0, 0, 0, 0}; + uint8_t selfTest[6]; + float factory_trim[6]; + int result = 0; + int ii; + + reg_set_20602.SMPLRT_DIV.reg_u.REG.SMPLRT_DIV = 0; + result |= icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV); + + reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = INV_ICM20602_GYRO_LFP_92HZ; + result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG); + + reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0; + reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = ICM20602_GYRO_FSR_250DPS; + result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG); + + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = ICM20602_ACCLFP_99; + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0X0; + result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG2); + + reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = ICM20602_ACC_FSR_2G; + result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG); + + icm20602_read_ST_code(st); + + return 0; +} + +static int icm20602_do_test_acc(struct inv_icm20602_state *st, + struct X_Y_Z *acc, struct X_Y_Z *acc_st) +{ + struct struct_icm20602_real_data *real_data = + kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC); + struct icm20602_user_config *config = st->config; + int i, j; + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, ACCEL); + acc->X += real_data->ACCEL_XOUT; + acc->Y += real_data->ACCEL_YOUT; + acc->Z += real_data->ACCEL_ZOUT; + /* sample rate is 1kHz*/ + usleep_range(1000, 1001); + } + acc->X /= SELFTEST_COUNT; + acc->X *= ST_PRECISION; + + acc->Y /= SELFTEST_COUNT; + acc->Y *= ST_PRECISION; + + acc->Z /= SELFTEST_COUNT; + acc->Z *= ST_PRECISION; + + reg_set_20602.ACCEL_CONFIG.reg_u.REG.XG_ST = 0x1; + reg_set_20602.ACCEL_CONFIG.reg_u.REG.YG_ST = 0x1; + reg_set_20602.ACCEL_CONFIG.reg_u.REG.ZG_ST = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG); + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, ACCEL); + acc_st->X += real_data->ACCEL_XOUT; + acc_st->Y += real_data->ACCEL_YOUT; + acc_st->Z += real_data->ACCEL_ZOUT; + /* sample rate is 1kHz */ + usleep_range(1000, 1001); + } + acc_st->X /= SELFTEST_COUNT; + acc_st->X *= ST_PRECISION; + + acc_st->Y /= SELFTEST_COUNT; + acc_st->Y *= ST_PRECISION; + + acc_st->Z /= SELFTEST_COUNT; + acc_st->Z *= ST_PRECISION; + + return MPU_SUCCESS; +} + +static int icm20602_do_test_gyro(struct inv_icm20602_state *st, + struct X_Y_Z *gyro, struct X_Y_Z *gyro_st) +{ + struct struct_icm20602_real_data *real_data = + kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC); + int i, j; + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, GYRO); + gyro->X += real_data->GYRO_XOUT; + gyro->Y += real_data->GYRO_YOUT; + gyro->Z += real_data->GYRO_ZOUT; + /* sample rate is 1kHz*/ + usleep_range(1000, 1001); + } + gyro->X /= SELFTEST_COUNT; + gyro->X *= ST_PRECISION; + + gyro->Y /= SELFTEST_COUNT; + gyro->Y *= ST_PRECISION; + + gyro->Z /= SELFTEST_COUNT; + gyro->Z *= ST_PRECISION; + + reg_set_20602.GYRO_CONFIG.reg_u.REG.XG_ST = 0x1; + reg_set_20602.GYRO_CONFIG.reg_u.REG.YG_ST = 0x1; + reg_set_20602.GYRO_CONFIG.reg_u.REG.ZG_ST = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG); + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, ACCEL); + gyro_st->X += real_data->GYRO_XOUT; + gyro_st->Y += real_data->GYRO_YOUT; + gyro_st->Z += real_data->GYRO_ZOUT; + /* sample rate is 1kHz */ + usleep_range(1000, 1001); + } + gyro_st->X /= SELFTEST_COUNT; + gyro_st->X *= ST_PRECISION; + + gyro_st->Y /= SELFTEST_COUNT; + gyro_st->Y *= ST_PRECISION; + + gyro_st->Z /= SELFTEST_COUNT; + gyro_st->Z *= ST_PRECISION; + + return MPU_SUCCESS; +} + +static bool icm20602_check_acc_selftest(struct inv_icm20602_state *st, + struct X_Y_Z *acc, struct X_Y_Z *acc_st) +{ + struct X_Y_Z acc_ST_code, st_otp, st_shift_cust; + bool otp_value_zero = false, test_result = true; + + acc_ST_code.X = st->config->acc_self_test.X; + acc_ST_code.Y = st->config->acc_self_test.Y; + acc_ST_code.Z = st->config->acc_self_test.Z; + + st_otp.X = (st_otp.X != 0) ? mpu_st_tb[acc_ST_code.X - 1] : 0; + st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[acc_ST_code.Y - 1] : 0; + st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[acc_ST_code.Z - 1] : 0; + + if (st_otp.X & st_otp.Y & st_otp.Z == 0) { + otp_value_zero = true; + } + + st_shift_cust.X = acc_st->X - acc->X; + st_shift_cust.Y = acc_st->X - acc->Y; + st_shift_cust.Z = acc_st->X - acc->Z; + if (!otp_value_zero) { + if ( + st_shift_cust.X < + (st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) || + st_shift_cust.Y < + (st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) || + st_shift_cust.Z < + (st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) || + + st_shift_cust.X > + (st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) || + st_shift_cust.Y > + (st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) || + st_shift_cust.Z > + (st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) + ) { + test_result = false; + } + } else { + if ( + abs(st_shift_cust.X) < + (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Y) < + (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Z) < + (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) || + + abs(st_shift_cust.X) > + (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Y) > + (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Z) > + (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) + ) { + test_result = false; + } + } + + return test_result; +} + +static int icm20602_check_gyro_selftest(struct inv_icm20602_state *st, + struct X_Y_Z *gyro, struct X_Y_Z *gyro_st) +{ + struct X_Y_Z gyro_ST_code, st_otp, st_shift_cust; + bool otp_value_zero = false, test_result = true; + + gyro_ST_code.X = st->config->gyro_self_test.X; + gyro_ST_code.Y = st->config->gyro_self_test.Y; + gyro_ST_code.Z = st->config->gyro_self_test.Z; + + st_otp.X = (st_otp.X != 0) ? mpu_st_tb[gyro_ST_code.X - 1] : 0; + st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[gyro_ST_code.Y - 1] : 0; + st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[gyro_ST_code.Z - 1] : 0; + + if (st_otp.X & st_otp.Y & st_otp.Z == 0) { + otp_value_zero = true; + } + + st_shift_cust.X = gyro_st->X - gyro->X; + st_shift_cust.Y = gyro_st->X - gyro->Y; + st_shift_cust.Z = gyro_st->X - gyro->Z; + if (!otp_value_zero) { + if ( + st_shift_cust.X < + (st_otp.X * ST_PRECISION * GYRO_ST_SHIFT / 100) || + st_shift_cust.Y < + (st_otp.Y * ST_PRECISION * GYRO_ST_SHIFT / 100) || + st_shift_cust.Z < + (st_otp.Z * ST_PRECISION * GYRO_ST_SHIFT / 100) + ) { + test_result = false; + } + } else { + if ( + abs(st_shift_cust.X) < + (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) || + abs(st_shift_cust.Y) < + (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) || + abs(st_shift_cust.Z) < + (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) + ) { + test_result = false; + } + } + + if (test_result == true) { + /* Self Test Pass/Fail Criteria C */ + if ( + abs(st_shift_cust.X) > + GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION || + abs(st_shift_cust.Y) > + GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION || + abs(st_shift_cust.Z) > + GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION + ) { + test_result = false; + } + } + + return test_result; +} + +bool icm20602_self_test(struct inv_icm20602_state *st) +{ + struct X_Y_Z acc, acc_st; + struct X_Y_Z gyro, gyro_st; + bool test_result = true; + + icm20602_set_self_test(st); + icm20602_do_test_acc(st, &acc, &acc_st); + icm20602_do_test_gyro(st, &gyro, &gyro_st); + test_result = icm20602_check_acc_selftest(st, &acc, &acc_st); + test_result = icm20602_check_gyro_selftest(st, &gyro, &gyro_st); + + return test_result; +} + +static int icm20602_config_fifo(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + + config = st->config; + if (config->fifo_enabled != true) + return MPU_SUCCESS; + + /* + * Set CONFIG.USER_SET_BIT = 0, No reason as datasheet said + */ + reg_set_20602.CONFIG.reg_u.REG.USER_SET_BIT = 0x0; + /* + * Set CONFIG.FIFO_MODE = 1, + * i.e. when FIFO is full, additional writes will + * not be written to FIFO + */ + reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1; + if (icm20602_write_reg_simple(st, reg_set_20602.CONFIG)) + return -MPU_FAIL; + + /* reset fifo */ + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1; + if (icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL)) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + return -MPU_FAIL; + } + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + + /* Enable FIFO on specified sensors */ + reg_set_20602.FIFO_EN.reg_u.REG.GYRO_FIFO_EN = 0x1; + reg_set_20602.FIFO_EN.reg_u.REG.ACCEL_FIFO_EN = 0x1; + if (icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN)) + return -MPU_FAIL; + + if (icm20602_config_waterlevel(st)) + return -MPU_FAIL; + + if (icm20602_start_fifo(st)) + return -MPU_FAIL; + + return MPU_SUCCESS; +} + +static int icm20602_initialize_gyro(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + int result = MPU_SUCCESS; + int sample_rate; + uint8_t fchoice_b; + + if (st == NULL) + return -MPU_FAIL; + + /* + * ICM20602 supports gyro sampling rate up to 32KHz + * when fchoice_b != 0x00 + * In our driver, we supports up to 8KHz + * thus always set fchoice_b to 0x00; + */ + config = st->config; + /* + * SAPLRT_DIV in ICM20602_REG_SMPLRT_DIV is only used for 1kHz internal + * sampling, i.e. fchoice_b in ICM20602_REG_GYRO_CONFIG is 00 + * and 0 < dlpf_cfg in ICM20602_REG_CONFIG < 7 + * SAMPLE_RATE=Internal_Sample_Rate / (1 + SMPLRT_DIV) + */ + if (config->gyro_accel_sample_rate <= ICM20602_SAMPLE_RATE_1000HZ) + reg_set_20602.SMPLRT_DIV.reg_u.reg = + ICM20602_INTERNAL_SAMPLE_RATE_HZ / + config->gyro_accel_sample_rate - 1; + + result = icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV); + + /* Set gyro&temperature(combine) LPF */ + reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = config->gyro_lpf; + result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG); + + /* Set gyro full scale range */ + reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0; + reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = config->gyro_fsr; + result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG); + + /* Set Accel full scale range */ + reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = config->acc_fsr; + result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG); + + /* + * Set accel LPF + * Support accel sample rate up to 1KHz + * thus set accel_fchoice_b to 0x00 + * The actual accel sample rate is 1KHz/(1+SMPLRT_DIV) + */ + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0x0; + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = config->acc_lpf; + result |= icm20602_write_reg_simple(st, + reg_set_20602.ACCEL_CONFIG2); + + if (result) { + dev_dbgerr("icm20602 init gyro and accel failed\n"); + return -MPU_FAIL; + } + + return result; +} + +int icm20602_set_power_itg(struct inv_mpu9250_state *st, bool power_on) +{ + int result = MPU_SUCCESS; + + if (power_on) { + reg_set_20602.PWR_MGMT_1.reg_u.reg = 0; + result = icm20602_write_reg_simple(st, + reg_set_20602.PWR_MGMT_1); + } else { + reg_set_20602.PWR_MGMT_1.reg_u.REG.SLEEP = 0x1; + result = icm20602_write_reg_simple(st, + reg_set_20602.PWR_MGMT_1); + } + if (result) { + dev_dbgerr("set power failed power %d err %d\n", + power_on, result); + return result; + } + + if (power_on) + msleep(30); + + return result; +} + +int icm20602_init_device(struct inv_icm20602_state *st) +{ + int result = MPU_SUCCESS; + struct icm20602_user_config *config = NULL; + int package_count; + + config = st->config; + if (st == NULL || st->config == NULL) { + dev_dbgerr("icm20602 validate config failed\n"); + return -MPU_FAIL; + } + + /* turn on gyro and accel */ + reg_set_20602.PWR_MGMT_2.reg_u.reg = 0x0; + result |= icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2); + msleep(30); + + /* disable INT */ + reg_set_20602.INT_ENABLE.reg_u.reg = 0x0; + result |= icm20602_write_reg_simple(st, reg_set_20602.INT_ENABLE); + + /* disbale FIFO */ + reg_set_20602.FIFO_EN.reg_u.reg = 0x0; + result |= icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN); + + /* reset FIFO */ + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1; + result |= icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL); + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + msleep(30); + + /* init gyro and accel */ + if (icm20602_initialize_gyro(st)) { + dev_dbgerr("icm20602 init device failed\n"); + return -MPU_FAIL; + } + + /* if FIFO enable, config FIFO */ + if (config->fifo_enabled) { + if (icm20602_config_fifo(st)) { + dev_dbgerr("icm20602 init config fifo failed\n"); + return -MPU_FAIL; + } + } else { + /* enable interrupt */ + reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0; + if (icm20602_write_reg_simple(st, + reg_set_20602.INT_ENABLE)) { + dev_dbgerr("icm20602 set raw rdy failed\n"); + return -MPU_FAIL; + } + } + + /* buffer malloc */ + package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE; + + st->buf = kmalloc(config->fifo_waterlevel * 2, GFP_ATOMIC); + memset(st->buf, 0, config->fifo_waterlevel * 2); + + st->data_push = kmalloc_array(package_count, + sizeof(struct struct_icm20602_data), GFP_ATOMIC); + memset(st->data_push, + 0, (sizeof(struct struct_icm20602_data)*package_count)); + + return result; +} + +int icm20602_rw_test(struct inv_icm20602_state *st) +{ + u8 val = 0; + + reg_set_20602.PWR_MGMT_2.reg_u.REG.STBY_ZG = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2); + reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.CONFIG); + + icm20602_read_reg(st, reg_set_20602.PWR_MGMT_2.address, &val); + icm20602_read_reg(st, reg_set_20602.CONFIG.address, &val); + + return 0; +} + +int icm20602_detect(struct inv_icm20602_state *st) +{ + int result = MPU_SUCCESS; + uint8_t retry = 0, val = 0; + uint8_t usr_ctrl = 0; + + dev_dbginfo("icm20602_detect\n"); + /* reset to make sure previous state are not there */ + reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x1; + result = icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_1); + if (result) { + dev_dbgerr("mpu write reg 0x%x value 0x%x failed\n", + reg_set_20602.PWR_MGMT_1.reg_u.reg, + reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET); + return result; + } + reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x0; + + /* the power up delay */ + msleep(30); + + /* out of sleep */ + result = icm20602_set_power_itg(st, true); + if (result) + return result; + /* get who am i register */ + while (retry < 10) { + /* get version (expecting 0x12 for the icm20602) */ + icm20602_read_reg(st, reg_set_20602.WHO_AM_I.address, &val); + if (val == ICM20602_WHO_AM_I) + break; + retry++; + } + + if (val != ICM20602_WHO_AM_I) { + dev_dbgerr("detect mpu failed,whoami reg 0x%x\n", val); + result = -MPU_FAIL; + } else { + dev_dbginfo("detect mpu ok,whoami reg 0x%x\n", val); + } + icm20602_rw_test(st); + + return result; +} diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h new file mode 100644 index 0000000000000000000000000000000000000000..17f9882c620fff35cdacb3e88546db1e528f4486 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h @@ -0,0 +1,978 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +/* register high bit=1 for read */ +#define ICM20602_READ_REG(reg) (reg | 0x80) + +/* register high bit=0 for write */ +#define ICM20602_WRITE_REG(reg) (reg & (~0x80)) +#define ICM20602_WHO_AM_I 0x12 +#define ICM20602_INTERNAL_SAMPLE_RATE_HZ 1000 + +#define SELFTEST_COUNT 200 +#define ST_PRECISION 1000 +#define ACC_ST_SHIFT_MAX 150 +#define ACC_ST_SHIFT_MIN 50 +#define ACC_ST_AL_MIN 225 +#define ACC_ST_AL_MAX 675 +#define GYRO_ST_SHIFT 50 +#define GYRO_ST_AL 60 +#define GYRO_OFFSET_MAX 20 + +static const uint16_t mpu_st_tb[256] = { + 2620, 2646, 2672, 2699, 2726, 2753, 2781, 2808, + 2837, 2865, 2894, 2923, 2952, 2981, 3011, 3041, + 3072, 3102, 3133, 3165, 3196, 3228, 3261, 3293, + 3326, 3359, 3393, 3427, 3461, 3496, 3531, 3566, + 3602, 3638, 3674, 3711, 3748, 3786, 3823, 3862, + 3900, 3939, 3979, 4019, 4059, 4099, 4140, 4182, + 4224, 4266, 4308, 4352, 4395, 4439, 4483, 4528, + 4574, 4619, 4665, 4712, 4759, 4807, 4855, 4903, + 4953, 5002, 5052, 5103, 5154, 5205, 5257, 5310, + 5363, 5417, 5471, 5525, 5581, 5636, 5693, 5750, + 5807, 5865, 5924, 5983, 6043, 6104, 6165, 6226, + 6289, 6351, 6415, 6479, 6544, 6609, 6675, 6742, + 6810, 6878, 6946, 7016, 7086, 7157, 7229, 7301, + 7374, 7448, 7522, 7597, 7673, 7750, 7828, 7906, + 7985, 8065, 8145, 8227, 8309, 8392, 8476, 8561, + 8647, 8733, 8820, 8909, 8998, 9088, 9178, 9270, + 9363, 9457, 9551, 9647, 9743, 9841, 9939, 10038, + 10139, 10240, 10343, 10446, 10550, 10656, 10763, 10870, + 10979, 11089, 11200, 11312, 11425, 11539, 11654, 11771, + 11889, 12008, 12128, 12249, 12371, 12495, 12620, 12746, + 12874, 13002, 13132, 13264, 13396, 13530, 13666, 13802, + 13940, 14080, 14221, 14363, 14506, 14652, 14798, 14946, + 15096, 15247, 15399, 15553, 15709, 15866, 16024, 16184, + 16346, 16510, 16675, 16842, 17010, 17180, 17352, 17526, + 17701, 17878, 18057, 18237, 18420, 18604, 18790, 18978, + 19167, 19359, 19553, 19748, 19946, 20145, 20347, 20550, + 20756, 20963, 21173, 21385, 21598, 21814, 22033, 22253, + 22475, 22700, 22927, 23156, 23388, 23622, 23858, 24097, + 24338, 24581, 24827, 25075, 25326, 25579, 25835, 26093, + 26354, 26618, 26884, 27153, 27424, 27699, 27976, 28255, + 28538, 28823, 29112, 29403, 29697, 29994, 30294, 30597, + 30903, 31212, 31524, 31839, 32157, 32479, 32804 +}; + +enum inv_icm20602_reg_addr { + ADDR_XG_OFFS_TC_H = 0x04, + ADDR_XG_OFFS_TC_L, + ADDR_YG_OFFS_TC_H = 0x07, + ADDR_YG_OFFS_TC_L, + ADDR_ZG_OFFS_TC_H = 0x0A, + ADDR_ZG_OFFS_TC_L, + + ADDR_SELF_TEST_X_ACCEL = 0x0D, + ADDR_SELF_TEST_Y_ACCEL, + ADDR_SELF_TEST_Z_ACCEL, + + ADDR_XG_OFFS_USRH = 0x13, + ADDR_XG_OFFS_USRL, + ADDR_YG_OFFS_USRH, + ADDR_YG_OFFS_USRL, + ADDR_ZG_OFFS_USRH, + ADDR_ZG_OFFS_USRL, + + ADDR_SMPLRT_DIV, + ADDR_CONFIG, + + ADDR_GYRO_CONFIG, + + ADDR_ACCEL_CONFIG, + ADDR_ACCEL_CONFIG2, + + ADDR_LP_MODE_CFG, + + ADDR_ACCEL_WOM_X_THR = 0x20, + ADDR_ACCEL_WOM_Y_THR, + ADDR_ACCEL_WOM_Z_THR, + ADDR_FIFO_EN, + + ADDR_FSYNC_INT = 0x36, + ADDR_INT_PIN_CFG, + ADDR_INT_ENABLE, + ADDR_FIFO_WM_INT_STATUS, + ADDR_INT_STATUS, + + ADDR_ACCEL_XOUT_H, + ADDR_ACCEL_XOUT_L, + ADDR_ACCEL_YOUT_H, + ADDR_ACCEL_YOUT_L, + ADDR_ACCEL_ZOUT_H, + ADDR_ACCEL_ZOUT_L, + + ADDR_TEMP_OUT_H, + ADDR_TEMP_OUT_L, + + ADDR_GYRO_XOUT_H, + ADDR_GYRO_XOUT_L, + ADDR_GYRO_YOUT_H, + ADDR_GYRO_YOUT_L, + ADDR_GYRO_ZOUT_H, + ADDR_GYRO_ZOUT_L, + + ADDR_SELF_TEST_X_GYRO = 0x50, + ADDR_SELF_TEST_Y_GYRO, + ADDR_SELF_TEST_Z_GYRO, + + ADDR_FIFO_WM_TH1 = 0x60, + ADDR_FIFO_WM_TH2, + + ADDR_SIGNAL_PATH_RESET = 0x68, + ADDR_ACCEL_INTEL_CTRL, + ADDR_USER_CTRL, + + ADDR_PWR_MGMT_1, + ADDR_PWR_MGMT_2, + + ADDR_I2C_IF = 0x70, + + ADDR_FIFO_COUNTH = 0x72, + ADDR_FIFO_COUNTL, + ADDR_FIFO_R_W, + + ADDR_WHO_AM_I, + + ADDR_XA_OFFSET_H, + ADDR_XA_OFFSET_L, + ADDR_YA_OFFSET_H = 0x7A, + ADDR_YA_OFFSET_L, + ADDR_ZA_OFFSET_H = 0x7D, + ADDR_ZA_OFFSET_L +}; + +struct struct_XG_OFFS_TC_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_XG_OFFS_TC_H :2; + u8 REG_XG_OFFS_LP :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XG_OFFS_TC_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_XG_OFFS_TC_L :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_TC_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_YG_OFFS_TC_H :2; + u8 REG_YG_OFFS_LP :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_TC_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_YG_OFFS_TC_L :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_TC_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_ZG_OFFS_TC_H :2; + u8 REG_ZG_OFFS_LP :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_TC_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_ZG_OFFS_TC_L :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_X_ACCEL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XA_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Y_ACCEL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YA_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Z_ACCEL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZA_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XG_OFFS_USRH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 X_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XG_OFFS_USRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 X_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_USRH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Y_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_USRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Y_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_USRH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Z_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_USRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Z_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SMPLRT_DIV { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 SMPLRT_DIV :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_CONFIG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 DLFP_CFG :3; + u8 EXT_SYNC_SET :3; + u8 FIFO_MODE :1; + u8 USER_SET_BIT :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_CONFIG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FCHOICE_B :2; + u8 RESERVE0 :1; + u8 FS_SEL :2; + u8 ZG_ST :1; + u8 YG_ST :1; + u8 XG_ST :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_CONFIG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :3; + u8 ACCEL_FS_SEL :2; + u8 ZG_ST :1; + u8 YG_ST :1; + u8 XG_ST :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_CONFIG2 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 A_DLPF_CFG :3; + u8 ACCEL_FCHOICE_B :1; + u8 DEC2_CFG :2; + u8 RESERVE0 :2; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_LP_MODE_CFG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :4; + u8 G_AVGCFG :3; + u8 GYRO_CYCLE :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_WOM_X_THR { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_X_TH :8; + } REG; + u8 reg; + } reg_u; +}; + + +struct struct_ACCEL_WOM_Y_THR { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_Y_TH :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_WOM_Z_THR { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_Z_TH :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_EN { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE1 :3; + u8 ACCEL_FIFO_EN :1; + u8 GYRO_FIFO_EN :1; + u8 RESERVE0 :3; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FSYNC_INT { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :7; + u8 FSYNC_INT :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_INT_PIN_CFG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :2; + u8 FSYNC_INT_MODE_EN:1; + u8 FSYNC_INT_LEVEL :1; + u8 INT_RD_CLEAR :1; + u8 LATCH_INT_EN :1; + u8 INT_OPEN :1; + u8 INT_LEVEL :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_INT_ENABLE { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 DATA_RDY_INT_EN :1; + u8 RESERVE0 :1; + u8 GDRIVE_INT_EN :1; + u8 FSYNC_INT_EN :1; + u8 FIFO_OFLOW_EN :1; + u8 WOM_Z_INT_EN :1; + u8 WOM_Y_INT_EN :1; + u8 WOM_X_INT_EN :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_WM_INT_STATUS { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE1 :6; + u8 FIFO_WM_INT :1; + u8 RESERVE0 :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_INT_STATUS { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 DATA_RDY_INT :1; + u8 RESERVE1 :1; + u8 GDRIVE_INT :1; + u8 RESERVE0 :1; + u8 FIFO_OFLOW_INT :1; + u8 WOM_Z_INT :1; + u8 WOM_Y_INT :1; + u8 WOM_X_INT :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_XOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_XOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_YOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_YOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_ZOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_ZOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_TEMP_OUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 TEMP_OUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_TEMP_OUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 TEMP_OUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_XOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_XOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_YOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_YOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_ZOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_ZOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_X_GYRO { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XG_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Y_GYRO { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YG_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Z_GYRO { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZG_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_WM_TH1 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :6; + u8 FIFO_WM_TH :2; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_WM_TH2 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_WM_TH :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SIGNAL_PATH_RESET { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 TEMP_RST :1; + u8 ACCEL_RST :1; + u8 FIFO_WM_TH :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_INTEL_CTRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_TH_MODE :1; + u8 OUTPUT_LIMIT :1; + u8 RESERVE0 :4; + u8 ACCEL_INTEL_MODE :1; + u8 ACCEL_INTEL_EN :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_USER_CTRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 SIG_COND_RST :1; + u8 RESERVE2 :1; + u8 FIFO_RST :1; + u8 RESERVE1 :3; + u8 FIFO_EN :1; + u8 RESERVE0 :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_PWR_MGMT_1 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 CLKSEL :3; + u8 TEMP_DIS :1; + u8 GYRO_STANDBY :1; + u8 CYCLE :1; + u8 SLEEP :1; + u8 DEVICE_RESET :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_PWR_MGMT_2 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 STBY_ZG :1; + u8 STBY_YG :1; + u8 STBY_XG :1; + u8 STBY_ZA :1; + u8 STBY_YA :1; + u8 STBY_XA :1; + u8 RESERVE0 :2; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_I2C_IF { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE1 :6; + u8 I2C_IF_DIS :1; + u8 RESERVE0 :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_COUNTH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_COUNT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_COUNTL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_COUNT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_R_W { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_WHO_AM_I { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WHOAMI :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XA_OFFSET_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XA_OFFSET_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YA_OFFSET_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YA_OFFSET_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZA_OFFSET_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZA_OFFSET_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +/* + * struct inv_icm20602_reg_map - Notable registers. + * @sample_rate_div: Divider applied to gyro output rate. + * @lpf: Configures internal low pass filter. + * @user_ctrl: Enables/resets the FIFO. + * @fifo_en: Determines which data will appear in FIFO. + * @gyro_config: gyro config register. + * @accl_config: accel config register + * @fifo_count_h: Upper byte of FIFO count. + * @fifo_r_w: FIFO register. + * @raw_gyro: Address of first gyro register. + * @raw_accl: Address of first accel register. + * @temperature: temperature register + * @int_enable: Interrupt enable register. + * @pwr_mgmt_1: Controls chip's power state and clock source. + * @pwr_mgmt_2: Controls power state of individual sensors. + */ +struct inv_icm20602_reg_map { + struct struct_XG_OFFS_TC_H XG_OFFS_TC_H; + struct struct_XG_OFFS_TC_L XG_OFFS_TC_L; + struct struct_YG_OFFS_TC_H YG_OFFS_TC_H; + struct struct_YG_OFFS_TC_L YG_OFFS_TC_L; + struct struct_ZG_OFFS_TC_H ZG_OFFS_TC_H; + struct struct_ZG_OFFS_TC_L ZG_OFFS_TC_L; + + struct struct_SELF_TEST_X_ACCEL SELF_TEST_X_ACCEL; + struct struct_SELF_TEST_Y_ACCEL SELF_TEST_Y_ACCEL; + struct struct_SELF_TEST_Z_ACCEL SELF_TEST_Z_ACCEL; + + struct struct_XG_OFFS_USRH XG_OFFS_USRH; + struct struct_XG_OFFS_USRL XG_OFFS_USRL; + struct struct_YG_OFFS_USRH YG_OFFS_USRH; + struct struct_YG_OFFS_USRL YG_OFFS_USRL; + struct struct_ZG_OFFS_USRH ZG_OFFS_USRH; + struct struct_ZG_OFFS_USRL ZG_OFFS_USRL; + + struct struct_SMPLRT_DIV SMPLRT_DIV; + struct struct_CONFIG CONFIG; + + struct struct_GYRO_CONFIG GYRO_CONFIG; + + struct struct_ACCEL_CONFIG ACCEL_CONFIG; + struct struct_ACCEL_CONFIG2 ACCEL_CONFIG2; + + struct struct_LP_MODE_CFG LP_MODE_CFG; + + struct struct_ACCEL_WOM_X_THR ACCEL_WOM_X_THR; + struct struct_ACCEL_WOM_Y_THR ACCEL_WOM_Y_THR; + struct struct_ACCEL_WOM_Z_THR ACCEL_WOM_Z_THR; + + struct struct_FIFO_EN FIFO_EN; + struct struct_FSYNC_INT FSYNC_INT; + struct struct_INT_PIN_CFG INT_PIN_CFG; + struct struct_INT_ENABLE INT_ENABLE; + struct struct_FIFO_WM_INT_STATUS FIFO_WM_INT_STATUS; + struct struct_INT_STATUS INT_STATUS; + + struct struct_ACCEL_XOUT_H ACCEL_XOUT_H; + struct struct_ACCEL_XOUT_L ACCEL_XOUT_L; + struct struct_ACCEL_YOUT_H ACCEL_YOUT_H; + struct struct_ACCEL_YOUT_L ACCEL_YOUT_L; + struct struct_ACCEL_ZOUT_H ACCEL_ZOUT_H; + struct struct_ACCEL_ZOUT_L ACCEL_ZOUT_L; + + struct struct_TEMP_OUT_H TEMP_OUT_H; + struct struct_TEMP_OUT_L TEMP_OUT_L; + + struct struct_GYRO_XOUT_H GYRO_XOUT_H; + struct struct_GYRO_XOUT_L GYRO_XOUT_L; + struct struct_GYRO_YOUT_H GYRO_YOUT_H; + struct struct_GYRO_YOUT_L GYRO_YOUT_L; + struct struct_GYRO_ZOUT_H GYRO_ZOUT_H; + struct struct_GYRO_ZOUT_L GYRO_ZOUT_L; + + struct struct_SELF_TEST_X_GYRO SELF_TEST_X_GYRO; + struct struct_SELF_TEST_Y_GYRO SELF_TEST_Y_GYRO; + struct struct_SELF_TEST_Z_GYRO SELF_TEST_Z_GYRO; + struct struct_FIFO_WM_TH1 FIFO_WM_TH1; + struct struct_FIFO_WM_TH2 FIFO_WM_TH2; + struct struct_SIGNAL_PATH_RESET SIGNAL_PATH_RESET; + struct struct_ACCEL_INTEL_CTRL ACCEL_INTEL_CTRL; + struct struct_USER_CTRL USER_CTRL; + + struct struct_PWR_MGMT_1 PWR_MGMT_1; + struct struct_PWR_MGMT_2 PWR_MGMT_2; + + struct struct_I2C_IF I2C_IF; + + struct struct_FIFO_COUNTH FIFO_COUNTH; + struct struct_FIFO_COUNTL FIFO_COUNTL; + struct struct_FIFO_R_W FIFO_R_W; + + struct struct_WHO_AM_I WHO_AM_I; + + struct struct_XA_OFFSET_H XA_OFFSET_H; + struct struct_XA_OFFSET_L XA_OFFSET_L; + struct struct_YA_OFFSET_H YA_OFFSET_H; + struct struct_YA_OFFSET_L YA_OFFSET_L; + struct struct_ZA_OFFSET_H ZA_OFFSET_H; + struct struct_ZA_OFFSET_L ZA_OFFSET_L; +}; + + diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c new file mode 100644 index 0000000000000000000000000000000000000000..878ac2a33477297d62fd94eb93935d36d9d180d2 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm20602_iio.h" +int icm20602_debug_enable = 1; + +/* Attribute of icm20602 device init */ +static ssize_t inv_icm20602_init_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return MPU_SUCCESS; +} + +static int inv_icm20602_def_config(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = st->config; + + config->user_fps_in_ms = 10; + config->gyro_lpf = INV_ICM20602_GYRO_LFP_92HZ; + config->gyro_fsr = ICM20602_GYRO_FSR_1000DPS; + config->acc_lpf = ICM20602_ACCLFP_99; + config->acc_fsr = ICM20602_ACC_FSR_4G; + config->gyro_accel_sample_rate = ICM20602_SAMPLE_RATE_100HZ; + config->fifo_enabled = true; +} + +static int inv_icm20602_load_config(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = st->config; + + if (config->user_fps_in_ms == 0) + inv_icm20602_def_config(st); + config->fifo_enabled = true; + + return MPU_SUCCESS; +} + +static ssize_t inv_icm20602_init_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int enum_config = 0; + int result = MPU_SUCCESS; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + inv_icm20602_load_config(st); + result |= icm20602_detect(st); + result |= icm20602_init_device(st); + icm20602_start_fifo(st); + if (result) + dev_dbgerr("inv_select_config_store failed\n"); + + return count; +} + +static IIO_DEVICE_ATTR( + inv_icm20602_init, + S_IRUGO | S_IWUSR, + inv_icm20602_init_show, + inv_icm20602_init_store, + 0); + +/* Attribute of gyro lpf base on enum inv_icm20602_gyro_temp_lpf_e */ +static int inv_gyro_lpf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return config->gyro_lpf; +} + +static int inv_gyro_lpf_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int gyro_lpf; + + if (kstrtoint(buf, 10, &gyro_lpf)) + return -EINVAL; + if (gyro_lpf > INV_ICM20602_GYRO_LFP_NUM) + return -EINVAL; + config->gyro_lpf = gyro_lpf; + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_gyro_lpf, + S_IRUGO | S_IWUSR, + inv_gyro_lpf_show, + inv_gyro_lpf_store, + 0); + +/* Attribute of gyro fsr base on enum inv_icm20602_gyro_temp_lpf_e */ +static int inv_gyro_fsr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return config->gyro_fsr; +} + +static int inv_gyro_fsr_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int gyro_fsr; + + if (kstrtoint(buf, 10, &gyro_fsr)) + return -EINVAL; + if (gyro_fsr > ICM20602_GYRO_FSR_NUM) + return -EINVAL; + + config->gyro_fsr = gyro_fsr; + return count; +} + +static IIO_DEVICE_ATTR( + inv_icm20602_gyro_fsr, + S_IRUGO | S_IWUSR, + inv_gyro_fsr_show, + inv_gyro_fsr_store, + 0); + +/* Attribute of gyro_self_test */ +static int inv_gyro_self_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return 0; +} + +static int inv_gyro_self_test_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_gyro_self_test, + S_IRUGO | S_IWUSR, + inv_gyro_self_test_show, + inv_gyro_self_test_store, + 0); + +/* Attribute of gyro fsr base on enum inv_icm20602_acc_fsr_e */ +static int inv_gyro_acc_fsr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return config->acc_fsr; +} + +static int inv_gyro_acc_fsr_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int acc_fsr; + + if (kstrtoint(buf, 10, &acc_fsr)) + return -EINVAL; + if (acc_fsr > ICM20602_ACC_FSR_NUM) + return -EINVAL; + + config->acc_fsr = acc_fsr; + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_acc_fsr, + S_IRUGO | S_IWUSR, + inv_gyro_acc_fsr_show, + inv_gyro_acc_fsr_store, + 0); + +/* Attribute of gyro fsr base on enum inv_icm20602_acc_lpf_e */ +static int inv_gyro_acc_lpf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return config->acc_lpf; +} + +static int inv_gyro_acc_lpf_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int acc_lpf; + + if (kstrtoint(buf, 10, &acc_lpf)) + return -EINVAL; + if (acc_lpf > ICM20602_ACCLPF_NUM) + return -EINVAL; + + config->acc_fsr = acc_lpf; + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_acc_lpf, + S_IRUGO | S_IWUSR, + inv_gyro_acc_lpf_show, + inv_gyro_acc_lpf_store, + 0); + +/* Attribute of acc_self_test */ +static int inv_acc_self_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return 0; +} + +static int inv_acc_self_test_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_acc_self_test, + S_IRUGO | S_IWUSR, + inv_acc_self_test_show, + inv_acc_self_test_store, + 0); + +/* Attribute of user_fps_in_ms */ +static int inv_user_fps_in_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return config->user_fps_in_ms; +} + +static int inv_user_fps_in_ms_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int user_fps_in_ms; + + if (kstrtoint(buf, 10, &user_fps_in_ms)) + return -EINVAL; + if (user_fps_in_ms < 10) + return -EINVAL; + + config->user_fps_in_ms = user_fps_in_ms; + return count; +} +static IIO_DEVICE_ATTR( + inv_user_fps_in_ms, + S_IRUGO | S_IWUSR, + inv_user_fps_in_ms_show, + inv_user_fps_in_ms_store, + 0); + +/* Attribute of gyro_accel_sample_rate */ +static int inv_sampling_frequency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return config->gyro_accel_sample_rate; +} + +static int inv_sampling_frequency_store(struct device *dev, + struct device_attribute *attr, char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + + return count; +} +static IIO_DEV_ATTR_SAMP_FREQ( + S_IRUGO | S_IWUSR, + inv_sampling_frequency_show, + inv_sampling_frequency_store); + +static struct attribute *inv_icm20602_attributes[] = { + &iio_dev_attr_inv_icm20602_init.dev_attr.attr, + + &iio_dev_attr_inv_icm20602_gyro_self_test.dev_attr.attr, + &iio_dev_attr_inv_icm20602_gyro_fsr.dev_attr.attr, + &iio_dev_attr_inv_icm20602_gyro_lpf.dev_attr.attr, + + &iio_dev_attr_inv_icm20602_acc_self_test.dev_attr.attr, + &iio_dev_attr_inv_icm20602_acc_fsr.dev_attr.attr, + &iio_dev_attr_inv_icm20602_acc_lpf.dev_attr.attr, + + &iio_dev_attr_sampling_frequency.dev_attr.attr, + + &iio_dev_attr_inv_user_fps_in_ms.dev_attr.attr, + NULL, +}; + +#define INV_ICM20602_CHAN(_type, _channel2, _index) \ +{ \ + .type = _type, \ + .modified = 1, \ + .channel2 = _channel2, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .shift = 0 , \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec inv_icm20602_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP), + + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_OFFSET) + | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = INV_ICM20602_SCAN_TEMP, + .channel2 = IIO_MOD_X, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .shift = 0, + .endianness = IIO_BE, + }, + }, + INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_ICM20602_SCAN_GYRO_X), + INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_ICM20602_SCAN_GYRO_Y), + INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_ICM20602_SCAN_GYRO_Z), + + INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_X, INV_ICM20602_SCAN_ACCL_X), + INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_ICM20602_SCAN_ACCL_Y), + INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_ICM20602_SCAN_ACCL_Z), +}; + +static const struct attribute_group inv_icm20602_attribute_group = { + .attrs = inv_icm20602_attributes +}; + +static const struct iio_info icm20602_info = { + .driver_module = THIS_MODULE, + .read_raw = &icm20602_read_raw, + .write_raw = NULL, + .attrs = &inv_icm20602_attribute_group, + .validate_trigger = inv_icm20602_validate_trigger, +}; + +static int of_populate_icm20602_dt(struct inv_icm20602_state *st) +{ + int result = MPU_SUCCESS; + + /* use client device irq */ + st->gpio = of_get_named_gpio(st->client->dev.of_node, + "invn,icm20602-irq", 0); + result = gpio_is_valid(st->gpio); + if (!result) { + dev_dbgerr("gpio_is_valid %d failed\n", st->gpio); + return -MPU_FAIL; + } + + result = gpio_request(st->gpio, "icm20602-irq"); + if (result) { + dev_dbgerr("gpio_request failed\n"); + return -MPU_FAIL; + } + + result = gpio_direction_input(st->gpio); + if (result) { + dev_dbgerr("gpio_direction_input failed\n"); + return -MPU_FAIL; + } + + st->client->irq = gpio_to_irq(st->gpio); + if (st->client->irq < 0) { + dev_dbgerr("gpio_to_irq failed\n"); + return -MPU_FAIL; + } + + return MPU_SUCCESS; +} + +/* + * inv_icm20602_probe() - probe function. + * @client: i2c client. + * @id: i2c device id. + * + * Returns 0 on success, a negative error code otherwise. + * The I2C address of the ICM-20602 is 0x68 or 0x69 + * depending upon the value driven on AD0 pin. + */ +static int inv_icm20602_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct inv_icm20602_state *st; + struct iio_dev *indio_dev; + int result = MPU_SUCCESS; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (indio_dev == NULL) { + result = -ENOMEM; + dev_dbgerr("alloc iio device failed\n"); + goto out_remove_trigger; + } + st = iio_priv(indio_dev); + st->client = client; + st->interface = ICM20602_I2C; + + dev_dbginfo("i2c address is %x\n", client->addr); + result = of_populate_icm20602_dt(st); + if (result) + dev_dbgerr("populate dt failed\n"); + + st->config = kmalloc(sizeof(struct icm20602_user_config), GFP_ATOMIC); + memset(st->config, 0, sizeof(struct icm20602_user_config)); + icm20602_init_reg_map(); + + i2c_set_clientdata(&client->dev, indio_dev); + + dev_set_drvdata(&client->dev, indio_dev); + indio_dev->dev.parent = &client->dev; + indio_dev->name = ICM20602_DEV_NAME; + indio_dev->channels = inv_icm20602_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels); + + indio_dev->info = &icm20602_info; + indio_dev->modes = INDIO_BUFFER_TRIGGERED; + result = iio_triggered_buffer_setup(indio_dev, + inv_icm20602_irq_handler, inv_icm20602_read_fifo_fn, NULL); + if (result) { + dev_err(&st->client->dev, " configure buffer fail %d\n", + result); + goto out_remove_trigger; + } + + result = inv_icm20602_probe_trigger(indio_dev); + if (result) { + dev_err(&st->client->dev, "trigger probe fail %d\n", result); + goto out_unreg_ring; + } + + INIT_KFIFO(st->timestamps); + spin_lock_init(&st->time_stamp_lock); + result = iio_device_register(indio_dev); + if (result) { + dev_err(&st->client->dev, "IIO register fail %d\n", result); + goto out_remove_trigger; + } + + return 0; + +out_remove_trigger: + inv_icm20602_remove_trigger(st); +out_unreg_ring: + iio_triggered_buffer_cleanup(indio_dev); +out_free: + iio_device_free(indio_dev); + gpio_free(st->gpio); + + return 0; +} + +static int inv_icm20602_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + gpio_free(st->gpio); + iio_device_unregister(indio_dev); + inv_icm20602_remove_trigger(st); + iio_triggered_buffer_cleanup(indio_dev); + iio_device_free(indio_dev); + + return 0; +} + +#ifdef CONFIG_PM +static int inv_icm20602_suspend(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return 0; +} + +static int inv_icm20602_resume(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return 0; +} +#else +#define inv_icm20602_suspend NULL +#define inv_icm20602_resume NULL +#endif + +static struct of_device_id icm20602_match_table[] = { + {.compatible = "invn,icm20602"}, + {} +}; +MODULE_DEVICE_TABLE(of, icm20602_match_table); + +static const struct i2c_device_id inv_icm20602_id[] = { + {"icm20602", 0}, + {} +}; + +static struct i2c_driver icm20602_i2c_driver = { + .probe = inv_icm20602_probe, + .remove = inv_icm20602_remove, + .id_table = inv_icm20602_id, + .suspend = inv_icm20602_suspend, + .resume = inv_icm20602_resume, + .driver = { + .owner = THIS_MODULE, + .name = "inv-icm20602", + .of_match_table = icm20602_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = NULL, + }, +}; + +static int __init inv_icm20602_init(void) +{ + return i2c_add_driver(&icm20602_i2c_driver); +} +module_init(inv_icm20602_init); + +static void __exit inv_icm20602_exit(void) +{ + i2c_del_driver(&icm20602_i2c_driver); +} +module_exit(inv_icm20602_exit); + +MODULE_DESCRIPTION("icm20602 IMU driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h new file mode 100644 index 0000000000000000000000000000000000000000..f8b149b7869a71ff6a4dcdeb1fd58f762f8916cf --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +#ifndef _INV_ICM20602_IIO_H_ +#define _INV_ICM20602_IIO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * it uses sensor irq to trigger + * if set INV20602_DEVICE_IRQ_TRIGGER as 1, + * otherwise use SMD IRQ to trigger + */ +#define INV20602_DEVICE_IRQ_TRIGGER 0 +extern int icm20602_debug_enable; + +#if INV20602_DEVICE_IRQ_TRIGGER +#define INV20602_SMD_IRQ_TRIGGER 0 +#else +#define INV20602_SMD_IRQ_TRIGGER 1 +#endif + + +#define dev_dbginfo(fmt, ...) \ + do { \ + if (icm20602_debug_enable > 0) { \ + printk(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define dev_dbgerr(fmt, ...) printk(fmt, ##__VA_ARGS__) +#define INV_ICM20602_TIME_STAMP_TOR 5 +#define ICM20602_PACKAGE_SIZE 14 + +/* device enum */ +enum inv_devices { + INV_ICM20602, + INV_NUM_PARTS +}; + +enum _mpu_err { + MPU_SUCCESS = 0, + MPU_FAIL = 1, + MPU_READ_FAIL = 2, + MPU_WRITE_FAIL = 3, +}; + +/* Gyro Full Scale Range Enum */ +enum inv_icm20602_gyro_fsr_e { + ICM20602_GYRO_FSR_250DPS = 0, + ICM20602_GYRO_FSR_500DPS, + ICM20602_GYRO_FSR_1000DPS, + ICM20602_GYRO_FSR_2000DPS, + ICM20602_GYRO_FSR_NUM +}; + +/* Accelerometor Full Scale Range Enum */ +enum inv_icm20602_acc_fsr_e { + ICM20602_ACC_FSR_2G = 0, + ICM20602_ACC_FSR_4G, + ICM20602_ACC_FSR_8G, + ICM20602_ACC_FSR_16G, + ICM20602_ACC_FSR_NUM +}; + +/* scan element definition */ +enum inv_icm20602_scan { + INV_ICM20602_SCAN_ACCL_X, + INV_ICM20602_SCAN_ACCL_Y, + INV_ICM20602_SCAN_ACCL_Z, + INV_ICM20602_SCAN_GYRO_X, + INV_ICM20602_SCAN_GYRO_Y, + INV_ICM20602_SCAN_GYRO_Z, + INV_ICM20602_SCAN_TEMP, + INV_ICM20602_SCAN_TIMESTAMP, +}; + +/* this is for CONFIGURATION reg bit[2:0] DLFP_CFG */ +enum inv_icm20602_gyro_temp_lpf_e { + INV_ICM20602_GLFP_250HZ = 0, /* 8KHz */ + INV_ICM20602_GYRO_LFP_176HZ, /* 1KHz */ + INV_ICM20602_GYRO_LFP_92HZ, + INV_ICM20602_GYRO_LFP_41HZ, + INV_ICM20602_GYRO_LFP_20HZ, + INV_ICM20602_GYRO_LFP_10HZ, + INV_ICM20602_GYRO_LFP_5HZ, + INV_ICM20602_GYRO_LFP_NUM, +}; + +enum inv_icm20602_gyro_sample_rate_e { + ICM20602_SAMPLE_RATE_100HZ = 100, + ICM20602_SAMPLE_RATE_200HZ = 200, + ICM20602_SAMPLE_RATE_500HZ = 500, + ICM20602_SAMPLE_RATE_1000HZ = 1000 +}; + +/* this is for ACCEL CONFIGURATION 2 reg */ +enum inv_icm20602_acc_lpf_e { + ICM20602_ACCLFP_218 = 1, + ICM20602_ACCLFP_99, + ICM20602_ACCLFP_44, + ICM20602_ACCLFP_21, + ICM20602_ACCLFP_10, + ICM20602_ACCLFP_5, + ICM20602_ACCLFP_420_NOLPF, + ICM20602_ACCLPF_NUM = 7 +}; + +/* IIO attribute address */ +enum INV_ICM20602_IIO_ATTR_ADDR { + ATTR_ICM20602_GYRO_MATRIX, + ATTR_ICM20602_ACCL_MATRIX, +}; + +/* this is for GYRO CONFIGURATION reg */ +enum inv_icm20602_fs_e { + INV_ICM20602_FS_250DPS = 0, + INV_ICM20602_FS_500DPS, + INV_ICM20602_FS_1000DPS, + INV_ICM20602_FS_2000DPS, + NUM_ICM20602_FS +}; + +enum inv_icm20602_clock_sel_e { + INV_ICM20602_CLK_INTERNAL = 0, + INV_ICM20602_CLK_PLL, + INV_NUM_CLK +}; + +enum inv_icm20602_spi_freq { + MPU_SPI_FREQUENCY_1MHZ = 960000UL, + MPU_SPI_FREQUENCY_5MHZ = 4800000UL, + MPU_SPI_FREQUENCY_8MHZ = 8000000UL, + MPU_SPI_FREQUENCY_10MHZ = 10000000UL, + MPU_SPI_FREQUENCY_15MHZ = 15000000UL, + MPU_SPI_FREQUENCY_20MHZ = 20000000UL, +}; + +#define MPU_SPI_BUF_LEN 512 +#define ICM20602_DEV_NAME "icm20602_iio" + +struct inv_icm20602_platform_data { + __s8 orientation[9]; +}; + +struct X_Y_Z { + u32 X; + u32 Y; + u32 Z; +}; + +enum RAW_TYPE { + ACCEL = 1, + GYRO = 2, + TEMP = 4, +}; + +struct icm20602_user_config { + enum inv_icm20602_gyro_temp_lpf_e gyro_lpf; + enum inv_icm20602_gyro_fsr_e gyro_fsr; + struct X_Y_Z gyro_self_test; + + enum inv_icm20602_acc_lpf_e acc_lpf; + enum inv_icm20602_acc_fsr_e acc_fsr; + struct X_Y_Z acc_self_test; + + uint32_t gyro_accel_sample_rate; + uint32_t user_fps_in_ms; + + bool fifo_enabled; + uint32_t fifo_waterlevel; + struct X_Y_Z wake_on_motion; +}; + +enum inv_icm20602_interface { + ICM20602_I2C = 0, + ICM20602_SPI +}; + +/* + * struct inv_icm20602_state - Driver state variables. + * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp. + * @trig: IIO trigger. + * @chip_config: Cached attribute information. + * @reg: Map of important registers. + * @hw: Other hardware-specific information. + * @chip_type: chip type. + * @time_stamp_lock: spin lock to time stamp. + * @spi: spi devices + * @plat_data: platform data. + * @timestamps: kfifo queue to store time stamp. + */ +struct inv_icm20602_state { +#define TIMESTAMP_FIFO_SIZE 32 + enum inv_icm20602_interface interface; + struct iio_trigger *trig; + const struct inv_icm20602_reg_map *reg; + struct icm20602_user_config *config; + spinlock_t time_stamp_lock; + struct spi_device *spi; + struct i2c_client *client; + u8 fifo_packet_size; + int fifo_cnt_threshold; + char *buf; + struct struct_icm20602_data *data_push; + enum inv_devices chip_type; + int gpio; + DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); +}; + +struct struct_icm20602_raw_data { + u8 ACCEL_XOUT_H; + u8 ACCEL_XOUT_L; + + u8 ACCEL_YOUT_H; + u8 ACCEL_YOUT_L; + + u8 ACCEL_ZOUT_H; + u8 ACCEL_ZOUT_L; + + u8 TEMP_OUT_H; + u8 TEMP_OUT_L; + + u8 GYRO_XOUT_H; + u8 GYRO_XOUT_L; + + u8 GYRO_YOUT_H; + u8 GYRO_YOUT_L; + + u8 GYRO_ZOUT_H; + u8 GYRO_ZOUT_L; +}; + +struct struct_icm20602_real_data { + u16 ACCEL_XOUT; + u16 ACCEL_YOUT; + u16 ACCEL_ZOUT; + + u16 GYRO_XOUT; + u16 GYRO_YOUT; + u16 GYRO_ZOUT; + + u16 TEMP_OUT; +}; + +struct struct_icm20602_data { + s64 timestamps; + struct struct_icm20602_raw_data raw_data; + struct struct_icm20602_real_data real_data; +}; + +extern struct iio_trigger *inv_trig; +irqreturn_t inv_icm20602_irq_handler(int irq, void *p); +irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p); +int inv_icm20602_reset_fifo(struct iio_dev *indio_dev); + +int inv_icm20602_probe_trigger(struct iio_dev *indio_dev); +void inv_icm20602_remove_trigger(struct inv_icm20602_state *st); +int inv_icm20602_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig); + +int icm20602_read_raw(struct inv_icm20602_state *st, + struct struct_icm20602_real_data *real_data, u8 type); + +int icm20602_init_reg_map(void); +int icm20602_init_device(struct inv_icm20602_state *st); +int icm20602_detect(struct inv_icm20602_state *st); +int icm20602_read_fifo(struct inv_icm20602_state *st, + void *buf, const int size); +int icm20602_start_fifo(struct inv_icm20602_state *st); +#endif diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c new file mode 100644 index 0000000000000000000000000000000000000000..d7d0bbd126d7d3a0d2fc4fda46985fe32f055157 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c @@ -0,0 +1,129 @@ +/* +* Copyright (c) 2018, The Linux Foundation. All rights reserved. +* +* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_icm20602_iio.h" +#include + +#define combine_8_to_16(upper, lower) ((_upper << 8) | _lower) + +static void inv_clear_kfifo(struct inv_icm20602_state *st) +{ + unsigned long flags; + + /* take the spin lock sem to avoid interrupt kick in */ + spin_lock_irqsave(&st->time_stamp_lock, flags); + kfifo_reset(&st->timestamps); + spin_unlock_irqrestore(&st->time_stamp_lock, flags); +} + +int inv_icm20602_reset_fifo(struct iio_dev *indio_dev) +{ + int result; + u8 d; + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return result; +} + +/* + * inv_icm20602_irq_handler() - Cache a timestamp at each data ready interrupt. + */ +irqreturn_t inv_icm20602_irq_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct inv_icm20602_state *st = iio_priv(indio_dev); + s64 timestamp; + + timestamp = iio_get_time_ns(); + + kfifo_in_spinlocked(&st->timestamps, ×tamp, 1, + &st->time_stamp_lock); + + return IRQ_WAKE_THREAD; +} + +static int inv_icm20602_read_data(struct iio_dev *indio_dev) +{ + int result = MPU_SUCCESS; + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int package_count; + char *buf = st->buf; + struct struct_icm20602_data *data_push = st->data_push; + s64 timestamp; + int i; + + if (!st) + return -MPU_FAIL; + package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE; + mutex_lock(&indio_dev->mlock); + if (config->fifo_enabled) { + result = icm20602_read_fifo(st, + st->buf, config->fifo_waterlevel); + if (result != config->fifo_waterlevel) { + dev_dbgerr("icm20602 read fifo failed, result = %d\n", + result); + goto flush_fifo; + } + + for (i = 0; i < package_count; i++) { + memcpy((char *)(&st->data_push[i].raw_data), + st->buf, ICM20602_PACKAGE_SIZE); + result = kfifo_out(&st->timestamps, + ×tamp, 1); + /* when there is no timestamp, put it as 0 */ + if (0 == result) + timestamp = 0; + st->data_push[i].timestamps = timestamp; + iio_push_to_buffers(indio_dev, st->data_push+i); + st->buf += ICM20602_PACKAGE_SIZE; + } + } +end_session: + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + return MPU_SUCCESS; + +flush_fifo: + /* Flush HW and SW FIFOs. */ + inv_clear_kfifo(st); + inv_icm20602_reset_fifo(indio_dev); + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + return MPU_SUCCESS; +} + +/* + * inv_icm20602_read_fifo() - Transfer data from hardware FIFO to KFIFO. + */ +irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + + inv_icm20602_read_data(indio_dev); + return IRQ_HANDLED; +} diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c new file mode 100644 index 0000000000000000000000000000000000000000..298015b0e93ee9315f6dd2b95d1d346fbb5d1d5c --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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 +#include +#include +#include "inv_icm20602_iio.h" +#include + +static const struct iio_trigger_ops inv_icm20602_trigger_ops = { + .owner = THIS_MODULE, +}; + +int inv_icm20602_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct inv_icm20602_state *st = iio_priv(indio_dev); + + if (st->trig != trig) + return -EINVAL; + + return MPU_SUCCESS; +} + +int inv_icm20602_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct inv_icm20602_state *st = iio_priv(indio_dev); + + st->trig = iio_trigger_alloc("%s-dev%d", + indio_dev->name, + indio_dev->id); + if (st->trig == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, + "inv_icm20602", + st->trig); + if (ret) { + dev_dbgerr("request_irq\n"); + goto error_free_trig; + } + st->trig->dev.parent = &st->client->dev; + st->trig->ops = &inv_icm20602_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = iio_trigger_register(st->trig); + if (ret) { + dev_dbgerr("iio_trigger_register\n"); + goto error_free_irq; + } + indio_dev->trig = st->trig; + + return 0; + +error_free_irq: + free_irq(st->client->irq, st->trig); +error_free_trig: + iio_trigger_free(st->trig); +error_ret: + return ret; +} + +void inv_icm20602_remove_trigger(struct inv_icm20602_state *st) +{ + iio_trigger_unregister(st->trig); + free_irq(st->client->irq, st->trig); + iio_trigger_free(st->trig); +} diff --git a/drivers/iio/imu/inv_mpu/Kconfig b/drivers/iio/imu/inv_mpu/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..d729e3a9bd590b04b3675261e8e71906c6120ea6 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/Kconfig @@ -0,0 +1,70 @@ +# +# inv-mpu-iio driver for Invensense MPU devices +# + +config INV_MPU_IIO + tristate + select IIO_BUFFER + select IIO_KFIFO_BUF + select IIO_TRIGGER + select CRC32 + +choice + prompt "Chip name" + depends on INV_MPU_IIO + +config INV_MPU_IIO_ICM20648 + bool "ICM20648/ICM20948" + help + Select this if you are using a ICM20648/ICM20948 chip. + +config INV_MPU_IIO_ICM20608D + bool "ICM20608D/ICM20609/ICM20689" + help + Select this if you are using a ICM20608D/ICM20609/ICM20689 chip. + +config INV_MPU_IIO_ICM20602 + bool "ICM20602" + help + Select this if you are using a ICM20602 chip. + +config INV_MPU_IIO_ICM20690 + bool "ICM20690" + help + Select this if you are using a ICM20690 chip. + +config INV_MPU_IIO_IAM20680 + bool "IAM20680" + help + Select this if you are using a IAM20680 chip. + +endchoice + +config INV_MPU_IIO_I2C + tristate "Invensense ICM20xxx devices (I2C)" + depends on I2C && !INV_MPU6050_IIO + select INV_MPU_IIO + default n + help + This driver supports Invensense ICM20xxx devices over I2C. + This driver can be built as a module. The module will be called + inv-mpu-iio-i2c. + +config INV_MPU_IIO_SPI + tristate "Invensense ICM20xxx devices (SPI)" + depends on SPI_MASTER && !INV_MPU6050_IIO + select INV_MPU_IIO + default n + help + This driver supports Invensense ICM20xxx devices over SPI. + This driver can be built as a module. The module will be called + inv-mpu-iio-spi. + +config ENABLE_IAM_ACC_GYRO_BUFFERING + bool "Enable accel & gyro boot time sensor sample buffering" + depends on INV_MPU_IIO + help + Say Y here if you want to buffer boot time sensor + samples for IAM20680 accelerometer and gyroscope + +source "drivers/iio/imu/inv_mpu/inv_test/Kconfig" diff --git a/drivers/iio/imu/inv_mpu/Makefile b/drivers/iio/imu/inv_mpu/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dfc4c257ef735b5db457cc4452f5f049d047351a --- /dev/null +++ b/drivers/iio/imu/inv_mpu/Makefile @@ -0,0 +1,61 @@ +# +# Makefile for Invensense inv-mpu-iio device. +# + +obj-$(CONFIG_INV_MPU_IIO) += inv-mpu-iio.o + +inv-mpu-iio-objs += inv_mpu_common.o +inv-mpu-iio-objs += inv_mpu_ring.o +inv-mpu-iio-objs += inv_mpu_timestamp.o +inv-mpu-iio-objs += inv_mpu_dts.o + +# chip support +ifeq ($(CONFIG_INV_MPU_IIO_ICM20648), y) +inv-mpu-iio-objs += icm20648/inv_mpu_init.o +inv-mpu-iio-objs += icm20648/inv_mpu_core.o +inv-mpu-iio-objs += icm20648/inv_mpu_parsing.o +inv-mpu-iio-objs += icm20648/inv_mpu_setup.o +inv-mpu-iio-objs += icm20648/inv_mpu_dmp_fifo.o +inv-mpu-iio-objs += icm20648/inv_slave_compass.o +inv-mpu-iio-objs += icm20648/inv_slave_pressure.o +inv-mpu-iio-objs += icm20648/inv_slave_als.o +inv-mpu-iio-objs += icm20648/inv_mpu_load_dmp.o +inv-mpu-iio-objs += icm20648/inv_mpu_selftest.o +inv-mpu-iio-objs += dmp_support/inv_mpu_misc.o +else ifeq ($(CONFIG_INV_MPU_IIO_ICM20690), y) +inv-mpu-iio-objs += icm20690/inv_mpu_init_20690.o +inv-mpu-iio-objs += icm20690/inv_mpu_core_20690.o +inv-mpu-iio-objs += icm20690/inv_mpu_parsing_20690.o +inv-mpu-iio-objs += icm20690/inv_mpu_setup_20690.o +inv-mpu-iio-objs += icm20690/inv_mpu_selftest_20690.o +inv-mpu-iio-objs += icm20690/inv_slave_compass.o +else ifeq ($(CONFIG_INV_MPU_IIO_ICM20602), y) +inv-mpu-iio-objs += icm20602/inv_mpu_init_20602.o +inv-mpu-iio-objs += icm20602/inv_mpu_core_20602.o +inv-mpu-iio-objs += icm20602/inv_mpu_parsing_20602.o +inv-mpu-iio-objs += icm20602/inv_mpu_setup_20602.o +inv-mpu-iio-objs += icm20602/inv_mpu_selftest_20602.o +else ifeq ($(CONFIG_INV_MPU_IIO_ICM20608D), y) +inv-mpu-iio-objs += icm20608d/inv_mpu_init_20608.o +inv-mpu-iio-objs += icm20608d/inv_mpu_core_20608.o +inv-mpu-iio-objs += icm20608d/inv_mpu_parsing_20608.o +inv-mpu-iio-objs += icm20608d/inv_mpu_setup_20608D.o +inv-mpu-iio-objs += icm20608d/inv_mpu_dmp_fifo.o +inv-mpu-iio-objs += icm20608d/inv_mpu_load_dmp.o +inv-mpu-iio-objs += icm20608d/inv_mpu_selftest_20608.o +inv-mpu-iio-objs += dmp_support/inv_mpu_misc.o +else ifeq ($(CONFIG_INV_MPU_IIO_IAM20680), y) +inv-mpu-iio-objs += iam20680/inv_mpu_init_20680.o +inv-mpu-iio-objs += iam20680/inv_mpu_core_20680.o +inv-mpu-iio-objs += iam20680/inv_mpu_parsing_20680.o +inv-mpu-iio-objs += iam20680/inv_mpu_setup_20680.o +inv-mpu-iio-objs += iam20680/inv_mpu_selftest_20680.o +endif + +# Bus support +obj-$(CONFIG_INV_MPU_IIO_I2C) += inv-mpu-iio-i2c.o +inv-mpu-iio-i2c-objs := inv_mpu_i2c.o +obj-$(CONFIG_INV_MPU_IIO_SPI) += inv-mpu-iio-spi.o +inv-mpu-iio-spi-objs := inv_mpu_spi.o + +obj-y += inv_test/ diff --git a/drivers/iio/imu/inv_mpu/README b/drivers/iio/imu/inv_mpu/README new file mode 100644 index 0000000000000000000000000000000000000000..47ff5029ee6e18236101e9d3f90e1ecd2728be9c --- /dev/null +++ b/drivers/iio/imu/inv_mpu/README @@ -0,0 +1,117 @@ +Kernel driver inv-mpu-iio +Author: InvenSense, Inc. + + +Table of Contents +================= +- Description +- Integrating the Driver in the Linux Kernel +- Dts file +- Communicating with the Driver in Userspace + + +Description +=========== +This document describes how to install the Invensense device driver into a +Linux kernel. The supported chips are listed in Kconfig and user selects an +appropriate one from .e.g. menuconfig. + + +Integrating the Driver in the Linux Kernel +========================================== +Please add the files as follows (kernel 3.10): +- Copy mpu.h to /include/linux/iio/imu/ +- Copy inv_mpu folder under /drivers/iio/imu/ + +In order to see the driver in menuconfig when building the kernel, please +make modifications as shown below: + + add "source "drivers/iio/imu/inv_mpu/Kconfig"" + in /drivers/iio/imu/Kconfig + + add "obj-y += inv_mpu/" + in /drivers/iio/imu/Makefile + + + +Dts file +======== +In order to recognize the Invensense device on the I2C/SPI bus, dts(or dtsi) +file must be modified. + +Example) +ICM20648 + AK09911/BMP280/APDS9930 on AUX I2C + + i2c@f9968000 { + /* Invensense */ + mpu6515_acc@68 { + compatible = "inven,icm20648"; + reg = <0x68>; + interrupt-parent = <&msmgpio>; + interrupts = <73 0x2>; + inven,vdd_ana-supply = <&pm8941_l17>; + inven,vcc_i2c-supply = <&pm8941_lvs1>; + inven,gpio_int1 = <&msmgpio 73 0x00>; + fs_range = <0x00>; + /* mount matrix */ + axis_map_x = <1>; + axis_map_y = <0>; + axis_map_z = <2>; + negate_x = <0>; + negate_y = <0>; + negate_z = <1>; + poll_interval = <200>; + min_interval = <5>; + inven,secondary_reg = <0x0c>; + /* If no compass sensor, + * replace "compass" with "none" + */ + inven,secondary_type = "compass"; + inven,secondary_name = "ak09911"; + inven,secondary_axis_map_x = <1>; + inven,secondary_axis_map_y = <0>; + inven,secondary_axis_map_z = <2>; + inven,secondary_negate_x = <1>; + inven,secondary_negate_y = <1>; + inven,secondary_negate_z = <1>; + /* If no pressure sensor, + * replace "pressure" with "none" + */ + inven,aux_type = "pressure"; + inven,aux_name = "bmp280"; + inven,aux_reg = <0x76>; + /* If no ALS sensor + * replace "als" with "none" + */ + inven,read_only_slave_type = "als"; + inven,read_only_slave_name = "apds9930"; + inven,read_only_slave_reg = <0x39>; + }; + }; + + +Communicating with the Driver in Userspace +========================================== +The driver generates several files in sysfs upon installation. +These files are used to communicate with the driver. The files can be found at: + +(I2C) /sys/devices/*.i2c/i2c-*/*-*/iio:device* +(SPI) /sys/devices/*.spi/spi_master/spi*/spi*.*/iio:device* + +Group and Owner for all entries should be updated to system/system at +boot time to allow userspace to access properly. + + +License +======= +Copyright (C) 2018 InvenSense, 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. + diff --git a/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_core_20680.c b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_core_20680.c new file mode 100644 index 0000000000000000000000000000000000000000..35bff4b5703c7a2f1b953a9e78e3653cb5d53608 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_core_20680.c @@ -0,0 +1,1277 @@ +/* + * Copyright (C) 2017-2018 InvenSense, 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. + */ +#define pr_fmt(fmt) "inv_mpu: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../inv_mpu_iio.h" + +static const struct inv_hw_s hw_info[INV_NUM_PARTS] = { + {128, "ICM20608D"}, + {128, "ICM20690"}, + {128, "ICM20602"}, + {128, "IAM20680"}, +}; + +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static char debug_reg_addr = 0x6; +#endif + +const char sensor_l_info[][30] = { + "SENSOR_L_ACCEL", + "SENSOR_L_GYRO", + "SENSOR_L_MAG", + "SENSOR_L_ALS", + "SENSOR_L_SIXQ", + "SENSOR_L_THREEQ", + "SENSOR_L_NINEQ", + "SENSOR_L_PEDQ", + "SENSOR_L_GEOMAG", + "SENSOR_L_PRESSURE", + "SENSOR_L_GYRO_CAL", + "SENSOR_L_MAG_CAL", + "SENSOR_L_EIS_GYRO", + "SENSOR_L_ACCEL_WAKE", + "SENSOR_L_GYRO_WAKE", + "SENSOR_L_MAG_WAKE", + "SENSOR_L_ALS_WAKE", + "SENSOR_L_SIXQ_WAKE", + "SENSOR_L_NINEQ_WAKE", + "SENSOR_L_PEDQ_WAKE", + "SENSOR_L_GEOMAG_WAKE", + "SENSOR_L_PRESSURE_WAKE", + "SENSOR_L_GYRO_CAL_WAKE", + "SENSOR_L_MAG_CAL_WAKE", + "SENSOR_L_NUM_MAX", +}; + +static int inv_set_accel_bias_reg(struct inv_mpu_state *st, + int accel_bias, int axis) +{ + int accel_reg_bias; + u8 addr; + u8 d[2]; + int result = 0; + + switch (axis) { + case 0: + /* X */ + addr = REG_XA_OFFS_H; + break; + case 1: + /* Y */ + addr = REG_YA_OFFS_H; + break; + case 2: + /* Z* */ + addr = REG_ZA_OFFS_H; + break; + default: + result = -EINVAL; + goto accel_bias_set_err; + } + + result = inv_plat_read(st, addr, 2, d); + if (result) + goto accel_bias_set_err; + accel_reg_bias = ((int)d[0] << 8) | d[1]; + + /* accel_bias is 2g scaled by 1<<16. + * Convert to 16g, and mask bit0 */ + accel_reg_bias -= ((accel_bias / 8 / 65536) & ~1); + + d[0] = (accel_reg_bias >> 8) & 0xff; + d[1] = (accel_reg_bias) & 0xff; + result = inv_plat_single_write(st, addr, d[0]); + if (result) + goto accel_bias_set_err; + result = inv_plat_single_write(st, addr + 1, d[1]); + if (result) + goto accel_bias_set_err; + +accel_bias_set_err: + return result; +} + +static int inv_set_gyro_bias_reg(struct inv_mpu_state *st, + const int gyro_bias, int axis) +{ + int gyro_reg_bias; + u8 addr; + u8 d[2]; + int result = 0; + + switch (axis) { + case 0: + /* X */ + addr = REG_XG_OFFS_USR_H; + break; + case 1: + /* Y */ + addr = REG_YG_OFFS_USR_H; + break; + case 2: + /* Z */ + addr = REG_ZG_OFFS_USR_H; + break; + default: + result = -EINVAL; + goto gyro_bias_set_err; + } + + /* gyro_bias is 2000dps scaled by 1<<16. + * Convert to 1000dps */ + gyro_reg_bias = (-gyro_bias * 2 / 65536); + + d[0] = (gyro_reg_bias >> 8) & 0xff; + d[1] = (gyro_reg_bias) & 0xff; + result = inv_plat_single_write(st, addr, d[0]); + if (result) + goto gyro_bias_set_err; + result = inv_plat_single_write(st, addr + 1, d[1]); + if (result) + goto gyro_bias_set_err; + +gyro_bias_set_err: + return result; +} + +static int _bias_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int result, data; + + result = inv_switch_power_in_lp(st, true); + if (result) + return result; + + result = kstrtoint(buf, 10, &data); + if (result) + goto bias_store_fail; + switch (this_attr->address) { + case ATTR_ACCEL_X_OFFSET: + result = inv_set_accel_bias_reg(st, data, 0); + if (result) + goto bias_store_fail; + st->input_accel_bias[0] = data; + break; + case ATTR_ACCEL_Y_OFFSET: + result = inv_set_accel_bias_reg(st, data, 1); + if (result) + goto bias_store_fail; + st->input_accel_bias[1] = data; + break; + case ATTR_ACCEL_Z_OFFSET: + result = inv_set_accel_bias_reg(st, data, 2); + if (result) + goto bias_store_fail; + st->input_accel_bias[2] = data; + break; + case ATTR_GYRO_X_OFFSET: + result = inv_set_gyro_bias_reg(st, data, 0); + if (result) + goto bias_store_fail; + st->input_gyro_bias[0] = data; + break; + case ATTR_GYRO_Y_OFFSET: + result = inv_set_gyro_bias_reg(st, data, 1); + if (result) + goto bias_store_fail; + st->input_gyro_bias[1] = data; + break; + case ATTR_GYRO_Z_OFFSET: + result = inv_set_gyro_bias_reg(st, data, 2); + if (result) + goto bias_store_fail; + st->input_gyro_bias[2] = data; + break; + default: + break; + } + +bias_store_fail: + if (result) + return result; + result = inv_switch_power_in_lp(st, false); + if (result) + return result; + + return count; +} + +static ssize_t inv_bias_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + int result; + + mutex_lock(&indio_dev->mlock); + result = _bias_store(dev, attr, buf, count); + mutex_unlock(&indio_dev->mlock); + + return result; +} + +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static ssize_t inv_debug_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int result, data; + + result = kstrtoint(buf, 10, &data); + if (result) + return result; + switch (this_attr->address) { + case ATTR_DMP_LP_EN_OFF: + st->chip_config.lp_en_mode_off = !!data; + inv_switch_power_in_lp(st, !!data); + break; + case ATTR_DMP_CLK_SEL: + st->chip_config.clk_sel = !!data; + inv_switch_power_in_lp(st, !!data); + break; + case ATTR_DEBUG_REG_ADDR: + debug_reg_addr = data; + break; + case ATTR_DEBUG_REG_WRITE: + inv_plat_single_write(st, debug_reg_addr, data); + break; + } + return count; +} +#endif + +static int _misc_attr_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int result, data; + + result = inv_switch_power_in_lp(st, true); + if (result) + return result; + result = kstrtoint(buf, 10, &data); + if (result) + return result; + switch (this_attr->address) { + case ATTR_GYRO_SCALE: + if (data > 3) + return -EINVAL; + st->chip_config.fsr = data; + result = inv_set_gyro_sf(st); + return result; + case ATTR_ACCEL_SCALE: + if (data > 3) + return -EINVAL; + st->chip_config.accel_fs = data; + result = inv_set_accel_sf(st); + return result; + default: + return -EINVAL; + } + st->trigger_state = MISC_TRIGGER; + result = set_inv_enable(indio_dev); + + return result; +} + +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING +static inline int inv_check_acc_gyro_early_buff_enable_flag( + struct iio_dev *indio_dev) +{ + struct inv_mpu_state *st = iio_priv(indio_dev); + + if (st->acc_buffer_inv_samples == true || + st->gyro_buffer_inv_samples == true) + return 1; + else + return 0; +} +#else +static inline int inv_check_acc_gyro_early_buff_enable_flag( + struct iio_dev *indio_dev) +{ + return 0; +} +#endif + +/* + * inv_misc_attr_store() - calling this function + */ +static ssize_t inv_misc_attr_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + int result; + + if (inv_check_acc_gyro_early_buff_enable_flag(indio_dev)) + return count; + + mutex_lock(&indio_dev->mlock); + result = _misc_attr_store(dev, attr, buf, count); + mutex_unlock(&indio_dev->mlock); + if (result) + return result; + + return count; +} + +static ssize_t inv_sensor_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + return snprintf(buf, MAX_WR_SZ, "%d\n", + st->sensor_l[this_attr->address].rate); +} + +static ssize_t inv_sensor_rate_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int data, rate, ind; + int result; + + if (inv_check_acc_gyro_early_buff_enable_flag(indio_dev)) + return count; + + result = kstrtoint(buf, 10, &data); + if (result) + return -EINVAL; + if (data <= 0) { + pr_err("sensor_rate_store: invalid data=%d\n", data); + return -EINVAL; + } + ind = this_attr->address; + rate = inv_rate_convert(st, ind, data); + + pr_debug("sensor [%s] requested rate %d input [%d]\n", + sensor_l_info[ind], rate, data); + + if (rate == st->sensor_l[ind].rate) + return count; + mutex_lock(&indio_dev->mlock); + st->sensor_l[ind].rate = rate; + st->trigger_state = DATA_TRIGGER; + inv_check_sensor_on(st); + result = set_inv_enable(indio_dev); + pr_debug("%s rate %d div %d\n", sensor_l_info[ind], + st->sensor_l[ind].rate, st->sensor_l[ind].div); + mutex_unlock(&indio_dev->mlock); + + return count; +} + +static ssize_t inv_sensor_on_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + return snprintf(buf, MAX_WR_SZ, "%d\n", st->sensor_l[this_attr->address].on); +} + +static ssize_t inv_sensor_on_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int data, on, ind; + int result; + + if (inv_check_acc_gyro_early_buff_enable_flag(indio_dev)) + return count; + + result = kstrtoint(buf, 10, &data); + if (result) + return -EINVAL; + if (data < 0) { + pr_err("sensor_on_store: invalid data=%d\n", data); + return -EINVAL; + } + ind = this_attr->address; + on = !!data; + + pr_debug("sensor [%s] requested %s, input [%d]\n", + sensor_l_info[ind], (on == 1) ? "On" : "Off", data); + + if (on == st->sensor_l[ind].on) { + pr_debug("sensor [%s] is already %s, input [%d]\n", + sensor_l_info[ind], (on == 1) ? "On" : "Off", data); + return count; + } + + mutex_lock(&indio_dev->mlock); + st->sensor_l[ind].on = on; + st->trigger_state = RATE_TRIGGER; + inv_check_sensor_on(st); + result = set_inv_enable(indio_dev); + mutex_unlock(&indio_dev->mlock); + if (result) + return result; + + pr_debug("Sensor [%s] is %s by sysfs\n", + sensor_l_info[ind], (on == 1) ? "On" : "Off"); + return count; +} + +static int inv_check_l_step(struct inv_mpu_state *st) +{ + if (st->step_counter_l_on || st->step_counter_wake_l_on) + st->ped.on = true; + else + st->ped.on = false; + + return 0; +} + +static int _basic_attr_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int data; + int result; + u32 power_on_data; + + result = kstrtoint(buf, 10, &data); + if (result || (data < 0)) + return -EINVAL; + + switch (this_attr->address) { + case ATTR_DMP_PED_ON: + if ((!!data) == st->ped.on) + return count; + st->ped.on = !!data; + break; + case ATTR_DMP_TILT_ENABLE: + if ((!!data) == st->chip_config.tilt_enable) + return count; + st->chip_config.tilt_enable = !!data; + pr_info("Tile %s\n", + st->chip_config.tilt_enable == + 1 ? "Enabled" : "Disabled"); + break; + case ATTR_DMP_PICK_UP_ENABLE: + if ((!!data) == st->chip_config.pick_up_enable) { + pr_info("Pick_up enable already %s\n", + st->chip_config.pick_up_enable == + 1 ? "Enabled" : "Disabled"); + return count; + } + st->chip_config.pick_up_enable = !!data; + pr_info("Pick up %s\n", + st->chip_config.pick_up_enable == + 1 ? "Enable" : "Disable"); + break; + case ATTR_IN_POWER_ON: + { + u8 p0[2]; + u8 p1[2]; + + power_on_data = (u32)data; + p0[0] = (power_on_data & 0xff); + p0[1] = ((power_on_data >> 8) & 0xff); + p1[0] = ((power_on_data >> 16) & 0xff); + p1[1] = ((power_on_data >> 24) & 0xff); + + if (st->bus_type == BUS_IIO_SPI) { + struct spi_transfer power_on; + struct spi_message msg; + + memset(&power_on, 0, sizeof(struct spi_transfer)); + + power_on.bits_per_word = 8; + power_on.len = 2; + + power_on.tx_buf = p0; + power_on.rx_buf = p1; + spi_message_init(&msg); + spi_message_add_tail(&power_on, &msg); + spi_sync(to_spi_device(st->dev), &msg); + + } else if (st->bus_type == BUS_IIO_I2C) { + struct i2c_msg msgs[2]; + + p0[0] &= 0x7f; + + msgs[0].addr = st->i2c_addr; + msgs[0].flags = 0; /* write */ + msgs[0].buf = &p0[0]; + msgs[0].len = 1; + + msgs[1].addr = st->i2c_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = &p1[1]; + msgs[1].len = 1; + + result = i2c_transfer(st->sl_handle, msgs, 2); + if (result < 2) + return -EIO; + } + st->power_on_data = ((p0[0] << 24) | (p0[1] << 16) | + (p1[0] << 8) | p1[1]); + return count; + } + case ATTR_DMP_EIS_ENABLE: + if ((!!data) == st->chip_config.eis_enable) + return count; + st->chip_config.eis_enable = !!data; + pr_info("Eis %s\n", + st->chip_config.eis_enable == 1 ? "Enable" : "Disable"); + break; + case ATTR_DMP_STEP_DETECTOR_ON: + st->step_detector_l_on = !!data; + break; + case ATTR_DMP_STEP_DETECTOR_WAKE_ON: + st->step_detector_wake_l_on = !!data; + break; + case ATTR_DMP_STEP_COUNTER_ON: + st->step_counter_l_on = !!data; + break; + case ATTR_DMP_STEP_COUNTER_WAKE_ON: + st->step_counter_wake_l_on = !!data; + break; + case ATTR_DMP_BATCHMODE_TIMEOUT: + if (data == st->batch.timeout) + return count; + st->batch.timeout = data; + break; + default: + return -EINVAL; + }; + inv_check_l_step(st); + inv_check_sensor_on(st); + + st->trigger_state = EVENT_TRIGGER; + result = set_inv_enable(indio_dev); + if (result) + return result; + + return count; +} + +/* + * inv_basic_attr_store() + */ +static ssize_t inv_basic_attr_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + int result; + + if (inv_check_acc_gyro_early_buff_enable_flag(indio_dev)) + return count; + + mutex_lock(&indio_dev->mlock); + result = _basic_attr_store(dev, attr, buf, count); + + mutex_unlock(&indio_dev->mlock); + + return result; +} + +/* + * inv_attr_show() + */ +static ssize_t inv_attr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s8 *m; + + switch (this_attr->address) { + case ATTR_GYRO_SCALE: + { + const s16 gyro_scale[] = { 250, 500, 1000, 2000 }; + + return snprintf(buf, MAX_WR_SZ, "%d\n", + gyro_scale[st->chip_config.fsr]); + } + case ATTR_ACCEL_SCALE: + { + const s16 accel_scale[] = { 2, 4, 8, 16 }; + return snprintf(buf, MAX_WR_SZ, "%d\n", + accel_scale[st->chip_config.accel_fs]); + } + case ATTR_GYRO_ENABLE: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->chip_config.gyro_enable); + case ATTR_ACCEL_ENABLE: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->chip_config.accel_enable); + case ATTR_IN_POWER_ON: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->power_on_data); + case ATTR_DMP_BATCHMODE_TIMEOUT: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->batch.timeout); + case ATTR_DMP_PED_ON: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->ped.on); + case ATTR_DMP_TILT_ENABLE: + return snprintf(buf, MAX_WR_SZ, "%d\n", + st->chip_config.tilt_enable); + case ATTR_DMP_PICK_UP_ENABLE: + return snprintf(buf, MAX_WR_SZ, "%d\n", + st->chip_config.pick_up_enable); + case ATTR_DMP_EIS_ENABLE: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->chip_config.eis_enable); + case ATTR_DMP_LP_EN_OFF: + return snprintf(buf, MAX_WR_SZ, "%d\n", + st->chip_config.lp_en_mode_off); + case ATTR_DMP_STEP_COUNTER_ON: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->step_counter_l_on); + case ATTR_DMP_STEP_COUNTER_WAKE_ON: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->step_counter_wake_l_on); + case ATTR_DMP_STEP_DETECTOR_ON: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->step_detector_l_on); + case ATTR_DMP_STEP_DETECTOR_WAKE_ON: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->step_detector_wake_l_on); + case ATTR_GYRO_MATRIX: + m = st->plat_data.orientation; + return snprintf(buf, MAX_WR_SZ, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], + m[8]); + case ATTR_ACCEL_MATRIX: + m = st->plat_data.orientation; + return snprintf(buf, MAX_WR_SZ, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], + m[8]); + case ATTR_GYRO_SF: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->gyro_sf); + case ATTR_ANGLVEL_X_ST_CALIBBIAS: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->gyro_st_bias[0]); + case ATTR_ANGLVEL_Y_ST_CALIBBIAS: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->gyro_st_bias[1]); + case ATTR_ANGLVEL_Z_ST_CALIBBIAS: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->gyro_st_bias[2]); + case ATTR_ACCEL_X_ST_CALIBBIAS: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->accel_st_bias[0]); + case ATTR_ACCEL_Y_ST_CALIBBIAS: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->accel_st_bias[1]); + case ATTR_ACCEL_Z_ST_CALIBBIAS: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->accel_st_bias[2]); + case ATTR_GYRO_X_OFFSET: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->input_gyro_bias[0]); + case ATTR_GYRO_Y_OFFSET: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->input_gyro_bias[1]); + case ATTR_GYRO_Z_OFFSET: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->input_gyro_bias[2]); + case ATTR_ACCEL_X_OFFSET: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->input_accel_bias[0]); + case ATTR_ACCEL_Y_OFFSET: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->input_accel_bias[1]); + case ATTR_ACCEL_Z_OFFSET: + return snprintf(buf, MAX_WR_SZ, "%d\n", st->input_accel_bias[2]); + default: + return -EPERM; + } +} + +static ssize_t inv_self_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + int res; + + mutex_lock(&indio_dev->mlock); + res = inv_hw_self_test(st); + set_inv_enable(indio_dev); + mutex_unlock(&indio_dev->mlock); + + return snprintf(buf, MAX_WR_SZ, "%d\n", res); +} + + +/* + * inv_temperature_show() - Read temperature data directly from registers. + */ +static ssize_t inv_temperature_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + + u8 data[2]; + s32 temp; + int res; + + mutex_lock(&indio_dev->mlock); + res = inv_plat_read(st, REG_RAW_TEMP, 2, data); + if (res) + return res; + mutex_unlock(&indio_dev->mlock); + + temp = (s16)be16_to_cpup((__be16 *)(data)) * 10000; + temp = temp / TEMP_SENSITIVITY + TEMP_OFFSET; + + return snprintf(buf, MAX_WR_SZ, "%d %lld\n", temp, get_time_ns()); +} + +/* + * inv_reg_dump_show() - Register dump for testing. + */ +static ssize_t inv_reg_dump_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ii; + char data; + int bytes_printed = 0; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + + mutex_lock(&indio_dev->mlock); + bytes_printed += snprintf(buf + bytes_printed, MAX_WR_SZ, "bank 0\n"); + + for (ii = 0; ii < 0x7F; ii++) { + /* don't read fifo r/w register */ + if ((ii == REG_MEM_R_W) || (ii == REG_FIFO_R_W)) + data = 0; + else + inv_plat_read(st, ii, 1, &data); + bytes_printed += snprintf(buf + bytes_printed, MAX_WR_SZ, + "%#2x: %#2x\n", ii, data); + } + set_inv_enable(indio_dev); + mutex_unlock(&indio_dev->mlock); + + return bytes_printed; +} + +static ssize_t inv_flush_batch_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + int result, data; + + result = kstrtoint(buf, 10, &data); + if (result) + return result; + + mutex_lock(&indio_dev->mlock); + result = inv_flush_batch_data(indio_dev, data); + mutex_unlock(&indio_dev->mlock); + + return count; +} + +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING +static int inv_gyro_read_bootsampl(struct inv_mpu_state *st, + unsigned long enable_read) +{ + int i = 0; + + if (enable_read) { + st->gyro_buffer_inv_samples = false; + for (i = 0; i < st->gyro_bufsample_cnt; i++) { + dev_dbg(st->dev, "gyro_cnt=%d,x=%d,y=%d,z=%d,tsec=%d,nsec=%lld\n", + i, st->inv_gyro_samplist[i]->xyz[0], + st->inv_gyro_samplist[i]->xyz[1], + st->inv_gyro_samplist[i]->xyz[2], + st->inv_gyro_samplist[i]->tsec, + st->inv_gyro_samplist[i]->tnsec); + input_report_abs(st->gyrobuf_dev, ABS_X, + st->inv_gyro_samplist[i]->xyz[0]); + input_report_abs(st->gyrobuf_dev, ABS_Y, + st->inv_gyro_samplist[i]->xyz[1]); + input_report_abs(st->gyrobuf_dev, ABS_Z, + st->inv_gyro_samplist[i]->xyz[2]); + input_report_abs(st->gyrobuf_dev, ABS_RX, + st->inv_gyro_samplist[i]->tsec); + input_report_abs(st->gyrobuf_dev, ABS_RY, + st->inv_gyro_samplist[i]->tnsec); + input_sync(st->gyrobuf_dev); + } + } else { + /* clean up */ + if (st->gyro_bufsample_cnt != 0) { + for (i = 0; i < INV_GYRO_MAXSAMPLE; i++) + kmem_cache_free(st->inv_gyro_cachepool, + st->inv_gyro_samplist[i]); + kmem_cache_destroy(st->inv_gyro_cachepool); + st->gyro_bufsample_cnt = 0; + } + + } + /*SYN_CONFIG indicates end of data*/ + input_event(st->gyrobuf_dev, EV_SYN, SYN_CONFIG, 0xFFFFFFFF); + input_sync(st->gyrobuf_dev); + dev_dbg(st->dev, "End of gyro samples bufsample_cnt=%d\n", + st->gyro_bufsample_cnt); + return 0; +} +static int inv_acc_read_bootsampl(struct inv_mpu_state *st, + unsigned long enable_read) +{ + int i = 0; + + if (enable_read) { + st->acc_buffer_inv_samples = false; + for (i = 0; i < st->acc_bufsample_cnt; i++) { + dev_dbg(st->dev, "acc_cnt=%d,x=%d,y=%d,z=%d,tsec=%d,nsec=%lld\n", + i, st->inv_acc_samplist[i]->xyz[0], + st->inv_acc_samplist[i]->xyz[1], + st->inv_acc_samplist[i]->xyz[2], + st->inv_acc_samplist[i]->tsec, + st->inv_acc_samplist[i]->tnsec); + input_report_abs(st->accbuf_dev, ABS_X, + st->inv_acc_samplist[i]->xyz[0]); + input_report_abs(st->accbuf_dev, ABS_Y, + st->inv_acc_samplist[i]->xyz[1]); + input_report_abs(st->accbuf_dev, ABS_Z, + st->inv_acc_samplist[i]->xyz[2]); + input_report_abs(st->accbuf_dev, ABS_RX, + st->inv_acc_samplist[i]->tsec); + input_report_abs(st->accbuf_dev, ABS_RY, + st->inv_acc_samplist[i]->tnsec); + input_sync(st->accbuf_dev); + } + } else { + /* clean up */ + if (st->acc_bufsample_cnt != 0) { + for (i = 0; i < INV_ACC_MAXSAMPLE; i++) + kmem_cache_free(st->inv_acc_cachepool, + st->inv_acc_samplist[i]); + kmem_cache_destroy(st->inv_acc_cachepool); + st->acc_bufsample_cnt = 0; + } + + } + /*SYN_CONFIG indicates end of data*/ + input_event(st->accbuf_dev, EV_SYN, SYN_CONFIG, 0xFFFFFFFF); + input_sync(st->accbuf_dev); + dev_dbg(st->dev, "End of acc samples bufsample_cnt=%d\n", + st->acc_bufsample_cnt); + return 0; +} + +static ssize_t read_gyro_boot_sample_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + + return snprintf(buf, MAX_WR_SZ, "%d\n", + st->read_gyro_boot_sample); +} + +static ssize_t read_gyro_boot_sample_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long enable = 0; + + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable > 1) { + err = dev_err(st->dev, + "Invalid value of input, input=%ld\n", enable); + return -EINVAL; + } + err = inv_gyro_read_bootsampl(st, enable); + if (err) + return err; + st->read_gyro_boot_sample = enable; + return count; + +} + +static ssize_t read_acc_boot_sample_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + + return snprintf(buf, MAX_WR_SZ, "%d\n", + st->read_acc_boot_sample); +} +static ssize_t read_acc_boot_sample_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct inv_mpu_state *st = iio_priv(indio_dev); + + unsigned long enable = 0; + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable > 1) { + err = dev_err(st->dev, + "Invalid value of input, input=%ld\n", enable); + return -EINVAL; + } + err = inv_acc_read_bootsampl(st, enable); + if (err) + return err; + st->read_acc_boot_sample = enable; + return count; +} +#endif + +static const struct iio_chan_spec inv_mpu_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU_SCAN_TIMESTAMP), +}; + +/* special run time sysfs entry, read only */ +static DEVICE_ATTR(debug_reg_dump, S_IRUGO | S_IWUSR, inv_reg_dump_show, NULL); +static DEVICE_ATTR(out_temperature, S_IRUGO | S_IWUSR, + inv_temperature_show, NULL); +static DEVICE_ATTR(misc_self_test, S_IRUGO | S_IWUSR, inv_self_test, NULL); +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING +static IIO_DEVICE_ATTR(read_acc_boot_sample, S_IRUGO | S_IWUSR, + read_acc_boot_sample_show, read_acc_boot_sample_store, SENSOR_L_ACCEL); +static IIO_DEVICE_ATTR(read_gyro_boot_sample, S_IRUGO | S_IWUSR, + read_gyro_boot_sample_show, read_gyro_boot_sample_store, SENSOR_L_GYRO); +#endif + +static IIO_DEVICE_ATTR(info_anglvel_matrix, S_IRUGO, inv_attr_show, NULL, + ATTR_GYRO_MATRIX); +static IIO_DEVICE_ATTR(info_accel_matrix, S_IRUGO, inv_attr_show, NULL, + ATTR_ACCEL_MATRIX); + +static IIO_DEVICE_ATTR(info_gyro_sf, S_IRUGO, inv_attr_show, NULL, + ATTR_GYRO_SF); +/* write only sysfs */ +static DEVICE_ATTR(misc_flush_batch, S_IWUSR, NULL, inv_flush_batch_store); + +/* sensor on/off sysfs control */ +static IIO_DEVICE_ATTR(in_accel_enable, S_IRUGO | S_IWUSR, + inv_sensor_on_show, inv_sensor_on_store, SENSOR_L_ACCEL); +static IIO_DEVICE_ATTR(in_anglvel_enable, S_IRUGO | S_IWUSR, + inv_sensor_on_show, inv_sensor_on_store, SENSOR_L_GYRO); +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static IIO_DEVICE_ATTR(in_eis_enable, S_IRUGO | S_IWUSR, + inv_sensor_on_show, inv_sensor_on_store, + SENSOR_L_EIS_GYRO); +#endif +static IIO_DEVICE_ATTR(in_accel_wake_enable, S_IRUGO | S_IWUSR, + inv_sensor_on_show, inv_sensor_on_store, + SENSOR_L_ACCEL_WAKE); +static IIO_DEVICE_ATTR(in_anglvel_wake_enable, S_IRUGO | S_IWUSR, + inv_sensor_on_show, inv_sensor_on_store, + SENSOR_L_GYRO_WAKE); + +/* sensor rate sysfs control */ +static IIO_DEVICE_ATTR(in_accel_rate, S_IRUGO | S_IWUSR, + inv_sensor_rate_show, inv_sensor_rate_store, + SENSOR_L_ACCEL); +static IIO_DEVICE_ATTR(in_anglvel_rate, S_IRUGO | S_IWUSR, inv_sensor_rate_show, + inv_sensor_rate_store, SENSOR_L_GYRO); +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static IIO_DEVICE_ATTR(in_eis_rate, S_IRUGO | S_IWUSR, + inv_sensor_rate_show, inv_sensor_rate_store, + SENSOR_L_EIS_GYRO); +#endif +static IIO_DEVICE_ATTR(in_accel_wake_rate, S_IRUGO | S_IWUSR, + inv_sensor_rate_show, inv_sensor_rate_store, + SENSOR_L_ACCEL_WAKE); +static IIO_DEVICE_ATTR(in_anglvel_wake_rate, S_IRUGO | S_IWUSR, + inv_sensor_rate_show, inv_sensor_rate_store, + SENSOR_L_GYRO_WAKE); + +static IIO_DEVICE_ATTR(misc_batchmode_timeout, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_DMP_BATCHMODE_TIMEOUT); + +/* engine scale */ +static IIO_DEVICE_ATTR(in_accel_scale, S_IRUGO | S_IWUSR, inv_attr_show, + inv_misc_attr_store, ATTR_ACCEL_SCALE); +static IIO_DEVICE_ATTR(in_anglvel_scale, S_IRUGO | S_IWUSR, inv_attr_show, + inv_misc_attr_store, ATTR_GYRO_SCALE); + + +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static IIO_DEVICE_ATTR(debug_lp_en_off, S_IRUGO | S_IWUSR, inv_attr_show, + inv_debug_store, ATTR_DMP_LP_EN_OFF); +static IIO_DEVICE_ATTR(debug_clock_sel, S_IRUGO | S_IWUSR, inv_attr_show, + inv_debug_store, ATTR_DMP_CLK_SEL); +static IIO_DEVICE_ATTR(debug_reg_write, S_IRUGO | S_IWUSR, inv_attr_show, + inv_debug_store, ATTR_DEBUG_REG_WRITE); +static IIO_DEVICE_ATTR(debug_reg_write_addr, S_IRUGO | S_IWUSR, inv_attr_show, + inv_debug_store, ATTR_DEBUG_REG_ADDR); +#endif + +static IIO_DEVICE_ATTR(in_accel_x_st_calibbias, S_IRUGO | S_IWUSR, + inv_attr_show, NULL, ATTR_ACCEL_X_ST_CALIBBIAS); +static IIO_DEVICE_ATTR(in_accel_y_st_calibbias, S_IRUGO | S_IWUSR, + inv_attr_show, NULL, ATTR_ACCEL_Y_ST_CALIBBIAS); +static IIO_DEVICE_ATTR(in_accel_z_st_calibbias, S_IRUGO | S_IWUSR, + inv_attr_show, NULL, ATTR_ACCEL_Z_ST_CALIBBIAS); + +static IIO_DEVICE_ATTR(in_anglvel_x_st_calibbias, S_IRUGO | S_IWUSR, + inv_attr_show, NULL, ATTR_ANGLVEL_X_ST_CALIBBIAS); +static IIO_DEVICE_ATTR(in_anglvel_y_st_calibbias, S_IRUGO | S_IWUSR, + inv_attr_show, NULL, ATTR_ANGLVEL_Y_ST_CALIBBIAS); +static IIO_DEVICE_ATTR(in_anglvel_z_st_calibbias, S_IRUGO | S_IWUSR, + inv_attr_show, NULL, ATTR_ANGLVEL_Z_ST_CALIBBIAS); + +static IIO_DEVICE_ATTR(in_accel_x_offset, S_IRUGO | S_IWUSR, + inv_attr_show, inv_bias_store, ATTR_ACCEL_X_OFFSET); +static IIO_DEVICE_ATTR(in_accel_y_offset, S_IRUGO | S_IWUSR, + inv_attr_show, inv_bias_store, ATTR_ACCEL_Y_OFFSET); +static IIO_DEVICE_ATTR(in_accel_z_offset, S_IRUGO | S_IWUSR, + inv_attr_show, inv_bias_store, ATTR_ACCEL_Z_OFFSET); + +static IIO_DEVICE_ATTR(in_anglvel_x_offset, S_IRUGO | S_IWUSR, + inv_attr_show, inv_bias_store, ATTR_GYRO_X_OFFSET); +static IIO_DEVICE_ATTR(in_anglvel_y_offset, S_IRUGO | S_IWUSR, + inv_attr_show, inv_bias_store, ATTR_GYRO_Y_OFFSET); +static IIO_DEVICE_ATTR(in_anglvel_z_offset, S_IRUGO | S_IWUSR, + inv_attr_show, inv_bias_store, ATTR_GYRO_Z_OFFSET); + +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static IIO_DEVICE_ATTR(in_step_detector_enable, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_DMP_STEP_DETECTOR_ON); +static IIO_DEVICE_ATTR(in_step_detector_wake_enable, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_DMP_STEP_DETECTOR_WAKE_ON); +static IIO_DEVICE_ATTR(in_step_counter_enable, S_IRUGO | S_IWUSR, inv_attr_show, + inv_basic_attr_store, ATTR_DMP_STEP_COUNTER_ON); +static IIO_DEVICE_ATTR(in_step_counter_wake_enable, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_DMP_STEP_COUNTER_WAKE_ON); + +static IIO_DEVICE_ATTR(event_tilt_enable, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_DMP_TILT_ENABLE); + +static IIO_DEVICE_ATTR(event_eis_enable, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_DMP_EIS_ENABLE); + +static IIO_DEVICE_ATTR(event_pick_up_enable, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_DMP_PICK_UP_ENABLE); + +static IIO_DEVICE_ATTR(in_power_on, S_IRUGO | S_IWUSR, + inv_attr_show, inv_basic_attr_store, + ATTR_IN_POWER_ON); +#endif + +static const struct attribute *inv_raw_attributes[] = { + &dev_attr_debug_reg_dump.attr, + &dev_attr_out_temperature.attr, + &dev_attr_misc_flush_batch.attr, + &dev_attr_misc_self_test.attr, +#ifndef SUPPORT_ONLY_BASIC_FEATURES + &iio_dev_attr_in_power_on.dev_attr.attr, +#endif +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING + &iio_dev_attr_read_acc_boot_sample.dev_attr.attr, + &iio_dev_attr_read_gyro_boot_sample.dev_attr.attr, +#endif + &iio_dev_attr_in_accel_enable.dev_attr.attr, + &iio_dev_attr_in_accel_wake_enable.dev_attr.attr, + &iio_dev_attr_info_accel_matrix.dev_attr.attr, + &iio_dev_attr_in_accel_scale.dev_attr.attr, + &iio_dev_attr_misc_batchmode_timeout.dev_attr.attr, + &iio_dev_attr_in_accel_rate.dev_attr.attr, + &iio_dev_attr_in_accel_wake_rate.dev_attr.attr, +}; + +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static const struct attribute *inv_debug_attributes[] = { + &iio_dev_attr_debug_lp_en_off.dev_attr.attr, + &iio_dev_attr_debug_clock_sel.dev_attr.attr, + &iio_dev_attr_debug_reg_write.dev_attr.attr, + &iio_dev_attr_debug_reg_write_addr.dev_attr.attr, +}; +#endif + +static const struct attribute *inv_gyro_attributes[] = { + &iio_dev_attr_info_anglvel_matrix.dev_attr.attr, + &iio_dev_attr_in_anglvel_enable.dev_attr.attr, + &iio_dev_attr_in_anglvel_rate.dev_attr.attr, +#ifndef SUPPORT_ONLY_BASIC_FEATURES + &iio_dev_attr_in_eis_enable.dev_attr.attr, +#endif + &iio_dev_attr_in_anglvel_wake_enable.dev_attr.attr, + &iio_dev_attr_in_anglvel_scale.dev_attr.attr, +#ifndef SUPPORT_ONLY_BASIC_FEATURES + &iio_dev_attr_in_eis_rate.dev_attr.attr, +#endif + &iio_dev_attr_in_anglvel_wake_rate.dev_attr.attr, + &iio_dev_attr_info_gyro_sf.dev_attr.attr, +}; + +static const struct attribute *inv_bias_attributes[] = { + &iio_dev_attr_in_accel_x_st_calibbias.dev_attr.attr, + &iio_dev_attr_in_accel_y_st_calibbias.dev_attr.attr, + &iio_dev_attr_in_accel_z_st_calibbias.dev_attr.attr, + &iio_dev_attr_in_accel_x_offset.dev_attr.attr, + &iio_dev_attr_in_accel_y_offset.dev_attr.attr, + &iio_dev_attr_in_accel_z_offset.dev_attr.attr, + &iio_dev_attr_in_anglvel_x_st_calibbias.dev_attr.attr, + &iio_dev_attr_in_anglvel_y_st_calibbias.dev_attr.attr, + &iio_dev_attr_in_anglvel_z_st_calibbias.dev_attr.attr, + &iio_dev_attr_in_anglvel_x_offset.dev_attr.attr, + &iio_dev_attr_in_anglvel_y_offset.dev_attr.attr, + &iio_dev_attr_in_anglvel_z_offset.dev_attr.attr, +}; + +#ifndef SUPPORT_ONLY_BASIC_FEATURES +static const struct attribute *inv_pedometer_attributes[] = { + &iio_dev_attr_event_tilt_enable.dev_attr.attr, + &iio_dev_attr_event_eis_enable.dev_attr.attr, + &iio_dev_attr_event_pick_up_enable.dev_attr.attr, + &iio_dev_attr_in_step_counter_enable.dev_attr.attr, + &iio_dev_attr_in_step_counter_wake_enable.dev_attr.attr, + &iio_dev_attr_in_step_detector_enable.dev_attr.attr, + &iio_dev_attr_in_step_detector_wake_enable.dev_attr.attr, +}; +#endif + +static struct attribute *inv_attributes[ARRAY_SIZE(inv_raw_attributes) + +#ifndef SUPPORT_ONLY_BASIC_FEATURES + ARRAY_SIZE(inv_debug_attributes) + +#endif + ARRAY_SIZE(inv_gyro_attributes) + + ARRAY_SIZE(inv_bias_attributes) + +#ifndef SUPPORT_ONLY_BASIC_FEATURES + ARRAY_SIZE(inv_pedometer_attributes) + +#endif + + 1]; + +static const struct attribute_group inv_attribute_group = { + .name = "mpu", + .attrs = inv_attributes +}; + +static const struct iio_info mpu_info = { + .driver_module = THIS_MODULE, + .attrs = &inv_attribute_group, +}; + +/* + * inv_check_chip_type() - check and setup chip type. + */ +int inv_check_chip_type(struct iio_dev *indio_dev, const char *name) +{ + int result; + int t_ind; + struct inv_chip_config_s *conf; + struct mpu_platform_data *plat; + struct inv_mpu_state *st; + + st = iio_priv(indio_dev); + conf = &st->chip_config; + plat = &st->plat_data; + + if (!strcmp(name, "iam20680")) + st->chip_type = IAM20680; + else + return -EPERM; + st->chip_config.has_gyro = 1; + + st->hw = &hw_info[st->chip_type]; + result = inv_mpu_initialize(st); + if (result) + return result; + + t_ind = 0; + memcpy(&inv_attributes[t_ind], inv_raw_attributes, + sizeof(inv_raw_attributes)); + t_ind += ARRAY_SIZE(inv_raw_attributes); + +#ifndef SUPPORT_ONLY_BASIC_FEATURES + memcpy(&inv_attributes[t_ind], inv_pedometer_attributes, + sizeof(inv_pedometer_attributes)); + t_ind += ARRAY_SIZE(inv_pedometer_attributes); +#endif + + memcpy(&inv_attributes[t_ind], inv_gyro_attributes, + sizeof(inv_gyro_attributes)); + t_ind += ARRAY_SIZE(inv_gyro_attributes); + + memcpy(&inv_attributes[t_ind], inv_bias_attributes, + sizeof(inv_bias_attributes)); + t_ind += ARRAY_SIZE(inv_bias_attributes); + +#ifndef SUPPORT_ONLY_BASIC_FEATURES + memcpy(&inv_attributes[t_ind], inv_debug_attributes, + sizeof(inv_debug_attributes)); + t_ind += ARRAY_SIZE(inv_debug_attributes); +#endif + + inv_attributes[t_ind] = NULL; + + indio_dev->channels = inv_mpu_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); + + indio_dev->info = &mpu_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->currentmode = INDIO_DIRECT_MODE; + + return result; +} +EXPORT_SYMBOL_GPL(inv_check_chip_type); + +int inv_create_dmp_sysfs(struct iio_dev *ind) +{ + // dummy + return 0; +} +EXPORT_SYMBOL_GPL(inv_create_dmp_sysfs); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Invensense device ICM20xxx driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_iio_reg_20680.h b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_iio_reg_20680.h new file mode 100644 index 0000000000000000000000000000000000000000..3f8ce71be024d63205094428f398a5e25eb9a632 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_iio_reg_20680.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2017-2018 InvenSense, 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. + */ + +#ifndef _INV_MPU_IIO_REG_20680_H_ +#define _INV_MPU_IIO_REG_20680_H_ + +/* Uncomment when HAL does not support the algorithm library + * for calibration and sensor fusion not to expose unused + * sysfs entries */ +#define SUPPORT_ONLY_BASIC_FEATURES + +/* Uncomment to read data registers for sensor data instead of FIFO */ +//#define SENSOR_DATA_FROM_REGISTERS + +/* Uncomment to enable timer based batching */ +#define TIMER_BASED_BATCHING + +/* Polling (batch mode) can be enabled only when FIFO read */ +#if defined(SENSOR_DATA_FROM_REGISTERS) +#undef TIMER_BASED_BATCHING +#endif + +/*register and associated bit definition*/ +#define REG_XA_OFFS_H 0x77 +#define REG_YA_OFFS_H 0x7A +#define REG_ZA_OFFS_H 0x7D +#define REG_XG_OFFS_USR_H 0x13 +#define REG_YG_OFFS_USR_H 0x15 +#define REG_ZG_OFFS_USR_H 0x17 +#define REG_SAMPLE_RATE_DIV 0x19 + +#define REG_CONFIG 0x1A +#define EXT_SYNC_SET 8 + +#define REG_GYRO_CONFIG 0x1B +#define BITS_SELF_TEST_EN 0xE0 +#define SHIFT_GYRO_FS_SEL 0x03 + +#define REG_ACCEL_CONFIG 0x1C +#define SHIFT_ACCEL_FS 0x03 + +#define REG_LP_MODE_CTRL 0x1E +#define BIT_GYRO_CYCLE_EN 0x80 + +#define REG_ACCEL_WOM_THR 0x1F +#define REG_ACCEL_WOM_X_THR 0x20 +#define REG_ACCEL_WOM_Y_THR 0x21 +#define REG_ACCEL_WOM_Z_THR 0x22 + +#define REG_ACCEL_MOT_THR 0x1F +#define REG_ACCEL_MOT_DUR 0x20 + +#define REG_ACCEL_CONFIG_2 0x1D +#define BIT_ACCEL_FCHOCIE_B 0x08 + +#define REG_FIFO_EN 0x23 +#define BITS_GYRO_FIFO_EN 0x70 +#define BIT_ACCEL_FIFO_EN 0x08 + +#define REG_FSYNC_INT 0x36 +#define BIT_FSYNC_INT 0x80 + +#define REG_INT_PIN_CFG 0x37 + +#define REG_INT_ENABLE 0x38 +#define BIT_WOM_X_INT_EN 0x80 +#define BIT_WOM_Y_INT_EN 0x40 +#define BIT_WOM_Z_INT_EN 0x20 +#define BIT_WOM_ALL_INT_EN 0xE0 +#define BIT_FSYNC_INT_EN 0x8 +#define BIT_DATA_RDY_EN 0x1 + +#define REG_INT_STATUS 0x3A +#define BIT_WOM_X_INT 0x80 +#define BIT_WOM_Y_INT 0x40 +#define BIT_WOM_Z_INT 0x20 + +#define REG_RAW_ACCEL 0x3B +#define REG_RAW_TEMP 0x41 +#define REG_RAW_GYRO 0x43 +#define REG_EXT_SENS_DATA_00 0x49 +#define REG_EXT_SENS_DATA_08 0x51 +#define REG_EXT_SENS_DATA_09 0x52 + +#define REG_ACCEL_INTEL_CTRL 0x69 +#define BIT_ACCEL_INTEL_EN 0x80 +#define BIT_ACCEL_INTEL_MODE 0x40 + +#define REG_USER_CTRL 0x6A +#define BIT_COND_RST 0x01 +#define BIT_FIFO_RST 0x04 +#define BIT_FIFO_EN 0x40 + +#define REG_PWR_MGMT_1 0x6B +#define BIT_H_RESET 0x80 +#define BIT_SLEEP 0x40 +#define BIT_LP_EN 0x20 +#define BIT_CLK_PLL 0x01 +#define BIT_CLK_MASK 0x07 + +#define REG_PWR_MGMT_2 0x6C +#define BIT_PWR_ACCEL_STBY 0x38 +#define BIT_PWR_GYRO_STBY 0x07 +#define BIT_PWR_ALL_OFF 0x3F +#define BIT_FIFO_LP_EN 0x80 + +#define REG_MEM_BANK_SEL 0x6D +#define REG_MEM_START_ADDR 0x6E +#define REG_MEM_R_W 0x6F + +#define REG_FIFO_COUNT_H 0x72 +#define REG_FIFO_R_W 0x74 +#define REG_WHO_AM_I 0x75 + +#define REG_6500_XG_ST_DATA 0x50 +#define REG_6500_XA_ST_DATA 0xD +#define REG_6500_XA_OFFS_H 0x77 +#define REG_6500_YA_OFFS_H 0x7A +#define REG_6500_ZA_OFFS_H 0x7D +#define REG_6500_ACCEL_CONFIG2 0x1D +#define BIT_ACCEL_FCHOCIE_B 0x08 +#define BIT_FIFO_SIZE_1K 0x40 + +#define REG_LP_MODE_CFG 0x1E + +#define REG_6500_LP_ACCEL_ODR 0x1E +#define REG_6500_ACCEL_WOM_THR 0x1F + +/* data output control reg 2 */ +#define ACCEL_ACCURACY_SET 0x4000 +#define GYRO_ACCURACY_SET 0x2000 +#define CPASS_ACCURACY_SET 0x1000 + +/* data definitions */ +#define ACCEL_COVARIANCE 0 +#define BYTES_PER_SENSOR 6 +#define BYTES_FOR_TEMP 2 +#define FIFO_COUNT_BYTE 2 +#define HARDWARE_FIFO_SIZE 512 +#define FIFO_SIZE (HARDWARE_FIFO_SIZE * 7 / 10) +#define POWER_UP_TIME 100 +#define REG_UP_TIME_USEC 100 +#define LEFT_OVER_BYTES 128 +#define IIO_BUFFER_BYTES 8 +#define BASE_SAMPLE_RATE 1000 +#define DRY_RUN_TIME 50 +#define INV_IAM20680_GYRO_START_TIME 35 +#define INV_IAM20680_ACCEL_START_TIME 30 +#define MODE_1K_INIT_SAMPLE 5 +#define FIRST_SAMPLE_BUF_MS 30 + +#ifdef BIAS_CONFIDENCE_HIGH +#define DEFAULT_ACCURACY 3 +#else +#define DEFAULT_ACCURACY 1 +#endif + +/* temperature */ +#define TEMP_SENSITIVITY 32680 // 326.8 LSB/degC * 100 +#define TEMP_OFFSET 2500 // 25 degC * 100 + +/* enum for sensor */ +enum INV_SENSORS { + SENSOR_ACCEL = 0, + SENSOR_TEMP, + SENSOR_GYRO, + SENSOR_COMPASS, + SENSOR_NUM_MAX, + SENSOR_INVALID, +}; + +enum inv_filter_e { + INV_FILTER_256HZ_NOLPF2 = 0, + INV_FILTER_188HZ, + INV_FILTER_98HZ, + INV_FILTER_42HZ, + INV_FILTER_20HZ, + INV_FILTER_10HZ, + INV_FILTER_5HZ, + INV_FILTER_2100HZ_NOLPF, + NUM_FILTER +}; + +#define MPU_DEFAULT_DMP_FREQ 200 +#define PEDOMETER_FREQ (MPU_DEFAULT_DMP_FREQ >> 2) +#define SENSOR_FUSION_MIN_RATE 100 +#define GESTURE_ACCEL_RATE 50 +#define ESI_GYRO_RATE 1000 +#define MAX_FIFO_PACKET_READ 6 +#define MAX_BATCH_FIFO_SIZE FIFO_SIZE + +#define MIN_MST_ODR_CONFIG 4 +#define MAX_MST_ODR_CONFIG 5 +/* initial rate is important. For non-DMP mode, it is set as 4 1000/256*/ +#define MPU_INIT_SENSOR_RATE 4 +#define MAX_MST_NON_COMPASS_ODR_CONFIG 7 +#define THREE_AXES 3 +#define NINE_ELEM (THREE_AXES * THREE_AXES) +#define MPU_TEMP_SHIFT 16 + +#define DMP_DIVIDER (BASE_SAMPLE_RATE / MPU_DEFAULT_DMP_FREQ) +#define DEFAULT_BATCH_RATE 400 +#define DEFAULT_BATCH_TIME (MSEC_PER_SEC / DEFAULT_BATCH_RATE) + +#define TEMPERATURE_SCALE 3340827L +#define TEMPERATURE_OFFSET 1376256L +#define SECONDARY_INIT_WAIT 100 +#define MPU_SOFT_REV_ADDR 0x86 +#define MPU_SOFT_REV_MASK 0xf +#define SW_REV_LP_EN_MODE 4 + +/* data limit definitions */ +#define MIN_FIFO_RATE 4 +#define MAX_FIFO_RATE MPU_DEFAULT_DMP_FREQ + +#define MAX_MPU_MEM 8192 +#define MAX_PRS_RATE 281 + +enum inv_devices { + ICM20608D, + ICM20690, + ICM20602, + IAM20680, + INV_NUM_PARTS, +}; +#endif diff --git a/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_init_20680.c b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_init_20680.c new file mode 100644 index 0000000000000000000000000000000000000000..58bd8d073890f4fc3e06ca5ebeb21454f5e04668 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_init_20680.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2017-2018 InvenSense, 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. + */ +#define pr_fmt(fmt) "inv_mpu: " fmt +#include "../inv_mpu_iio.h" + +static int inv_calc_gyro_sf(s8 pll) +{ + int a, r; + int value, t; + + t = 102870L + 81L * pll; + a = (1L << 30) / t; + r = (1L << 30) - a * t; + value = a * 797 * DMP_DIVIDER; + value += (s64) ((a * 1011387LL * DMP_DIVIDER) >> 20); + value += r * 797L * DMP_DIVIDER / t; + value += (s32) ((s64) ((r * 1011387LL * DMP_DIVIDER) >> 20)) / t; + value <<= 1; + + return value; +} + +static int inv_read_timebase(struct inv_mpu_state *st) +{ + + inv_plat_single_write(st, REG_CONFIG, 3); + + st->eng_info[ENGINE_ACCEL].base_time = NSEC_PER_SEC; + st->eng_info[ENGINE_ACCEL].base_time_1k = NSEC_PER_SEC; + /* talor expansion to calculate base time unit */ + st->eng_info[ENGINE_GYRO].base_time = NSEC_PER_SEC; + st->eng_info[ENGINE_GYRO].base_time_1k = NSEC_PER_SEC; + st->eng_info[ENGINE_I2C].base_time = NSEC_PER_SEC; + st->eng_info[ENGINE_I2C].base_time_1k = NSEC_PER_SEC; + + st->eng_info[ENGINE_ACCEL].orig_rate = BASE_SAMPLE_RATE; + st->eng_info[ENGINE_GYRO].orig_rate = BASE_SAMPLE_RATE; + st->eng_info[ENGINE_I2C].orig_rate = BASE_SAMPLE_RATE; + + st->gyro_sf = inv_calc_gyro_sf(0); + + return 0; +} + +int inv_set_gyro_sf(struct inv_mpu_state *st) +{ + int result; + + result = inv_plat_single_write(st, REG_GYRO_CONFIG, + st->chip_config.fsr << SHIFT_GYRO_FS_SEL); + + return result; +} + +int inv_set_accel_sf(struct inv_mpu_state *st) +{ + int result; + + result = inv_plat_single_write(st, REG_ACCEL_CONFIG, + st->chip_config.accel_fs << SHIFT_ACCEL_FS); + return result; +} + +// dummy for 20602 +int inv_set_accel_intel(struct inv_mpu_state *st) +{ + return 0; +} + +static void inv_init_sensor_struct(struct inv_mpu_state *st) +{ + int i; + + for (i = 0; i < SENSOR_NUM_MAX; i++) + st->sensor[i].rate = MPU_INIT_SENSOR_RATE; + + st->sensor[SENSOR_ACCEL].sample_size = BYTES_PER_SENSOR; + st->sensor[SENSOR_TEMP].sample_size = BYTES_FOR_TEMP; + st->sensor[SENSOR_GYRO].sample_size = BYTES_PER_SENSOR; + + st->sensor_l[SENSOR_L_SIXQ].base = SENSOR_GYRO; + st->sensor_l[SENSOR_L_PEDQ].base = SENSOR_GYRO; + + st->sensor_l[SENSOR_L_SIXQ_WAKE].base = SENSOR_GYRO; + st->sensor_l[SENSOR_L_PEDQ_WAKE].base = SENSOR_GYRO; + + st->sensor[SENSOR_ACCEL].a_en = true; + st->sensor[SENSOR_GYRO].a_en = false; + + st->sensor[SENSOR_ACCEL].g_en = false; + st->sensor[SENSOR_GYRO].g_en = true; + + st->sensor[SENSOR_ACCEL].c_en = false; + st->sensor[SENSOR_GYRO].c_en = false; + + st->sensor[SENSOR_ACCEL].p_en = false; + st->sensor[SENSOR_GYRO].p_en = false; + + st->sensor[SENSOR_ACCEL].engine_base = ENGINE_ACCEL; + st->sensor[SENSOR_GYRO].engine_base = ENGINE_GYRO; + + st->sensor_l[SENSOR_L_ACCEL].base = SENSOR_ACCEL; + st->sensor_l[SENSOR_L_GESTURE_ACCEL].base = SENSOR_ACCEL; + st->sensor_l[SENSOR_L_GYRO].base = SENSOR_GYRO; + st->sensor_l[SENSOR_L_GYRO_CAL].base = SENSOR_GYRO; + st->sensor_l[SENSOR_L_EIS_GYRO].base = SENSOR_GYRO; + + st->sensor_l[SENSOR_L_ACCEL_WAKE].base = SENSOR_ACCEL; + st->sensor_l[SENSOR_L_GYRO_WAKE].base = SENSOR_GYRO; + + st->sensor_l[SENSOR_L_GYRO_CAL_WAKE].base = SENSOR_GYRO; + + st->sensor_l[SENSOR_L_ACCEL].header = ACCEL_HDR; + st->sensor_l[SENSOR_L_GESTURE_ACCEL].header = ACCEL_HDR; + st->sensor_l[SENSOR_L_GYRO].header = GYRO_HDR; + st->sensor_l[SENSOR_L_GYRO_CAL].header = GYRO_CALIB_HDR; + + st->sensor_l[SENSOR_L_EIS_GYRO].header = EIS_GYRO_HDR; + st->sensor_l[SENSOR_L_SIXQ].header = SIXQUAT_HDR; + st->sensor_l[SENSOR_L_THREEQ].header = LPQ_HDR; + st->sensor_l[SENSOR_L_NINEQ].header = NINEQUAT_HDR; + st->sensor_l[SENSOR_L_PEDQ].header = PEDQUAT_HDR; + + st->sensor_l[SENSOR_L_ACCEL_WAKE].header = ACCEL_WAKE_HDR; + st->sensor_l[SENSOR_L_GYRO_WAKE].header = GYRO_WAKE_HDR; + st->sensor_l[SENSOR_L_GYRO_CAL_WAKE].header = GYRO_CALIB_WAKE_HDR; + st->sensor_l[SENSOR_L_MAG_WAKE].header = COMPASS_WAKE_HDR; + st->sensor_l[SENSOR_L_MAG_CAL_WAKE].header = COMPASS_CALIB_WAKE_HDR; + st->sensor_l[SENSOR_L_SIXQ_WAKE].header = SIXQUAT_WAKE_HDR; + st->sensor_l[SENSOR_L_NINEQ_WAKE].header = NINEQUAT_WAKE_HDR; + st->sensor_l[SENSOR_L_PEDQ_WAKE].header = PEDQUAT_WAKE_HDR; + + st->sensor_l[SENSOR_L_ACCEL].wake_on = false; + st->sensor_l[SENSOR_L_GYRO].wake_on = false; + st->sensor_l[SENSOR_L_GYRO_CAL].wake_on = false; + st->sensor_l[SENSOR_L_MAG].wake_on = false; + st->sensor_l[SENSOR_L_MAG_CAL].wake_on = false; + st->sensor_l[SENSOR_L_EIS_GYRO].wake_on = false; + st->sensor_l[SENSOR_L_SIXQ].wake_on = false; + st->sensor_l[SENSOR_L_NINEQ].wake_on = false; + st->sensor_l[SENSOR_L_PEDQ].wake_on = false; + + st->sensor_l[SENSOR_L_ACCEL_WAKE].wake_on = true; + st->sensor_l[SENSOR_L_GYRO_WAKE].wake_on = true; + st->sensor_l[SENSOR_L_GYRO_CAL_WAKE].wake_on = true; + st->sensor_l[SENSOR_L_MAG_WAKE].wake_on = true; + st->sensor_l[SENSOR_L_SIXQ_WAKE].wake_on = true; + st->sensor_l[SENSOR_L_NINEQ_WAKE].wake_on = true; + st->sensor_l[SENSOR_L_PEDQ_WAKE].wake_on = true; +} + +static int inv_init_config(struct inv_mpu_state *st) +{ + int res, i; + + st->batch.overflow_on = 0; + st->chip_config.fsr = MPU_INIT_GYRO_SCALE; + st->chip_config.accel_fs = MPU_INIT_ACCEL_SCALE; + st->ped.int_thresh = MPU_INIT_PED_INT_THRESH; + st->ped.step_thresh = MPU_INIT_PED_STEP_THRESH; + st->chip_config.low_power_gyro_on = 1; + st->eis.count_precision = NSEC_PER_MSEC; + st->firmware = 0; + st->fifo_count_mode = BYTE_MODE; +#ifdef TIMER_BASED_BATCHING + st->batch_timeout = 0; + st->is_batch_timer_running = false; +#endif + + st->eng_info[ENGINE_GYRO].base_time = NSEC_PER_SEC; + st->eng_info[ENGINE_ACCEL].base_time = NSEC_PER_SEC; + + inv_init_sensor_struct(st); + res = inv_read_timebase(st); + if (res) + return res; + + res = inv_set_gyro_sf(st); + if (res) + return res; + res = inv_set_accel_sf(st); + if (res) + return res; + res = inv_set_accel_intel(st); + if (res) + return res; + + for (i = 0; i < SENSOR_NUM_MAX; i++) + st->sensor[i].ts = 0; + + for (i = 0; i < SENSOR_NUM_MAX; i++) + st->sensor[i].previous_ts = 0; + + return res; +} + +int inv_mpu_initialize(struct inv_mpu_state *st) +{ + u8 v; + int result; + struct inv_chip_config_s *conf; + struct mpu_platform_data *plat; + + conf = &st->chip_config; + plat = &st->plat_data; + + /* verify whoami */ + result = inv_plat_read(st, REG_WHO_AM_I, 1, &v); + if (result) + return result; + pr_info("whoami= %x\n", v); + if (v == 0x00 || v == 0xff) + return -ENODEV; + + /* reset to make sure previous state are not there */ + result = inv_plat_single_write(st, REG_PWR_MGMT_1, BIT_H_RESET); + if (result) + return result; + usleep_range(REG_UP_TIME_USEC, REG_UP_TIME_USEC); + msleep(100); + /* toggle power state */ + result = inv_set_power(st, false); + if (result) + return result; + result = inv_set_power(st, true); + if (result) + return result; + + result = inv_plat_single_write(st, REG_USER_CTRL, st->i2c_dis); + if (result) + return result; + result = inv_init_config(st); + if (result) + return result; + + result = mem_r(MPU_SOFT_REV_ADDR, 1, &v); + pr_info("sw_rev=%x, res=%d\n", v, result); + if (result) + return result; + st->chip_config.lp_en_mode_off = 0; + + pr_info("%s: Mask %X, v = %X, lp mode = %d\n", __func__, + MPU_SOFT_REV_MASK, v, st->chip_config.lp_en_mode_off); + result = inv_set_power(st, false); + + pr_info("%s: initialize result is %d....\n", __func__, result); + return 0; +} diff --git a/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_parsing_20680.c b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_parsing_20680.c new file mode 100644 index 0000000000000000000000000000000000000000..0f17b6dd2c5260b6f979f1acf1d22dd66c6e5abb --- /dev/null +++ b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_parsing_20680.c @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2017-2018 InvenSense, 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. + */ +#define pr_fmt(fmt) "inv_mpu: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../inv_mpu_iio.h" + +static char iden[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + +static int inv_process_gyro(struct inv_mpu_state *st, u8 *d, u64 t) +{ + s16 raw[3]; + s32 calib[3]; + int i; +#define BIAS_UNIT 2859 + + for (i = 0; i < 3; i++) + raw[i] = be16_to_cpup((__be16 *) (d + i * 2)); + + for (i = 0; i < 3; i++) + calib[i] = (raw[i] << 15); + + + inv_push_gyro_data(st, raw, calib, t); + + return 0; +} + +static int inv_check_fsync(struct inv_mpu_state *st, u8 fsync_status) +{ + u8 data[1]; + + if (!st->chip_config.eis_enable) + return 0; + inv_plat_read(st, REG_FSYNC_INT, 1, data); + if (data[0] & BIT_FSYNC_INT) { + pr_debug("fsync\n"); + st->eis.eis_triggered = true; + st->eis.fsync_delay = 1; + st->eis.prev_state = 1; + st->eis.frame_count++; + st->eis.eis_frame = true; + } + st->header_count--; + + return 0; +} + +static int inv_push_sensor(struct inv_mpu_state *st, int ind, u64 t, u8 *d) +{ +#ifdef ACCEL_BIAS_TEST + s16 acc[3], avg[3]; +#endif + + switch (ind) { + case SENSOR_ACCEL: + inv_convert_and_push_8bytes(st, ind, d, t, iden); +#ifdef ACCEL_BIAS_TEST + acc[0] = be16_to_cpup((__be16 *) (d)); + acc[1] = be16_to_cpup((__be16 *) (d + 2)); + acc[2] = be16_to_cpup((__be16 *) (d + 4)); + if(inv_get_3axis_average(acc, avg, 0)){ + pr_debug("accel 200 samples average = %5d, %5d, %5d\n", avg[0], avg[1], avg[2]); + } +#endif + break; + case SENSOR_TEMP: + inv_check_fsync(st, d[1]); + break; + case SENSOR_GYRO: + inv_process_gyro(st, d, t); + break; + default: + break; + } + + return 0; +} + +static int inv_push_20680_data(struct inv_mpu_state *st, u8 *d) +{ + u8 *dptr; + int i; + + dptr = d; + + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) { + inv_get_dmp_ts(st, i); + if (st->sensor[i].send && (!st->ts_algo.first_sample)) { + st->sensor[i].sample_calib++; + inv_push_sensor(st, i, st->sensor[i].ts, dptr); + } + dptr += st->sensor[i].sample_size; + } + } + if (st->ts_algo.first_sample) + st->ts_algo.first_sample--; + st->header_count--; + + return 0; +} + +static int inv_process_20680_data(struct inv_mpu_state *st) +{ + int total_bytes, tmp, res, fifo_count, pk_size, i; + u8 *dptr, *d; + u8 data[14]; + bool done_flag; + u8 v; +#ifdef SENSOR_DATA_FROM_REGISTERS + u8 reg; + int len; +#endif + + if(st->gesture_only_on && (!st->batch.timeout)) { + res = inv_plat_read(st, REG_INT_STATUS, 1, data); + if (res) + return res; + pr_debug("ges cnt=%d, statu=%x\n", + st->gesture_int_count, data[0]); + if (data[0] & (BIT_WOM_ALL_INT_EN)) { + if (!st->gesture_int_count) { + inv_switch_power_in_lp(st, true); + res = inv_plat_single_write(st, REG_INT_ENABLE, + BIT_WOM_ALL_INT_EN | BIT_DATA_RDY_EN); + if (res) + return res; + v = 0; + if (st->chip_config.gyro_enable) + v |= BITS_GYRO_FIFO_EN; + + if (st->chip_config.accel_enable) + v |= BIT_ACCEL_FIFO_EN; + res = inv_plat_single_write(st, REG_FIFO_EN, v); + if (res) + return res; + /* First time wake up from WOM. + We don't need data in the FIFO */ + res = inv_reset_fifo(st, true); + if (res) + return res; + res = inv_switch_power_in_lp(st, false); + st->gesture_int_count = WOM_DELAY_THRESHOLD; + + return res; + } + st->gesture_int_count = WOM_DELAY_THRESHOLD; + } else { + if (!st->gesture_int_count) { + inv_switch_power_in_lp(st, true); + res = inv_plat_single_write(st, REG_FIFO_EN, 0); + res = inv_plat_single_write(st, REG_INT_ENABLE, + BIT_WOM_ALL_INT_EN); + inv_switch_power_in_lp(st, false); + + return res; + } + st->gesture_int_count--; + } + } + + fifo_count = inv_get_last_run_time_non_dmp_record_mode(st); + pr_debug("fifc= %d\n", fifo_count); + if (!fifo_count) { + pr_debug("REG_FIFO_COUNT_H size is 0\n"); + return 0; + } + pk_size = st->batch.pk_size; + if (!pk_size) + return -EINVAL; + + if (fifo_count >= (HARDWARE_FIFO_SIZE / st->batch.pk_size)) { + pr_warn("fifo overflow pkt count=%d pkt sz=%d\n", fifo_count, st->batch.pk_size); + return -EOVERFLOW; + } + + fifo_count *= st->batch.pk_size; + st->fifo_count = fifo_count; + d = st->fifo_data_store; + dptr = d; + total_bytes = fifo_count; + +#ifdef SENSOR_DATA_FROM_REGISTERS + len = 0; + if (st->sensor[SENSOR_GYRO].on) { + reg = REG_RAW_GYRO; + len += BYTES_PER_SENSOR; + if (st->sensor[SENSOR_ACCEL].on && !st->sensor[SENSOR_TEMP].on) + len += BYTES_FOR_TEMP; + } + if (st->sensor[SENSOR_TEMP].on) { + reg = REG_RAW_TEMP; + len += BYTES_FOR_TEMP; + } + if (st->sensor[SENSOR_ACCEL].on) { + reg = REG_RAW_ACCEL; + len += BYTES_PER_SENSOR; + } + + if (len == 0) { + pr_debug("No sensor is enabled\n"); + return 0; + } + + /* read data registers */ + res = inv_plat_read(st, reg, len, data); + if (res < 0) { + pr_err("read data registers is failed\n"); + return res; + } + + /* copy sensor data to buffer as FIFO data format */ + tmp = 0; + if (st->sensor[SENSOR_ACCEL].on) { + for (i = 0; i < BYTES_PER_SENSOR; i++) + dptr[i] = data[tmp + i]; + dptr += BYTES_PER_SENSOR; + tmp += BYTES_PER_SENSOR; + } + + if (st->sensor[SENSOR_TEMP].on) { + for (i = 0; i < BYTES_FOR_TEMP; i++) + dptr[i] = data[tmp + i]; + dptr += BYTES_FOR_TEMP; + tmp += BYTES_FOR_TEMP; + } + + if (st->sensor[SENSOR_GYRO].on) { + if (st->sensor[SENSOR_ACCEL].on && !st->sensor[SENSOR_TEMP].on) + tmp += BYTES_FOR_TEMP; + for (i = 0; i < BYTES_PER_SENSOR; i++) + dptr[i] = data[tmp + i]; + } +#else + while (total_bytes > 0) { + if (total_bytes < pk_size * MAX_FIFO_PACKET_READ) + tmp = total_bytes; + else + tmp = pk_size * MAX_FIFO_PACKET_READ; + res = inv_plat_read(st, REG_FIFO_R_W, tmp, dptr); + if (res < 0) { + pr_err("read REG_FIFO_R_W is failed\n"); + return res; + } + pr_debug("inside: %x, %x, %x, %x, %x, %x, %x, %x\n", dptr[0], dptr[1], dptr[2], + dptr[3], dptr[4], dptr[5], dptr[6], dptr[7]); + pr_debug("insid2: %x, %x, %x, %x, %x, %x, %x, %x\n", dptr[8], dptr[9], dptr[10], + dptr[11], dptr[12], dptr[13], dptr[14], dptr[15]); + + dptr += tmp; + total_bytes -= tmp; + } +#endif /* SENSOR_DATA_FROM_REGISTERS */ + dptr = d; + pr_debug("dd: %x, %x, %x, %x, %x, %x, %x, %x\n", d[0], d[1], d[2], + d[3], d[4], d[5], d[6], d[7]); + pr_debug("dd2: %x, %x, %x, %x, %x, %x, %x, %x\n", d[8], d[9], d[10], + d[11], d[12], d[13], d[14], d[15]); + total_bytes = fifo_count; + + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) { + st->sensor[i].count = total_bytes / pk_size; + } + } + st->header_count = 0; + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) + st->header_count = max(st->header_count, + st->sensor[i].count); + } + + st->ts_algo.calib_counter++; + inv_bound_timestamp(st); + + dptr = d; + done_flag = false; + + while (!done_flag) { + pr_debug("total%d, pk=%d\n", total_bytes, pk_size); + if (total_bytes >= pk_size) { + res = inv_push_20680_data(st, dptr); + if (res) + return res; + total_bytes -= pk_size; + dptr += pk_size; + } else { + done_flag = true; + } + } + + return 0; +} + +/* + * _inv_read_fifo() - Transfer data from FIFO to ring buffer. + */ +static void _inv_read_fifo(struct inv_mpu_state *st) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + int result; + + result = wait_event_interruptible_timeout(st->wait_queue, + st->resume_state, msecs_to_jiffies(300)); + if (result <= 0) + return; + mutex_lock(&indio_dev->mlock); +#ifdef TIMER_BASED_BATCHING + if (st->batch_timeout) { + if (inv_plat_single_write(st, REG_INT_ENABLE, st->int_en)) + pr_err("REG_INT_ENABLE write error\n"); + } +#endif + st->wake_sensor_received = false; + result = inv_process_20680_data(st); + if (result) + goto err_reset_fifo; + mutex_unlock(&indio_dev->mlock); + + if (st->wake_sensor_received) +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_timeout(&st->wake_lock, msecs_to_jiffies(200)); +#else + __pm_wakeup_event(&st->wake_lock, 200); /* 200 msecs */ +#endif + return; + +err_reset_fifo: + if ((!st->chip_config.gyro_enable) && + (!st->chip_config.accel_enable) && + (!st->chip_config.slave_enable) && + (!st->chip_config.pressure_enable)) { + inv_switch_power_in_lp(st, false); + mutex_unlock(&indio_dev->mlock); + + return; + } + + pr_err("error to reset fifo\n"); + inv_switch_power_in_lp(st, true); + inv_reset_fifo(st, true); + inv_switch_power_in_lp(st, false); + mutex_unlock(&indio_dev->mlock); + + return; +} + +irqreturn_t inv_read_fifo(int irq, void *dev_id) +{ + struct inv_mpu_state *st = (struct inv_mpu_state *)dev_id; + + _inv_read_fifo(st); + + return IRQ_HANDLED; +} + +#ifdef TIMER_BASED_BATCHING +void inv_batch_work(struct work_struct *work) +{ + struct inv_mpu_state *st = + container_of(work, struct inv_mpu_state, batch_work); + struct iio_dev *indio_dev = iio_priv_to_dev(st); + + mutex_lock(&indio_dev->mlock); + if (inv_plat_single_write(st, REG_INT_ENABLE, st->int_en | BIT_DATA_RDY_EN)) + pr_err("REG_INT_ENABLE write error\n"); + mutex_unlock(&indio_dev->mlock); + + return; +} +#endif + +int inv_flush_batch_data(struct iio_dev *indio_dev, int data) +{ + struct inv_mpu_state *st = iio_priv(indio_dev); + +#ifndef SENSOR_DATA_FROM_REGISTERS + if (st->chip_config.gyro_enable || + st->chip_config.accel_enable || + st->chip_config.slave_enable || + st->chip_config.pressure_enable) { + st->wake_sensor_received = 0; + inv_process_20680_data(st); + if (st->wake_sensor_received) +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_timeout(&st->wake_lock, msecs_to_jiffies(200)); +#else + __pm_wakeup_event(&st->wake_lock, 200); /* 200 msecs */ +#endif + inv_switch_power_in_lp(st, false); + } +#endif /* SENSOR_DATA_FROM_REGISTERS */ + inv_push_marker_to_buffer(st, END_MARKER, data); + + return 0; +} + diff --git a/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_selftest_20680.c b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_selftest_20680.c new file mode 100644 index 0000000000000000000000000000000000000000..7a90b4d8b8825451372ebf9913b70a201df99058 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_selftest_20680.c @@ -0,0 +1,752 @@ +/* +* Copyright (C) 2017-2018 InvenSense, 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. +*/ +#define pr_fmt(fmt) "inv_mpu: " fmt + +#include "../inv_mpu_iio.h" + +/* register settings */ +#define DEF_SELFTEST_GYRO_SENS (32768 / 250) +/* wait time before collecting data */ +#define MAX_PACKETS 20 +#define SELFTEST_WAIT_TIME (MAX_PACKETS * 10) +#define DEF_ST_STABLE_TIME 20 +#define DEF_GYRO_SCALE 131 +#define DEF_ST_PRECISION 1000 +#define DEF_ST_ACCEL_FS_MG 2000UL +#define DEF_ST_SCALE 32768 +#define DEF_ST_TRY_TIMES 2 +#define DEF_ST_ACCEL_RESULT_SHIFT 1 +#define DEF_ST_SAMPLES 200 + +#define DEF_ACCEL_ST_SHIFT_DELTA_MIN 500 +#define DEF_ACCEL_ST_SHIFT_DELTA_MAX 1500 +#define DEF_GYRO_CT_SHIFT_DELTA 500 + +#define SENSOR_UP_TIME 30 +#define REG_UP_TIME 2 + +#define DEF_ST_ACCEL_FS_MG 2000UL +#define DEF_ACCEL_ST_SHIFT_DELTA 500 +#define ACCEL_ST_AL_MIN ((DEF_ACCEL_ST_AL_MIN * DEF_ST_SCALE \ + / DEF_ST_ACCEL_FS_MG) * DEF_ST_PRECISION) +#define ACCEL_ST_AL_MAX ((DEF_ACCEL_ST_AL_MAX * DEF_ST_SCALE \ + / DEF_ST_ACCEL_FS_MG) * DEF_ST_PRECISION) + +#define THREE_AXIS 3 +#define DEF_ST_MPU6500_ACCEL_LPF 2 +#define DEF_SELFTEST_SAMPLE_RATE 0 /* 1000Hz */ +#define DEF_SELFTEST_SAMPLE_RATE_LP 3 /* 250Hz */ +#define DEF_SELFTEST_SAMPLE_RATE_ACC_LP 10 /* 250Hz LPOSC_CLKSEL */ +#define INV_MPU_SAMPLE_RATE_CHANGE_STABLE 50 +#define DEF_SELFTEST_6500_ACCEL_FS (0 << 3) +#define DEF_SELFTEST_GYRO_FS (0 << 3) +#define DEF_ST_6500_STABLE_TIME 20 +#define BIT_ACCEL_OUT 0x08 +#define BITS_GYRO_OUT 0x70 +#define THREE_AXIS 3 +#define DEF_GYRO_WAIT_TIME 10 +#define DEF_GYRO_WAIT_TIME_LP 50 + +/* Gyro Offset Max Value (dps) */ +#define DEF_GYRO_OFFSET_MAX 20 +/* Gyro Self Test Absolute Limits ST_AL (dps) */ +#define DEF_GYRO_ST_AL 60 +/* Accel Self Test Absolute Limits ST_AL (mg) */ +#define DEF_ACCEL_ST_AL_MIN 225 +#define DEF_ACCEL_ST_AL_MAX 675 + +struct recover_regs { + u8 int_enable; /* REG_INT_ENABLE */ + u8 fifo_en; /* REG_FIFO_EN */ + u8 user_ctrl; /* REG_USER_CTRL */ + u8 config; /* REG_CONFIG */ + u8 gyro_config; /* REG_GYRO_CONFIG */ + u8 accel_config; /* REG_ACCEL_CONFIG */ + u8 accel_config_2; /* REG_ACCEL_CONFIG_2 */ + u8 smplrt_div; /* REG_SAMPLE_RATE_DIV */ + u8 lp_mode; /* REG_LP_MODE_CTRL */ + u8 pwr_mgmt_1; /* REG_PWR_MGMT_1 */ + u8 pwr_mgmt_2; /* REG_PWR_MGMT_2 */ +}; + +static struct recover_regs saved_regs; + +static const u16 mpu_st_tb[256] = { + 2620, 2646, 2672, 2699, 2726, 2753, 2781, 2808, + 2837, 2865, 2894, 2923, 2952, 2981, 3011, 3041, + 3072, 3102, 3133, 3165, 3196, 3228, 3261, 3293, + 3326, 3359, 3393, 3427, 3461, 3496, 3531, 3566, + 3602, 3638, 3674, 3711, 3748, 3786, 3823, 3862, + 3900, 3939, 3979, 4019, 4059, 4099, 4140, 4182, + 4224, 4266, 4308, 4352, 4395, 4439, 4483, 4528, + 4574, 4619, 4665, 4712, 4759, 4807, 4855, 4903, + 4953, 5002, 5052, 5103, 5154, 5205, 5257, 5310, + 5363, 5417, 5471, 5525, 5581, 5636, 5693, 5750, + 5807, 5865, 5924, 5983, 6043, 6104, 6165, 6226, + 6289, 6351, 6415, 6479, 6544, 6609, 6675, 6742, + 6810, 6878, 6946, 7016, 7086, 7157, 7229, 7301, + 7374, 7448, 7522, 7597, 7673, 7750, 7828, 7906, + 7985, 8065, 8145, 8227, 8309, 8392, 8476, 8561, + 8647, 8733, 8820, 8909, 8998, 9088, 9178, 9270, + 9363, 9457, 9551, 9647, 9743, 9841, 9939, 10038, + 10139, 10240, 10343, 10446, 10550, 10656, 10763, 10870, + 10979, 11089, 11200, 11312, 11425, 11539, 11654, 11771, + 11889, 12008, 12128, 12249, 12371, 12495, 12620, 12746, + 12874, 13002, 13132, 13264, 13396, 13530, 13666, 13802, + 13940, 14080, 14221, 14363, 14506, 14652, 14798, 14946, + 15096, 15247, 15399, 15553, 15709, 15866, 16024, 16184, + 16346, 16510, 16675, 16842, 17010, 17180, 17352, 17526, + 17701, 17878, 18057, 18237, 18420, 18604, 18790, 18978, + 19167, 19359, 19553, 19748, 19946, 20145, 20347, 20550, + 20756, 20963, 21173, 21385, 21598, 21814, 22033, 22253, + 22475, 22700, 22927, 23156, 23388, 23622, 23858, 24097, + 24338, 24581, 24827, 25075, 25326, 25579, 25835, 26093, + 26354, 26618, 26884, 27153, 27424, 27699, 27976, 28255, + 28538, 28823, 29112, 29403, 29697, 29994, 30294, 30597, + 30903, 31212, 31524, 31839, 32157, 32479, 32804 +}; + +static void inv_show_saved_setting(struct inv_mpu_state *st) +{ + pr_debug(" REG_INT_ENABLE : 0x%02X\n", saved_regs.int_enable); + pr_debug(" REG_FIFO_EN : 0x%02X\n", saved_regs.fifo_en); + pr_debug(" REG_USER_CTRL : 0x%02X\n", saved_regs.user_ctrl); + pr_debug(" REG_CONFIG : 0x%02X\n", saved_regs.config); + pr_debug(" REG_GYRO_CONFIG : 0x%02X\n", saved_regs.gyro_config); + pr_debug(" REG_ACCEL_CONFIG : 0x%02X\n", saved_regs.accel_config); + pr_debug(" REG_ACCEL_CONFIG_2 : 0x%02X\n", saved_regs.accel_config_2); + pr_debug(" REG_SAMPLE_RATE_DIV : 0x%02X\n", saved_regs.smplrt_div); + pr_debug(" REG_LP_MODE_CTRL : 0x%02X\n", saved_regs.lp_mode); + pr_debug(" REG_PWR_MGMT_1 : 0x%02X\n", saved_regs.pwr_mgmt_1); + pr_debug(" REG_PWR_MGMT_2 : 0x%02X\n", saved_regs.pwr_mgmt_2); +} + +static int inv_save_setting(struct inv_mpu_state *st) +{ + int result; + + result = inv_plat_read(st, REG_PWR_MGMT_1, 1, + &saved_regs.pwr_mgmt_1); + if (result) + return result; + + /* wake up */ + result = inv_plat_single_write(st, REG_PWR_MGMT_1, + (saved_regs.pwr_mgmt_1 & ~BIT_SLEEP)); + if (result) + return result; + + result = inv_plat_read(st, REG_INT_ENABLE, 1, + &saved_regs.int_enable); + if (result) + return result; + result = inv_plat_read(st, REG_FIFO_EN, 1, + &saved_regs.fifo_en); + if (result) + return result; + result = inv_plat_read(st, REG_USER_CTRL, 1, + &saved_regs.user_ctrl); + if (result) + return result; + result = inv_plat_read(st, REG_CONFIG, 1, + &saved_regs.config); + if (result) + return result; + result = inv_plat_read(st, REG_GYRO_CONFIG, 1, + &saved_regs.gyro_config); + if (result) + return result; + result = inv_plat_read(st, REG_ACCEL_CONFIG, 1, + &saved_regs.accel_config); + if (result) + return result; + result = inv_plat_read(st, REG_ACCEL_CONFIG_2, 1, + &saved_regs.accel_config_2); + if (result) + return result; + result = inv_plat_read(st, REG_SAMPLE_RATE_DIV, 1, + &saved_regs.smplrt_div); + if (result) + return result; + result = inv_plat_read(st, REG_LP_MODE_CTRL, 1, + &saved_regs.lp_mode); + if (result) + return result; + result = inv_plat_read(st, REG_PWR_MGMT_2, 1, + &saved_regs.pwr_mgmt_2); + if (result) + return result; + + inv_show_saved_setting(st); + + return result; +} + +static int inv_recover_setting(struct inv_mpu_state *st) +{ + int result; + /* Stop sensors */ + result = inv_plat_single_write(st, REG_PWR_MGMT_2, + BIT_PWR_ACCEL_STBY | BIT_PWR_GYRO_STBY); + if (result) + return result; + + /* Restore sensor configurations */ + result = inv_plat_single_write(st, REG_INT_ENABLE, + saved_regs.int_enable); + if (result) + return result; + result = inv_plat_single_write(st, REG_FIFO_EN, + saved_regs.fifo_en); + if (result) + return result; + result = inv_plat_single_write(st, REG_USER_CTRL, + saved_regs.user_ctrl); + if (result) + return result; + result = inv_plat_single_write(st, REG_CONFIG, + saved_regs.config); + if (result) + return result; + result = inv_plat_single_write(st, REG_GYRO_CONFIG, + saved_regs.gyro_config); + if (result) + return result; + result = inv_plat_single_write(st, REG_ACCEL_CONFIG, + saved_regs.accel_config); + if (result) + return result; + result = inv_plat_single_write(st, REG_ACCEL_CONFIG_2, + saved_regs.accel_config_2); + if (result) + return result; + result = inv_plat_single_write(st, REG_SAMPLE_RATE_DIV, + saved_regs.smplrt_div); + if (result) + return result; + result = inv_plat_single_write(st, REG_LP_MODE_CTRL, + saved_regs.lp_mode); + if (result) + return result; + result = inv_plat_single_write(st, REG_PWR_MGMT_1, + saved_regs.pwr_mgmt_1); + if (result) + return result; + + result = inv_plat_single_write(st, REG_PWR_MGMT_2, + saved_regs.pwr_mgmt_2); + if (result) + return result; + + return result; +} + +int inv_switch_engine(struct inv_mpu_state *st, bool en, u32 mask) +{ + u8 data, mgmt_1; + int result; + + if (BIT_PWR_GYRO_STBY == mask) { + result = inv_plat_read(st, REG_PWR_MGMT_1, 1, &mgmt_1); + if (result) + return result; + mgmt_1 &= ~BIT_CLK_MASK; + } + + if ((BIT_PWR_GYRO_STBY == mask) && (!en)) { + result = inv_plat_single_write(st, REG_PWR_MGMT_1, mgmt_1); + if (result) + return result; + } + + result = inv_plat_read(st, REG_PWR_MGMT_2, 1, &data); + if (result) + return result; + if (en) + data &= (~mask); + else + data |= mask; + data |= BIT_FIFO_LP_EN; + result = inv_plat_single_write(st, REG_PWR_MGMT_2, data); + if (result) + return result; + + if ((BIT_PWR_GYRO_STBY == mask) && en) { + /* only gyro on needs sensor up time */ + msleep(SENSOR_UP_TIME); + /* after gyro is on & stable, switch internal clock to PLL */ + mgmt_1 |= BIT_CLK_PLL; + result = inv_plat_single_write(st, REG_PWR_MGMT_1, mgmt_1); + if (result) + return result; + } + if ((BIT_PWR_ACCEL_STBY == mask) && en) + msleep(REG_UP_TIME); + + return 0; +} + +int inv_set_offset_reg(struct inv_mpu_state *st, int reg, int val) +{ + int result; + u8 d; + + d = ((val >> 8) & 0xff); + result = inv_plat_single_write(st, reg, d); + if (result) + return result; + + d = (val & 0xff); + result = inv_plat_single_write(st, reg + 1, d); + + return result; +} + +/** +* inv_check_gyro_self_test() - check gyro self test. this function +* returns zero as success. A non-zero return +* value indicates failure in self test. +* @*st: main data structure. +* @*reg_avg: average value of normal test. +* @*st_avg: average value of self test +*/ +int inv_check_gyro_self_test(struct inv_mpu_state *st, + int *reg_avg, int *st_avg) { + u8 regs[3]; + int ret_val, result; + int otp_value_zero = 0; + int st_shift_prod[3], st_shift_cust[3], i; + + ret_val = 0; + result = inv_plat_read(st, REG_6500_XG_ST_DATA, 3, regs); + if (result) + return result; + pr_debug("%s self_test gyro shift_code - %02x %02x %02x\n", + st->hw->name, regs[0], regs[1], regs[2]); + + for (i = 0; i < 3; i++) { + if (regs[i] != 0) { + st_shift_prod[i] = mpu_st_tb[regs[i] - 1]; + } else { + st_shift_prod[i] = 0; + otp_value_zero = 1; + } + } + pr_debug("%s self_test gyro st_shift_prod - %+d %+d %+d\n", + st->hw->name, st_shift_prod[0], st_shift_prod[1], + st_shift_prod[2]); + + for (i = 0; i < 3; i++) { + st_shift_cust[i] = st_avg[i] - reg_avg[i]; + if (!otp_value_zero) { + /* Self Test Pass/Fail Criteria A */ + if (st_shift_cust[i] < DEF_GYRO_CT_SHIFT_DELTA + * st_shift_prod[i]) + ret_val = 1; + } else { + /* Self Test Pass/Fail Criteria B */ + if (st_shift_cust[i] < DEF_GYRO_ST_AL * + DEF_SELFTEST_GYRO_SENS * + DEF_ST_PRECISION) + ret_val = 1; + } + } + pr_debug("%s self_test gyro st_shift_cust - %+d %+d %+d\n", + st->hw->name, st_shift_cust[0], st_shift_cust[1], + st_shift_cust[2]); + + if (ret_val == 0) { + /* Self Test Pass/Fail Criteria C */ + for (i = 0; i < 3; i++) + if (abs(reg_avg[i]) > DEF_GYRO_OFFSET_MAX * + DEF_SELFTEST_GYRO_SENS * + DEF_ST_PRECISION) + ret_val = 1; + } + + return ret_val; +} + +/** +* inv_check_accel_self_test() - check 6500 accel self test. this function +* returns zero as success. A non-zero return +* value indicates failure in self test. +* @*st: main data structure. +* @*reg_avg: average value of normal test. +* @*st_avg: average value of self test +*/ +int inv_check_accel_self_test(struct inv_mpu_state *st, + int *reg_avg, int *st_avg) { + int ret_val, result; + int st_shift_prod[3], st_shift_cust[3], st_shift_ratio[3], i; + u8 regs[3]; + int otp_value_zero = 0; + + ret_val = 0; + result = inv_plat_read(st, REG_6500_XA_ST_DATA, 3, regs); + if (result) + return result; + pr_debug("%s self_test accel shift_code - %02x %02x %02x\n", + st->hw->name, regs[0], regs[1], regs[2]); + + for (i = 0; i < 3; i++) { + if (regs[i] != 0) { + st_shift_prod[i] = mpu_st_tb[regs[i] - 1]; + } else { + st_shift_prod[i] = 0; + otp_value_zero = 1; + } + } + pr_debug("%s self_test accel st_shift_prod - %+d %+d %+d\n", + st->hw->name, st_shift_prod[0], st_shift_prod[1], + st_shift_prod[2]); + + if (!otp_value_zero) { + /* Self Test Pass/Fail Criteria A */ + for (i = 0; i < 3; i++) { + st_shift_cust[i] = st_avg[i] - reg_avg[i]; + st_shift_ratio[i] = abs(st_shift_cust[i] / + st_shift_prod[i] - DEF_ST_PRECISION); + if (st_shift_ratio[i] > DEF_ACCEL_ST_SHIFT_DELTA) + ret_val = 1; + } + } else { + /* Self Test Pass/Fail Criteria B */ + for (i = 0; i < 3; i++) { + st_shift_cust[i] = abs(st_avg[i] - reg_avg[i]); + if (st_shift_cust[i] < ACCEL_ST_AL_MIN || + st_shift_cust[i] > ACCEL_ST_AL_MAX) + ret_val = 1; + } + } + pr_debug("%s self_test accel st_shift_cust - %+d %+d %+d\n", + st->hw->name, st_shift_cust[0], st_shift_cust[1], + st_shift_cust[2]); + + return ret_val; +} + +/* + * inv_do_test() - do the actual test of self testing + */ +int inv_do_test(struct inv_mpu_state *st, int self_test_flag, + int *gyro_result, int *accel_result, int lp_mode) +{ + int result, i, j, packet_size; + u8 data[BYTES_PER_SENSOR * 2], d, dd; + int fifo_count, packet_count, ind, s; + + packet_size = BYTES_PER_SENSOR * 2; + + /* disable interrupt */ + result = inv_plat_single_write(st, REG_INT_ENABLE, 0); + if (result) + return result; + /* disable the sensor output to FIFO */ + result = inv_plat_single_write(st, REG_FIFO_EN, 0); + if (result) + return result; + /* disable fifo reading */ + result = inv_plat_single_write(st, REG_USER_CTRL, 0); + if (result) + return result; + /* clear FIFO */ + result = inv_plat_single_write(st, REG_USER_CTRL, BIT_FIFO_RST); + if (result) + return result; + /* setup parameters */ + result = inv_plat_single_write(st, REG_CONFIG, INV_FILTER_98HZ); + if (result) + return result; + + /* gyro lp mode */ + if (lp_mode == 1) + d = BIT_GYRO_CYCLE_EN; + else if (lp_mode == 2) + d = DEF_SELFTEST_SAMPLE_RATE_ACC_LP; + else + d = 0; + result = inv_plat_single_write(st, REG_LP_MODE_CTRL, d); + if (result) + return result; + + /* config accel LPF register */ + if (lp_mode == 2) + d = BIT_ACCEL_FCHOCIE_B; + else + d = DEF_ST_MPU6500_ACCEL_LPF; + result = inv_plat_single_write(st, REG_6500_ACCEL_CONFIG2, d); + if (result) + return result; + + if (lp_mode) { + result = inv_plat_single_write(st, REG_SAMPLE_RATE_DIV, + DEF_SELFTEST_SAMPLE_RATE_LP); + } else { + result = inv_plat_single_write(st, REG_SAMPLE_RATE_DIV, + DEF_SELFTEST_SAMPLE_RATE); + } + if (result) + return result; + /* wait for the sampling rate change to stabilize */ + mdelay(INV_MPU_SAMPLE_RATE_CHANGE_STABLE); + result = inv_plat_single_write(st, REG_GYRO_CONFIG, + self_test_flag | DEF_SELFTEST_GYRO_FS); + if (result) + return result; + + d = DEF_SELFTEST_6500_ACCEL_FS; + d |= self_test_flag; + result = inv_plat_single_write(st, REG_ACCEL_CONFIG, d); + if (result) + return result; + + /* wait for the output to get stable */ + msleep(DEF_ST_6500_STABLE_TIME); + + /* enable FIFO reading */ + result = inv_plat_single_write(st, REG_USER_CTRL, BIT_FIFO_EN); + if (result) + return result; + /* enable sensor output to FIFO */ + d = BITS_GYRO_OUT | BIT_ACCEL_OUT; + for (i = 0; i < THREE_AXIS; i++) { + gyro_result[i] = 0; + accel_result[i] = 0; + } + s = 0; + while (s < 200 /*st->self_test.samples*/) { + /* Stop FIFO */ + result = inv_plat_single_write(st, REG_USER_CTRL, 0); + if (result) + return result; + /* clear FIFO */ + result = inv_plat_single_write(st, REG_USER_CTRL, BIT_FIFO_RST); + if (result) + return result; + /* enable FIFO reading */ + result = inv_plat_single_write(st, REG_USER_CTRL, BIT_FIFO_EN); + if (result) + return result; + + /* accel lp mode */ + dd = BIT_CLK_PLL; + if (lp_mode == 2) + dd |= BIT_LP_EN; + else + dd &= ~BIT_LP_EN; + result = inv_plat_single_write(st, REG_PWR_MGMT_1, dd); + if (result) + return result; + + result = inv_plat_single_write(st, REG_FIFO_EN, d); + if (result) + return result; + if (lp_mode) + mdelay(DEF_GYRO_WAIT_TIME_LP); + else + mdelay(DEF_GYRO_WAIT_TIME); + + result = inv_plat_single_write(st, REG_FIFO_EN, 0); + if (result) + return result; + + result = inv_plat_read(st, REG_FIFO_COUNT_H, + FIFO_COUNT_BYTE, data); + if (result) + return result; + fifo_count = be16_to_cpup((__be16 *)(&data[0])); + pr_debug("%s self_test fifo_count - %d\n", + st->hw->name, fifo_count); + packet_count = fifo_count / packet_size; + i = 0; + while ((i < packet_count) && (s < 200 /*st->self_test.samples*/)) { + short vals[3]; + result = inv_plat_read(st, REG_FIFO_R_W, + packet_size, data); + if (result) + return result; + ind = 0; + + for (j = 0; j < THREE_AXIS; j++) { + vals[j] = (short)be16_to_cpup( + (__be16 *)(&data[ind + 2 * j])); + accel_result[j] += vals[j]; + } + ind += BYTES_PER_SENSOR; + pr_debug( + "%s self_test accel data - %d %+d %+d %+d", + st->hw->name, s, vals[0], vals[1], vals[2]); + + for (j = 0; j < THREE_AXIS; j++) { + vals[j] = (short)be16_to_cpup( + (__be16 *)(&data[ind + 2 * j])); + gyro_result[j] += vals[j]; + } + pr_debug("%s self_test gyro data - %d %+d %+d %+d", + st->hw->name, s, vals[0], vals[1], vals[2]); + + s++; + i++; + } + } + + for (j = 0; j < THREE_AXIS; j++) { + accel_result[j] = accel_result[j] / s; + accel_result[j] *= DEF_ST_PRECISION; + } + for (j = 0; j < THREE_AXIS; j++) { + gyro_result[j] = gyro_result[j] / s; + gyro_result[j] *= DEF_ST_PRECISION; + } + + return 0; +} + + +int inv_power_up_self_test(struct inv_mpu_state *st) +{ + int result; + + result = inv_switch_power_in_lp(st, true); + + /* make sure no interrupts */ + result = inv_plat_single_write(st, REG_INT_ENABLE, 0); + if (result) + return result; + + if (result) + return result; + result = inv_switch_engine(st, true, BIT_PWR_ACCEL_STBY); + if (result) + return result; + result = inv_switch_engine(st, true, BIT_PWR_GYRO_STBY); + if (result) + return result; + + return 0; +} + +/* + * inv_hw_self_test() - main function to do hardware self test + */ +int inv_hw_self_test(struct inv_mpu_state *st) +{ + int result; + int gyro_bias_st[THREE_AXIS], gyro_bias_regular[THREE_AXIS]; + int accel_bias_st[THREE_AXIS], accel_bias_regular[THREE_AXIS]; +#if 0 + int gyro_bias_regular_lp[THREE_AXIS]; + int accel_bias_regular_lp[THREE_AXIS]; + int dummy_bias_regular[THREE_AXIS]; +#endif + int test_times, i; + char accel_result, gyro_result; + + result = inv_save_setting(st); + if (result) + return result; + + result = inv_power_up_self_test(st); + if (result) + return result; + accel_result = 0; + gyro_result = 0; + test_times = DEF_ST_TRY_TIMES; + while (test_times > 0) { + result = inv_do_test(st, 0, gyro_bias_regular, + accel_bias_regular, 0); + if (result == -EAGAIN) + test_times--; + else + test_times = 0; + } + if (result) + goto test_fail; + pr_debug("%s self_test accel bias_regular - %+d %+d %+d\n", + st->hw->name, accel_bias_regular[0], + accel_bias_regular[1], accel_bias_regular[2]); + pr_debug("%s self_test gyro bias_regular - %+d %+d %+d\n", + st->hw->name, gyro_bias_regular[0], gyro_bias_regular[1], + gyro_bias_regular[2]); + + test_times = DEF_ST_TRY_TIMES; + while (test_times > 0) { + result = inv_do_test(st, BITS_SELF_TEST_EN, gyro_bias_st, + accel_bias_st, 0); + if (result == -EAGAIN) + test_times--; + else + break; + } + if (result) + goto test_fail; + pr_debug("%s self_test accel bias_st - %+d %+d %+d\n", + st->hw->name, accel_bias_st[0], accel_bias_st[1], + accel_bias_st[2]); + pr_debug("%s self_test gyro bias_st - %+d %+d %+d\n", + st->hw->name, gyro_bias_st[0], gyro_bias_st[1], + gyro_bias_st[2]); + +#if 0 + /* lp gyro mode */ + test_times = DEF_ST_TRY_TIMES; + while (test_times > 0) { + result = inv_do_test(st, 0, gyro_bias_regular_lp, + dummy_bias_regular, 1); + if (result == -EAGAIN) + test_times--; + else + test_times = 0; + } + if (result) + goto test_fail; + pr_debug("%s self_test gyro bias_regular lp - %+d %+d %+d\n", + st->hw->name, gyro_bias_regular_lp[0], gyro_bias_regular_lp[1], + gyro_bias_regular_lp[2]); + + /* lp accel mode */ + test_times = DEF_ST_TRY_TIMES; + while (test_times > 0) { + result = inv_do_test(st, 0, dummy_bias_regular, + accel_bias_regular_lp, 2); + if (result == -EAGAIN) + test_times--; + else + test_times = 0; + } + if (result) + goto test_fail; + pr_debug("%s self_test accel bias_regular lp - %+d %+d %+d\n", + st->hw->name, accel_bias_regular_lp[0], + accel_bias_regular_lp[1], accel_bias_regular_lp[2]); +#endif + + /* copy bias */ + for (i = 0; i < 3; i++) { + /* gyro : LN bias as LN is default mode */ + st->gyro_st_bias[i] = gyro_bias_regular[i] / DEF_ST_PRECISION; + /* accel : LN bias as LN is default mode */ + st->accel_st_bias[i] = accel_bias_regular[i] / DEF_ST_PRECISION; + } + + /* Check is done on continuous mode data */ + accel_result = !inv_check_accel_self_test(st, + accel_bias_regular, accel_bias_st); + gyro_result = !inv_check_gyro_self_test(st, + gyro_bias_regular, gyro_bias_st); + +test_fail: + inv_recover_setting(st); + return (accel_result << DEF_ST_ACCEL_RESULT_SHIFT) | gyro_result; +} diff --git a/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_setup_20680.c b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_setup_20680.c new file mode 100644 index 0000000000000000000000000000000000000000..b3ae5dd77e84934652889bdb0c2464da44489365 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/iam20680/inv_mpu_setup_20680.c @@ -0,0 +1,469 @@ +/* +* Copyright (C) 2017-2018 InvenSense, 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. +*/ +#define pr_fmt(fmt) "inv_mpu: " fmt +#include "../inv_mpu_iio.h" + +/* set LN mode for gyro regardless of conditions */ +#define USE_GYRO_LN_MODE + +static int inv_calc_engine_dur(struct inv_engine_info *ei) +{ + if (!ei->running_rate) + return -EINVAL; + ei->dur = ei->base_time / ei->orig_rate; + ei->dur *= ei->divider; + + return 0; +} + +static int inv_turn_on_fifo(struct inv_mpu_state *st) +{ + u8 int_en, fifo_en, mode, user; + int r; + + r = inv_plat_single_write(st, REG_FIFO_EN, 0); + if (r) + return r; + r = inv_plat_single_write(st, REG_USER_CTRL, BIT_FIFO_RST); + if (r) + return r; + fifo_en = 0; + int_en = 0; + + if (st->gesture_only_on && (!st->batch.timeout)) { + st->gesture_int_count = WOM_DELAY_THRESHOLD; + int_en |= BIT_WOM_ALL_INT_EN; + } +#ifdef TIMER_BASED_BATCHING + if (st->chip_config.eis_enable) + int_en |= BIT_FSYNC_INT_EN; + if (!st->batch_timeout) { + int_en |= BIT_DATA_RDY_EN; + } +#else + if (st->batch.timeout) { + if(!st->batch.fifo_wm_th) + int_en = BIT_DATA_RDY_EN; + } else { + int_en = BIT_DATA_RDY_EN; + if (st->chip_config.eis_enable) + int_en |= BIT_FSYNC_INT_EN; + } +#endif + if (st->sensor[SENSOR_GYRO].on) + fifo_en |= BITS_GYRO_FIFO_EN; + + if (st->sensor[SENSOR_ACCEL].on) + fifo_en |= BIT_ACCEL_FIFO_EN; + r = inv_plat_single_write(st, REG_FIFO_EN, fifo_en); + if (r) + return r; + st->int_en = int_en; + r = inv_plat_single_write(st, REG_INT_ENABLE, int_en); + if (r) + return r; + if (st->gesture_only_on && (!st->batch.timeout)) { + mode = BIT_ACCEL_INTEL_EN | BIT_ACCEL_INTEL_MODE; + } else { + mode = 0; + } + r = inv_plat_single_write(st, REG_ACCEL_INTEL_CTRL, mode); +#ifdef SENSOR_DATA_FROM_REGISTERS + user = 0; +#else + user = BIT_FIFO_EN; +#endif + r = inv_plat_single_write(st, REG_USER_CTRL, user | st->i2c_dis); +#ifdef TIMER_BASED_BATCHING + if (fifo_en && st->batch_timeout) { + if (st->is_batch_timer_running) + hrtimer_cancel(&st ->hr_batch_timer); + st->is_batch_timer_running = true; + hrtimer_start(&st ->hr_batch_timer, + ns_to_ktime(st->batch_timeout), HRTIMER_MODE_REL); + } else { + if (st->is_batch_timer_running) + hrtimer_cancel(&st ->hr_batch_timer); + st->is_batch_timer_running = false; + } +#endif + + return r; +} + +/* + * inv_reset_fifo() - Reset FIFO related registers. + */ +int inv_reset_fifo(struct inv_mpu_state *st, bool turn_off) +{ + int r, i; + struct inv_timestamp_algo *ts_algo = &st->ts_algo; + int dur_ms; + + r = inv_turn_on_fifo(st); + if (r) + return r; + + ts_algo->last_run_time = get_time_ns(); + ts_algo->reset_ts = ts_algo->last_run_time; + if (st->mode_1k_on) + ts_algo->first_sample = MODE_1K_INIT_SAMPLE; + else + ts_algo->first_sample = 1; + + dur_ms = st->smplrt_div + 1; + if ((ts_algo->first_sample * dur_ms) < FIRST_SAMPLE_BUF_MS) + ts_algo->first_sample = FIRST_SAMPLE_BUF_MS / dur_ms; + if (ts_algo->first_sample == 0) + ts_algo->first_sample = 1; + + st->last_temp_comp_time = ts_algo->last_run_time; + st->left_over_size = 0; + for (i = 0; i < SENSOR_NUM_MAX; i++) { + st->sensor[i].calib_flag = 0; + st->sensor[i].sample_calib = 0; + st->sensor[i].time_calib = ts_algo->last_run_time; + } + + ts_algo->calib_counter = 0; + + return 0; +} + +static int inv_turn_on_engine(struct inv_mpu_state *st) +{ + u8 v, w; + int r; + unsigned int wait_ms; + + if (st->chip_config.gyro_enable | st->chip_config.accel_enable) { + w = 0; + if (!st->chip_config.gyro_enable) + w |= BIT_PWR_GYRO_STBY; + if (!st->chip_config.accel_enable) + w |= BIT_PWR_ACCEL_STBY; + } else if (st->chip_config.compass_enable) { + w = BIT_PWR_GYRO_STBY; + } else { + w = (BIT_PWR_GYRO_STBY | BIT_PWR_ACCEL_STBY); + } + + r = inv_plat_read(st, REG_PWR_MGMT_2, 1, &v); + if (r) + return r; + r = inv_plat_single_write(st, REG_PWR_MGMT_2, w); + if (r) + return r; + + wait_ms = 0; + if (st->chip_config.gyro_enable + && (v & BIT_PWR_GYRO_STBY)) { + wait_ms = INV_IAM20680_GYRO_START_TIME; + } + if (st->chip_config.accel_enable + && (v & BIT_PWR_ACCEL_STBY)) { + if (INV_IAM20680_ACCEL_START_TIME > wait_ms) + wait_ms = INV_IAM20680_ACCEL_START_TIME; + } + if (wait_ms) + msleep(wait_ms); + + if (st->chip_config.has_compass) { + if (st->chip_config.compass_enable) + r = st->slave_compass->resume(st); + else + r = st->slave_compass->suspend(st); + if (r) + return r; + } + + return 0; +} + +static int inv_setup_dmp_rate(struct inv_mpu_state *st) +{ + int i; + + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) { + st->cntl |= st->sensor[i].output; + st->sensor[i].dur = + st->eng_info[st->sensor[i].engine_base].dur; + st->sensor[i].div = 1; + } + } + + return 0; +} + +/* + * inv_set_lpf() - set low pass filer based on fifo rate. + */ +static int inv_set_lpf(struct inv_mpu_state *st, int rate) +{ + const short hz[] = {188, 98, 42, 20, 10, 5}; + const int d[] = {INV_FILTER_188HZ, INV_FILTER_98HZ, + INV_FILTER_42HZ, INV_FILTER_20HZ, + INV_FILTER_10HZ, INV_FILTER_5HZ}; + int i, h, data, result; + +#ifdef USE_GYRO_LN_MODE + if (1) { +#else + if (st->chip_config.eis_enable || st->ois.en || st->mode_1k_on) { +#endif + h = (rate >> 1); + i = 0; + while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1)) + i++; + data = d[i]; + data |= EXT_SYNC_SET; + result = inv_plat_single_write(st, REG_CONFIG, data); + if (result) + return result; + + st->chip_config.lpf = data; + result = inv_plat_single_write(st, REG_LP_MODE_CTRL, 0); + } else { + result = inv_plat_single_write(st, REG_LP_MODE_CTRL, + BIT_GYRO_CYCLE_EN); + if (result) + return result; + data = 0; + result = inv_plat_single_write(st, REG_CONFIG, data | 3); + } + + return result; +} + +static int inv_set_div(struct inv_mpu_state *st, int a_d, int g_d) +{ + int result, div; + + if (st->chip_config.gyro_enable) + div = g_d; + else + div = a_d; + if (st->chip_config.eis_enable) + div = 0; + + st->smplrt_div = div; + pr_debug("div= %d\n", div); + result = inv_plat_single_write(st, REG_SAMPLE_RATE_DIV, div); + + return result; +} + +// 20680 does not support batching +static int inv_set_batch(struct inv_mpu_state *st) +{ +#ifdef TIMER_BASED_BATCHING + u64 timeout; + int required_fifo_size; + +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING + st->batch.timeout = 100; +#endif + if (st->batch.timeout) { + required_fifo_size = st->batch.timeout * st->eng_info[ENGINE_GYRO].running_rate + * st->batch.pk_size / 1000; + if (required_fifo_size > MAX_BATCH_FIFO_SIZE) { + required_fifo_size = MAX_BATCH_FIFO_SIZE; + timeout = (required_fifo_size / st->batch.pk_size) * (1000 / st->eng_info[ENGINE_GYRO].running_rate); + } else { + timeout = st->batch.timeout; + } + } else { + timeout = 1000 / st->eng_info[ENGINE_GYRO].running_rate; + } + if (timeout <= 1000 / st->eng_info[ENGINE_GYRO].running_rate) + st->batch_timeout = 0; + else + st->batch_timeout = timeout * 1000000; // ms to ns +#endif + st->batch.fifo_wm_th = 0; + + return 0; +} + +static int inv_set_rate(struct inv_mpu_state *st) +{ + int g_d, a_d, result, i; + + result = inv_setup_dmp_rate(st); + if (result) + return result; + + g_d = st->eng_info[ENGINE_GYRO].divider - 1; + a_d = st->eng_info[ENGINE_ACCEL].divider - 1; + result = inv_set_div(st, a_d, g_d); + if (result) + return result; + result = inv_set_lpf(st, st->eng_info[ENGINE_GYRO].running_rate); + if (result) + return result; + // set ADLPF at this point not to change after accel is enabled + result = inv_set_accel_config2(st, false); + st->batch.pk_size = 0; + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) + st->batch.pk_size += st->sensor[i].sample_size; + } + + inv_set_batch(st); + + return result; +} + +static int inv_determine_engine(struct inv_mpu_state *st) +{ + int i; + bool a_en, g_en; + int accel_rate, gyro_rate; + + a_en = false; + g_en = false; + gyro_rate = MPU_INIT_SENSOR_RATE; + accel_rate = MPU_INIT_SENSOR_RATE; + /* loop the streaming sensors to see which engine needs to be turned on + */ + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) { + a_en |= st->sensor[i].a_en; + g_en |= st->sensor[i].g_en; + } + } + + if (st->chip_config.eis_enable) { + g_en = true; + st->eis.frame_count = 0; + st->eis.fsync_delay = 0; + st->eis.gyro_counter = 0; + st->eis.voting_count = 0; + st->eis.voting_count_sub = 0; + gyro_rate = BASE_SAMPLE_RATE; + } else { + st->eis.eis_triggered = false; + st->eis.prev_state = false; + } + + accel_rate = st->sensor[SENSOR_ACCEL].rate; + gyro_rate = max(gyro_rate, st->sensor[SENSOR_GYRO].rate); + + st->ts_algo.clock_base = ENGINE_ACCEL; + + if (g_en) { + /* gyro engine needs to be fastest */ + if (a_en) + gyro_rate = max(gyro_rate, accel_rate); + accel_rate = gyro_rate; + st->ts_algo.clock_base = ENGINE_GYRO; + } else if (a_en) { + /* accel engine needs to be fastest if gyro engine is off */ + gyro_rate = accel_rate; + st->ts_algo.clock_base = ENGINE_ACCEL; + } + + st->eng_info[ENGINE_GYRO].running_rate = gyro_rate; + st->eng_info[ENGINE_ACCEL].running_rate = accel_rate; + if ((gyro_rate >= BASE_SAMPLE_RATE) || + (accel_rate >= BASE_SAMPLE_RATE)) + st->mode_1k_on = true; + else + st->mode_1k_on = false; + /* engine divider for pressure and compass is set later */ + if (st->chip_config.eis_enable || st->mode_1k_on) { + st->eng_info[ENGINE_GYRO].divider = 1; + st->eng_info[ENGINE_ACCEL].divider = 1; + // need to update rate and div for 1khz mode + for ( i = 0 ; i < SENSOR_L_NUM_MAX ; i++ ) { + if (st->sensor_l[i].on) { + st->sensor_l[i].counter = 0; + if (st->sensor_l[i].rate) + st->sensor_l[i].div = + BASE_SAMPLE_RATE + / st->sensor_l[i].rate; + else + st->sensor_l[i].div = 0xffff; + } + } + } else { + st->eng_info[ENGINE_GYRO].divider = BASE_SAMPLE_RATE / + st->eng_info[ENGINE_GYRO].running_rate; + st->eng_info[ENGINE_ACCEL].divider = BASE_SAMPLE_RATE / + st->eng_info[ENGINE_ACCEL].running_rate; + } + + for ( i = 0 ; i < SENSOR_L_NUM_MAX ; i++ ) + st->sensor_l[i].counter = 0; + + inv_calc_engine_dur(&st->eng_info[ENGINE_GYRO]); + inv_calc_engine_dur(&st->eng_info[ENGINE_ACCEL]); + + pr_debug("gen: %d aen: %d grate: %d arate: %d\n", + g_en, a_en, gyro_rate, accel_rate); + + st->chip_config.gyro_enable = g_en; + st->chip_config.accel_enable = a_en; + + return 0; +} + +/* + * set_inv_enable() - enable function. + */ +int set_inv_enable(struct iio_dev *indio_dev) +{ + int result; + struct inv_mpu_state *st = iio_priv(indio_dev); + + result = inv_switch_power_in_lp(st, true); + if (result) + return result; + inv_stop_interrupt(st); + inv_determine_engine(st); + result = inv_set_rate(st); + if (result) { + pr_err("inv_set_rate error\n"); + return result; + } + result = inv_turn_on_engine(st); + if (result) { + pr_err("inv_turn_on_engine error\n"); + return result; + } + result = inv_reset_fifo(st, false); + if (result) + return result; + result = inv_switch_power_in_lp(st, false); + if ((!st->chip_config.gyro_enable) && + (!st->chip_config.accel_enable)) { + inv_set_power(st, false); + return 0; + } + + return result; +} +/* dummy function for 20608D */ +int inv_enable_pedometer_interrupt(struct inv_mpu_state *st, bool en) +{ + return 0; +} +int inv_dmp_read(struct inv_mpu_state *st, int off, int size, u8 *buf) +{ + return 0; +} +int inv_firmware_load(struct inv_mpu_state *st) +{ + return 0; +} diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_common.c b/drivers/iio/imu/inv_mpu/inv_mpu_common.c new file mode 100644 index 0000000000000000000000000000000000000000..33db03418b92df82adf9516edf1dfab240ef8cc5 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_common.c @@ -0,0 +1,988 @@ +/* + * Copyright (C) 2012-2017 InvenSense, 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. + */ +#define pr_fmt(fmt) "inv_mpu: " fmt +#include "inv_mpu_iio.h" +#ifdef CONFIG_RTC_INTF_ALARM +#include +#endif +#include + +#ifdef CONFIG_RTC_INTF_ALARM +s64 get_time_ns(void) +{ + struct timespec ts; + + /* get_monotonic_boottime(&ts); */ + + /* Workaround for some platform on which monotonic clock and + * Android SystemClock has a gap. + * Use ktime_to_timespec(alarm_get_elapsed_realtime()) instead of + * get_monotonic_boottime() for these platform + */ + + ts = ktime_to_timespec(alarm_get_elapsed_realtime()); + + return timespec_to_ns(&ts); +} +#else +s64 get_time_ns(void) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + + /* Workaround for some platform on which monotonic clock and + * Android SystemClock has a gap. + * Use ktime_to_timespec(alarm_get_elapsed_realtime()) instead of + * get_monotonic_boottime() for these platform + */ + return timespec_to_ns(&ts); +} + +#endif + +#ifdef ACCEL_BIAS_TEST +int inv_get_3axis_average(s16 src[], s16 dst[], s16 reset) +{ +#define BUFFER_SIZE 200 + static s16 buffer[BUFFER_SIZE][3]; + static s16 current_position = 0; + static s16 ready = 0; + int sum[3]= {0,}; + int i; + + if(reset){ + current_position = 0; + ready = 0; + } + buffer[current_position][0] = src[0]; + buffer[current_position][1] = src[1]; + buffer[current_position][2] = src[2]; + current_position++; + if(current_position == BUFFER_SIZE){ + ready = 1; + current_position = 0; + } + if(ready){ + for(i = 0 ; i < BUFFER_SIZE ; i++){ + sum[0] += buffer[i][0]; + sum[1] += buffer[i][1]; + sum[2] += buffer[i][2]; + } + dst[0] = sum[0]/BUFFER_SIZE; + dst[1] = sum[1]/BUFFER_SIZE; + dst[2] = sum[2]/BUFFER_SIZE; + return 1; + } + return 0; +} +#endif + +int inv_q30_mult(int a, int b) +{ +#define DMP_MULTI_SHIFT 30 + u64 temp; + int result; + + temp = ((u64)a) * b; + result = (int)(temp >> DMP_MULTI_SHIFT); + + return result; +} +#if defined(CONFIG_INV_MPU_IIO_ICM20648) || \ + defined(CONFIG_INV_MPU_IIO_ICM20690) +/* inv_read_secondary(): set secondary registers for reading. + The chip must be set as bank 3 before calling. + */ +int inv_read_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int len) +{ + int result; + + result = inv_plat_single_write(st, st->slv_reg[ind].addr, + INV_MPU_BIT_I2C_READ | addr); + if (result) + return result; + result = inv_plat_single_write(st, st->slv_reg[ind].reg, reg); + if (result) + return result; + result = inv_plat_single_write(st, st->slv_reg[ind].ctrl, + INV_MPU_BIT_SLV_EN | len); + + return result; +} + +int inv_execute_read_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int len, u8 *d) +{ + int result; + + inv_set_bank(st, BANK_SEL_3); + result = inv_read_secondary(st, ind, addr, reg, len); + if (result) + return result; + inv_set_bank(st, BANK_SEL_0); + result = inv_plat_single_write(st, REG_USER_CTRL, st->i2c_dis | + BIT_I2C_MST_EN); + msleep(SECONDARY_INIT_WAIT); + result = inv_plat_single_write(st, REG_USER_CTRL, st->i2c_dis); + if (result) + return result; + result = inv_plat_read(st, REG_EXT_SLV_SENS_DATA_00, len, d); + + return result; +} + +/* inv_write_secondary(): set secondary registers for writing. + The chip must be set as bank 3 before calling. + */ +int inv_write_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int v) +{ + int result; + + result = inv_plat_single_write(st, st->slv_reg[ind].addr, addr); + if (result) + return result; + result = inv_plat_single_write(st, st->slv_reg[ind].reg, reg); + if (result) + return result; + result = inv_plat_single_write(st, st->slv_reg[ind].ctrl, + INV_MPU_BIT_SLV_EN | 1); + + result = inv_plat_single_write(st, st->slv_reg[ind].d0, v); + + return result; +} + +int inv_execute_write_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int v) +{ + int result; + + inv_set_bank(st, BANK_SEL_3); + result = inv_write_secondary(st, ind, addr, reg, v); + if (result) + return result; + inv_set_bank(st, BANK_SEL_0); + result = inv_plat_single_write(st, REG_USER_CTRL, st->i2c_dis | + BIT_I2C_MST_EN); + msleep(SECONDARY_INIT_WAIT); + result = inv_plat_single_write(st, REG_USER_CTRL, st->i2c_dis); + + return result; +} + +int inv_set_bank(struct inv_mpu_state *st, u8 bank) +{ +#ifdef CONFIG_INV_MPU_IIO_ICM20648 + int r; + + r = inv_plat_single_write(st, REG_BANK_SEL, bank); + + return r; +#else + return 0; +#endif +} +#endif + +#ifdef CONFIG_INV_MPU_IIO_ICM20648 +/** + * inv_write_cntl() - Write control word to designated address. + * @st: Device driver instance. + * @wd: control word. + * @en: enable/disable. + * @cntl: control address to be written. + */ +int inv_write_cntl(struct inv_mpu_state *st, u16 wd, bool en, int cntl) +{ + int result; + u8 reg[2], d_out[2]; + + result = mem_r(cntl, 2, d_out); + if (result) + return result; + reg[0] = ((wd >> 8) & 0xff); + reg[1] = (wd & 0xff); + if (!en) { + d_out[0] &= ~reg[0]; + d_out[1] &= ~reg[1]; + } else { + d_out[0] |= reg[0]; + d_out[1] |= reg[1]; + } + result = mem_w(cntl, 2, d_out); + + return result; +} +#endif + +int inv_set_power(struct inv_mpu_state *st, bool power_on) +{ + u8 d; + int r; + + if ((!power_on) == st->chip_config.is_asleep) + return 0; + + d = BIT_CLK_PLL; + if (!power_on) + d |= BIT_SLEEP; + + r = inv_plat_single_write(st, REG_PWR_MGMT_1, d); + if (r) + return r; + + if (power_on) + usleep_range(REG_UP_TIME_USEC, REG_UP_TIME_USEC); + + st->chip_config.is_asleep = !power_on; + + return 0; +} +EXPORT_SYMBOL_GPL(inv_set_power); + +int inv_stop_interrupt(struct inv_mpu_state *st) +{ + int res; +#if defined(CONFIG_INV_MPU_IIO_ICM20648) + /* disable_irq_wake alone should work already. However, + it might need system configuration change. From driver side, + we will disable IRQ altogether for non-wakeup sensors. */ + res = inv_plat_read(st, REG_INT_ENABLE, 1, &st->int_en); + if (res) + return res; + res = inv_plat_read(st, REG_INT_ENABLE_2, 1, &st->int_en_2); + if (res) + return res; + res = inv_plat_single_write(st, REG_INT_ENABLE, 0); + if (res) + return res; + res = inv_plat_single_write(st, REG_INT_ENABLE_2, 0); + if (res) + return res; +#endif +#if defined(CONFIG_INV_MPU_IIO_ICM20608D) + res = inv_plat_read(st, REG_INT_ENABLE, 1, &st->int_en); + if (res) + return res; + res = inv_plat_single_write(st, REG_INT_ENABLE, 0); + if (res) + return res; +#endif +#if defined(CONFIG_INV_MPU_IIO_ICM20602) \ + || defined(CONFIG_INV_MPU_IIO_ICM20690) \ + || defined(CONFIG_INV_MPU_IIO_IAM20680) + res = inv_plat_read(st, REG_INT_ENABLE, 1, &st->int_en); + if (res) + return res; + res = inv_plat_single_write(st, REG_INT_ENABLE, 0); + if (res) + return res; +#endif + return 0; +} +int inv_reenable_interrupt(struct inv_mpu_state *st) +{ + int res = 0; +#if defined(CONFIG_INV_MPU_IIO_ICM20648) + res = inv_plat_single_write(st, REG_INT_ENABLE, st->int_en); + if (res) + return res; + res = inv_plat_single_write(st, REG_INT_ENABLE_2, st->int_en_2); + if (res) + return res; +#elif defined(CONFIG_INV_MPU_IIO_ICM20608D) + res = inv_plat_single_write(st, REG_INT_ENABLE, st->int_en); + if (res) + return res; +#endif +#if defined(CONFIG_INV_MPU_IIO_ICM20602) \ + || defined(CONFIG_INV_MPU_IIO_ICM20690) \ + || defined(CONFIG_INV_MPU_IIO_IAM20680) + res = inv_plat_single_write(st, REG_INT_ENABLE, st->int_en); + if (res) + return res; +#endif + return res; +} + +static int inv_lp_en_off_mode(struct inv_mpu_state *st, bool on) +{ + int r; + + if (!st->chip_config.is_asleep) + return 0; + + r = inv_plat_single_write(st, REG_PWR_MGMT_1, BIT_CLK_PLL); + st->chip_config.is_asleep = 0; + + return r; +} +#ifdef CONFIG_INV_MPU_IIO_ICM20648 +static int inv_lp_en_on_mode(struct inv_mpu_state *st, bool on) +{ + int r = 0; + u8 w; + + if ((!st->chip_config.is_asleep) && + ((!on) == st->chip_config.lp_en_set)) + return 0; + + w = BIT_CLK_PLL; + if ((!on) && (!st->eis.eis_triggered)) + w |= BIT_LP_EN; + r = inv_plat_single_write(st, REG_PWR_MGMT_1, w); + st->chip_config.is_asleep = 0; + st->chip_config.lp_en_set = (!on); + return r; +} +#endif +#if defined(CONFIG_INV_MPU_IIO_ICM20602) \ + || defined(CONFIG_INV_MPU_IIO_ICM20690) \ + || defined(CONFIG_INV_MPU_IIO_IAM20680) +int inv_set_accel_config2(struct inv_mpu_state *st, bool cycle_mode) +{ + int cycle_freq[] = {275, 192, 111, 59}; + int cont_freq[] = {219, 219, 99, 45, 22, 11, 6}; + int i, r, rate; + u8 v; + + v = 0; +#ifdef CONFIG_INV_MPU_IIO_ICM20690 + v |= BIT_FIFO_SIZE_1K; +#endif + if (cycle_mode) { + rate = (st->eng_info[ENGINE_ACCEL].running_rate << 1); + i = ARRAY_SIZE(cycle_freq) - 1; + while (i > 0) { + if (rate < cycle_freq[i]) { + break; + } + i--; + } + r = inv_plat_single_write(st, REG_ACCEL_CONFIG_2, v | + (i << 4) | 7); + if (r) + return r; + } else { + rate = (st->eng_info[ENGINE_ACCEL].running_rate >> 1); + for (i = 1; i < ARRAY_SIZE(cont_freq); i++) { + if (rate >= cont_freq[i]) + break; + } + if (i > 6) + i = 6; + r = inv_plat_single_write(st, REG_ACCEL_CONFIG_2, v | i); + if (r) + return r; + } + + return 0; +} +static int inv_lp_en_on_mode(struct inv_mpu_state *st, bool on) +{ + int r = 0; + u8 w; + bool cond_check; + + if ((!st->chip_config.is_asleep) && + ((!on) == st->chip_config.lp_en_set)) + return 0; + cond_check = (!on) && st->cycle_on; + + w = BIT_CLK_PLL; + r = inv_plat_single_write(st, REG_PWR_MGMT_1, w); + if (cond_check) { + w |= BIT_LP_EN; + inv_set_accel_config2(st, true); + st->chip_config.lp_en_set = true; + r = inv_plat_single_write(st, REG_PWR_MGMT_1, w); + } else { + inv_set_accel_config2(st, false); +#ifdef CONFIG_INV_MPU_IIO_ICM20690 + r = inv_plat_single_write(st, REG_PWR_MGMT_1, w | BIT_SLEEP); + if (r) + return r; +#endif + st->chip_config.lp_en_set = false; + r = inv_plat_single_write(st, REG_PWR_MGMT_1, w); + msleep(10); + } + st->chip_config.is_asleep = 0; + + return r; +} +#endif +#ifdef CONFIG_INV_MPU_IIO_ICM20608D +static int inv_set_accel_config2(struct inv_mpu_state *st) +{ + int cont_freq[] = {219, 219, 99, 45, 22, 11, 6}; + int dec2_cfg = 0; + int i, r, rate; + + rate = (st->eng_info[ENGINE_ACCEL].running_rate << 1); + i = 0; + if (!st->chip_config.eis_enable){ + while ((rate < cont_freq[i]) && (i < ARRAY_SIZE(cont_freq) - 1)) + i++; + dec2_cfg = 2<<4; //4x + } + r = inv_plat_single_write(st, REG_ACCEL_CONFIG_2, i | dec2_cfg); + if (r) + return r; + return 0; +} +static int inv_lp_en_on_mode(struct inv_mpu_state *st, bool on) +{ + int r = 0; + u8 w; + + w = BIT_CLK_PLL; + if ((!on) && (!st->chip_config.eis_enable)) + w |= BIT_LP_EN; + inv_set_accel_config2(st); + r = inv_plat_single_write(st, REG_PWR_MGMT_1, w); + + return r; +} +#endif +int inv_switch_power_in_lp(struct inv_mpu_state *st, bool on) +{ + int r; + + if (st->chip_config.lp_en_mode_off) + r = inv_lp_en_off_mode(st, on); + else + r = inv_lp_en_on_mode(st, on); + + return r; +} +EXPORT_SYMBOL_GPL(inv_switch_power_in_lp); + +int write_be16_to_mem(struct inv_mpu_state *st, u16 data, int addr) +{ + u8 d[2]; + + d[0] = (data >> 8) & 0xff; + d[1] = data & 0xff; + + return mem_w(addr, sizeof(d), d); +} + +int write_be32_to_mem(struct inv_mpu_state *st, u32 data, int addr) +{ + cpu_to_be32s(&data); + return mem_w(addr, sizeof(data), (u8 *)&data); +} + +int read_be16_from_mem(struct inv_mpu_state *st, u16 *o, int addr) +{ + int result; + u8 d[2]; + + result = mem_r(addr, 2, (u8 *) &d); + *o = d[0] << 8 | d[1]; + + return result; +} + +int read_be32_from_mem(struct inv_mpu_state *st, u32 *o, int addr) +{ + int result; + u32 d = 0; + + result = mem_r(addr, 4, (u8 *) &d); + *o = be32_to_cpup((__be32 *)(&d)); + + return result; +} + +int be32_to_int(u8 *d) +{ + return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3]; +} + +u32 inv_get_cntr_diff(u32 curr_counter, u32 prev) +{ + u32 diff; + + if (curr_counter > prev) + diff = curr_counter - prev; + else + diff = 0xffffffff - prev + curr_counter + 1; + + return diff; +} + +int inv_write_2bytes(struct inv_mpu_state *st, int addr, int data) +{ + u8 d[2]; + + if (data < 0 || data > USHRT_MAX) + return -EINVAL; + + d[0] = (u8) ((data >> 8) & 0xff); + d[1] = (u8) (data & 0xff); + + return mem_w(addr, ARRAY_SIZE(d), d); +} + + + +int inv_process_eis(struct inv_mpu_state *st, u16 delay) +{ + int tmp1, tmp2, tmp3; + + switch (st->eis.voting_state) { + case 0: + st->eis.gyro_counter_s[0] = st->eis.gyro_counter; + st->eis.fsync_delay_s[0] = delay - st->eis.fsync_delay; + st->eis.voting_count = 1; + st->eis.voting_count_sub = 0; + st->eis.voting_state = 1; + break; + case 1: + if (abs(st->eis.gyro_counter_s[0] - + st->eis.gyro_counter) <= 1) { + st->eis.voting_count++; + } else { + st->eis.gyro_counter_s[2] = st->eis.gyro_counter; + st->eis.voting_count_sub++; + st->eis.voting_state = 2; + } + if (st->eis.voting_count > 5) + st->eis.voting_state = 3; + break; + case 2: + tmp1 = abs(st->eis.gyro_counter_s[0] - st->eis.gyro_counter); + tmp2 = abs(st->eis.gyro_counter_s[2] - st->eis.gyro_counter); + + if ((tmp1 < tmp2) && (tmp1 <= 1)) + st->eis.voting_count++; + else + st->eis.voting_count_sub++; + if (st->eis.voting_count > 5) { + st->eis.voting_state = 3; + st->eis.voting_count = 0; + st->eis.voting_count_sub = 0; + } + + if (st->eis.voting_count_sub > 5) { + st->eis.gyro_counter_s[0] = st->eis.gyro_counter; + st->eis.fsync_delay_s[0] = delay - st->eis.fsync_delay; + st->eis.voting_state = 1; + st->eis.voting_count = 1; + st->eis.voting_count_sub = 0; + } + break; + case 3: + tmp1 = abs(st->eis.gyro_counter_s[0] - st->eis.gyro_counter); + if (tmp1 == 1) { + st->eis.gyro_counter_s[1] = st->eis.gyro_counter; + st->eis.fsync_delay_s[1] = delay - st->eis.fsync_delay; + st->eis.voting_state = 4; + st->eis.voting_count_sub = 1; + st->eis.voting_count = 1; + } + break; + case 4: + if (st->eis.gyro_counter == st->eis.gyro_counter_s[0]) { + tmp1 = delay - st->eis.fsync_delay; + tmp2 = abs(tmp1 - st->eis.fsync_delay_s[0]); + if (tmp2 < 3) { + st->eis.voting_count++; + } else { + st->eis.fsync_delay_s[2] = tmp1; + st->eis.voting_count_sub = 1; + st->eis.voting_state = 5; + } + if (st->eis.voting_count > 5) { + st->eis.voting_count = 1; + st->eis.voting_state = 6; + } + } + break; + case 5: + if (st->eis.gyro_counter == st->eis.gyro_counter_s[0]) { + tmp1 = delay - st->eis.fsync_delay; + + tmp2 = abs(tmp1 - st->eis.fsync_delay_s[0]); + tmp3 = abs(tmp1 - st->eis.fsync_delay_s[2]); + if ((tmp2 < tmp3) && (tmp2 < 3)) + st->eis.voting_count++; + else + st->eis.voting_count_sub++; + if ((st->eis.voting_count > 5) && + (st->eis.voting_count_sub + < st->eis.voting_count)) { + st->eis.voting_state = 6; + st->eis.voting_count = 1; + } else if (st->eis.voting_count_sub > 5) { + st->eis.fsync_delay_s[0] = tmp1; + st->eis.voting_state = 4; + st->eis.voting_count = 1; + } + + } + break; + case 6: + if (st->eis.gyro_counter == st->eis.gyro_counter_s[1]) { + tmp1 = delay - st->eis.fsync_delay; + tmp2 = abs(tmp1 - st->eis.fsync_delay_s[1]); + if (tmp2 < 3) { + st->eis.voting_count++; + } else { + st->eis.fsync_delay_s[2] = tmp1; + st->eis.voting_count_sub = 1; + st->eis.voting_count = 1; + st->eis.voting_state = 7; + } + if (st->eis.voting_count > 5) + st->eis.voting_state = 8; + } + break; + case 7: + if (st->eis.gyro_counter == st->eis.gyro_counter_s[1]) { + tmp1 = delay - st->eis.fsync_delay; + + tmp2 = abs(tmp1 - st->eis.fsync_delay_s[1]); + tmp3 = abs(tmp1 - st->eis.fsync_delay_s[2]); + if ((tmp2 < tmp3) && (tmp2 < 3)) + st->eis.voting_count++; + else + st->eis.voting_count_sub++; + if ((st->eis.voting_count > 5) && + (st->eis.voting_count_sub + < st->eis.voting_count)) { + st->eis.voting_state = 8; + } else if (st->eis.voting_count_sub > 5) { + st->eis.fsync_delay_s[1] = tmp1; + st->eis.voting_state = 6; + st->eis.voting_count = 1; + } + + } + break; + default: + break; + } + + pr_debug("de= %d gc= %d\n", delay, st->eis.gyro_counter); + st->eis.fsync_delay = delay; + st->eis.gyro_counter = 0; + + pr_debug("state=%d g1= %d d1= %d g2= %d d2= %d\n", + st->eis.voting_state, + st->eis.gyro_counter_s[0], + st->eis.fsync_delay_s[0], + st->eis.gyro_counter_s[1], + st->eis.fsync_delay_s[1]); + + return 0; +} + +int inv_rate_convert(struct inv_mpu_state *st, int ind, int data) +{ + int t, out, out1, out2; + int base_freq; + + if (data <= MPU_DEFAULT_DMP_FREQ) + base_freq = MPU_DEFAULT_DMP_FREQ; + else + base_freq = BASE_SAMPLE_RATE; + + t = base_freq / data; + if (!t) + t = 1; + out1 = base_freq / (t + 1); + out2 = base_freq / t; + if ((data - out1) * INV_ODR_BUFFER_MULTI < data) + out = out1; + else + out = out2; + + return out; +} + +static void inv_check_wake_non_wake(struct inv_mpu_state *st, + enum SENSOR_L wake, enum SENSOR_L non_wake) +{ + int tmp_rate; + + if (!st->sensor_l[wake].on && !st->sensor_l[non_wake].on) + return; + + tmp_rate = MPU_INIT_SENSOR_RATE; + if (st->sensor_l[wake].on) + tmp_rate = st->sensor_l[wake].rate; + if (st->sensor_l[non_wake].on) + tmp_rate = max(tmp_rate, st->sensor_l[non_wake].rate); + st->sensor_l[wake].rate = tmp_rate; + st->sensor_l[non_wake].rate = tmp_rate; +} + +static void inv_check_wake_non_wake_divider(struct inv_mpu_state *st, + enum SENSOR_L wake, enum SENSOR_L non_wake) +{ + if (st->sensor_l[wake].on && st->sensor_l[non_wake].on) + st->sensor_l[non_wake].div = 0xffff; + +} + +#if defined(CONFIG_INV_MPU_IIO_ICM20602) \ + || defined(CONFIG_INV_MPU_IIO_ICM20690) \ + || defined(CONFIG_INV_MPU_IIO_IAM20680) +int inv_check_sensor_on(struct inv_mpu_state *st) +{ + int i, max_rate; + enum SENSOR_L wake[] = {SENSOR_L_GYRO_WAKE, SENSOR_L_ACCEL_WAKE, + SENSOR_L_MAG_WAKE}; + enum SENSOR_L non_wake[] = {SENSOR_L_GYRO, SENSOR_L_ACCEL, + SENSOR_L_MAG}; + + st->sensor_l[SENSOR_L_GESTURE_ACCEL].rate = GESTURE_ACCEL_RATE; + for (i = 0; i < SENSOR_NUM_MAX; i++) + st->sensor[i].on = false; + for (i = 0; i < SENSOR_NUM_MAX; i++) + st->sensor[i].rate = MPU_INIT_SENSOR_RATE; + + if ((st->step_detector_l_on + || st->step_detector_wake_l_on + || st->step_counter_l_on + || st->step_counter_wake_l_on + || st->chip_config.pick_up_enable + || st->chip_config.tilt_enable) + && (!st->sensor_l[SENSOR_L_ACCEL].on) + && (!st->sensor_l[SENSOR_L_ACCEL_WAKE].on)) + st->sensor_l[SENSOR_L_GESTURE_ACCEL].on = true; + else + st->sensor_l[SENSOR_L_GESTURE_ACCEL].on = false; + + + st->chip_config.wake_on = false; + for (i = 0; i < SENSOR_L_NUM_MAX; i++) { + if (st->sensor_l[i].on && st->sensor_l[i].rate) { + st->sensor[st->sensor_l[i].base].on = true; + st->chip_config.wake_on |= st->sensor_l[i].wake_on; + } + } + if (st->sensor_l[SENSOR_L_GESTURE_ACCEL].on && + (!st->sensor[SENSOR_GYRO].on) && + (!st->sensor[SENSOR_COMPASS].on)) + st->gesture_only_on = true; + else + st->gesture_only_on = false; + + for (i = 0; i < SENSOR_L_NUM_MAX; i++) { + if (st->sensor_l[i].on) { + st->sensor[st->sensor_l[i].base].rate = + max(st->sensor[st->sensor_l[i].base].rate, + st->sensor_l[i].rate); + } + } + max_rate = MPU_INIT_SENSOR_RATE; + if (st->chip_config.eis_enable) { + max_rate = ESI_GYRO_RATE; + st->sensor_l[SENSOR_L_EIS_GYRO].rate = ESI_GYRO_RATE; + } + + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) { + max_rate = max(max_rate, st->sensor[i].rate); + } + } + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) { + st->sensor[i].rate = max_rate; + } + } + for (i = 0; i < ARRAY_SIZE(wake); i++) + inv_check_wake_non_wake(st, wake[i], non_wake[i]); + + for (i = 0; i < SENSOR_L_NUM_MAX; i++) { + if (st->sensor_l[i].on) { + if (st->sensor_l[i].rate) + st->sensor_l[i].div = + st->sensor[st->sensor_l[i].base].rate + / st->sensor_l[i].rate; + else + st->sensor_l[i].div = 0xffff; + pr_debug("sensor= %d, div= %d\n", + i, st->sensor_l[i].div); + } + } + for (i = 0; i < ARRAY_SIZE(wake); i++) + inv_check_wake_non_wake_divider(st, wake[i], non_wake[i]); + + if (st->step_detector_wake_l_on || + st->step_counter_wake_l_on || + st->chip_config.pick_up_enable || + st->chip_config.tilt_enable) + st->chip_config.wake_on = true; + + return 0; +} +#else +static void inv_do_check_sensor_on(struct inv_mpu_state *st, + enum SENSOR_L *wake, + enum SENSOR_L *non_wake, int sensor_size) +{ + int i; + + for (i = 0; i < SENSOR_NUM_MAX; i++) + st->sensor[i].on = false; + + for (i = 0; i < SENSOR_NUM_MAX; i++) + st->sensor[i].rate = MPU_INIT_SENSOR_RATE; + + st->chip_config.wake_on = false; + for (i = 0; i < SENSOR_L_NUM_MAX; i++) { + if (st->sensor_l[i].on && st->sensor_l[i].rate) { + st->sensor[st->sensor_l[i].base].on = true; + st->chip_config.wake_on |= st->sensor_l[i].wake_on; + } + } + + for (i = 0; i < SENSOR_L_NUM_MAX; i++) { + if (st->sensor_l[i].on) { + st->sensor[st->sensor_l[i].base].rate = + max(st->sensor[st->sensor_l[i].base].rate, + st->sensor_l[i].rate); + } + } + for (i = 0; i < sensor_size; i++) + inv_check_wake_non_wake(st, wake[i], non_wake[i]); + + for (i = 0; i < SENSOR_L_NUM_MAX; i++) { + if (st->sensor_l[i].on) { + if (st->sensor_l[i].rate) + st->sensor_l[i].div = + st->sensor[st->sensor_l[i].base].rate + / st->sensor_l[i].rate; + else + st->sensor_l[i].div = 0xffff; + } + } + for (i = 0; i < sensor_size; i++) + inv_check_wake_non_wake_divider(st, wake[i], non_wake[i]); + + if (st->step_detector_wake_l_on || + st->step_counter_wake_l_on || + st->chip_config.pick_up_enable || + st->chip_config.tilt_enable || + st->smd.on) + st->chip_config.wake_on = true; + +} +#endif + +#if defined(CONFIG_INV_MPU_IIO_ICM20608D) +int inv_check_sensor_on(struct inv_mpu_state *st) +{ + enum SENSOR_L wake[] = {SENSOR_L_GYRO_WAKE, SENSOR_L_ACCEL_WAKE, + SENSOR_L_SIXQ_WAKE, SENSOR_L_PEDQ_WAKE, + SENSOR_L_GYRO_CAL_WAKE}; + enum SENSOR_L non_wake[] = {SENSOR_L_GYRO, SENSOR_L_ACCEL, + SENSOR_L_SIXQ, SENSOR_L_PEDQ, + SENSOR_L_GYRO_CAL}; + + inv_do_check_sensor_on(st, wake, non_wake, ARRAY_SIZE(wake)); + + return 0; +} +#endif + +#if defined(CONFIG_INV_MPU_IIO_ICM20648) +int inv_check_sensor_on(struct inv_mpu_state *st) +{ + enum SENSOR_L wake[] = {SENSOR_L_GYRO_WAKE, SENSOR_L_ACCEL_WAKE, + SENSOR_L_MAG_WAKE, SENSOR_L_ALS_WAKE, + SENSOR_L_SIXQ_WAKE, SENSOR_L_PEDQ_WAKE, + SENSOR_L_NINEQ_WAKE, SENSOR_L_GEOMAG_WAKE, + SENSOR_L_PRESSURE_WAKE, + SENSOR_L_GYRO_CAL_WAKE, + SENSOR_L_MAG_CAL_WAKE}; + enum SENSOR_L non_wake[] = {SENSOR_L_GYRO, SENSOR_L_ACCEL, + SENSOR_L_MAG, SENSOR_L_ALS, + SENSOR_L_SIXQ, SENSOR_L_PEDQ, + SENSOR_L_NINEQ, SENSOR_L_GEOMAG, + SENSOR_L_PRESSURE, + SENSOR_L_GYRO_CAL, + SENSOR_L_MAG_CAL}; + + inv_do_check_sensor_on(st, wake, non_wake, ARRAY_SIZE(wake)); + + return 0; +} +#endif + +#ifdef CONFIG_PM_SLEEP +int inv_mpu_suspend(struct iio_dev *indio_dev) +{ + struct inv_mpu_state *st = iio_priv(indio_dev); + + /* add code according to different request Start */ + dev_info(st->dev, "%s suspend\n", st->hw->name); + mutex_lock(&indio_dev->mlock); + + st->resume_state = false; + if (st->chip_config.wake_on) { + enable_irq_wake(st->irq); + } else { + inv_stop_interrupt(st); + } + + mutex_unlock(&indio_dev->mlock); + + return 0; +} +EXPORT_SYMBOL_GPL(inv_mpu_suspend); + +/* + * inv_mpu_complete(): complete method for this driver. + * This method can be modified according to the request of different + * customers. It basically undo everything suspend is doing + * and recover the chip to what it was before suspend. We use complete to + * make sure that alarm clock resume is finished. If we use resume, the + * alarm clock may not resume yet and get incorrect clock reading. + */ +void inv_mpu_complete(struct iio_dev *indio_dev) +{ + struct inv_mpu_state *st = iio_priv(indio_dev); + + dev_info(st->dev, "%s resume\n", st->hw->name); + if (st->resume_state) + return; + + mutex_lock(&indio_dev->mlock); + + if (!st->chip_config.wake_on) { + inv_reenable_interrupt(st); + } else { + disable_irq_wake(st->irq); + } + /* resume state is used to synchronize read_fifo such that it won't + proceed unless resume is finished. */ + st->resume_state = true; + /* resume flag is indicating that current clock reading is from resume, + it has up to 1 second drift and should do proper processing */ + st->ts_algo.resume_flag = true; + mutex_unlock(&indio_dev->mlock); + wake_up_interruptible(&st->wait_queue); + + return; +} +EXPORT_SYMBOL_GPL(inv_mpu_complete); +#endif diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_dts.c b/drivers/iio/imu/inv_mpu/inv_mpu_dts.c new file mode 100644 index 0000000000000000000000000000000000000000..0b8b3fc29b0ae87962da89621bac22a345796256 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_dts.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2012-2017 InvenSense, 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 +#include +#include +#include +#include +#include +#include + +#include +#include "inv_mpu_dts.h" +#include "inv_mpu_iio.h" + +#ifdef CONFIG_OF + +static int inv_mpu_power_on(struct mpu_platform_data *pdata) +{ + int err; + + if (!IS_ERR(pdata->vdd_ana)) { + err = regulator_enable(pdata->vdd_ana); + if (err) + return err; + } + if (!IS_ERR(pdata->vdd_i2c)) { + err = regulator_enable(pdata->vdd_i2c); + if (err) + goto error_disable_vdd_ana; + } + + return 0; + +error_disable_vdd_ana: + regulator_disable(pdata->vdd_ana); + return err; +} + +static int inv_mpu_power_off(struct mpu_platform_data *pdata) +{ + if (!IS_ERR(pdata->vdd_ana)) + regulator_disable(pdata->vdd_ana); + if (!IS_ERR(pdata->vdd_i2c)) + regulator_disable(pdata->vdd_i2c); + + return 0; +} + +static int inv_parse_orientation_matrix(struct device *dev, s8 *orient) +{ + int rc, i; + struct device_node *np = dev->of_node; + u32 temp_val, temp_val2; + + for (i = 0; i < 9; i++) + orient[i] = 0; + + /* parsing axis x orientation matrix */ + rc = of_property_read_u32(np, "axis_map_x", &temp_val); + if (rc) { + dev_err(dev, "Unable to read axis_map_x\n"); + return rc; + } + rc = of_property_read_u32(np, "negate_x", &temp_val2); + if (rc) { + dev_err(dev, "Unable to read negate_x\n"); + return rc; + } + if (temp_val2) + orient[temp_val] = -1; + else + orient[temp_val] = 1; + + /* parsing axis y orientation matrix */ + rc = of_property_read_u32(np, "axis_map_y", &temp_val); + if (rc) { + dev_err(dev, "Unable to read axis_map_y\n"); + return rc; + } + rc = of_property_read_u32(np, "negate_y", &temp_val2); + if (rc) { + dev_err(dev, "Unable to read negate_y\n"); + return rc; + } + if (temp_val2) + orient[3 + temp_val] = -1; + else + orient[3 + temp_val] = 1; + + /* parsing axis z orientation matrix */ + rc = of_property_read_u32(np, "axis_map_z", &temp_val); + if (rc) { + dev_err(dev, "Unable to read axis_map_z\n"); + return rc; + } + rc = of_property_read_u32(np, "negate_z", &temp_val2); + if (rc) { + dev_err(dev, "Unable to read negate_z\n"); + return rc; + } + if (temp_val2) + orient[6 + temp_val] = -1; + else + orient[6 + temp_val] = 1; + + return 0; +} + +static int inv_parse_secondary_orientation_matrix(struct device *dev, + s8 *orient) +{ + int rc, i; + struct device_node *np = dev->of_node; + u32 temp_val, temp_val2; + + for (i = 0; i < 9; i++) + orient[i] = 0; + + /* parsing axis x orientation matrix */ + rc = of_property_read_u32(np, "inven,secondary_axis_map_x", &temp_val); + if (rc) { + dev_err(dev, "Unable to read secondary axis_map_x\n"); + return rc; + } + rc = of_property_read_u32(np, "inven,secondary_negate_x", &temp_val2); + if (rc) { + dev_err(dev, "Unable to read secondary negate_x\n"); + return rc; + } + if (temp_val2) + orient[temp_val] = -1; + else + orient[temp_val] = 1; + + /* parsing axis y orientation matrix */ + rc = of_property_read_u32(np, "inven,secondary_axis_map_y", &temp_val); + if (rc) { + dev_err(dev, "Unable to read secondary axis_map_y\n"); + return rc; + } + rc = of_property_read_u32(np, "inven,secondary_negate_y", &temp_val2); + if (rc) { + dev_err(dev, "Unable to read secondary negate_y\n"); + return rc; + } + if (temp_val2) + orient[3 + temp_val] = -1; + else + orient[3 + temp_val] = 1; + + /* parsing axis z orientation matrix */ + rc = of_property_read_u32(np, "inven,secondary_axis_map_z", &temp_val); + if (rc) { + dev_err(dev, "Unable to read secondary axis_map_z\n"); + return rc; + } + rc = of_property_read_u32(np, "inven,secondary_negate_z", &temp_val2); + if (rc) { + dev_err(dev, "Unable to read secondary negate_z\n"); + return rc; + } + if (temp_val2) + orient[6 + temp_val] = -1; + else + orient[6 + temp_val] = 1; + + return 0; +} + +static int inv_parse_secondary(struct device *dev, + struct mpu_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + u32 temp_val; + const char *name; + + if (of_property_read_string(np, "inven,secondary_type", &name)) { + dev_err(dev, "Missing secondary type.\n"); + return -EINVAL; + } + if (!strcmp(name, "compass")) { + pdata->sec_slave_type = SECONDARY_SLAVE_TYPE_COMPASS; + } else if (!strcmp(name, "none")) { + pdata->sec_slave_type = SECONDARY_SLAVE_TYPE_NONE; + return 0; + } else { + return -EINVAL; + } + + if (of_property_read_string(np, "inven,secondary_name", &name)) { + dev_err(dev, "Missing secondary name.\n"); + return -EINVAL; + } + if (!strcmp(name, "ak8963")) + pdata->sec_slave_id = COMPASS_ID_AK8963; + else if (!strcmp(name, "ak8975")) + pdata->sec_slave_id = COMPASS_ID_AK8975; + else if (!strcmp(name, "ak8972")) + pdata->sec_slave_id = COMPASS_ID_AK8972; + else if (!strcmp(name, "ak09911")) + pdata->sec_slave_id = COMPASS_ID_AK09911; + else if (!strcmp(name, "ak09912")) + pdata->sec_slave_id = COMPASS_ID_AK09912; + else if (!strcmp(name, "ak09916")) + pdata->sec_slave_id = COMPASS_ID_AK09916; + else + return -EINVAL; + rc = of_property_read_u32(np, "inven,secondary_reg", &temp_val); + if (rc) { + dev_err(dev, "Unable to read secondary register\n"); + return rc; + } + pdata->secondary_i2c_addr = temp_val; + rc = inv_parse_secondary_orientation_matrix(dev, + pdata-> + secondary_orientation); + + return rc; +} + +static int inv_parse_aux(struct device *dev, struct mpu_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + u32 temp_val; + const char *name; + + if (of_property_read_string(np, "inven,aux_type", &name)) { + dev_err(dev, "Missing aux type.\n"); + return -EINVAL; + } + if (!strcmp(name, "pressure")) { + pdata->aux_slave_type = SECONDARY_SLAVE_TYPE_PRESSURE; + } else if (!strcmp(name, "none")) { + pdata->aux_slave_type = SECONDARY_SLAVE_TYPE_NONE; + return 0; + } else { + return -EINVAL; + } + + if (of_property_read_string(np, "inven,aux_name", &name)) { + dev_err(dev, "Missing aux name.\n"); + return -EINVAL; + } + if (!strcmp(name, "bmp280")) + pdata->aux_slave_id = PRESSURE_ID_BMP280; + else + return -EINVAL; + + rc = of_property_read_u32(np, "inven,aux_reg", &temp_val); + if (rc) { + dev_err(dev, "Unable to read aux register\n"); + return rc; + } + pdata->aux_i2c_addr = temp_val; + + return 0; +} + +static int inv_parse_readonly_secondary(struct device *dev, + struct mpu_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + u32 temp_val; + const char *name; + + if (of_property_read_string(np, "inven,read_only_slave_type", &name)) { + dev_err(dev, "Missing read only slave type type.\n"); + return -EINVAL; + } + if (!strcmp(name, "als")) { + pdata->read_only_slave_type = SECONDARY_SLAVE_TYPE_ALS; + } else if (!strcmp(name, "none")) { + pdata->read_only_slave_type = SECONDARY_SLAVE_TYPE_NONE; + return 0; + } else { + return -EINVAL; + } + + if (of_property_read_string(np, "inven,read_only_slave_name", &name)) { + dev_err(dev, "Missing read only slave type name.\n"); + return -EINVAL; + } + if (!strcmp(name, "apds9930")) + pdata->read_only_slave_id = ALS_ID_APDS_9930; + else + return -EINVAL; + + rc = of_property_read_u32(np, "inven,read_only_slave_reg", &temp_val); + if (rc) { + dev_err(dev, "Unable to read read only slave reg register\n"); + return rc; + } + pdata->read_only_i2c_addr = temp_val; + + return 0; +} + +int invensense_mpu_parse_dt(struct device *dev, struct mpu_platform_data *pdata) +{ + int rc; + + rc = inv_parse_orientation_matrix(dev, pdata->orientation); + if (rc) + return rc; + rc = inv_parse_secondary(dev, pdata); + if (rc) + return rc; + inv_parse_aux(dev, pdata); + + inv_parse_readonly_secondary(dev, pdata); + + pdata->vdd_ana = regulator_get(dev, "inven,vdd_ana"); + if (IS_ERR(pdata->vdd_ana)) { + rc = PTR_ERR(pdata->vdd_ana); + dev_warn(dev, "regulator get failed vdd_ana-supply rc=%d\n", rc); + } + pdata->vdd_i2c = regulator_get(dev, "inven,vcc_i2c"); + if (IS_ERR(pdata->vdd_i2c)) { + rc = PTR_ERR(pdata->vdd_i2c); + dev_warn(dev, "regulator get failed vcc-i2c-supply rc=%d\n", rc); + } + pdata->power_on = inv_mpu_power_on; + pdata->power_off = inv_mpu_power_off; + dev_dbg(dev, "parse dt complete\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(invensense_mpu_parse_dt); + +#endif /* CONFIG_OF */ diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_dts.h b/drivers/iio/imu/inv_mpu/inv_mpu_dts.h new file mode 100644 index 0000000000000000000000000000000000000000..90966febb93028fa4aace073588779df20f87fae --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_dts.h @@ -0,0 +1,25 @@ +/* +* Copyright (C) 2012-2017 InvenSense, 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. +*/ + +#ifndef _INV_MPU_DTS_H_ +#define _INV_MPU_DTS_H_ + +#include +#include + +#ifdef CONFIG_OF +int invensense_mpu_parse_dt(struct device *dev, + struct mpu_platform_data *pdata); +#endif + +#endif /* #ifndef _INV_MPU_DTS_H_ */ diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu/inv_mpu_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..65089f2fab130e9264fa2f41d14a456906197dcc --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_i2c.c @@ -0,0 +1,774 @@ +/* +* Copyright (C) 2012-2018 InvenSense, 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. +*/ +#define pr_fmt(fmt) "inv_mpu: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_mpu_iio.h" +#include "inv_mpu_dts.h" + +#define CONFIG_DYNAMIC_DEBUG_I2C 0 + +/** + * inv_i2c_read_base() - Read one or more bytes from the device registers. + * @st: Device driver instance. + * @i2c_addr: i2c address of device. + * @reg: First device register to be read from. + * @length: Number of bytes to read. + * @data: Data read from device. + * NOTE:This is not re-implementation of i2c_smbus_read because i2c + * address could be specified in this case. We could have two different + * i2c address due to secondary i2c interface. + */ +int inv_i2c_read_base(struct inv_mpu_state *st, u16 i2c_addr, + u8 reg, u16 length, u8 *data) +{ + struct i2c_msg msgs[2]; + int res; + + if (!data) + return -EINVAL; + + msgs[0].addr = i2c_addr; + msgs[0].flags = 0; /* write */ + msgs[0].buf = ® + msgs[0].len = 1; + + msgs[1].addr = i2c_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = data; + msgs[1].len = length; + + res = i2c_transfer(st->sl_handle, msgs, 2); + + if (res < 2) { + if (res >= 0) + res = -EIO; + } else + res = 0; + INV_I2C_INC_MPUWRITE(3); + INV_I2C_INC_MPUREAD(length); + + return res; +} + +/** + * inv_i2c_single_write_base() - Write a byte to a device register. + * @st: Device driver instance. + * @i2c_addr: I2C address of the device. + * @reg: Device register to be written to. + * @data: Byte to write to device. + * NOTE:This is not re-implementation of i2c_smbus_write because i2c + * address could be specified in this case. We could have two different + * i2c address due to secondary i2c interface. + */ +int inv_i2c_single_write_base(struct inv_mpu_state *st, + u16 i2c_addr, u8 reg, u8 data) +{ + u8 tmp[2]; + struct i2c_msg msg; + int res; + + tmp[0] = reg; + tmp[1] = data; + + msg.addr = i2c_addr; + msg.flags = 0; /* write */ + msg.buf = tmp; + msg.len = 2; + + INV_I2C_INC_MPUWRITE(3); + + res = i2c_transfer(st->sl_handle, &msg, 1); + if (res < 1) { + if (res == 0) + res = -EIO; + return res; + } else + return 0; +} + +static int inv_i2c_single_write(struct inv_mpu_state *st, u8 reg, u8 data) +{ + return inv_i2c_single_write_base(st, st->i2c_addr, reg, data); +} + +static int inv_i2c_read(struct inv_mpu_state *st, u8 reg, int len, u8 *data) +{ + return inv_i2c_read_base(st, st->i2c_addr, reg, len, data); +} + +static int _memory_write(struct inv_mpu_state *st, u8 mpu_addr, u16 mem_addr, + u32 len, u8 const *data) +{ + u8 bank[2]; + u8 addr[2]; + u8 buf[513]; + + struct i2c_msg msgs[3]; + int res; + + if (!data || !st) + return -EINVAL; + + if (len >= (sizeof(buf) - 1)) + return -ENOMEM; + + bank[0] = REG_MEM_BANK_SEL; + bank[1] = mem_addr >> 8; + + addr[0] = REG_MEM_START_ADDR; + addr[1] = mem_addr & 0xFF; + + buf[0] = REG_MEM_R_W; + memcpy(buf + 1, data, len); + + /* write message */ + msgs[0].addr = mpu_addr; + msgs[0].flags = 0; + msgs[0].buf = bank; + msgs[0].len = sizeof(bank); + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = (u8 *) buf; + msgs[2].len = len + 1; + + INV_I2C_INC_MPUWRITE(3 + 3 + (2 + len)); + +#if CONFIG_DYNAMIC_DEBUG_I2C + { + char *write = 0; + pr_debug("%s WM%02X%02X%02X%s%s - %d\n", st->hw->name, + mpu_addr, bank[1], addr[1], + wr_pr_debug_begin(data, len, write), + wr_pr_debug_end(write), len); + } +#endif + + res = i2c_transfer(st->sl_handle, msgs, 3); + if (res != 3) { + if (res >= 0) + res = -EIO; + return res; + } else { + return 0; + } +} + +static int inv_i2c_mem_write(struct inv_mpu_state *st, u8 mpu_addr, u16 mem_addr, + u32 len, u8 const *data) +{ + int r, i, j; +#define DMP_MEM_CMP_SIZE 16 + u8 w[DMP_MEM_CMP_SIZE]; + bool retry; + + j = 0; + retry = true; + while ((j < 3) && retry) { + retry = false; + r = _memory_write(st, mpu_addr, mem_addr, len, data); + if (len < DMP_MEM_CMP_SIZE) { + r = mem_r(mem_addr, len, w); + for (i = 0; i < len; i++) { + if (data[i] != w[i]) { + pr_debug + ("error write=%x, len=%d,data=%x, w=%x, i=%d\n", + mem_addr, len, data[i], w[i], i); + retry = true; + } + } + } + j++; + } + + return r; +} + +static int inv_i2c_mem_read(struct inv_mpu_state *st, u8 mpu_addr, u16 mem_addr, + u32 len, u8 *data) +{ + u8 bank[2]; + u8 addr[2]; + u8 buf; + + struct i2c_msg msgs[4]; + int res; + + if (!data || !st) + return -EINVAL; + + bank[0] = REG_MEM_BANK_SEL; + bank[1] = mem_addr >> 8; + + addr[0] = REG_MEM_START_ADDR; + addr[1] = mem_addr & 0xFF; + + buf = REG_MEM_R_W; + + /* write message */ + msgs[0].addr = mpu_addr; + msgs[0].flags = 0; + msgs[0].buf = bank; + msgs[0].len = sizeof(bank); + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = &buf; + msgs[2].len = 1; + + msgs[3].addr = mpu_addr; + msgs[3].flags = I2C_M_RD; + msgs[3].buf = data; + msgs[3].len = len; + + res = i2c_transfer(st->sl_handle, msgs, 4); + if (res != 4) { + if (res >= 0) + res = -EIO; + } else + res = 0; + INV_I2C_INC_MPUWRITE(3 + 3 + 3); + INV_I2C_INC_MPUREAD(len); + +#if CONFIG_DYNAMIC_DEBUG_I2C + { + char *read = 0; + pr_debug("%s RM%02X%02X%02X%02X - %s%s\n", st->hw->name, + mpu_addr, bank[1], addr[1], len, + wr_pr_debug_begin(data, len, read), + wr_pr_debug_end(read)); + } +#endif + + return res; +} + +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING +static void inv_enable_acc_gyro(struct inv_mpu_state *st) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + int accel_hz = 100; + int gyro_hz = 100; + + /**Enable the ACCEL**/ + st->sensor_l[SENSOR_L_ACCEL].on = 0; + st->trigger_state = RATE_TRIGGER; + inv_check_sensor_on(st); + set_inv_enable(indio_dev); + + inv_switch_power_in_lp(st, true); + st->chip_config.accel_fs = ACCEL_FSR_2G; + inv_set_accel_sf(st); + st->trigger_state = MISC_TRIGGER; + set_inv_enable(indio_dev); + + st->sensor_l[SENSOR_L_ACCEL].rate = accel_hz; + st->trigger_state = DATA_TRIGGER; + inv_check_sensor_on(st); + set_inv_enable(indio_dev); + + st->sensor_l[SENSOR_L_ACCEL].on = 1; + st->trigger_state = RATE_TRIGGER; + inv_check_sensor_on(st); + set_inv_enable(indio_dev); + + /**Enable the GYRO**/ + st->sensor_l[SENSOR_L_GYRO].on = 0; + st->trigger_state = RATE_TRIGGER; + inv_check_sensor_on(st); + set_inv_enable(indio_dev); + + inv_switch_power_in_lp(st, true); + st->chip_config.fsr = GYRO_FSR_250DPS; + inv_set_gyro_sf(st); + st->trigger_state = MISC_TRIGGER; + set_inv_enable(indio_dev); + + st->sensor_l[SENSOR_L_GYRO].rate = gyro_hz; + st->trigger_state = DATA_TRIGGER; + inv_check_sensor_on(st); + set_inv_enable(indio_dev); + + st->sensor_l[SENSOR_L_GYRO].on = 1; + st->trigger_state = RATE_TRIGGER; + inv_check_sensor_on(st); + set_inv_enable(indio_dev); +} + +static int inv_acc_gyro_early_buff_init(struct iio_dev *indio_dev) +{ + int i = 0, err = 0; + struct inv_mpu_state *st; + + st = iio_priv(indio_dev); + st->acc_bufsample_cnt = 0; + st->gyro_bufsample_cnt = 0; + st->report_evt_cnt = 5; + st->max_buffer_time = 40; + + st->inv_acc_cachepool = kmem_cache_create("acc_sensor_sample", + sizeof(struct inv_acc_sample), + 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!st->inv_acc_cachepool) { + pr_err("inv_acc_cachepool cache create failed\n"); + err = -ENOMEM; + return 0; + } + + for (i = 0; i < INV_ACC_MAXSAMPLE; i++) { + st->inv_acc_samplist[i] = + kmem_cache_alloc(st->inv_acc_cachepool, + GFP_KERNEL); + if (!st->inv_acc_samplist[i]) { + err = -ENOMEM; + goto clean_exit1; + } + } + + st->inv_gyro_cachepool = kmem_cache_create("gyro_sensor_sample" + , sizeof(struct inv_gyro_sample), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!st->inv_gyro_cachepool) { + pr_err("inv_gyro_cachepool cache create failed\n"); + err = -ENOMEM; + goto clean_exit1; + } + + for (i = 0; i < INV_GYRO_MAXSAMPLE; i++) { + st->inv_gyro_samplist[i] = + kmem_cache_alloc(st->inv_gyro_cachepool, + GFP_KERNEL); + if (!st->inv_gyro_samplist[i]) { + err = -ENOMEM; + goto clean_exit2; + } + } + + st->accbuf_dev = input_allocate_device(); + if (!st->accbuf_dev) { + err = -ENOMEM; + pr_err("input device allocation failed\n"); + goto clean_exit2; + } + st->accbuf_dev->name = "inv_accbuf"; + st->accbuf_dev->id.bustype = BUS_I2C; + input_set_events_per_packet(st->accbuf_dev, + st->report_evt_cnt * INV_ACC_MAXSAMPLE); + set_bit(EV_ABS, st->accbuf_dev->evbit); + input_set_abs_params(st->accbuf_dev, ABS_X, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->accbuf_dev, ABS_Y, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->accbuf_dev, ABS_Z, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->accbuf_dev, ABS_RX, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->accbuf_dev, ABS_RY, + -G_MAX, G_MAX, 0, 0); + err = input_register_device(st->accbuf_dev); + if (err) { + pr_err("unable to register input device %s\n", + st->accbuf_dev->name); + goto clean_exit3; + } + + st->gyrobuf_dev = input_allocate_device(); + if (!st->gyrobuf_dev) { + err = -ENOMEM; + pr_err("input device allocation failed\n"); + goto clean_exit4; + } + st->gyrobuf_dev->name = "inv_gyrobuf"; + st->gyrobuf_dev->id.bustype = BUS_I2C; + input_set_events_per_packet(st->gyrobuf_dev, + st->report_evt_cnt * INV_GYRO_MAXSAMPLE); + set_bit(EV_ABS, st->gyrobuf_dev->evbit); + input_set_abs_params(st->gyrobuf_dev, ABS_X, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->gyrobuf_dev, ABS_Y, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->gyrobuf_dev, ABS_Z, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->gyrobuf_dev, ABS_RX, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(st->gyrobuf_dev, ABS_RY, + -G_MAX, G_MAX, 0, 0); + err = input_register_device(st->gyrobuf_dev); + if (err) { + pr_err("unable to register input device %s\n", + st->gyrobuf_dev->name); + goto clean_exit5; + } + + st->acc_buffer_inv_samples = true; + st->gyro_buffer_inv_samples = true; + + inv_enable_acc_gyro(st); + + return 1; + +clean_exit5: + input_free_device(st->gyrobuf_dev); +clean_exit4: + input_unregister_device(st->accbuf_dev); +clean_exit3: + input_free_device(st->accbuf_dev); +clean_exit2: + for (i = 0; i < INV_GYRO_MAXSAMPLE; i++) + kmem_cache_free(st->inv_gyro_cachepool, + st->inv_gyro_samplist[i]); + kmem_cache_destroy(st->inv_gyro_cachepool); +clean_exit1: + for (i = 0; i < INV_ACC_MAXSAMPLE; i++) + kmem_cache_free(st->inv_acc_cachepool, + st->inv_acc_samplist[i]); + kmem_cache_destroy(st->inv_acc_cachepool); + + return 0; +} +static void inv_acc_gyro_input_cleanup( + struct iio_dev *indio_dev) +{ + int i = 0; + struct inv_mpu_state *st; + + st = iio_priv(indio_dev); + input_free_device(st->accbuf_dev); + input_unregister_device(st->gyrobuf_dev); + input_free_device(st->gyrobuf_dev); + for (i = 0; i < INV_GYRO_MAXSAMPLE; i++) + kmem_cache_free(st->inv_gyro_cachepool, + st->inv_gyro_samplist[i]); + kmem_cache_destroy(st->inv_gyro_cachepool); + for (i = 0; i < INV_ACC_MAXSAMPLE; i++) + kmem_cache_free(st->inv_acc_cachepool, + st->inv_acc_samplist[i]); + kmem_cache_destroy(st->inv_acc_cachepool); +} +#else +static int inv_acc_gyro_early_buff_init(struct iio_dev *indio_dev) +{ + return 1; +} +static void inv_acc_gyro_input_cleanup( + struct iio_dev *indio_dev) +{ +} +#endif + +/* + * inv_mpu_probe() - probe function. + */ +static int inv_mpu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct inv_mpu_state *st; + struct iio_dev *indio_dev; + int result; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENOSYS; + pr_err("I2c function error\n"); + goto out_no_free; + } + +#ifdef KERNEL_VERSION_4_X + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (indio_dev == NULL) { + pr_err("memory allocation failed\n"); + result = -ENOMEM; + goto out_no_free; + } +#else + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + pr_err("memory allocation failed\n"); + result = -ENOMEM; + goto out_no_free; + } +#endif + st = iio_priv(indio_dev); + st->client = client; + st->sl_handle = client->adapter; + st->i2c_addr = client->addr; + st->write = inv_i2c_single_write; + st->read = inv_i2c_read; + st->mem_write = inv_i2c_mem_write; + st->mem_read = inv_i2c_mem_read; + st->dev = &client->dev; + st->bus_type = BUS_IIO_I2C; +#ifdef CONFIG_OF + result = invensense_mpu_parse_dt(st->dev, &st->plat_data); + if (result) +# ifdef KERNEL_VERSION_4_X + return -ENODEV; +# else + goto out_free; +# endif + + /* Power on device */ + if (st->plat_data.power_on) { + result = st->plat_data.power_on(&st->plat_data); + if (result < 0) { + dev_err(st->dev, "power_on failed: %d\n", result); +# ifdef KERNEL_VERSION_4_X + return -ENODEV; +# else + goto out_free; +# endif + } + pr_info("%s: power on here.\n", __func__); + } + pr_info("%s: power on.\n", __func__); + + msleep(100); +#else + if (dev_get_platdata(st->dev) == NULL) +# ifdef KERNEL_VERSION_4_X + return -ENODEV; +# else + goto out_free; +# endif + st->plat_data = *(struct mpu_platform_data *)dev_get_platdata(st->dev); +#endif + + /* power is turned on inside check chip type */ + result = inv_check_chip_type(indio_dev, id->name); + if (result) +#ifdef KERNEL_VERSION_4_X + return -ENODEV; +#else + goto out_free; +#endif + + /* Make state variables available to all _show and _store functions. */ + i2c_set_clientdata(client, indio_dev); + indio_dev->dev.parent = st->dev; + indio_dev->name = id->name; + + st->irq = client->irq; + + result = inv_mpu_configure_ring(indio_dev); + if (result) { + pr_err("configure ring buffer fail\n"); + goto out_free; + } +#ifdef KERNEL_VERSION_4_X + INV_I2C_SETIRQ(IRQ_MPU, st->irq); + result = devm_iio_device_register(st->dev, indio_dev); + if (result) { + pr_err("IIO device register fail\n"); + goto out_unreg_ring; + } +#else + result = iio_buffer_register(indio_dev, indio_dev->channels, + indio_dev->num_channels); + if (result) { + pr_err("ring buffer register fail\n"); + goto out_unreg_ring; + } + INV_I2C_SETIRQ(IRQ_MPU, client->irq); + result = iio_device_register(indio_dev); + if (result) { + pr_err("IIO device register fail\n"); + goto out_remove_ring; + } +#endif + + result = inv_create_dmp_sysfs(indio_dev); + if (result) { + pr_err("create dmp sysfs failed\n"); + goto out_unreg_iio; + } + init_waitqueue_head(&st->wait_queue); + st->resume_state = true; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&st->wake_lock, WAKE_LOCK_SUSPEND, "inv_mpu"); +#else + wakeup_source_init(&st->wake_lock, "inv_mpu"); +#endif + dev_info(st->dev, "%s ma-kernel-%s is ready to go!\n", + indio_dev->name, INVENSENSE_DRIVER_VERSION); + +#ifdef SENSOR_DATA_FROM_REGISTERS + pr_info("Data read from registers\n"); +#else + pr_info("Data read from FIFO\n"); +#endif +#ifdef TIMER_BASED_BATCHING + pr_info("Timer based batching\n"); +#endif + result = inv_acc_gyro_early_buff_init(indio_dev); + if (!result) + return -EIO; + + return 0; +#ifdef KERNEL_VERSION_4_X +out_unreg_iio: + devm_iio_device_unregister(st->dev, indio_dev); +out_unreg_ring: + inv_mpu_unconfigure_ring(indio_dev); +out_free: + devm_iio_device_free(st->dev, indio_dev); +out_no_free: +#else +out_unreg_iio: + iio_device_unregister(indio_dev); +out_remove_ring: + iio_buffer_unregister(indio_dev); +out_unreg_ring: + inv_mpu_unconfigure_ring(indio_dev); +out_free: + dev_err(st->dev, "%s failed %d\n", __func__, result); + iio_device_free(indio_dev); +out_no_free: +#endif + + return -EIO; +} + +static void inv_mpu_shutdown(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct inv_mpu_state *st = iio_priv(indio_dev); + int result; + + mutex_lock(&indio_dev->mlock); + inv_switch_power_in_lp(st, true); + dev_dbg(st->dev, "Shutting down %s...\n", st->hw->name); + + /* reset to make sure previous state are not there */ + result = inv_plat_single_write(st, REG_PWR_MGMT_1, BIT_H_RESET); + if (result) + dev_err(st->dev, "Failed to reset %s\n", + st->hw->name); + msleep(POWER_UP_TIME); + /* turn off power to ensure gyro engine is off */ + result = inv_set_power(st, false); + if (result) + dev_err(st->dev, "Failed to turn off %s\n", + st->hw->name); + inv_switch_power_in_lp(st, false); + mutex_unlock(&indio_dev->mlock); +} + +/* + * inv_mpu_remove() - remove function. + */ +static int inv_mpu_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct inv_mpu_state *st = iio_priv(indio_dev); + + inv_acc_gyro_input_cleanup(indio_dev); +#ifdef KERNEL_VERSION_4_X + devm_iio_device_unregister(st->dev, indio_dev); +#else + iio_device_unregister(indio_dev); + iio_buffer_unregister(indio_dev); +#endif + inv_mpu_unconfigure_ring(indio_dev); +#ifdef KERNEL_VERSION_4_X + devm_iio_device_free(st->dev, indio_dev); +#else + iio_device_free(indio_dev); +#endif + dev_info(st->dev, "inv-mpu-iio module removed.\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int inv_mpu_i2c_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + return inv_mpu_suspend(indio_dev); +} + +static void inv_mpu_i2c_complete(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + inv_mpu_complete(indio_dev); +} +#endif + +static const struct dev_pm_ops inv_mpu_i2c_pmops = { +#ifdef CONFIG_PM_SLEEP + .suspend = inv_mpu_i2c_suspend, + .complete = inv_mpu_i2c_complete, +#endif +}; + +/* device id table is used to identify what device can be + * supported by this driver + */ +static const struct i2c_device_id inv_mpu_id[] = { +#ifdef CONFIG_INV_MPU_IIO_ICM20648 + {"icm20645", ICM20645}, + {"icm10340", ICM10340}, + {"icm20648", ICM20648}, +#else + {"icm20608d", ICM20608D}, + {"icm20690", ICM20690}, + {"icm20602", ICM20602}, + {"iam20680", IAM20680}, +#endif + {} +}; + +MODULE_DEVICE_TABLE(i2c, inv_mpu_id); + +static struct i2c_driver inv_mpu_driver = { + .probe = inv_mpu_probe, + .remove = inv_mpu_remove, + .shutdown = inv_mpu_shutdown, + .id_table = inv_mpu_id, + .driver = { + .owner = THIS_MODULE, + .name = "inv-mpu-iio-i2c", + .pm = &inv_mpu_i2c_pmops, + }, +}; +module_i2c_driver(inv_mpu_driver); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Invensense I2C device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu/inv_mpu_iio.h new file mode 100644 index 0000000000000000000000000000000000000000..1e0a1769e5f31ce93f6568d3b7a95a0dec596251 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_iio.h @@ -0,0 +1,1186 @@ +/* + * Copyright (C) 2012-2018 InvenSense, 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. + */ + +#ifndef _INV_MPU_IIO_H_ +#define _INV_MPU_IIO_H_ + +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)) +#define KERNEL_VERSION_4_X +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_WAKELOCK +#include +#else +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_INV_MPU_IIO_ICM20648 +#include "icm20648/dmp3Default.h" +#endif +#ifdef CONFIG_INV_MPU_IIO_ICM20608D +#include "icm20608d/dmp3Default_20608D.h" +#endif + +#include "inv_test/inv_counters.h" + +#if defined(CONFIG_INV_MPU_IIO_ICM20648) +#include "icm20648/inv_mpu_iio_reg_20648.h" +#elif defined(CONFIG_INV_MPU_IIO_ICM20602) +#include "icm20602/inv_mpu_iio_reg_20602.h" +#elif defined(CONFIG_INV_MPU_IIO_ICM20608D) +#include "icm20608d/inv_mpu_iio_reg_20608.h" +#elif defined(CONFIG_INV_MPU_IIO_ICM20690) +#include "icm20690/inv_mpu_iio_reg_20690.h" +#elif defined(CONFIG_INV_MPU_IIO_IAM20680) +#include "iam20680/inv_mpu_iio_reg_20680.h" +#endif + +#define INVENSENSE_DRIVER_VERSION "8.1.2-simple-test1" + +/* #define DEBUG */ + +/* #define ACCEL_BIAS_TEST */ + +/* #define BIAS_CONFIDENCE_HIGH 1 */ + +#define MAX_FIFO_READ_SIZE 128 +#define MAX_DMP_READ_SIZE 16 + +/* data header defines */ +#define WAKE_HDR 0x8000 + +#define ACCEL_HDR 1 +#define GYRO_HDR 2 +#define COMPASS_HDR 3 +#define ALS_HDR 4 +#define SIXQUAT_HDR 5 +#define NINEQUAT_HDR 6 +#define PEDQUAT_HDR 7 +#define GEOMAG_HDR 8 +#define PRESSURE_HDR 9 +#define GYRO_CALIB_HDR 10 +#define COMPASS_CALIB_HDR 11 +#define STEP_COUNTER_HDR 12 +#define STEP_DETECTOR_HDR 13 +#define STEP_COUNT_HDR 14 +#define ACTIVITY_HDR 15 +#define PICK_UP_HDR 16 +#define EMPTY_MARKER 17 +#define END_MARKER 18 +#define COMPASS_ACCURACY_HDR 19 +#define ACCEL_ACCURACY_HDR 20 +#define GYRO_ACCURACY_HDR 21 +#define EIS_GYRO_HDR 36 +#define EIS_CALIB_HDR 37 +#define LPQ_HDR 38 + +#define ACCEL_WAKE_HDR (ACCEL_HDR | WAKE_HDR) +#define GYRO_WAKE_HDR (GYRO_HDR | WAKE_HDR) +#define COMPASS_WAKE_HDR (COMPASS_HDR | WAKE_HDR) +#define ALS_WAKE_HDR (ALS_HDR | WAKE_HDR) +#define SIXQUAT_WAKE_HDR (SIXQUAT_HDR | WAKE_HDR) +#define NINEQUAT_WAKE_HDR (NINEQUAT_HDR | WAKE_HDR) +#define PEDQUAT_WAKE_HDR (PEDQUAT_HDR | WAKE_HDR) +#define GEOMAG_WAKE_HDR (GEOMAG_HDR | WAKE_HDR) +#define PRESSURE_WAKE_HDR (PRESSURE_HDR | WAKE_HDR) +#define GYRO_CALIB_WAKE_HDR (GYRO_CALIB_HDR | WAKE_HDR) +#define COMPASS_CALIB_WAKE_HDR (COMPASS_CALIB_HDR | WAKE_HDR) +#define STEP_COUNTER_WAKE_HDR (STEP_COUNTER_HDR | WAKE_HDR) +#define STEP_DETECTOR_WAKE_HDR (STEP_DETECTOR_HDR | WAKE_HDR) + +/* init parameters */ +#define MPU_INIT_SMD_THLD 1500 +#define MPU_INIT_GYRO_SCALE 3 +#define MPU_INIT_ACCEL_SCALE 2 +#define MPU_INIT_PED_INT_THRESH 2 +#define MPU_INIT_PED_STEP_THRESH 6 +#define MPU_4X_TS_GYRO_SHIFT (3160000 / 2) +#define DMP_START_ADDR_20645 0x900 +#define DMP_START_ADDR_20648 0x1000 +#define DMP_START_ADDR_10340 0x0a60 +#define DMP_START_ADDR_20608D 0x4B0 +#define MAX_WR_SZ 100 +#define WOM_DELAY_THRESHOLD 200 +#define INV_ODR_BUFFER_MULTI 20 +#define INV_ODR_OVER_FACTOR 20 + +#define COVARIANCE_SIZE 14 +#define ACCEL_COVARIANCE_SIZE (COVARIANCE_SIZE * sizeof(int)) + +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING +#define INV_ACC_MAXSAMPLE 4000 +#define INV_GYRO_MAXSAMPLE 4000 +#define G_MAX 23920640 +struct inv_acc_sample { + int xyz[3]; + unsigned int tsec; + unsigned long long tnsec; +}; +struct inv_gyro_sample { + int xyz[3]; + unsigned int tsec; + unsigned long long tnsec; +}; +enum { + ACCEL_FSR_2G = 0, + ACCEL_FSR_4G = 1, + ACCEL_FSR_8G = 2, + ACCEL_FSR_16G = 3 +}; +enum { + GYRO_FSR_250DPS = 0, + GYRO_FSR_500DPS = 1, + GYRO_FSR_1000DPS = 2, + GYRO_FSR_2000DPS = 3 +}; +#endif + +enum inv_bus_type { + BUS_IIO_I2C = 0, + BUS_IIO_SPI, +}; + +struct inv_mpu_state; + +enum INV_ENGINE { + ENGINE_GYRO = 0, + ENGINE_ACCEL, + ENGINE_PRESSURE, + ENGINE_I2C, + ENGINE_NUM_MAX, +}; + +/** + * struct inv_hw_s - Other important hardware information. + * @num_reg: Number of registers on device. + * @name: name of the chip + */ +struct inv_hw_s { + u8 num_reg; + u8 *name; +}; + +/** + * struct inv_sensor - information for each sensor. + * @ts: this sensors timestamp. + * @ts_adj: sensor timestamp adjustment. + * @previous_ts: previous timestamp for this sensor. + * @dur: duration between samples in ns. + * @rate: sensor data rate. + * @sample_size: number of bytes for the sensor. + * @odr_addr: output data rate address in DMP. + * @counter_addr: output counter address in DMP. + * @output: output on/off control word. + * @time_calib: calibrate timestamp. + * @sample_calib: calibrate bytes accumulated. + * @div: divider in DMP mode. + * @calib_flag: calibrate flag used to improve the accuracy of estimation. + * @on: sensor on/off. + * @a_en: accel engine requirement. + * @g_en: gyro engine requirement. + * @c_en: compass_engine requirement. + * @p_en: pressure engine requirement. + * @engine_base: engine base for this sensor. + * @count: number of samples in one session. + * @send: decide whether to send this sample or not. + */ +struct inv_sensor { + u64 ts; + s64 ts_adj; + u64 previous_ts; + int dur; + int rate; + u8 sample_size; + int odr_addr; + int counter_addr; + u16 output; + u64 time_calib; + u32 sample_calib; + int div; + bool calib_flag; + bool on; + bool a_en; + bool g_en; + bool c_en; + bool p_en; + enum INV_ENGINE engine_base; + int count; + bool send; +}; + +/** + * struct inv_sensor - information for each sensor. + * @sample_size: number of bytes for the sensor. + * @output: output on/off control word. + * @on: sensor on/off. + * @header: accuracy header for communicate with HAL + *dd @count: number of samples in one session. + */ +struct inv_sensor_accuracy { + u16 output; + u8 sample_size; + bool on; + u16 header; +}; + +enum SENSOR_ACCURACY { + SENSOR_ACCEL_ACCURACY = 0, + SENSOR_GYRO_ACCURACY, + SENSOR_COMPASS_ACCURACY, + SENSOR_ACCURACY_NUM_MAX, +}; + +enum SENSOR_L { + SENSOR_L_ACCEL = 0, + SENSOR_L_GYRO, + SENSOR_L_MAG, + SENSOR_L_ALS, + SENSOR_L_SIXQ, + SENSOR_L_THREEQ, + SENSOR_L_NINEQ, + SENSOR_L_PEDQ, + SENSOR_L_GEOMAG, + SENSOR_L_PRESSURE, + SENSOR_L_GYRO_CAL, + SENSOR_L_MAG_CAL, + SENSOR_L_EIS_GYRO, + /*wake sensors */ + SENSOR_L_ACCEL_WAKE = 13, + SENSOR_L_GYRO_WAKE, + SENSOR_L_MAG_WAKE, + SENSOR_L_ALS_WAKE, + SENSOR_L_SIXQ_WAKE, + SENSOR_L_NINEQ_WAKE, + SENSOR_L_PEDQ_WAKE, + SENSOR_L_GEOMAG_WAKE, + SENSOR_L_PRESSURE_WAKE, + SENSOR_L_GYRO_CAL_WAKE, + SENSOR_L_MAG_CAL_WAKE, + SENSOR_L_GESTURE_ACCEL, + SENSOR_L_NUM_MAX, +}; + +/** + * struct android_l_sensor - information for each android sensor. + * @ts: this sensors timestamp. + * @base: android sensor based on invensense sensor. + * @rate: output rate. + * @on: sensor on/off. + * @wake_on: wake on sensor is on/off. + * @div: divider for the output. + * @counter: counter works with the divider. + * @header: header for the output. + */ +struct android_l_sensor { + u64 ts; + enum INV_SENSORS base; + int rate; + bool on; + bool wake_on; + int div; + int counter; + u16 header; +}; + +/** + * struct inv_batch - information for batchmode. + * @on: normal batch mode on. + * @default_on: default batch on. This is optimization option. + * @overflow_on: overflow mode for batchmode. + * @wake_fifo_on: overflow for suspend mode. + * @step_only: mean only step detector data is batched. + * @post_isr_run: mean post isr has runned once. + * @counter: counter for batch mode. + * @timeout: nominal timeout value for batchmode in milliseconds. + * @max_rate: max rate for all batched sensors. + * @pk_size: packet size; + * @engine_base: engine base batch mode should stick to. + */ +struct inv_batch { + bool on; + bool default_on; + bool overflow_on; + bool wake_fifo_on; + bool step_only; + bool post_isr_run; + u32 counter; + u32 timeout; + u32 max_rate; + u32 pk_size; + u32 fifo_wm_th; + enum INV_ENGINE engine_base; +}; + +/** + * struct inv_chip_config_s - Cached chip configuration data. + * @fsr: Full scale range. + * @lpf: Digital low pass filter frequency. + * @accel_fs: accel full scale range. + * @accel_enable: enable accel functionality + * @gyro_enable: enable gyro functionality + * @compass_enable: enable compass functinality. + * @geomag_enable: enable geomag sensor functions. + * @als_enable: enable ALS functionality. + * @pressure_enable: eanble pressure functionality. + * @secondary_enable: secondary I2C bus enabled or not. + * @has_gyro: has gyro or not. + * @has_compass: has secondary I2C compass or not. + * @has_pressure: has secondary I2C pressure or not. + * @has_als: has secondary I2C als or not. + * @slave_enable: secondary I2C interface enabled or not. + * @normal_compass_measure: discard first compass data after reset. + * @is_asleep: 1 if chip is powered down. + * @lp_en_set: 1 if LP_EN bit is set; + * @lp_en_mode_off: debug mode that turns off LP_EN mode off. + * @clk_sel: debug_mode that turns on/off clock selection. + * @dmp_on: dmp is on/off. + * @dmp_event_int_on: dmp event interrupt on/off. + * @wom_on: WOM interrupt on. This is an internal variable. + * @step_indicator_on: step indicate bit added to the sensor or not. + * @tilt_enable: tilt enable. + * @pick_up_enable: pick up gesture enable. + * @step_detector_on: step detector on or not. + * @activity_on: turn on/off activity. + * @activity_eng_on: activity engine on/off. + * @firmware_loaded: flag indicate firmware loaded or not. + * @low_power_gyro_on: flag indicating low power gyro on/off. + * @wake_on: any wake on sensor is on/off. + * @compass_rate: compass engine rate. Determined by underlying data. + */ +struct inv_chip_config_s { + u32 fsr:2; + u32 lpf:3; + u32 accel_fs:2; + u32 accel_enable:1; + u32 gyro_enable:1; + u32 compass_enable:1; + u32 geomag_enable:1; + u32 als_enable:1; + u32 prox_enable:1; + u32 pressure_enable:1; + u32 has_gyro:1; + u32 has_compass:1; + u32 has_pressure:1; + u32 has_als:1; + u32 slave_enable:1; + u32 normal_compass_measure:1; + u32 is_asleep:1; + u32 lp_en_set:1; + u32 lp_en_mode_off:1; + u32 clk_sel:1; + u32 dmp_on:1; + u32 dmp_event_int_on:1; + u32 wom_on:1; + u32 step_indicator_on:1; + u32 tilt_enable:1; + u32 pick_up_enable:1; + u32 eis_enable:1; + u32 step_detector_on:1; + u32 activity_on:1; + u32 activity_eng_on:1; + u32 firmware_loaded:1; + u32 low_power_gyro_on:1; + u32 wake_on:1; + int compass_rate; +}; + +/** + * struct inv_temp_comp - temperature compensation structure. + * @t_lo: raw temperature in low temperature. + * @t_hi: raw temperature in high temperature. + * @b_lo: gyro bias in low temperature. + * @b_hi: gyro bias in high temperature. + * @has_low: flag indicate low temperature parameters is updated. + * @has_high: flag indicates high temperature parameters is updated. + * @slope: slope for temperature compensation. + */ +struct inv_temp_comp { + int t_lo; + int t_hi; + int b_lo[3]; + int b_hi[3]; + bool has_low; + bool has_high; + int slope[3]; +}; + +/** + * struct inv_chip_info_s - Chip related information. + * @product_id: Product id. + * @product_revision: Product revision. + * @silicon_revision: Silicon revision. + * @software_revision: software revision. + * @compass_sens: compass sensitivity. + * @gyro_sens_trim: Gyro sensitivity trim factor. + * @accel_sens_trim: accel sensitivity trim factor. + */ +struct inv_chip_info_s { + u8 product_id; + u8 product_revision; + u8 silicon_revision; + u8 software_revision; + u8 compass_sens[3]; + u32 gyro_sens_trim; + u32 accel_sens_trim; +}; + +/** + * struct inv_smd significant motion detection structure. + * @threshold: accel threshold for motion detection. + * @delay: delay time to confirm 2nd motion. + * @delay2: delay window parameter. + * @on: smd on/off. + */ +struct inv_smd { + u32 threshold; + u32 delay; + u32 delay2; + bool on; +}; + +/** + * struct inv_ped pedometer related data structure. + * @step: steps taken. + * @time: time taken during the period. + * @last_step_time: last time the step is taken. + * @step_thresh: step threshold to show steps. + * @int_thresh: step threshold to generate interrupt. + * @int_on: pedometer interrupt enable/disable. + * @on: pedometer on/off. + * @engine_on: pedometer engine on/off. + */ +struct inv_ped { + u64 step; + u64 time; + u64 last_step_time; + u16 step_thresh; + u16 int_thresh; + bool int_on; + bool on; + bool engine_on; +}; + +/** + * struct inv_eis EIS related data structure. + * @prev_gyro: latest gyro data just before FSYNC triggerd + * @prev_timestamp: latest gyro timestamp just before FSYNC triggered + * @current_gyro: gyro data just after FSYNC triggerd + * @current_timestamp: gyro timestamp just after FSYNC triggered + * @fsync_timestamp: timestamp of FSYNC event + * @fsync_delay: delay time of FSYNC and Gyro data. DMP data of FSYNC event + * @eis_triggered: check fsync event is triggered or not. + * @eis_frame: current frame is eis frame; + * @current_sync: current frame contains fsync counter. + * @frame_count: frame count for synchronization. + */ +struct inv_eis { + int prev_gyro[3]; + u64 prev_timestamp; + int current_gyro[3]; + u64 current_timestamp; + u32 frame_dur; + u64 slope[3]; + u64 fsync_timestamp; + u64 last_fsync_timestamp; + u16 fsync_delay; + bool eis_triggered; + bool eis_frame; + bool current_sync; + bool prev_state; + u32 frame_count; + int gyro_counter; + int gyro_counter_s[3]; + int fsync_delay_s[3]; + int voting_count; + int voting_count_sub; + int voting_state; + int count_precision; +}; + +enum TRIGGER_STATE { + DATA_TRIGGER = 0, + RATE_TRIGGER, + EVENT_TRIGGER, + MISC_TRIGGER, + DEBUG_TRIGGER, +}; + +enum inv_fifo_count_mode { + BYTE_MODE, + RECORD_MODE +}; + +/** + * struct inv_secondary_reg - secondary registers data structure. + * @addr: address of the slave. + * @reg: register address of slave. + * @ctrl: control register. + * @d0: data out register. + */ +struct inv_secondary_reg { + u8 addr; + u8 reg; + u8 ctrl; + u8 d0; +}; + +struct inv_secondary_set { + u8 delay_enable; + u8 delay_time; + u8 odr_config; +}; +/** + * struct inv_engine_info - data structure for engines. + * @base_time: base time for each engine. + * @base_time_1k: base time when chip is running at 1K; + * @divider: divider used to downsample engine rate from original rate. + * @running_rate: the actually running rate of engine. + * @orig_rate: original rate for each engine before downsample. + * @dur: duration for one tick. + * @last_update_time: last update time. + */ +struct inv_engine_info { + u32 base_time; + u32 base_time_1k; + u32 divider; + u32 running_rate; + u32 orig_rate; + u32 dur; + u64 last_update_time; +}; + +struct inv_ois { + int gyro_fs; + int accel_fs; + bool en; +}; + +/** + * struct inv_timestamp_algo - timestamp algorithm . + * @last_run_time: last time the post ISR runs. + * @ts_for_calib: ts storage for calibration. + * @reset_ts: reset time. + * @dmp_ticks: dmp ticks storage for calibration. + * @start_dmp_counter: dmp counter when start a new session. + * @calib_counter: calibration counter for timestamp. + * @resume_flag: flag to indicate this is the first time after resume. time + could have up to 1 seconds difference. + * @clock_base: clock base to calculate the timestamp. + * @gyro_ts_shift: 9 K counter for EIS. + * @first_sample: first of 1K running should be dropped it affects timing + */ +struct inv_timestamp_algo { + u64 last_run_time; + u64 ts_for_calib; + u64 reset_ts; + u32 dmp_ticks; + u32 start_dmp_counter; + int calib_counter; + bool resume_flag; + enum INV_ENGINE clock_base; + u32 gyro_ts_shift; + u32 first_sample; +}; + +struct inv_mpu_slave; +/** + * struct inv_mpu_state - Driver state variables. + * @dev: device address of the current bus, i2c or spi. + * @chip_config: Cached attribute information. + * @chip_info: Chip information from read-only registers. + * @smd: SMD data structure. + * @ped: pedometer data structure. + * @batch: batchmode data structure. + * @temp_comp: gyro temperature compensation structure. + * @slave_compass: slave compass. + * @slave_pressure: slave pressure. + * @slave_als: slave als. + * @slv_reg: slave register data structure. + * @ts_algo: timestamp algorithm data structure. + * @sec_set: slave register odr config. + * @eng_info: information for each engine. + * @hw: Other hardware-specific information. + * @chip_type: chip type. + * @suspend_resume_sema: semaphore for suspend/resume. + * @wake_lock: wake lock of the system. + * @client: i2c client handle. + * @plat_data: platform data. + * @sl_handle: Handle to I2C port. + * @sensor{SENSOR_NUM_MAX]: sensor individual properties. + * @sensor_l[SENSOR_L_NUM_MAX]: android L sensors properties. + * @sensor_accuracy[SENSOR_ACCURACY_NUM_MAX]: sensor accuracy. + * @sensor_acurracy_flag: flag indiciate whether to check output accuracy. + * @irq: irq number store. + * @accel_bias: accel bias store. + * @gyro_bias: gyro bias store. + * @accel_st_bias: accel bias store, result of self-test. + * @gyro_st_bias: gyro bias store, result of self-test. + * @gyro_ois_st_bias: gyro bias store from ois self test result. + * @input_accel_dmp_bias[3]: accel bias for dmp. + * @input_gyro_dmp_bias[3]: gyro bias for dmp. + * @input_compass_dmp_bias[3]: compass bias for dmp. + * @input_accel_bias[3]: accel bias for offset register. + * @input_gyro_bias[3]: gyro bias for offset register. + * @fifo_data[8]: fifo data storage. + * @i2c_addr: i2c address. + * @header_count: header count in current FIFO. + * @step_det_count: number of step detectors in one batch. + * @gyro_sf: gyro scale factor. + * @left_over[LEFT_OVER_BYTES]: left over bytes storage. + * @left_over_size: left over size. + * @fifo_count: current fifo_count; + * @wake_sensor_received: wake up sensor received. + * @accel_cal_enable: accel calibration on/off + * @gyro_cal_enable: gyro calibration on/off + * @calib_compass_on: calibrate compass on. + * @debug_determine_engine_on: determine engine on/off. + * @poke_mode_on: poke mode on/off. + * @mode_1k_on: indicate 1K Hz mode is on. + * @poke_ts: time stamp for poke feature. + * @step_detector_base_ts: base time stamp for step detector calculation. + * @last_temp_comp_time: last time temperature compensation is done. + * @i2c_dis: disable I2C interface or not. + * @name: name for the chip. + * @gyro_st_data: gyro self test data. + * @accel_st_data: accel self test data. + * @secondary_name: name for the slave device in the secondary I2C. + * @compass_var: compass variance from DMP. + * @current_compass_matrix: matrix compass data multiplied to before soft iron. + * @final_compass_matrix: matrix compass data multiplied to before soft iron. + * @trigger_state: information that which part triggers set_inv_enable. + * @firmware: firmware data pointer. + * @accel_calib_threshold: accel calibration threshold; + * @accel_calib_rate: divider for accel calibration rate. + * @accel_covariance[COVARIANCE_SIZE]: accel covariance data; + * @kf: kfifo for activity store. + * @activity_size: size for activity. + * @cntl: control word for sensor enable. + * @cntl2: control word for sensor extension. + * @motion_event_cntl: control word for events. + * @dmp_image_size: dmp image size. + * @dmp_start_address: start address of dmp. + * @step_counter_l_on: step counter android L sensor on/off. + * @step_counter_wake_l_on: step counter android L sensor wake on/off . + * @step_detector_l_on: step detector android L sensor on/off. + * @step_detector_wake_l_on: step detector android L sensor wake on/off . + * @gesture_only_on: indicate it is gesture only. + * @mag_divider: mag divider when gyro/accel is faster than mag maximum rate. + * @special_mag_mode: for 20690, there is special mag mode need to be handled. + * @mag_start_flag: when mag divider is non zero, need to check the start. + * @prev_steps: previous steps sent to the user. + * @aut_key_in: authentication key input. + * @aut_key_out: authentication key output. + * @suspend_state: state variable to indicate that we are in suspend state. + * @secondary_gyro_on: DMP out signal to turn on gyro. + * @secondary_mag_on: DMP out signal to turn on mag. + * @secondary_prox_on: DMP out signal to turn on proximity. + * @secondary_switch: showing this setup is triggerred by secondary switch. + * @send_calib_gyro: flag to indicate to send calibrated gyro. + * @send_raw_compass: flag to send raw compass. + * @resume_state: flag to synchronize the processing of inv_read_fifo() + * @cycle_on: variable indicate accel cycle mode is on. + * @secondary_switch_data: secondary switch data for activity. + * @raw_gyro_data[6]: save raw gyro data. + * @raw_compass_data[3]: save raw compass data. + * @wait_queue: wait queue to wake up inv_read_fifo() + * @bac_drive_conf: bac drive configuration. + * @bac_walk_conf: bac walk configuration. + * @bac_smd_conf: bac smd configuration. + * @bac_bike_conf: bac bike configuration. + * @bac_run_conf: bac run configuration. + * @bac_still_conf: back still configuration. + * @power_on_data: power on data. + * @fifo_data_store: store of FIFO data. + * @int_en: store interrupt enable register data. + * @int_en2: store interrupt enable register 2 data. + * @gesture_int_count: interrupt count for gesture only mode. + * @smplrt_div: SMPLRT_DIV register value. + */ +struct inv_mpu_state { + struct device *dev; + int (*write)(struct inv_mpu_state *st, u8 reg, u8 data); + int (*read)(struct inv_mpu_state *st, u8 reg, int len, u8 *data); + int (*mem_write)(struct inv_mpu_state *st, u8 mpu_addr, u16 mem_addr, + u32 len, u8 const *data); + int (*mem_read)(struct inv_mpu_state *st, u8 mpu_addr, u16 mem_addr, + u32 len, u8 *data); + struct inv_chip_config_s chip_config; + struct inv_chip_info_s chip_info; + struct inv_smd smd; + struct inv_ped ped; + struct inv_eis eis; + struct inv_batch batch; + struct inv_temp_comp temp_comp; + struct inv_mpu_slave *slave_compass; + struct inv_mpu_slave *slave_pressure; + struct inv_mpu_slave *slave_als; + struct inv_secondary_reg slv_reg[4]; + struct inv_timestamp_algo ts_algo; + struct inv_secondary_set sec_set; + struct inv_engine_info eng_info[ENGINE_NUM_MAX]; + const struct inv_hw_s *hw; + enum inv_devices chip_type; + enum inv_bus_type bus_type; + enum inv_fifo_count_mode fifo_count_mode; +#ifdef CONFIG_HAS_WAKELOCK + struct wake_lock wake_lock; +#else + struct wakeup_source wake_lock; +#endif +#ifdef TIMER_BASED_BATCHING + struct hrtimer hr_batch_timer; + u64 batch_timeout; + bool is_batch_timer_running; + struct work_struct batch_work; +#endif + struct i2c_client *client; + struct mpu_platform_data plat_data; + void *sl_handle; + struct inv_sensor sensor[SENSOR_NUM_MAX]; + struct android_l_sensor sensor_l[SENSOR_L_NUM_MAX]; + struct inv_sensor_accuracy sensor_accuracy[SENSOR_ACCURACY_NUM_MAX]; + struct inv_ois ois; + bool sensor_acurracy_flag[SENSOR_ACCURACY_NUM_MAX]; + short irq; + int accel_bias[3]; + int gyro_bias[3]; + int accel_st_bias[3]; + int accel_ois_st_bias[3]; + int gyro_st_bias[3]; + int gyro_ois_st_bias[3]; + int input_accel_dmp_bias[3]; + int input_gyro_dmp_bias[3]; + int input_compass_dmp_bias[3]; + int input_accel_bias[3]; + int input_gyro_bias[3]; + u8 fifo_data[8]; + u8 i2c_addr; + int header_count; + int step_det_count; + s32 gyro_sf; + u8 left_over[LEFT_OVER_BYTES]; + u32 left_over_size; + u32 fifo_count; + bool wake_sensor_received; + bool accel_cal_enable; + bool gyro_cal_enable; + bool calib_compass_on; + bool debug_determine_engine_on; + bool poke_mode_on; + bool mode_1k_on; + u64 poke_ts; + u64 step_detector_base_ts; + u64 last_temp_comp_time; + u8 i2c_dis; + u8 name[20]; + u8 gyro_st_data[3]; + u8 accel_st_data[3]; + u8 secondary_name[20]; + s32 compass_var; + int current_compass_matrix[9]; + int final_compass_matrix[9]; + enum TRIGGER_STATE trigger_state; + u8 *firmware; + int accel_calib_threshold; + int accel_calib_rate; + u32 accel_covariance[COVARIANCE_SIZE]; + DECLARE_KFIFO(kf, u8, 128); + u32 activity_size; + int wom_thld; + u16 cntl; + u16 cntl2; + u16 motion_event_cntl; + int dmp_image_size; + int dmp_start_address; + bool step_counter_l_on; + bool step_counter_wake_l_on; + bool step_detector_l_on; + bool step_detector_wake_l_on; + bool gesture_only_on; + bool mag_start_flag; + int mag_divider; + bool special_mag_mode; + int prev_steps; + u32 curr_steps; + int aut_key_in; + int aut_key_out; + bool secondary_gyro_on; + bool secondary_mag_on; + bool secondary_prox_on; + bool secondary_switch; + bool send_calib_gyro; + bool send_raw_compass; + bool send_raw_gyro; + bool resume_state; + bool cycle_on; + int secondary_switch_data; + u8 raw_gyro_data[6]; + u32 raw_compass_data[3]; + wait_queue_head_t wait_queue; + u32 bac_drive_conf; + u32 bac_walk_conf; + u32 bac_smd_conf; + u32 bac_bike_conf; + u32 bac_run_conf; + u32 bac_still_conf; + u32 power_on_data; + u8 fifo_data_store[HARDWARE_FIFO_SIZE + LEFT_OVER_BYTES]; + u8 int_en; + u8 int_en_2; + u8 gesture_int_count; + u8 smplrt_div; +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING + bool read_acc_boot_sample; + bool read_gyro_boot_sample; + int acc_bufsample_cnt; + int gyro_bufsample_cnt; + bool acc_buffer_inv_samples; + bool gyro_buffer_inv_samples; + struct kmem_cache *inv_acc_cachepool; + struct kmem_cache *inv_gyro_cachepool; + struct inv_acc_sample *inv_acc_samplist[INV_ACC_MAXSAMPLE]; + struct inv_gyro_sample *inv_gyro_samplist[INV_GYRO_MAXSAMPLE]; + ktime_t timestamp; + int max_buffer_time; + struct input_dev *accbuf_dev; + struct input_dev *gyrobuf_dev; + int report_evt_cnt; +#endif + +}; + +/** + * struct inv_mpu_slave - MPU slave structure. + * @st_upper: compass self test upper limit. + * @st_lower: compass self test lower limit. + * @scale: compass scale. + * @rate_scale: decide how fast a compass can read. + * @min_read_time: minimum time between each reading. + * @self_test: self test method of the slave. + * @set_scale: set scale of slave + * @get_scale: read scale back of the slave. + * @suspend: suspend operation. + * @resume: resume operation. + * @setup: setup chip. initialization. + * @combine_data: combine raw data into meaningful data. + * @read_data: read external sensor and output + * @get_mode: get current chip mode. + * @set_lpf: set low pass filter. + * @set_fs: set full scale + * @prev_ts: last time it is read. + */ +struct inv_mpu_slave { + const short *st_upper; + const short *st_lower; + int scale; + int rate_scale; + int min_read_time; + int (*self_test) (struct inv_mpu_state *); + int (*set_scale) (struct inv_mpu_state *, int scale); + int (*get_scale) (struct inv_mpu_state *, int *val); + int (*suspend) (struct inv_mpu_state *); + int (*resume) (struct inv_mpu_state *); + int (*setup) (struct inv_mpu_state *); + int (*combine_data) (u8 *in, short *out); + int (*read_data) (struct inv_mpu_state *, short *out); + int (*get_mode) (void); + int (*set_lpf) (struct inv_mpu_state *, int rate); + int (*set_fs) (struct inv_mpu_state *, int fs); + u64 prev_ts; +}; + +/* scan element definition */ +enum inv_mpu_scan { + INV_MPU_SCAN_TIMESTAMP, +}; + +/* IIO attribute address */ +enum MPU_IIO_ATTR_ADDR { + ATTR_DMP_GYRO_X_DMP_BIAS, + ATTR_DMP_GYRO_Y_DMP_BIAS, + ATTR_DMP_GYRO_Z_DMP_BIAS, + ATTR_DMP_GYRO_CAL_ENABLE, + ATTR_DMP_ACCEL_X_DMP_BIAS, + ATTR_DMP_ACCEL_Y_DMP_BIAS, + ATTR_DMP_ACCEL_Z_DMP_BIAS, + ATTR_DMP_MAGN_X_DMP_BIAS, + ATTR_DMP_MAGN_Y_DMP_BIAS, + ATTR_DMP_MAGN_Z_DMP_BIAS, + ATTR_DMP_MAGN_ACCURACY, + ATTR_GYRO_X_OFFSET, + ATTR_GYRO_Y_OFFSET, + ATTR_GYRO_Z_OFFSET, + ATTR_ACCEL_X_OFFSET, + ATTR_ACCEL_Y_OFFSET, + ATTR_ACCEL_Z_OFFSET, + ATTR_DMP_SC_AUTH, + ATTR_DMP_EIS_AUTH, + ATTR_DMP_ACCEL_CAL_ENABLE, + ATTR_DMP_PED_INT_ON, + ATTR_DMP_PED_STEP_THRESH, + ATTR_DMP_PED_INT_THRESH, + ATTR_DMP_PED_ON, + ATTR_DMP_SMD_ENABLE, + ATTR_DMP_TILT_ENABLE, + ATTR_DMP_PICK_UP_ENABLE, + ATTR_DMP_EIS_ENABLE, + ATTR_DMP_PEDOMETER_STEPS, + ATTR_DMP_PEDOMETER_TIME, + ATTR_DMP_PEDOMETER_COUNTER, + ATTR_DMP_LOW_POWER_GYRO_ON, + ATTR_DMP_LP_EN_OFF, + ATTR_DMP_CLK_SEL, + ATTR_DMP_DEBUG_MEM_READ, + ATTR_DMP_DEBUG_MEM_WRITE, + ATTR_DEBUG_REG_WRITE, + ATTR_DEBUG_WRITE_CFG, + ATTR_DEBUG_REG_ADDR, + ATTR_WOM_THLD, + /* *****above this line, are DMP features, power needs on/off */ + /* *****below this line, are DMP features, no power needed */ + ATTR_IN_POWER_ON, + ATTR_DMP_ON, + ATTR_DMP_EVENT_INT_ON, + ATTR_DMP_STEP_COUNTER_ON, + ATTR_DMP_STEP_COUNTER_WAKE_ON, + ATTR_DMP_BATCHMODE_TIMEOUT, + ATTR_DMP_BATCHMODE_WAKE_FIFO_FULL, + ATTR_DMP_STEP_DETECTOR_ON, + ATTR_DMP_STEP_DETECTOR_WAKE_ON, + ATTR_DMP_ACTIVITY_ON, + ATTR_DMP_IN_ANGLVEL_ACCURACY_ENABLE, + ATTR_DMP_IN_ACCEL_ACCURACY_ENABLE, + ATTR_DMP_DEBUG_DETERMINE_ENGINE_ON, + ATTR_DMP_MISC_GYRO_RECALIBRATION, + ATTR_DMP_MISC_ACCEL_RECALIBRATION, + ATTR_DMP_PARAMS_ACCEL_CALIBRATION_THRESHOLD, + ATTR_DMP_PARAMS_ACCEL_CALIBRATION_RATE, + ATTR_GYRO_SCALE, + ATTR_ACCEL_SCALE, + ATTR_COMPASS_SCALE, + ATTR_COMPASS_SENSITIVITY_X, + ATTR_COMPASS_SENSITIVITY_Y, + ATTR_COMPASS_SENSITIVITY_Z, + ATTR_GYRO_ENABLE, + ATTR_ACCEL_ENABLE, + ATTR_COMPASS_ENABLE, + ATTR_FIRMWARE_LOADED, + ATTR_POKE_MODE, + ATTR_ANGLVEL_X_CALIBBIAS, + ATTR_ANGLVEL_Y_CALIBBIAS, + ATTR_ANGLVEL_Z_CALIBBIAS, + ATTR_ACCEL_X_CALIBBIAS, + ATTR_ACCEL_Y_CALIBBIAS, + ATTR_ACCEL_Z_CALIBBIAS, + ATTR_ANGLVEL_X_ST_CALIBBIAS, + ATTR_ANGLVEL_Y_ST_CALIBBIAS, + ATTR_ANGLVEL_Z_ST_CALIBBIAS, + ATTR_ANGLVEL_X_OIS_ST_CALIBBIAS, + ATTR_ANGLVEL_Y_OIS_ST_CALIBBIAS, + ATTR_ANGLVEL_Z_OIS_ST_CALIBBIAS, + ATTR_ACCEL_X_ST_CALIBBIAS, + ATTR_ACCEL_Y_ST_CALIBBIAS, + ATTR_ACCEL_Z_ST_CALIBBIAS, + ATTR_ACCEL_X_OIS_ST_CALIBBIAS, + ATTR_ACCEL_Y_OIS_ST_CALIBBIAS, + ATTR_ACCEL_Z_OIS_ST_CALIBBIAS, + ATTR_GYRO_MATRIX, + ATTR_ACCEL_MATRIX, + ATTR_COMPASS_MATRIX, + ATTR_FSYNC_FRAME_COUNT, + ATTR_SECONDARY_NAME, + ATTR_GYRO_SF, + ATTR_BAC_DRIVE_CONFIDENCE, + ATTR_BAC_WALK_CONFIDENCE, + ATTR_BAC_SMD_CONFIDENCE, + ATTR_BAC_BIKE_CONFIDENCE, + ATTR_BAC_STILL_CONFIDENCE, + ATTR_BAC_RUN_CONFIDENCE, + IN_OIS_ACCEL_FS, + IN_OIS_GYRO_FS, + IN_OIS_ENABLE, +}; + +int inv_mpu_configure_ring(struct iio_dev *indio_dev); +int inv_mpu_probe_trigger(struct iio_dev *indio_dev); +void inv_mpu_unconfigure_ring(struct iio_dev *indio_dev); +void inv_mpu_remove_trigger(struct iio_dev *indio_dev); +#ifdef CONFIG_PM_SLEEP +int inv_mpu_suspend(struct iio_dev *indio_dev); +void inv_mpu_complete(struct iio_dev *indio_dev); +#endif + +int inv_get_pedometer_steps(struct inv_mpu_state *st, int *ped); +int inv_get_pedometer_time(struct inv_mpu_state *st, int *ped); +int inv_read_pedometer_counter(struct inv_mpu_state *st); + +int inv_dmp_read(struct inv_mpu_state *st, int off, int size, u8 *buf); +int inv_firmware_load(struct inv_mpu_state *st); + +int set_inv_enable(struct iio_dev *indio_dev); + +int inv_mpu_setup_compass_slave(struct inv_mpu_state *st); +int inv_mpu_setup_pressure_slave(struct inv_mpu_state *st); +int inv_mpu_setup_als_slave(struct inv_mpu_state *st); +int inv_mpu_initialize(struct inv_mpu_state *st); +int inv_set_accel_sf(struct inv_mpu_state *st); +int inv_set_gyro_sf(struct inv_mpu_state *st); +s64 get_time_ns(void); +int inv_i2c_read_base(struct inv_mpu_state *st, u16 i, u8 r, u16 l, u8 *d); +int inv_i2c_single_write_base(struct inv_mpu_state *st, u16 i, u8 r, u8 d); +int write_be32_to_mem(struct inv_mpu_state *st, u32 data, int addr); +int write_be16_to_mem(struct inv_mpu_state *st, u16 data, int addr); +int read_be32_from_mem(struct inv_mpu_state *st, u32 *o, int addr); +int read_be16_from_mem(struct inv_mpu_state *st, u16 *o, int addr); +u32 inv_get_cntr_diff(u32 curr_counter, u32 prev); +int inv_write_2bytes(struct inv_mpu_state *st, int k, int data); +int inv_set_bank(struct inv_mpu_state *st, u8 bank); +int inv_set_power(struct inv_mpu_state *st, bool power_on); +int inv_switch_power_in_lp(struct inv_mpu_state *st, bool on); +#ifndef CONFIG_INV_MPU_IIO_ICM20608D +int inv_set_accel_config2(struct inv_mpu_state *st, bool cycle_mode); +#endif +int inv_stop_dmp(struct inv_mpu_state *st); +int inv_reset_fifo(struct inv_mpu_state *st, bool turn_off); +int inv_create_dmp_sysfs(struct iio_dev *ind); +int inv_check_chip_type(struct iio_dev *indio_dev, const char *name); +int inv_write_compass_matrix(struct inv_mpu_state *st, int *adj); +irqreturn_t inv_read_fifo(int irq, void *dev_id); +#ifdef TIMER_BASED_BATCHING +void inv_batch_work(struct work_struct *work); +#endif +int inv_flush_batch_data(struct iio_dev *indio_dev, int data); +static inline int mpu_memory_write(struct inv_mpu_state *st, u8 mpu_addr, + u16 mem_addr, u32 len, u8 const *data) +{ + int ret = -1; + + if (st->mem_write) + ret = st->mem_write(st, mpu_addr, mem_addr, len, data); + + return ret; +} +static inline int mpu_memory_read(struct inv_mpu_state *st, u8 mpu_addr, + u16 mem_addr, u32 len, u8 *data) +{ + int ret = -1; + + if (st->mem_read) + ret = st->mem_read(st, mpu_addr, mem_addr, len, data); + + return ret; +} +int inv_read_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int len); +int inv_write_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int v); +int inv_execute_write_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int v); +int inv_execute_read_secondary(struct inv_mpu_state *st, int ind, int addr, + int reg, int len, u8 *d); + +int inv_push_16bytes_buffer(struct inv_mpu_state *st, u16 hdr, + u64 t, int *q, s16 accur); +int inv_push_gyro_data(struct inv_mpu_state *st, s16 *raw, s32 *calib, u64 t); +int inv_push_8bytes_buffer(struct inv_mpu_state *st, u16 hdr, u64 t, s16 *d); +int inv_push_8bytes_kf(struct inv_mpu_state *st, u16 hdr, u64 t, s16 *d); + +void inv_push_step_indicator(struct inv_mpu_state *st, u64 t); +int inv_send_steps(struct inv_mpu_state *st, int step, u64 t); +int inv_push_marker_to_buffer(struct inv_mpu_state *st, u16 hdr, int data); + +int inv_check_sensor_on(struct inv_mpu_state *st); +int inv_write_cntl(struct inv_mpu_state *st, u16 wd, bool en, int cntl); + +int inv_get_packet_size(struct inv_mpu_state *st, u16 hdr, + u32 *pk_size, u8 *dptr); +int inv_parse_packet(struct inv_mpu_state *st, u16 hdr, u8 *dptr); +int inv_pre_parse_packet(struct inv_mpu_state *st, u16 hdr, u8 *dptr); +int inv_process_dmp_data(struct inv_mpu_state *st); + +int be32_to_int(u8 *d); +void inv_convert_and_push_16bytes(struct inv_mpu_state *st, u16 hdr, + u8 *d, u64 t, s8 *m); +void inv_convert_and_push_8bytes(struct inv_mpu_state *st, u16 hdr, + u8 *d, u64 t, s8 *m); +int inv_get_dmp_ts(struct inv_mpu_state *st, int i); +int inv_process_step_det(struct inv_mpu_state *st, u8 *dptr); +int inv_process_eis(struct inv_mpu_state *st, u16 delay); +int inv_rate_convert(struct inv_mpu_state *st, int ind, int data); + +int inv_setup_dmp_firmware(struct inv_mpu_state *st); +/* used to print i2c data using pr_debug */ +char *wr_pr_debug_begin(u8 const *data, u32 len, char *string); +char *wr_pr_debug_end(char *string); + +int inv_hw_self_test(struct inv_mpu_state *st); +int inv_q30_mult(int a, int b); +#ifdef ACCEL_BIAS_TEST +int inv_get_3axis_average(s16 src[], s16 dst[], s16 reset); +#endif + +static inline int inv_plat_single_write(struct inv_mpu_state *st, + u8 reg, u8 data) +{ + int ret = -1; + + if (st->write) + ret = st->write(st, reg, data); + + return ret; +} +static inline int inv_plat_read(struct inv_mpu_state *st, u8 reg, + int len, u8 *data) +{ + int ret = -1; + + if (st->read) + ret = st->read(st, reg, len, data); + + return ret; +} +irqreturn_t inv_read_fifo(int , void *); + +int inv_stop_interrupt(struct inv_mpu_state *st); +int inv_reenable_interrupt(struct inv_mpu_state *st); + +int inv_enable_pedometer_interrupt(struct inv_mpu_state *st, bool en); +int inv_dataout_control1(struct inv_mpu_state *st, u16 cntl1); +int inv_dataout_control2(struct inv_mpu_state *st, u16 cntl2); +int inv_motion_interrupt_control(struct inv_mpu_state *st, + u16 motion_event_cntl); + +int inv_bound_timestamp(struct inv_mpu_state *st); +int inv_update_dmp_ts(struct inv_mpu_state *st, int ind); +int inv_get_last_run_time_non_dmp_record_mode(struct inv_mpu_state *st); + +#define mem_w(a, b, c) mpu_memory_write(st, st->i2c_addr, a, b, c) +#define mem_r(a, b, c) mpu_memory_read(st, st->i2c_addr, a, b, c) + +#endif /* #ifndef _INV_MPU_IIO_H_ */ diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu/inv_mpu_ring.c new file mode 100644 index 0000000000000000000000000000000000000000..de64b2c03ae98794d8c3a52e02c47df1dc7c4ad7 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_ring.c @@ -0,0 +1,718 @@ +/* +* Copyright (C) 2012-2018 InvenSense, 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. +*/ +#define pr_fmt(fmt) "inv_mpu: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_mpu_iio.h" + +static void inv_push_timestamp(struct iio_dev *indio_dev, u64 t) +{ + u8 buf[IIO_BUFFER_BYTES]; + struct inv_mpu_state *st; + + st = iio_priv(indio_dev); + if (st->poke_mode_on) + memcpy(buf, &st->poke_ts, sizeof(t)); + else + memcpy(buf, &t, sizeof(t)); + iio_push_to_buffers(indio_dev, buf); +} + +int inv_push_marker_to_buffer(struct inv_mpu_state *st, u16 hdr, int data) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + u8 buf[IIO_BUFFER_BYTES]; + + memcpy(buf, &hdr, sizeof(hdr)); + memcpy(&buf[4], &data, sizeof(data)); + iio_push_to_buffers(indio_dev, buf); + + return 0; +} +static int inv_calc_precision(struct inv_mpu_state *st) +{ + int diff; + int init; + + if (st->eis.voting_state != 8) + return 0; + diff = abs(st->eis.fsync_delay_s[1] - st->eis.fsync_delay_s[0]); + init = 0; + if (diff) + init = st->sensor[SENSOR_GYRO].dur / diff; + + if (abs(init - NSEC_PER_USEC) < (NSEC_PER_USEC >> 3)) + st->eis.count_precision = init; + else + st->eis.voting_state = 0; + + pr_debug("dur= %d prc= %d\n", st->sensor[SENSOR_GYRO].dur, + st->eis.count_precision); + + return 0; +} + +static s64 calc_frame_ave(struct inv_mpu_state *st, int delay) +{ + s64 ts; + + ts = st->eis.current_timestamp - delay; +#if defined(CONFIG_INV_MPU_IIO_ICM20648) | defined(CONFIG_INV_MPU_IIO_ICM20690) + ts -= st->ts_algo.gyro_ts_shift; +#endif + pr_debug("shift= %d ts = %lld\n", st->ts_algo.gyro_ts_shift, ts); + + return ts; +} + +static void inv_push_eis_ring(struct inv_mpu_state *st, int *q, bool sync, + s64 t) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + struct inv_eis *eis = &st->eis; + u8 buf[IIO_BUFFER_BYTES]; + int tmp, ii; + + buf[0] = (EIS_GYRO_HDR & 0xff); + buf[1] = (EIS_GYRO_HDR >> 8); + memcpy(buf + 4, &q[0], sizeof(q[0])); + iio_push_to_buffers(indio_dev, buf); + for (ii = 0; ii < 2; ii++) + memcpy(buf + 4 * ii, &q[ii + 1], sizeof(q[ii])); + iio_push_to_buffers(indio_dev, buf); + tmp = eis->frame_count; + if (sync) + tmp |= 0x80000000; + memcpy(buf, &tmp, sizeof(tmp)); + iio_push_to_buffers(indio_dev, buf); + inv_push_timestamp(indio_dev, t); +} +static int inv_do_interpolation_gyro(struct inv_mpu_state *st, int *prev, + s64 prev_t, int *curr, s64 curr_t, s64 t, bool trigger) +{ + int i; + int out[3]; +#if defined(CONFIG_INV_MPU_IIO_ICM20648) | defined(CONFIG_INV_MPU_IIO_ICM20690) + prev_t -= st->ts_algo.gyro_ts_shift; + prev_t += MPU_4X_TS_GYRO_SHIFT; + curr_t -= st->ts_algo.gyro_ts_shift; + curr_t += MPU_4X_TS_GYRO_SHIFT; +#endif + if ((t > prev_t) && (t < curr_t)) { + for (i = 0; i < 3; i++) + out[i] = (int)div_s64((s64)(curr[i] - prev[i]) * + (s64)(t - prev_t), curr_t - prev_t) + prev[i]; + } else if (t < prev_t) { + for (i = 0; i < 3; i++) + out[i] = prev[i]; + } else { + for (i = 0; i < 3; i++) + out[i] = curr[i]; + } + pr_debug("prev= %lld t = %lld curr= %lld\n", prev_t, t, curr_t); + pr_debug("prev = %d, %d, %d\n", prev[0], prev[1], prev[2]); + pr_debug("curr = %d, %d, %d\n", curr[0], curr[1], curr[2]); + pr_debug("out = %d, %d, %d\n", out[0], out[1], out[2]); + inv_push_eis_ring(st, out, trigger, t); + + return 0; +} +#if defined(CONFIG_INV_MPU_IIO_ICM20648) | defined(CONFIG_INV_MPU_IIO_ICM20690) +static void inv_handle_triggered_eis(struct inv_mpu_state *st) +{ + struct inv_eis *eis = &st->eis; + int delay; + + if (st->eis.eis_frame) { + inv_calc_precision(st); + delay = ((int)st->eis.fsync_delay) * st->eis.count_precision; + eis->fsync_timestamp = calc_frame_ave(st, delay); + inv_do_interpolation_gyro(st, + st->eis.prev_gyro, st->eis.prev_timestamp, + st->eis.current_gyro, st->eis.current_timestamp, + eis->fsync_timestamp, true); + pr_debug("fsync=%lld, curr=%lld, delay=%d\n", + eis->fsync_timestamp, eis->current_timestamp, delay); + inv_push_eis_ring(st, st->eis.current_gyro, false, + st->eis.current_timestamp - st->ts_algo.gyro_ts_shift + + MPU_4X_TS_GYRO_SHIFT); + eis->last_fsync_timestamp = eis->fsync_timestamp; + } else { + pr_debug("cur= %lld\n", st->eis.current_timestamp); + inv_push_eis_ring(st, st->eis.current_gyro, false, + st->eis.current_timestamp - st->ts_algo.gyro_ts_shift + + MPU_4X_TS_GYRO_SHIFT); + } +} +#else +static void inv_handle_triggered_eis(struct inv_mpu_state *st) +{ + struct inv_eis *eis = &st->eis; + int delay; + + if ((st->eis.eis_frame && (st->eis.fsync_delay != 5)) || + (st->eis.eis_frame && (st->eis.fsync_delay == 5) && + (!st->eis.current_sync)) + ) { + inv_calc_precision(st); + delay = ((int)st->eis.fsync_delay) * st->eis.count_precision; + eis->fsync_timestamp = calc_frame_ave(st, delay); + inv_do_interpolation_gyro(st, + st->eis.prev_gyro, st->eis.prev_timestamp, + st->eis.current_gyro, st->eis.current_timestamp, + eis->fsync_timestamp, true); + pr_debug("fsync=%lld, curr=%lld, delay=%d\n", + eis->fsync_timestamp, eis->current_timestamp, delay); + inv_push_eis_ring(st, st->eis.current_gyro, false, + st->eis.current_timestamp); + eis->last_fsync_timestamp = eis->fsync_timestamp; + st->eis.eis_frame = false; + } else { + st->eis.current_sync = false; + pr_debug("cur= %lld\n", st->eis.current_timestamp); + inv_push_eis_ring(st, st->eis.current_gyro, false, + st->eis.current_timestamp); + } +} +#endif +static void inv_push_eis_buffer(struct inv_mpu_state *st, u64 t, int *q) +{ + int ii; + + if (st->eis.eis_triggered) { + for (ii = 0; ii < 3; ii++) + st->eis.prev_gyro[ii] = st->eis.current_gyro[ii]; + st->eis.prev_timestamp = st->eis.current_timestamp; + + for (ii = 0; ii < 3; ii++) + st->eis.current_gyro[ii] = q[ii]; + st->eis.current_timestamp = t; + inv_handle_triggered_eis(st); + } else { + for (ii = 0; ii < 3; ii++) + st->eis.current_gyro[ii] = q[ii]; + st->eis.current_timestamp = t; + } +} +static int inv_push_16bytes_final(struct inv_mpu_state *st, int j, + s32 *q, u64 t, s16 accur) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + u8 buf[IIO_BUFFER_BYTES]; + int ii; + + memcpy(buf, &st->sensor_l[j].header, sizeof(st->sensor_l[j].header)); + memcpy(buf + 2, &accur, sizeof(accur)); + memcpy(buf + 4, &q[0], sizeof(q[0])); + iio_push_to_buffers(indio_dev, buf); + for (ii = 0; ii < 2; ii++) + memcpy(buf + 4 * ii, &q[ii + 1], sizeof(q[ii])); + iio_push_to_buffers(indio_dev, buf); + inv_push_timestamp(indio_dev, t); + st->sensor_l[j].counter = 0; + if (st->sensor_l[j].wake_on) + st->wake_sensor_received = true; + + return 0; +} +int inv_push_16bytes_buffer(struct inv_mpu_state *st, u16 sensor, + u64 t, int *q, s16 accur) +{ + int j; + + for (j = 0; j < SENSOR_L_NUM_MAX; j++) { + if (st->sensor_l[j].on && (st->sensor_l[j].base == sensor)) { + st->sensor_l[j].counter++; + if ((st->sensor_l[j].div != 0xffff) && + (st->sensor_l[j].counter >= + st->sensor_l[j].div)) { + pr_debug( + "Sensor_l = %d sensor = %d header [%04X] div [%d] ts [%lld] %d %d %d\n", + j, sensor, + st->sensor_l[j].header, + st->sensor_l[j].div, + t, q[0], q[1], q[2]); + inv_push_16bytes_final(st, j, q, t, accur); + } + } + } + return 0; +} + +void inv_convert_and_push_16bytes(struct inv_mpu_state *st, u16 hdr, + u8 *d, u64 t, s8 *m) +{ + int i, j; + s32 in[3], out[3]; + + for (i = 0; i < 3; i++) + in[i] = be32_to_int(d + i * 4); + /* multiply with orientation matrix can be optimized like this */ + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if (m[i * 3 + j]) + out[i] = in[j] * m[i * 3 + j]; + + inv_push_16bytes_buffer(st, hdr, t, out, 0); +} + +void inv_convert_and_push_8bytes(struct inv_mpu_state *st, u16 hdr, + u8 *d, u64 t, s8 *m) +{ + int i, j; + s16 in[3], out[3]; + + for (i = 0; i < 3; i++) + in[i] = be16_to_cpup((__be16 *) (d + i * 2)); + + /* multiply with orientation matrix can be optimized like this */ + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if (m[i * 3 + j]) + out[i] = in[j] * m[i * 3 + j]; + + inv_push_8bytes_buffer(st, hdr, t, out); +} +#ifdef CONFIG_ENABLE_IAM_ACC_GYRO_BUFFERING +static void store_acc_boot_sample(struct inv_mpu_state *st, u64 t, + s16 x, s16 y, s16 z) +{ + if (false == st->acc_buffer_inv_samples) + return; + st->timestamp.tv64 = t; + if (ktime_to_timespec(st->timestamp).tv_sec + < st->max_buffer_time) { + if (st->acc_bufsample_cnt < INV_ACC_MAXSAMPLE) { + st->inv_acc_samplist[st-> + acc_bufsample_cnt]->xyz[0] = x; + st->inv_acc_samplist[st-> + acc_bufsample_cnt]->xyz[1] = y; + st->inv_acc_samplist[st-> + acc_bufsample_cnt]->xyz[2] = z; + st->inv_acc_samplist[st-> + acc_bufsample_cnt]->tsec = + ktime_to_timespec(st + ->timestamp).tv_sec; + st->inv_acc_samplist[st-> + acc_bufsample_cnt]->tnsec = + ktime_to_timespec(st + ->timestamp).tv_nsec; + st->acc_bufsample_cnt++; + } + } else { + dev_info(st->dev, "End of ACC buffering %d\n", + st->acc_bufsample_cnt); + st->acc_buffer_inv_samples = false; + } +} +static void store_gyro_boot_sample(struct inv_mpu_state *st, u64 t, + s16 x, s16 y, s16 z) +{ + + if (false == st->gyro_buffer_inv_samples) + return; + st->timestamp.tv64 = t; + if (ktime_to_timespec(st->timestamp).tv_sec + < st->max_buffer_time) { + if (st->gyro_bufsample_cnt < INV_GYRO_MAXSAMPLE) { + st->inv_gyro_samplist[st-> + gyro_bufsample_cnt]->xyz[0] = x; + st->inv_gyro_samplist[st-> + gyro_bufsample_cnt]->xyz[1] = y; + st->inv_gyro_samplist[st-> + gyro_bufsample_cnt]->xyz[2] = z; + st->inv_gyro_samplist[st-> + gyro_bufsample_cnt]->tsec = + ktime_to_timespec(st-> + timestamp).tv_sec; + st->inv_gyro_samplist[st-> + gyro_bufsample_cnt]->tnsec = + ktime_to_timespec(st-> + timestamp).tv_nsec; + st->gyro_bufsample_cnt++; + } + } else { + dev_info(st->dev, "End of GYRO buffering %d\n", + st->gyro_bufsample_cnt); + st->gyro_buffer_inv_samples = false; + } +} +#else +static void store_acc_boot_sample(struct inv_mpu_state *st, u64 t, + s16 x, s16 y, s16 z) +{ +} +static void store_gyro_boot_sample(struct inv_mpu_state *st, u64 t, + s16 x, s16 y, s16 z) +{ +} +#endif + +int inv_push_special_8bytes_buffer(struct inv_mpu_state *st, + u16 hdr, u64 t, s16 *d) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + u8 buf[IIO_BUFFER_BYTES]; + int j; + + memcpy(buf, &hdr, sizeof(hdr)); + memcpy(&buf[2], &d[0], sizeof(d[0])); + for (j = 0; j < 2; j++) + memcpy(&buf[4 + j * 2], &d[j + 1], sizeof(d[j])); + store_gyro_boot_sample(st, t, d[0], d[1], d[2]); + iio_push_to_buffers(indio_dev, buf); + inv_push_timestamp(indio_dev, t); + + return 0; +} + +static int inv_s16_gyro_push(struct inv_mpu_state *st, int i, s16 *raw, u64 t) +{ + if (st->sensor_l[i].on) { + st->sensor_l[i].counter++; + if ((st->sensor_l[i].div != 0xffff) && + (st->sensor_l[i].counter >= st->sensor_l[i].div)) { + inv_push_special_8bytes_buffer(st, + st->sensor_l[i].header, t, raw); + st->sensor_l[i].counter = 0; + if (st->sensor_l[i].wake_on) + st->wake_sensor_received = true; + } + } + + return 0; +} + +static int inv_s32_gyro_push(struct inv_mpu_state *st, int i, s32 *calib, u64 t) +{ + if (st->sensor_l[i].on) { + st->sensor_l[i].counter++; + if ((st->sensor_l[i].div != 0xffff) && + (st->sensor_l[i].counter >= st->sensor_l[i].div)) { + inv_push_16bytes_final(st, i, calib, t, 0); + st->sensor_l[i].counter = 0; + if (st->sensor_l[i].wake_on) + st->wake_sensor_received = true; + } + } + + return 0; +} + +int inv_push_gyro_data(struct inv_mpu_state *st, s16 *raw, s32 *calib, u64 t) +{ + int gyro_data[] = {SENSOR_L_GYRO, SENSOR_L_GYRO_WAKE}; + int calib_data[] = {SENSOR_L_GYRO_CAL, SENSOR_L_GYRO_CAL_WAKE}; + int i; + + if (st->sensor_l[SENSOR_L_EIS_GYRO].on) + inv_push_eis_buffer(st, t, calib); + + for (i = 0; i < 2; i++) + inv_s16_gyro_push(st, gyro_data[i], raw, t); + for (i = 0; i < 2; i++) + inv_s32_gyro_push(st, calib_data[i], calib, t); + + return 0; +} +int inv_push_8bytes_buffer(struct inv_mpu_state *st, u16 sensor, u64 t, s16 *d) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + u8 buf[IIO_BUFFER_BYTES]; + int ii, j; + + if ((sensor == STEP_DETECTOR_HDR) || + (sensor == STEP_DETECTOR_WAKE_HDR)) { + memcpy(buf, &sensor, sizeof(sensor)); + memcpy(&buf[2], &d[0], sizeof(d[0])); + for (j = 0; j < 2; j++) + memcpy(&buf[4 + j * 2], &d[j + 1], sizeof(d[j])); + iio_push_to_buffers(indio_dev, buf); + inv_push_timestamp(indio_dev, t); + if (sensor == STEP_DETECTOR_WAKE_HDR) + st->wake_sensor_received = true; + return 0; + } + for (ii = 0; ii < SENSOR_L_NUM_MAX; ii++) { + if (st->sensor_l[ii].on && + (st->sensor_l[ii].base == sensor) && + (st->sensor_l[ii].div != 0xffff)) { + st->sensor_l[ii].counter++; + if (st->sensor_l[ii].counter >= st->sensor_l[ii].div) { + pr_debug( + "Sensor_l = %d sensor = %d header [%04X] div [%d] ts [%lld] %d %d %d\n", + ii, sensor, st->sensor_l[ii].header, + st->sensor_l[ii].div, t, d[0], d[1], d[2]); + + memcpy(buf, &st->sensor_l[ii].header, + sizeof(st->sensor_l[ii].header)); + memcpy(&buf[2], &d[0], sizeof(d[0])); + for (j = 0; j < 2; j++) + memcpy(&buf[4 + j * 2], &d[j + 1], + sizeof(d[j])); + store_acc_boot_sample(st, t, d[0], d[1], d[2]); + iio_push_to_buffers(indio_dev, buf); + inv_push_timestamp(indio_dev, t); + st->sensor_l[ii].counter = 0; + if (st->sensor_l[ii].wake_on) + st->wake_sensor_received = true; + } + } + } + + return 0; +} +#ifdef CONFIG_INV_MPU_IIO_ICM20648 +/* Implemented activity to string function for BAC test */ +#define TILT_DETECTED 0x1000 +#define NONE 0x00 +#define DRIVE 0x01 +#define WALK 0x02 +#define RUN 0x04 +#define BIKE 0x08 +#define TILT 0x10 +#define STILL 0x20 +#define DRIVE_WALK (DRIVE | WALK) +#define DRIVE_RUN (DRIVE | RUN) + +char *act_string(s16 data) +{ + data &= (~TILT); + switch (data) { + case NONE: + return "None"; + case DRIVE: + return "Drive"; + case WALK: + return "Walk"; + case RUN: + return "Run"; + case BIKE: + return "Bike"; + case STILL: + return "Still"; + case DRIVE_WALK: + return "drive and walk"; + case DRIVE_RUN: + return "drive and run"; + default: + return "Unknown"; + } + return "Unknown"; +} + +char *inv_tilt_check(s16 data) +{ + if (data & TILT) + return "Tilt"; + else + return "None"; +} + +int inv_push_8bytes_kf(struct inv_mpu_state *st, u16 hdr, u64 t, s16 *d) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + u8 buf[IIO_BUFFER_BYTES]; + int i; + + if (st->chip_config.activity_on) { + memcpy(buf, &hdr, sizeof(hdr)); + for (i = 0; i < 3; i++) + memcpy(&buf[2 + i * 2], &d[i], sizeof(d[i])); + + kfifo_in(&st->kf, buf, IIO_BUFFER_BYTES); + memcpy(buf, &t, sizeof(t)); + kfifo_in(&st->kf, buf, IIO_BUFFER_BYTES); + st->activity_size += IIO_BUFFER_BYTES * 2; + } + if (st->chip_config.tilt_enable) { + pr_debug("d[0] = %04X, [%X : %s] to [%X : %s]", + d[0], d[0] & 0x00FF, + inv_tilt_check(d[0] & 0x00FF), + (d[0] & 0xFF00) >> 8, inv_tilt_check((d[0] & 0xFF00) >> 8)); + sysfs_notify(&indio_dev->dev.kobj, NULL, "poll_tilt"); + } + + pr_debug("d[0] = %04X, [%X : %s] to [%X : %s]", d[0], d[0] & 0x00FF, + act_string(d[0] & 0x00FF), + (d[0] & 0xFF00) >> 8, act_string((d[0] & 0xFF00) >> 8)); + + read_be32_from_mem(st, &st->bac_drive_conf, BAC_DRIVE_CONFIDENCE); + read_be32_from_mem(st, &st->bac_walk_conf, BAC_WALK_CONFIDENCE); + read_be32_from_mem(st, &st->bac_smd_conf, BAC_SMD_CONFIDENCE); + read_be32_from_mem(st, &st->bac_bike_conf, BAC_BIKE_CONFIDENCE); + read_be32_from_mem(st, &st->bac_still_conf, BAC_STILL_CONFIDENCE); + read_be32_from_mem(st, &st->bac_run_conf, BAC_RUN_CONFIDENCE); + + return 0; +} +#endif + +int inv_send_steps(struct inv_mpu_state *st, int step, u64 ts) +{ + s16 s[3]; + + s[0] = 0; + s[1] = (s16) (step & 0xffff); + s[2] = (s16) ((step >> 16) & 0xffff); + if (st->step_counter_l_on) + inv_push_special_8bytes_buffer(st, STEP_COUNTER_HDR, ts, s); + if (st->step_counter_wake_l_on) { + inv_push_special_8bytes_buffer(st, STEP_COUNTER_WAKE_HDR, + ts, s); + st->wake_sensor_received = true; + } + return 0; +} + +void inv_push_step_indicator(struct inv_mpu_state *st, u64 t) +{ + s16 sen[3]; +#define STEP_INDICATOR_HEADER 0x0001 + + sen[0] = 0; + sen[1] = 0; + sen[2] = 0; + inv_push_8bytes_buffer(st, STEP_INDICATOR_HEADER, t, sen); +} + +/* + * inv_irq_handler() - Cache a timestamp at each data ready interrupt. + */ +static irqreturn_t inv_irq_handler(int irq, void *dev_id) +{ + return IRQ_WAKE_THREAD; +} + +#ifdef TIMER_BASED_BATCHING +static enum hrtimer_restart inv_batch_timer_handler(struct hrtimer *timer) +{ + struct inv_mpu_state *st = + container_of(timer, struct inv_mpu_state, hr_batch_timer); + + if (st->chip_config.gyro_enable || st->chip_config.accel_enable) { + hrtimer_forward_now(&st->hr_batch_timer, + ns_to_ktime(st->batch_timeout)); + schedule_work(&st->batch_work); + return HRTIMER_RESTART; + } + st->is_batch_timer_running = 0; + return HRTIMER_NORESTART; +} +#endif + +void inv_mpu_unconfigure_ring(struct iio_dev *indio_dev) +{ + struct inv_mpu_state *st = iio_priv(indio_dev); +#ifdef KERNEL_VERSION_4_X + devm_free_irq(st->dev, st->irq, st); + devm_iio_kfifo_free(st->dev, indio_dev->buffer); +#else + free_irq(st->irq, st); + iio_kfifo_free(indio_dev->buffer); +#endif +}; +EXPORT_SYMBOL_GPL(inv_mpu_unconfigure_ring); + +#ifndef KERNEL_VERSION_4_X +static int inv_predisable(struct iio_dev *indio_dev) +{ + return 0; +} + +static int inv_preenable(struct iio_dev *indio_dev) +{ + return 0; +} + +static const struct iio_buffer_setup_ops inv_mpu_ring_setup_ops = { + .preenable = &inv_preenable, + .predisable = &inv_predisable, +}; +#endif + +int inv_mpu_configure_ring(struct iio_dev *indio_dev) +{ + int ret; + struct inv_mpu_state *st = iio_priv(indio_dev); + struct iio_buffer *ring; + +#ifdef TIMER_BASED_BATCHING + /* configure hrtimer */ + hrtimer_init(&st->hr_batch_timer, CLOCK_BOOTTIME, HRTIMER_MODE_REL); + st->hr_batch_timer.function = inv_batch_timer_handler; + INIT_WORK(&st->batch_work, inv_batch_work); +#endif +#ifdef KERNEL_VERSION_4_X + ring = devm_iio_kfifo_allocate(st->dev); + if (!ring) + return -ENOMEM; + ring->scan_timestamp = true; + iio_device_attach_buffer(indio_dev, ring); + ret = devm_request_threaded_irq(st->dev, + st->irq, + inv_irq_handler, + inv_read_fifo, + IRQF_TRIGGER_RISING | IRQF_SHARED, + "inv_irq", + st); + if (ret) { + devm_iio_kfifo_free(st->dev, ring); + return ret; + } + + // this mode does not use ops + indio_dev->modes = INDIO_ALL_BUFFER_MODES; + + return ret; +#else + ring = iio_kfifo_allocate(indio_dev); + if (!ring) + return -ENOMEM; + indio_dev->buffer = ring; + /* setup ring buffer */ + ring->scan_timestamp = true; + indio_dev->setup_ops = &inv_mpu_ring_setup_ops; + ret = request_threaded_irq(st->irq, + inv_irq_handler, + inv_read_fifo, + IRQF_TRIGGER_RISING | IRQF_SHARED, + "inv_irq", + st); + if (ret) + goto error_iio_sw_rb_free; + + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + + return 0; +error_iio_sw_rb_free: + iio_kfifo_free(indio_dev->buffer); + + return ret; +#endif +} +EXPORT_SYMBOL_GPL(inv_mpu_configure_ring); diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu/inv_mpu_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..5199e62f0d381706f74a60f4edd663d876729960 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_spi.c @@ -0,0 +1,410 @@ +/* +* Copyright (C) 2012-2018 InvenSense, 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. +*/ +#define pr_fmt(fmt) "inv_mpu: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_mpu_iio.h" +#include "inv_mpu_dts.h" + +#define INV_SPI_READ 0x80 + +static int inv_spi_single_write(struct inv_mpu_state *st, u8 reg, u8 data) +{ + struct spi_message msg; + int res; + u8 d[2]; + struct spi_transfer xfers = { + .tx_buf = d, + .bits_per_word = 8, + .len = 2, + }; + + pr_debug("reg_write: reg=0x%x data=0x%x\n", reg, data); + d[0] = reg; + d[1] = data; + spi_message_init(&msg); + spi_message_add_tail(&xfers, &msg); + res = spi_sync(to_spi_device(st->dev), &msg); + + return res; +} + +static int inv_spi_read(struct inv_mpu_state *st, u8 reg, int len, u8 *data) +{ + struct spi_message msg; + int res; + u8 d[1]; + struct spi_transfer xfers[] = { + { + .tx_buf = d, + .bits_per_word = 8, + .len = 1, + }, + { + .rx_buf = data, + .bits_per_word = 8, + .len = len, + } + }; + + if (!data) + return -EINVAL; + + d[0] = (reg | INV_SPI_READ); + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + res = spi_sync(to_spi_device(st->dev), &msg); + + if (len ==1) + pr_debug("reg_read: reg=0x%x length=%d data=0x%x\n", + reg, len, data[0]); + else + pr_debug("reg_read: reg=0x%x length=%d d0=0x%x d1=0x%x\n", + reg, len, data[0], data[1]); + + return res; + +} + +static int inv_spi_mem_write(struct inv_mpu_state *st, u8 mpu_addr, u16 mem_addr, + u32 len, u8 const *data) +{ + struct spi_message msg; + u8 buf[258]; + int res; + + struct spi_transfer xfers = { + .tx_buf = buf, + .bits_per_word = 8, + .len = len + 1, + }; + + if (!data || !st) + return -EINVAL; + + if (len > (sizeof(buf) - 1)) + return -ENOMEM; + + inv_plat_single_write(st, REG_MEM_BANK_SEL, mem_addr >> 8); + inv_plat_single_write(st, REG_MEM_START_ADDR, mem_addr & 0xFF); + + buf[0] = REG_MEM_R_W; + memcpy(buf + 1, data, len); + spi_message_init(&msg); + spi_message_add_tail(&xfers, &msg); + res = spi_sync(to_spi_device(st->dev), &msg); + + return res; +} + +static int inv_spi_mem_read(struct inv_mpu_state *st, u8 mpu_addr, u16 mem_addr, + u32 len, u8 *data) +{ + int res; + + if (!data || !st) + return -EINVAL; + + if (len > 256) + return -EINVAL; + + res = inv_plat_single_write(st, REG_MEM_BANK_SEL, mem_addr >> 8); + res = inv_plat_single_write(st, REG_MEM_START_ADDR, mem_addr & 0xFF); + res = inv_plat_read(st, REG_MEM_R_W, len, data); + + return res; +} + +/* + * inv_mpu_probe() - probe function. + */ +static int inv_mpu_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct inv_mpu_state *st; + struct iio_dev *indio_dev; + int result; + +#ifdef KERNEL_VERSION_4_X + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (indio_dev == NULL) { + pr_err("memory allocation failed\n"); + result = -ENOMEM; + goto out_no_free; + } +#else + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + pr_err("memory allocation failed\n"); + result = -ENOMEM; + goto out_no_free; + } +#endif + st = iio_priv(indio_dev); + st->write = inv_spi_single_write; + st->read = inv_spi_read; + st->mem_write = inv_spi_mem_write; + st->mem_read = inv_spi_mem_read; + st->dev = &spi->dev; + st->irq = spi->irq; +#if !defined(CONFIG_INV_MPU_IIO_ICM20602) \ + && !defined(CONFIG_INV_MPU_IIO_IAM20680) + st->i2c_dis = BIT_I2C_IF_DIS; +#endif + st->bus_type = BUS_IIO_SPI; + spi_set_drvdata(spi, indio_dev); + indio_dev->dev.parent = &spi->dev; + indio_dev->name = id->name; + +#ifdef CONFIG_OF + result = invensense_mpu_parse_dt(st->dev, &st->plat_data); + if (result) +# ifdef KERNEL_VERSION_4_X + return -ENODEV; +# else + goto out_free; +# endif + /* Power on device */ + if (st->plat_data.power_on) { + result = st->plat_data.power_on(&st->plat_data); + if (result < 0) { + dev_err(st->dev, "power_on failed: %d\n", result); +# ifdef KERNEL_VERSION_4_X + return -ENODEV; +# else + goto out_free; +# endif + } + pr_info("%s: power on here.\n", __func__); + } + pr_info("%s: power on.\n", __func__); + + msleep(100); +#else + if (dev_get_platdata(st->dev) == NULL) +# ifdef KERNEL_VERSION_4_X + return -ENODEV; +# else + goto out_free; +# endif + st->plat_data = *(struct mpu_platform_data *)dev_get_platdata(st->dev); +#endif + + /* power is turned on inside check chip type */ + result = inv_check_chip_type(indio_dev, id->name); + if (result) +#ifdef KERNEL_VERSION_4_X + return -ENODEV; +#else + goto out_free; +#endif + + result = inv_mpu_configure_ring(indio_dev); + if (result) { + pr_err("configure ring buffer fail\n"); + goto out_free; + } +#ifdef KERNEL_VERSION_4_X + result = devm_iio_device_register(st->dev, indio_dev); + if (result) { + pr_err("IIO device register fail\n"); + goto out_unreg_ring; + } +#else + result = iio_buffer_register(indio_dev, indio_dev->channels, + indio_dev->num_channels); + if (result) { + pr_err("ring buffer register fail\n"); + goto out_unreg_ring; + } + + result = iio_device_register(indio_dev); + if (result) { + pr_err("IIO device register fail\n"); + goto out_remove_ring; + } +#endif + + result = inv_create_dmp_sysfs(indio_dev); + if (result) { + pr_err("create dmp sysfs failed\n"); + goto out_unreg_iio; + } + init_waitqueue_head(&st->wait_queue); + st->resume_state = true; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&st->wake_lock, WAKE_LOCK_SUSPEND, "inv_mpu"); +#else + wakeup_source_init(&st->wake_lock, "inv_mpu"); +#endif + dev_info(st->dev, "%s ma-kernel-%s is ready to go!\n", + indio_dev->name, INVENSENSE_DRIVER_VERSION); + +#ifdef SENSOR_DATA_FROM_REGISTERS + pr_info("Data read from registers\n"); +#else + pr_info("Data read from FIFO\n"); +#endif +#ifdef TIMER_BASED_BATCHING + pr_info("Timer based batching\n"); +#endif + + return 0; +#ifdef KERNEL_VERSION_4_X +out_unreg_iio: + devm_iio_device_unregister(st->dev, indio_dev); +out_unreg_ring: + inv_mpu_unconfigure_ring(indio_dev); +out_free: + devm_iio_device_free(st->dev, indio_dev); +out_no_free: +#else +out_unreg_iio: + iio_device_unregister(indio_dev); +out_remove_ring: + iio_buffer_unregister(indio_dev); +out_unreg_ring: + inv_mpu_unconfigure_ring(indio_dev); +out_free: + iio_device_free(indio_dev); +out_no_free: +#endif + dev_err(st->dev, "%s failed %d\n", __func__, result); + + return -EIO; +} + +static void inv_mpu_shutdown(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct inv_mpu_state *st = iio_priv(indio_dev); + int result; + + mutex_lock(&indio_dev->mlock); + inv_switch_power_in_lp(st, true); + dev_dbg(st->dev, "Shutting down %s...\n", st->hw->name); + + /* reset to make sure previous state are not there */ + result = inv_plat_single_write(st, REG_PWR_MGMT_1, BIT_H_RESET); + if (result) + dev_err(st->dev, "Failed to reset %s\n", + st->hw->name); + msleep(POWER_UP_TIME); + /* turn off power to ensure gyro engine is off */ + result = inv_set_power(st, false); + if (result) + dev_err(st->dev, "Failed to turn off %s\n", + st->hw->name); + inv_switch_power_in_lp(st, false); + mutex_unlock(&indio_dev->mlock); +} + +/* + * inv_mpu_remove() - remove function. + */ +static int inv_mpu_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct inv_mpu_state *st = iio_priv(indio_dev); + +#ifdef KERNEL_VERSION_4_X + devm_iio_device_unregister(st->dev, indio_dev); +#else + iio_device_unregister(indio_dev); + iio_buffer_unregister(indio_dev); +#endif + inv_mpu_unconfigure_ring(indio_dev); +#ifdef KERNEL_VERSION_4_X + devm_iio_device_free(st->dev, indio_dev); +#else + iio_device_free(indio_dev); +#endif + dev_info(st->dev, "inv-mpu-iio module removed.\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int inv_mpu_spi_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev)); + + return inv_mpu_suspend(indio_dev); +} + +static void inv_mpu_spi_complete(struct device *dev) +{ + struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev)); + + inv_mpu_complete(indio_dev); +} +#endif + +static const struct dev_pm_ops inv_mpu_spi_pmops = { +#ifdef CONFIG_PM_SLEEP + .suspend = inv_mpu_spi_suspend, + .complete = inv_mpu_spi_complete, +#endif +}; + +/* device id table is used to identify what device can be + * supported by this driver + */ +static const struct spi_device_id inv_mpu_id[] = { +#ifdef CONFIG_INV_MPU_IIO_ICM20648 + {"icm20645", ICM20645}, + {"icm10340", ICM10340}, + {"icm20648", ICM20648}, +#else + {"icm20608d", ICM20608D}, + {"icm20690", ICM20690}, + {"icm20602", ICM20602}, + {"iam20680", IAM20680}, +#endif + {} +}; + +MODULE_DEVICE_TABLE(spi, inv_mpu_id); + +static struct spi_driver inv_mpu_driver = { + .probe = inv_mpu_probe, + .remove = inv_mpu_remove, + .shutdown = inv_mpu_shutdown, + .id_table = inv_mpu_id, + .driver = { + .owner = THIS_MODULE, + .name = "inv-mpu-iio-spi", + .pm = &inv_mpu_spi_pmops, + }, +}; +module_spi_driver(inv_mpu_driver); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Invensense SPI device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu/inv_mpu_timestamp.c b/drivers/iio/imu/inv_mpu/inv_mpu_timestamp.c new file mode 100644 index 0000000000000000000000000000000000000000..2cc721b18596db147b7fc39d89a9a0c4ecf1fe67 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_mpu_timestamp.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2012-2018 InvenSense, 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. + */ +#define pr_fmt(fmt) "inv_mpu: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_mpu_iio.h" + +#define INV_TIME_CALIB_THRESHOLD_1 2 + +#define MIN_DELAY (3 * NSEC_PER_MSEC) +#define JITTER_THRESH ( 1 * NSEC_PER_MSEC) + +int inv_update_dmp_ts(struct inv_mpu_state *st, int ind) +{ + int i; + u32 counter; + u64 ts; + enum INV_ENGINE en_ind; + struct inv_timestamp_algo *ts_algo = &st->ts_algo; + u32 base_time; + u64 cal_period; + + if (st->mode_1k_on) + cal_period = (NSEC_PER_SEC >> 2); + else + cal_period = 2 * NSEC_PER_SEC; + + ts = ts_algo->last_run_time - st->sensor[ind].time_calib; + counter = st->sensor[ind].sample_calib; + en_ind = st->sensor[ind].engine_base; + if (en_ind != ts_algo->clock_base) + return 0; + /* we average over 2 seconds period to do the timestamp calculation */ + if (ts < cal_period) + return 0; + /* this is the first time we do timestamp averaging, return */ + /* after resume from suspend, the clock of linux has up to 1 seconds + drift. We should start from the resume clock instead of using clock + before resume */ + if ((!st->sensor[ind].calib_flag) || ts_algo->resume_flag) { + st->sensor[ind].sample_calib = 0; + st->sensor[ind].time_calib = ts_algo->last_run_time; + st->sensor[ind].calib_flag = 1; + ts_algo->resume_flag = false; + + return 0; + } + /* if the sample number in current FIFO is not zero and between now and + last update time is more than 2 seconds, we do calculation */ + if ((counter > 0) && + (ts_algo->last_run_time - st->eng_info[en_ind].last_update_time > + cal_period)) { + /* duration for each sensor */ + st->sensor[ind].dur = (u32) div_u64(ts, counter); + /* engine duration derived from each sensor */ + if (st->sensor[ind].div) + st->eng_info[en_ind].dur = st->sensor[ind].dur / + st->sensor[ind].div; + else + pr_err("sensor %d divider zero!\n", ind); + /* update base time for each sensor */ + if (st->eng_info[en_ind].divider) { + base_time = (st->eng_info[en_ind].dur / + st->eng_info[en_ind].divider) * + st->eng_info[en_ind].orig_rate; + if (st->mode_1k_on) + st->eng_info[en_ind].base_time_1k = base_time; + else + st->eng_info[en_ind].base_time = base_time; + } else { + pr_err("engine %d divider zero!\n", en_ind); + } + + st->eng_info[en_ind].last_update_time = ts_algo->last_run_time; + /* update all the sensors duration based on the same engine */ + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on && + (st->sensor[i].engine_base == en_ind)) + st->sensor[i].dur = st->sensor[i].div * + st->eng_info[en_ind].dur; + } + + } + st->sensor[ind].sample_calib = 0; + st->sensor[ind].time_calib = ts_algo->last_run_time; + + return 0; +} +/** + * int inv_get_last_run_time_non_dmp_record_mode(struct inv_mpu_state *st) + * This is the function to get last run time in non dmp and record mode. + * This function will update the last_run_time, which is important parameter + * in overall timestamp algorithm. + * return value: this function returns fifo count value. +*/ +int inv_get_last_run_time_non_dmp_record_mode(struct inv_mpu_state *st) +{ + long long t_pre, t_post, dur; + int fifo_count; +#ifndef SENSOR_DATA_FROM_REGISTERS + int res; + u8 data[2]; +#endif + + t_pre = get_time_ns(); +#ifndef SENSOR_DATA_FROM_REGISTERS + res = inv_plat_read(st, REG_FIFO_COUNT_H, FIFO_COUNT_BYTE, data); + if (res) { + pr_info("read REG_FIFO_COUNT_H failed= %d\n", res); + return 0; + } +#endif + t_post = get_time_ns(); + +#ifdef SENSOR_DATA_FROM_REGISTERS + if (st->fifo_count_mode == BYTE_MODE) + fifo_count = st->batch.pk_size; + else + fifo_count = 1; +#else + fifo_count = be16_to_cpup((__be16 *) (data)); +#endif + pr_debug("fifc=%d\n", fifo_count); + if (!fifo_count) + return 0; + if (st->special_mag_mode && (fifo_count == 2)) { + pr_debug("special trigger\n"); + fifo_count = 1; + } + + /* In non DMP mode, either gyro or accel duration is the duration + for each sample */ + if (st->chip_config.gyro_enable) + dur = st->eng_info[ENGINE_GYRO].dur; + else + dur = st->eng_info[ENGINE_ACCEL].dur; + + if (st->fifo_count_mode == BYTE_MODE) { + fifo_count /= st->batch.pk_size; + } + + /* In record mode, each number in fifo_count is 1 record or 1 sample */ + st->ts_algo.last_run_time += dur * fifo_count; + if (st->ts_algo.last_run_time < t_pre) + st->ts_algo.last_run_time = t_pre; + if (st->ts_algo.last_run_time > t_post) + st->ts_algo.last_run_time = t_post; + + return fifo_count; +} + +int inv_get_dmp_ts(struct inv_mpu_state *st, int i) +{ + u64 current_time; + int expected_lower_duration, expected_upper_duration; + + current_time = get_time_ns(); + + st->sensor[i].ts += st->sensor[i].dur + st->sensor[i].ts_adj; + + if (st->sensor[i].ts < st->sensor[i].previous_ts) + st->sensor[i].ts = st->sensor[i].previous_ts + st->sensor[i].dur; + + //hifi sensor limits ts jitter to +/- 2% + expected_upper_duration = st->eng_info[st->sensor[i].engine_base].divider * 1020000; + expected_lower_duration = st->eng_info[st->sensor[i].engine_base].divider * 980000; +#if defined(CONFIG_INV_MPU_IIO_ICM20602) || defined(CONFIG_INV_MPU_IIO_ICM20690) || defined(CONFIG_INV_MPU_IIO_IAM20680) + if (st->sensor[i].ts < st->sensor[i].previous_ts + expected_lower_duration) + st->sensor[i].ts = st->sensor[i].previous_ts + expected_lower_duration; + if (st->sensor[i].ts > st->sensor[i].previous_ts + expected_upper_duration) + st->sensor[i].ts = st->sensor[i].previous_ts + expected_upper_duration; +#endif + if (st->sensor[i].ts > current_time ) + st->sensor[i].ts = current_time; + + st->sensor[i].previous_ts = st->sensor[i].ts; + + pr_debug("ts=%lld, reset=%lld\n", st->sensor[i].ts, st->ts_algo.reset_ts); + if (st->sensor[i].ts < st->ts_algo.reset_ts) { + pr_debug("less than reset\n"); + st->sensor[i].send = false; + } else { + st->sensor[i].send = true; + } + + if (st->header_count == 1) + inv_update_dmp_ts(st, i); + + return 0; +} + +static void process_sensor_bounding(struct inv_mpu_state *st, int i) +{ + s64 elaps_time, thresh1, thresh2; + struct inv_timestamp_algo *ts_algo = &st->ts_algo; + u32 dur; + + elaps_time = ((u64) (st->sensor[i].dur)) * st->sensor[i].count; + thresh1 = ts_algo->last_run_time - elaps_time; + + dur = max(st->sensor[i].dur, (int)MIN_DELAY); + thresh2 = thresh1 - dur; + if (thresh1 < 0) + thresh1 = 0; + if (thresh2 < 0) + thresh2 = 0; + st->sensor[i].ts_adj = 0; + if ((ts_algo->calib_counter >= INV_TIME_CALIB_THRESHOLD_1) && + (!ts_algo->resume_flag)) { + if (st->sensor[i].ts < thresh2) + st->sensor[i].ts_adj = thresh2 - st->sensor[i].ts; + } else if ((ts_algo->calib_counter >= + INV_TIME_CALIB_THRESHOLD_1) && ts_algo->resume_flag) { + if (st->sensor[i].ts < thresh2) + st->sensor[i].ts = ts_algo->last_run_time - + elaps_time - JITTER_THRESH; + } else { + st->sensor[i].ts = ts_algo->last_run_time - elaps_time - + JITTER_THRESH; + st->sensor[i].previous_ts = st->sensor[i].ts; + } + + if (st->sensor[i].ts > thresh1) + st->sensor[i].ts_adj = thresh1 - st->sensor[i].ts; + pr_debug("cali=%d\n", st->ts_algo.calib_counter); + pr_debug("adj= %lld\n", st->sensor[i].ts_adj); + pr_debug("dur= %d count= %d last= %lld\n", st->sensor[i].dur, + st->sensor[i].count, ts_algo->last_run_time); + if (st->sensor[i].ts_adj && (st->sensor[i].count > 1)) + st->sensor[i].ts_adj = div_s64(st->sensor[i].ts_adj, + st->sensor[i].count); +} +/* inv_bound_timestamp (struct inv_mpu_state *st) + The purpose this function is to give a generic bound to each + sensor timestamp. The timestamp cannot exceed current time. + The timestamp cannot backwards one sample time either, otherwise, there + would be another sample in between. Using this principle, we can bound + the sensor samples */ +int inv_bound_timestamp(struct inv_mpu_state *st) +{ + int i; + struct inv_timestamp_algo *ts_algo = &st->ts_algo; + + for (i = 0; i < SENSOR_NUM_MAX; i++) { + if (st->sensor[i].on) { + if (st->sensor[i].count) { + process_sensor_bounding(st, i); + } else if (ts_algo->calib_counter < + INV_TIME_CALIB_THRESHOLD_1) { + st->sensor[i].ts = ts_algo->reset_ts; + st->sensor[i].previous_ts = st->sensor[i].ts; + } + } + } + + return 0; +} diff --git a/drivers/iio/imu/inv_mpu/inv_test/Kconfig b/drivers/iio/imu/inv_mpu/inv_test/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a4dfd95db886bc3905b8489c7187d04457df0754 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_test/Kconfig @@ -0,0 +1,13 @@ +# +# Kconfig for Invensense IIO testing hooks +# + +config INV_TESTING + boolean "Invensense IIO testing hooks" + depends on INV_MPU_IIO || INV_AMI306_IIO || INV_YAS530 || INV_HUB_IIO + default n + help + This flag enables display of additional testing information from the + Invensense IIO drivers + It also enables the I2C counters facility to perform IO profiling. + Some additional sysfs entries will appear when this flag is enabled. diff --git a/drivers/iio/imu/inv_mpu/inv_test/Makefile b/drivers/iio/imu/inv_mpu/inv_test/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4f0edd3de9015b3caa3c23220fd1521a2d6957e4 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_test/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Invensense IIO testing hooks. +# + +obj-$(CONFIG_INV_TESTING) += inv_counters.o + diff --git a/drivers/iio/imu/inv_mpu/inv_test/inv_counters.c b/drivers/iio/imu/inv_mpu/inv_test/inv_counters.c new file mode 100644 index 0000000000000000000000000000000000000000..f60337caeeeded80c8b21831bca2a6a8c1b82f19 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_test/inv_counters.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2012-2017 InvenSense, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_counters.h" + +static int mpu_irq; +static int accel_irq; +static int compass_irq; + +struct inv_counters { + uint32_t i2c_tempreads; + uint32_t i2c_mpureads; + uint32_t i2c_mpuwrites; + uint32_t i2c_accelreads; + uint32_t i2c_accelwrites; + uint32_t i2c_compassreads; + uint32_t i2c_compasswrites; + uint32_t i2c_compassirq; + uint32_t i2c_accelirq; +}; + +static struct inv_counters Counters; + +static ssize_t i2c_counters_show(struct class *cls, + struct class_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, + "%ld.%03ld %u %u %u %u %u %u %u %u %u %u\n", + jiffies / HZ, ((jiffies % HZ) * (1024 / HZ)), + mpu_irq ? kstat_irqs(mpu_irq) : 0, + Counters.i2c_tempreads, + Counters.i2c_mpureads, Counters.i2c_mpuwrites, + accel_irq ? kstat_irqs(accel_irq) : Counters.i2c_accelirq, + Counters.i2c_accelreads, Counters.i2c_accelwrites, + compass_irq ? kstat_irqs(compass_irq) : Counters.i2c_compassirq, + Counters.i2c_compassreads, Counters.i2c_compasswrites); +} + +void inv_iio_counters_set_i2cirq(enum irqtype type, int irq) +{ + switch (type) { + case IRQ_MPU: + mpu_irq = irq; + break; + case IRQ_ACCEL: + accel_irq = irq; + break; + case IRQ_COMPASS: + compass_irq = irq; + break; + } +} +EXPORT_SYMBOL_GPL(inv_iio_counters_set_i2cirq); + +void inv_iio_counters_tempread(int count) +{ + Counters.i2c_tempreads += count; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_tempread); + +void inv_iio_counters_mpuread(int count) +{ + Counters.i2c_mpureads += count; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_mpuread); + +void inv_iio_counters_mpuwrite(int count) +{ + Counters.i2c_mpuwrites += count; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_mpuwrite); + +void inv_iio_counters_accelread(int count) +{ + Counters.i2c_accelreads += count; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_accelread); + +void inv_iio_counters_accelwrite(int count) +{ + Counters.i2c_accelwrites += count; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_accelwrite); + +void inv_iio_counters_compassread(int count) +{ + Counters.i2c_compassreads += count; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_compassread); + +void inv_iio_counters_compasswrite(int count) +{ + Counters.i2c_compasswrites += count; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_compasswrite); + +void inv_iio_counters_compassirq(void) +{ + Counters.i2c_compassirq++; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_compassirq); + +void inv_iio_counters_accelirq(void) +{ + Counters.i2c_accelirq++; +} +EXPORT_SYMBOL_GPL(inv_iio_counters_accelirq); + +static struct class_attribute inv_class_attr[] = { + __ATTR(i2c_counter, S_IRUGO, i2c_counters_show, NULL), + __ATTR_NULL +}; + +static struct class inv_counters_class = { + .name = "inv_counters", + .owner = THIS_MODULE, + .class_attrs = (struct class_attribute *) &inv_class_attr +}; + +static int __init inv_counters_init(void) +{ + memset(&Counters, 0, sizeof(Counters)); + + return class_register(&inv_counters_class); +} + +static void __exit inv_counters_exit(void) +{ + class_unregister(&inv_counters_class); +} + +module_init(inv_counters_init); +module_exit(inv_counters_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("GESL"); +MODULE_DESCRIPTION("inv_counters debug support"); + diff --git a/drivers/iio/imu/inv_mpu/inv_test/inv_counters.h b/drivers/iio/imu/inv_mpu/inv_test/inv_counters.h new file mode 100644 index 0000000000000000000000000000000000000000..62f76279e703dfcc75843326369e07c0cc8217c1 --- /dev/null +++ b/drivers/iio/imu/inv_mpu/inv_test/inv_counters.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012-2017 InvenSense, 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. + */ +#ifndef _INV_COUNTERS_H_ +#define _INV_COUNTERS_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INV_TESTING + +enum irqtype { + IRQ_MPU, + IRQ_ACCEL, + IRQ_COMPASS +}; + +#define INV_I2C_INC_MPUREAD(x) inv_iio_counters_mpuread(x) +#define INV_I2C_INC_MPUWRITE(x) inv_iio_counters_mpuwrite(x) +#define INV_I2C_INC_ACCELREAD(x) inv_iio_counters_accelread(x) +#define INV_I2C_INC_ACCELWRITE(x) inv_iio_counters_accelwrite(x) +#define INV_I2C_INC_COMPASSREAD(x) inv_iio_counters_compassread(x) +#define INV_I2C_INC_COMPASSWRITE(x) inv_iio_counters_compasswrite(x) + +#define INV_I2C_INC_TEMPREAD(x) inv_iio_counters_tempread(x) + +#define INV_I2C_SETIRQ(type, irq) inv_iio_counters_set_i2cirq(type, irq) +#define INV_I2C_INC_COMPASSIRQ() inv_iio_counters_compassirq() +#define INV_I2C_INC_ACCELIRQ() inv_iio_counters_accelirq() + +void inv_iio_counters_mpuread(int count); +void inv_iio_counters_mpuwrite(int count); +void inv_iio_counters_accelread(int count); +void inv_iio_counters_accelwrite(int count); +void inv_iio_counters_compassread(int count); +void inv_iio_counters_compasswrite(int count); + +void inv_iio_counters_tempread(int count); + +void inv_iio_counters_set_i2cirq(enum irqtype type, int irq); +void inv_iio_counters_compassirq(void); +void inv_iio_counters_accelirq(void); + +#else + +#define INV_I2C_INC_MPUREAD(x) +#define INV_I2C_INC_MPUWRITE(x) +#define INV_I2C_INC_ACCELREAD(x) +#define INV_I2C_INC_ACCELWRITE(x) +#define INV_I2C_INC_COMPASSREAD(x) +#define INV_I2C_INC_COMPASSWRITE(x) + +#define INV_I2C_INC_TEMPREAD(x) + +#define INV_I2C_SETIRQ(type, irq) +#define INV_I2C_INC_COMPASSIRQ() +#define INV_I2C_INC_ACCELIRQ() + +#endif /* CONFIG_INV_TESTING */ + +#endif /* _INV_COUNTERS_H_ */ + diff --git a/drivers/iio/imu/st_asm330lhh/Kconfig b/drivers/iio/imu/st_asm330lhh/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..ebdba3230e028ee99705c204569d4d68c936c581 --- /dev/null +++ b/drivers/iio/imu/st_asm330lhh/Kconfig @@ -0,0 +1,29 @@ + +config IIO_ST_ASM330LHH + tristate "STMicroelectronics ASM330LHH sensor" + depends on (I2C || SPI) + select IIO_BUFFER + select IIO_KFIFO_BUF + select IIO_ST_ASM330LHH_I2C if (I2C) + select IIO_ST_ASM330LHH_SPI if (SPI_MASTER) + help + Say yes here to build support for STMicroelectronics ASM330LHH imu + sensor. + + To compile this driver as a module, choose M here: the module + will be called st_asm330lhh. + +config IIO_ST_ASM330LHH_I2C + tristate + depends on IIO_ST_ASM330LHH + +config IIO_ST_ASM330LHH_SPI + tristate + depends on IIO_ST_ASM330LHH + +config ENABLE_ASM_ACC_GYRO_BUFFERING + bool "Enable accel & gyro boot time sensor sample buffering" + depends on IIO_ST_ASM330LHH + help + Say Y here if you want to buffer boot time sensor + samples for ASM330 accelerometer and gyroscope diff --git a/drivers/iio/imu/st_asm330lhh/Makefile b/drivers/iio/imu/st_asm330lhh/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c82009003c9eceb78f56c1b22d1192cad061e359 --- /dev/null +++ b/drivers/iio/imu/st_asm330lhh/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for ST ASM330 device. +# +obj-$(CONFIG_IIO_ST_ASM330LHH) += st_asm330lhh_core.o st_asm330lhh_buffer.o +obj-$(CONFIG_IIO_ST_ASM330LHH_I2C) += st_asm330lhh_i2c.o +obj-$(CONFIG_IIO_ST_ASM330LHH_SPI) += st_asm330lhh_spi.o diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh.h b/drivers/iio/imu/st_asm330lhh/st_asm330lhh.h new file mode 100644 index 0000000000000000000000000000000000000000..67552c16ae3d6e3aa3d68976bb4ea4770b855148 --- /dev/null +++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh.h @@ -0,0 +1,274 @@ +/* + * STMicroelectronics st_asm330lhh sensor driver + * + * Copyright 2018 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#ifndef ST_ASM330LHH_H +#define ST_ASM330LHH_H + +#include +#include +#include +#include +#include + +/* + * Module version: + * Version: Major.Minor + * Commit: last commit in branch + */ +#define ST_ASM330LHH_REVISION "1.0.1" +#define ST_ASM330LHH_PATCH "1" + +#define ST_ASM330LHH_VERSION "v" \ + ST_ASM330LHH_REVISION \ + "-" \ + ST_ASM330LHH_PATCH + +#define ST_ASM330LHH_DEV_NAME "asm330lhh" + +#define ST_ASM330LHH_SAMPLE_SIZE 6 +#define ST_ASM330LHH_TS_SAMPLE_SIZE 4 +#define ST_ASM330LHH_TAG_SIZE 1 +#define ST_ASM330LHH_FIFO_SAMPLE_SIZE (ST_ASM330LHH_SAMPLE_SIZE + \ + ST_ASM330LHH_TAG_SIZE) +#define ST_ASM330LHH_MAX_FIFO_DEPTH 416 + +#define ST_ASM330LHH_REG_FIFO_BATCH_ADDR 0x09 +#define ST_ASM330LHH_REG_FIFO_CTRL4_ADDR 0x0a +#define ST_ASM330LHH_REG_STATUS_ADDR 0x1e +#define ST_ASM330LHH_REG_STATUS_TDA BIT(2) +#define ST_ASM330LHH_REG_OUT_TEMP_L_ADDR 0x20 +#define ST_ASM330LHH_REG_OUT_TEMP_H_ADDR 0x21 + +#define ST_ASM330LHH_MAX_ODR 416 + +/* Define Custom events for FIFO flush */ +#define CUSTOM_IIO_EV_DIR_FIFO_EMPTY (IIO_EV_DIR_FALLING + 1) +#define CUSTOM_IIO_EV_DIR_FIFO_DATA (IIO_EV_DIR_FALLING + 2) +#define CUSTOM_IIO_EV_TYPE_FIFO_FLUSH (IIO_EV_TYPE_MAG_ADAPTIVE + 1) + +#define ST_ASM330LHH_CHANNEL(chan_type, addr, mod, ch2, scan_idx, \ + rb, sb, sg) \ +{ \ + .type = chan_type, \ + .address = addr, \ + .modified = mod, \ + .channel2 = ch2, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = scan_idx, \ + .scan_type = { \ + .sign = sg, \ + .realbits = rb, \ + .storagebits = sb, \ + .endianness = IIO_LE, \ + }, \ +} + +static const struct iio_event_spec st_asm330lhh_flush_event = { + .type = CUSTOM_IIO_EV_TYPE_FIFO_FLUSH, + .dir = IIO_EV_DIR_EITHER, +}; + +#define ST_ASM330LHH_FLUSH_CHANNEL(dtype) \ +{ \ + .type = dtype, \ + .modified = 0, \ + .scan_index = -1, \ + .indexed = -1, \ + .event_spec = &st_asm330lhh_flush_event, \ + .num_event_specs = 1, \ +} + +#define ST_ASM330LHH_RX_MAX_LENGTH 8 +#define ST_ASM330LHH_TX_MAX_LENGTH 8 + +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING +#define ASM_MAXSAMPLE 4000 +#define G_MAX 23920640 +struct asm_sample { + int xyz[3]; + unsigned int tsec; + unsigned long long tnsec; +}; +#endif + +struct st_asm330lhh_transfer_buffer { + u8 rx_buf[ST_ASM330LHH_RX_MAX_LENGTH]; + u8 tx_buf[ST_ASM330LHH_TX_MAX_LENGTH] ____cacheline_aligned; +}; + +struct st_asm330lhh_transfer_function { + int (*read)(struct device *dev, u8 addr, int len, u8 *data); + int (*write)(struct device *dev, u8 addr, int len, u8 *data); +}; + +struct st_asm330lhh_reg { + u8 addr; + u8 mask; +}; + +struct st_asm330lhh_odr { + u16 hz; + u8 val; +}; + +#define ST_ASM330LHH_ODR_LIST_SIZE 7 +struct st_asm330lhh_odr_table_entry { + struct st_asm330lhh_reg reg; + struct st_asm330lhh_odr odr_avl[ST_ASM330LHH_ODR_LIST_SIZE]; +}; + +struct st_asm330lhh_fs { + u32 gain; + u8 val; +}; + +#define ST_ASM330LHH_FS_ACC_LIST_SIZE 4 +#define ST_ASM330LHH_FS_GYRO_LIST_SIZE 6 +#define ST_ASM330LHH_FS_TEMP_LIST_SIZE 1 +#define ST_ASM330LHH_FS_LIST_SIZE 6 +struct st_asm330lhh_fs_table_entry { + u32 size; + struct st_asm330lhh_reg reg; + struct st_asm330lhh_fs fs_avl[ST_ASM330LHH_FS_LIST_SIZE]; +}; + +enum st_asm330lhh_sensor_id { + ST_ASM330LHH_ID_ACC, + ST_ASM330LHH_ID_GYRO, + ST_ASM330LHH_ID_TEMP, + ST_ASM330LHH_ID_MAX, +}; + +enum st_asm330lhh_fifo_mode { + ST_ASM330LHH_FIFO_BYPASS = 0x0, + ST_ASM330LHH_FIFO_CONT = 0x6, +}; + +enum { + ST_ASM330LHH_HW_FLUSH, + ST_ASM330LHH_HW_OPERATIONAL, +}; + +/** + * struct st_asm330lhh_sensor - ST IMU sensor instance + * @id: Sensor identifier. + * @hw: Pointer to instance of struct st_asm330lhh_hw. + * @gain: Configured sensor sensitivity. + * @odr: Output data rate of the sensor [Hz]. + * @watermark: Sensor watermark level. + * @batch_mask: Sensor mask for FIFO batching register + */ +struct st_asm330lhh_sensor { + enum st_asm330lhh_sensor_id id; + struct st_asm330lhh_hw *hw; + + u32 gain; + u16 odr; + u32 offset; + + __le16 old_data; + + u8 std_samples; + u8 std_level; + + u16 watermark; + u8 batch_mask; + u8 batch_addr; +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING + bool read_boot_sample; + int bufsample_cnt; + bool buffer_asm_samples; + struct kmem_cache *asm_cachepool; + struct asm_sample *asm_samplist[ASM_MAXSAMPLE]; + ktime_t timestamp; + int max_buffer_time; + struct input_dev *buf_dev; + int report_evt_cnt; +#endif +}; + +/** + * struct st_asm330lhh_hw - ST IMU MEMS hw instance + * @dev: Pointer to instance of struct device (I2C or SPI). + * @irq: Device interrupt line (I2C or SPI). + * @lock: Mutex to protect read and write operations. + * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO. + * @fifo_mode: FIFO operating mode supported by the device. + * @state: hw operational state. + * @enable_mask: Enabled sensor bitmask. + * @ts_offset: Hw timestamp offset. + * @hw_ts: Latest hw timestamp from the sensor. + * @ts: Latest timestamp from irq handler. + * @delta_ts: Delta time between two consecutive interrupts. + * @iio_devs: Pointers to acc/gyro iio_dev instances. + * @tf: Transfer function structure used by I/O operations. + * @tb: Transfer buffers used by SPI I/O operations. + */ +struct st_asm330lhh_hw { + struct device *dev; + int irq; + + struct mutex lock; + struct mutex fifo_lock; + + enum st_asm330lhh_fifo_mode fifo_mode; + unsigned long state; + u8 enable_mask; + + s64 ts_offset; + s64 hw_ts; + s64 delta_ts; + s64 ts; + s64 tsample; + s64 hw_ts_old; + s64 delta_hw_ts; + + /* Timestamp sample ODR */ + u16 odr; + + struct iio_dev *iio_devs[ST_ASM330LHH_ID_MAX]; + + const struct st_asm330lhh_transfer_function *tf; + struct st_asm330lhh_transfer_buffer tb; +}; + +extern const struct dev_pm_ops st_asm330lhh_pm_ops; + +int st_asm330lhh_probe(struct device *dev, int irq, + const struct st_asm330lhh_transfer_function *tf_ops); +int st_asm330lhh_remove(struct device *dev); +int st_asm330lhh_sensor_set_enable(struct st_asm330lhh_sensor *sensor, + bool enable); +int st_asm330lhh_fifo_setup(struct st_asm330lhh_hw *hw); +int st_asm330lhh_deallocate_fifo(struct st_asm330lhh_hw *hw); +int st_asm330lhh_write_with_mask(struct st_asm330lhh_hw *hw, u8 addr, u8 mask, + u8 val); +int st_asm330lhh_get_odr_val(enum st_asm330lhh_sensor_id id, u16 odr, u8 *val); +ssize_t st_asm330lhh_flush_fifo(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size); +ssize_t st_asm330lhh_get_max_watermark(struct device *dev, + struct device_attribute *attr, char *buf); +ssize_t st_asm330lhh_get_watermark(struct device *dev, + struct device_attribute *attr, char *buf); +ssize_t st_asm330lhh_set_watermark(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size); +int st_asm330lhh_set_fifo_mode(struct st_asm330lhh_hw *hw, + enum st_asm330lhh_fifo_mode fifo_mode); +int st_asm330lhh_suspend_fifo(struct st_asm330lhh_hw *hw); +int st_asm330lhh_update_watermark(struct st_asm330lhh_sensor *sensor, + u16 watermark); +int st_asm330lhh_update_fifo(struct iio_dev *iio_dev, bool enable); +int asm330_check_acc_gyro_early_buff_enable_flag( + struct st_asm330lhh_sensor *sensor); +#endif /* ST_ASM330LHH_H */ diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_buffer.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_buffer.c new file mode 100644 index 0000000000000000000000000000000000000000..2b43c04a91953f7d96fc1badd2d65c6ddeaeea7b --- /dev/null +++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_buffer.c @@ -0,0 +1,629 @@ +/* + * STMicroelectronics st_asm330lhh FIFO buffer library driver + * + * Copyright 2018 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "st_asm330lhh.h" + +#define ST_ASM330LHH_REG_FIFO_THL_ADDR 0x07 +#define ST_ASM330LHH_REG_FIFO_LEN_MASK GENMASK(8, 0) +#define ST_ASM330LHH_REG_FIFO_MODE_MASK GENMASK(2, 0) +#define ST_ASM330LHH_REG_DEC_TS_MASK GENMASK(7, 6) +#define ST_ASM330LHH_REG_HLACTIVE_ADDR 0x12 +#define ST_ASM330LHH_REG_HLACTIVE_MASK BIT(5) +#define ST_ASM330LHH_REG_PP_OD_ADDR 0x12 +#define ST_ASM330LHH_REG_PP_OD_MASK BIT(4) +#define ST_ASM330LHH_REG_FIFO_DIFFL_ADDR 0x3a +#define ST_ASM330LHH_REG_TS0_ADDR 0x40 +#define ST_ASM330LHH_REG_TS2_ADDR 0x42 +#define ST_ASM330LHH_REG_FIFO_OUT_TAG_ADDR 0x78 +#define ST_ASM330LHH_GYRO_TAG 0x01 +#define ST_ASM330LHH_ACC_TAG 0x02 +#define ST_ASM330LHH_TS_TAG 0x04 + +#define ST_ASM330LHH_TS_DELTA_NS 25000ULL /* 25us/LSB */ + +static inline s64 st_asm330lhh_get_time_ns(void) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + return timespec_to_ns(&ts); +} + +#define ST_ASM330LHH_EWMA_LEVEL 120 +#define ST_ASM330LHH_EWMA_DIV 128 +static inline s64 st_asm330lhh_ewma(s64 old, s64 new, int weight) +{ + s64 diff, incr; + + diff = new - old; + incr = div_s64((ST_ASM330LHH_EWMA_DIV - weight) * diff, + ST_ASM330LHH_EWMA_DIV); + + return old + incr; +} + +static inline int st_asm330lhh_reset_hwts(struct st_asm330lhh_hw *hw) +{ + u8 data = 0xaa; + + hw->ts = st_asm330lhh_get_time_ns(); + hw->ts_offset = hw->ts; + hw->hw_ts_old = 0ull; + hw->tsample = 0ull; + + return hw->tf->write(hw->dev, ST_ASM330LHH_REG_TS2_ADDR, sizeof(data), + &data); +} + +int st_asm330lhh_set_fifo_mode(struct st_asm330lhh_hw *hw, + enum st_asm330lhh_fifo_mode fifo_mode) +{ + int err; + + err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_FIFO_CTRL4_ADDR, + ST_ASM330LHH_REG_FIFO_MODE_MASK, + fifo_mode); + if (err < 0) + return err; + + hw->fifo_mode = fifo_mode; + + return 0; +} + +static int st_asm330lhh_set_sensor_batching_odr(struct st_asm330lhh_sensor *sensor, + bool enable) +{ + struct st_asm330lhh_hw *hw = sensor->hw; + u8 data = 0; + int err; + + if (enable) { + err = st_asm330lhh_get_odr_val(sensor->id, sensor->odr, &data); + if (err < 0) + return err; + } + + return st_asm330lhh_write_with_mask(hw, + sensor->batch_addr, + sensor->batch_mask, data); +} + +static u16 st_asm330lhh_ts_odr(struct st_asm330lhh_hw *hw) +{ + struct st_asm330lhh_sensor *sensor; + u16 odr = 0; + u8 i; + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + if (!hw->iio_devs[i]) + continue; + + sensor = iio_priv(hw->iio_devs[i]); + if (hw->enable_mask & BIT(sensor->id)) + odr = max_t(u16, odr, sensor->odr); + } + + return odr; +} + +int st_asm330lhh_update_watermark(struct st_asm330lhh_sensor *sensor, + u16 watermark) +{ + u16 fifo_watermark = ST_ASM330LHH_MAX_FIFO_DEPTH, cur_watermark = 0; + struct st_asm330lhh_hw *hw = sensor->hw; + struct st_asm330lhh_sensor *cur_sensor; + __le16 wdata; + int i, err; + u8 data; + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + cur_sensor = iio_priv(hw->iio_devs[i]); + + if (!(hw->enable_mask & BIT(cur_sensor->id))) + continue; + + cur_watermark = (cur_sensor == sensor) ? watermark + : cur_sensor->watermark; + + fifo_watermark = min_t(u16, fifo_watermark, cur_watermark); + } + + fifo_watermark = max_t(u16, fifo_watermark, 2); + mutex_lock(&hw->lock); + + err = hw->tf->read(hw->dev, ST_ASM330LHH_REG_FIFO_THL_ADDR + 1, + sizeof(data), &data); + if (err < 0) + goto out; + + fifo_watermark = ((data << 8) & ~ST_ASM330LHH_REG_FIFO_LEN_MASK) | + (fifo_watermark & ST_ASM330LHH_REG_FIFO_LEN_MASK); + wdata = cpu_to_le16(fifo_watermark); + err = hw->tf->write(hw->dev, ST_ASM330LHH_REG_FIFO_THL_ADDR, + sizeof(wdata), (u8 *)&wdata); + +out: + mutex_unlock(&hw->lock); + + return err < 0 ? err : 0; +} + +static inline void st_asm330lhh_sync_hw_ts(struct st_asm330lhh_hw *hw, s64 ts) +{ + s64 delta = ts - hw->hw_ts; + + hw->ts_offset = st_asm330lhh_ewma(hw->ts_offset, delta, + ST_ASM330LHH_EWMA_LEVEL); +} + +static struct iio_dev *st_asm330lhh_get_iiodev_from_tag(struct st_asm330lhh_hw *hw, + u8 tag) +{ + struct iio_dev *iio_dev; + + switch (tag) { + case ST_ASM330LHH_GYRO_TAG: + iio_dev = hw->iio_devs[ST_ASM330LHH_ID_GYRO]; + break; + case ST_ASM330LHH_ACC_TAG: + iio_dev = hw->iio_devs[ST_ASM330LHH_ID_ACC]; + break; + default: + iio_dev = NULL; + break; + } + + return iio_dev; +} +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING +int asm330_check_acc_gyro_early_buff_enable_flag( + struct st_asm330lhh_sensor *sensor) +{ + if (sensor->buffer_asm_samples == true) + return 1; + else + return 0; +} +#else +int asm330_check_acc_gyro_early_buff_enable_flag( + struct st_asm330lhh_sensor *sensor) +{ + return 0; +} +#endif + +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING +static void store_acc_gyro_boot_sample(struct st_asm330lhh_sensor *sensor, + u8 *iio_buf, s64 tsample) +{ + int x, y, z; + + if (false == sensor->buffer_asm_samples) + return; + + sensor->timestamp = (ktime_t)tsample; + x = iio_buf[1]<<8|iio_buf[0]; + y = iio_buf[3]<<8|iio_buf[2]; + z = iio_buf[5]<<8|iio_buf[4]; + + if (ktime_to_timespec(sensor->timestamp).tv_sec + < sensor->max_buffer_time) { + if (sensor->bufsample_cnt < ASM_MAXSAMPLE) { + sensor->asm_samplist[sensor->bufsample_cnt]->xyz[0] = x; + sensor->asm_samplist[sensor->bufsample_cnt]->xyz[1] = y; + sensor->asm_samplist[sensor->bufsample_cnt]->xyz[2] = z; + sensor->asm_samplist[sensor->bufsample_cnt]->tsec = + ktime_to_timespec(sensor->timestamp).tv_sec; + sensor->asm_samplist[sensor->bufsample_cnt]->tnsec = + ktime_to_timespec(sensor->timestamp).tv_nsec; + sensor->bufsample_cnt++; + } + } else { + dev_info(sensor->hw->dev, "End of sensor %duffering %d\n", + sensor->id, sensor->bufsample_cnt); + sensor->buffer_asm_samples = false; + } +} +#else +static void store_acc_gyro_boot_sample(struct st_asm330lhh_sensor *sensor, + u8 *iio_buf, s64 tsample) +{ +} +#endif + +static int st_asm330lhh_read_fifo(struct st_asm330lhh_hw *hw) +{ + u8 iio_buf[ALIGN(ST_ASM330LHH_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)]; + u8 buf[30 * ST_ASM330LHH_FIFO_SAMPLE_SIZE], tag, *ptr; + s64 ts_delta_hw_ts = 0, ts_irq; + s64 ts_delta_offs; + int i, err, read_len, word_len, fifo_len; + struct st_asm330lhh_sensor *sensor; + struct iio_dev *iio_dev; + __le16 fifo_status; + u16 fifo_depth; + u32 val; + int ts_processed = 0; + s64 hw_ts = 0ull, delta_hw_ts, cpu_timestamp; + + ts_irq = hw->ts - hw->delta_ts; + + do + { + err = hw->tf->read(hw->dev, ST_ASM330LHH_REG_FIFO_DIFFL_ADDR, + sizeof(fifo_status), (u8 *)&fifo_status); + if (err < 0) + return err; + + fifo_depth = le16_to_cpu(fifo_status) & ST_ASM330LHH_REG_FIFO_LEN_MASK; + if (!fifo_depth) + return 0; + + read_len = 0; + fifo_len = fifo_depth * ST_ASM330LHH_FIFO_SAMPLE_SIZE; + while (read_len < fifo_len) { + word_len = min_t(int, fifo_len - read_len, sizeof(buf)); + err = hw->tf->read(hw->dev, + ST_ASM330LHH_REG_FIFO_OUT_TAG_ADDR, + word_len, buf); + if (err < 0) + return err; + + for (i = 0; i < word_len; i += ST_ASM330LHH_FIFO_SAMPLE_SIZE) { + ptr = &buf[i + ST_ASM330LHH_TAG_SIZE]; + tag = buf[i] >> 3; + + if (tag == ST_ASM330LHH_TS_TAG) { + val = get_unaligned_le32(ptr); + hw->hw_ts = val * ST_ASM330LHH_TS_DELTA_NS; + ts_delta_hw_ts = hw->hw_ts - hw->hw_ts_old; + hw_ts += ts_delta_hw_ts; + ts_delta_offs = + div_s64(hw->delta_hw_ts * ST_ASM330LHH_MAX_ODR, hw->odr); + + hw->ts_offset = st_asm330lhh_ewma(hw->ts_offset, ts_irq - + hw->hw_ts + ts_delta_offs, ST_ASM330LHH_EWMA_LEVEL); + + ts_irq += (hw->hw_ts + ts_delta_offs); + hw->hw_ts_old = hw->hw_ts; + ts_processed++; + + if (!hw->tsample) + hw->tsample = + hw->ts_offset + (hw->hw_ts + ts_delta_offs); + else + hw->tsample = + hw->tsample + (ts_delta_hw_ts + ts_delta_offs); + } else { + iio_dev = st_asm330lhh_get_iiodev_from_tag(hw, tag); + if (!iio_dev) + continue; + + sensor = iio_priv(iio_dev); + if (sensor->std_samples < sensor->std_level) { + sensor->std_samples++; + continue; + } + + sensor = iio_priv(iio_dev); + + /* Check if timestamp is in the future. */ + cpu_timestamp = st_asm330lhh_get_time_ns(); + + /* Avoid samples in the future. */ + if (hw->tsample > cpu_timestamp) + hw->tsample = cpu_timestamp; + + memcpy(iio_buf, ptr, ST_ASM330LHH_SAMPLE_SIZE); + iio_push_to_buffers_with_timestamp(iio_dev, + iio_buf, + hw->tsample); + store_acc_gyro_boot_sample(sensor, + iio_buf, hw->tsample); + } + } + read_len += word_len; + } + + delta_hw_ts = div_s64(hw->delta_ts - hw_ts, ts_processed); + delta_hw_ts = div_s64(delta_hw_ts * hw->odr, ST_ASM330LHH_MAX_ODR); + hw->delta_hw_ts = st_asm330lhh_ewma(hw->delta_hw_ts, + delta_hw_ts, + ST_ASM330LHH_EWMA_LEVEL); + } while(read_len); + + return read_len; +} + +ssize_t st_asm330lhh_get_max_watermark(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", ST_ASM330LHH_MAX_FIFO_DEPTH); +} + +ssize_t st_asm330lhh_get_watermark(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + + return sprintf(buf, "%d\n", sensor->watermark); +} + +ssize_t st_asm330lhh_set_watermark(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + int err, val; + + if (asm330_check_acc_gyro_early_buff_enable_flag(sensor)) + return -EBUSY; + + mutex_lock(&iio_dev->mlock); + if (iio_buffer_enabled(iio_dev)) { + err = -EBUSY; + goto out; + } + + err = kstrtoint(buf, 10, &val); + if (err < 0) + goto out; + + err = st_asm330lhh_update_watermark(sensor, val); + if (err < 0) + goto out; + + sensor->watermark = val; + +out: + mutex_unlock(&iio_dev->mlock); + + return err < 0 ? err : size; +} + +ssize_t st_asm330lhh_flush_fifo(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + struct st_asm330lhh_hw *hw = sensor->hw; + s64 type, event; + int count; + s64 ts; + + mutex_lock(&hw->fifo_lock); + ts = st_asm330lhh_get_time_ns(); + hw->delta_ts = ts - hw->ts; + hw->ts = ts; + set_bit(ST_ASM330LHH_HW_FLUSH, &hw->state); + + count = st_asm330lhh_read_fifo(hw); + + mutex_unlock(&hw->fifo_lock); + + type = count > 0 ? CUSTOM_IIO_EV_DIR_FIFO_DATA : CUSTOM_IIO_EV_DIR_FIFO_EMPTY; + event = IIO_UNMOD_EVENT_CODE(iio_dev->channels[0].type, -1, + CUSTOM_IIO_EV_TYPE_FIFO_FLUSH, type); + iio_push_event(iio_dev, event, st_asm330lhh_get_time_ns()); + + return size; +} + +int st_asm330lhh_suspend_fifo(struct st_asm330lhh_hw *hw) +{ + int err; + + mutex_lock(&hw->fifo_lock); + + st_asm330lhh_read_fifo(hw); + err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_BYPASS); + + mutex_unlock(&hw->fifo_lock); + + return err; +} + +int st_asm330lhh_update_fifo(struct iio_dev *iio_dev, bool enable) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + struct st_asm330lhh_hw *hw = sensor->hw; + int err; + + mutex_lock(&hw->fifo_lock); + + err = st_asm330lhh_sensor_set_enable(sensor, enable); + if (err < 0) + goto out; + + err = st_asm330lhh_set_sensor_batching_odr(sensor, enable); + if (err < 0) + goto out; + + err = st_asm330lhh_update_watermark(sensor, sensor->watermark); + if (err < 0) + goto out; + + hw->odr = st_asm330lhh_ts_odr(hw); + + if (enable && hw->fifo_mode == ST_ASM330LHH_FIFO_BYPASS) { + st_asm330lhh_reset_hwts(hw); + err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_CONT); + } else if (!hw->enable_mask) { + err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_BYPASS); + } + +out: + mutex_unlock(&hw->fifo_lock); + + return err; +} + +static irqreturn_t st_asm330lhh_handler_irq(int irq, void *private) +{ + struct st_asm330lhh_hw *hw = (struct st_asm330lhh_hw *)private; + s64 ts = st_asm330lhh_get_time_ns(); + + hw->delta_ts = ts - hw->ts; + hw->ts = ts; + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t st_asm330lhh_handler_thread(int irq, void *private) +{ + struct st_asm330lhh_hw *hw = (struct st_asm330lhh_hw *)private; + + mutex_lock(&hw->fifo_lock); + + st_asm330lhh_read_fifo(hw); + clear_bit(ST_ASM330LHH_HW_FLUSH, &hw->state); + + mutex_unlock(&hw->fifo_lock); + + return IRQ_HANDLED; +} + +static int st_asm330lhh_buffer_preenable(struct iio_dev *iio_dev) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + + if (asm330_check_acc_gyro_early_buff_enable_flag(sensor)) + return 0; + else + return st_asm330lhh_update_fifo(iio_dev, true); +} + +static int st_asm330lhh_buffer_postdisable(struct iio_dev *iio_dev) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + + if (asm330_check_acc_gyro_early_buff_enable_flag(sensor)) + return 0; + else + return st_asm330lhh_update_fifo(iio_dev, false); +} + +static const struct iio_buffer_setup_ops st_asm330lhh_buffer_ops = { + .preenable = st_asm330lhh_buffer_preenable, + .postdisable = st_asm330lhh_buffer_postdisable, +}; + +static int st_asm330lhh_fifo_init(struct st_asm330lhh_hw *hw) +{ + return st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_FIFO_CTRL4_ADDR, + ST_ASM330LHH_REG_DEC_TS_MASK, 1); +} + +int st_asm330lhh_fifo_setup(struct st_asm330lhh_hw *hw) +{ + struct device_node *np = hw->dev->of_node; + struct iio_buffer *buffer; + unsigned long irq_type; + bool irq_active_low; + int i, err; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + irq_active_low = false; + break; + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_FALLING: + irq_active_low = true; + break; + default: + dev_info(hw->dev, "mode %lx unsupported\n", irq_type); + return -EINVAL; + } + + err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_HLACTIVE_ADDR, + ST_ASM330LHH_REG_HLACTIVE_MASK, + irq_active_low); + if (err < 0) + return err; + + if (np && of_property_read_bool(np, "drive-open-drain")) { + err = st_asm330lhh_write_with_mask(hw, + ST_ASM330LHH_REG_PP_OD_ADDR, + ST_ASM330LHH_REG_PP_OD_MASK, 1); + if (err < 0) + return err; + + irq_type |= IRQF_SHARED; + } + + err = devm_request_threaded_irq(hw->dev, hw->irq, + st_asm330lhh_handler_irq, + st_asm330lhh_handler_thread, + irq_type | IRQF_ONESHOT, + "asm330lhh", hw); + if (err) { + dev_err(hw->dev, "failed to request trigger irq %d\n", + hw->irq); + return err; + } + + for (i = ST_ASM330LHH_ID_ACC; i < ST_ASM330LHH_ID_MAX; i++) { + if (!hw->iio_devs[i]) + continue; + + buffer = iio_kfifo_allocate(hw->iio_devs[i]); + if (!buffer) + return -ENOMEM; + + iio_device_attach_buffer(hw->iio_devs[i], buffer); + hw->iio_devs[i]->modes |= INDIO_BUFFER_HARDWARE; + hw->iio_devs[i]->setup_ops = &st_asm330lhh_buffer_ops; + err = iio_buffer_register(hw->iio_devs[i], + hw->iio_devs[i]->channels, + hw->iio_devs[i]->num_channels); + if (err) + goto fifo_allocate_error; + } + + return st_asm330lhh_fifo_init(hw); + +fifo_allocate_error: + for (i--; i >= ST_ASM330LHH_ID_GYRO; i--) + iio_buffer_unregister(hw->iio_devs[i]); + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + if (!hw->iio_devs[i]->buffer) + continue; + iio_kfifo_free(hw->iio_devs[i]->buffer); + } + + return err; +} + +int st_asm330lhh_deallocate_fifo(struct st_asm330lhh_hw *hw) +{ + int i; + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + iio_buffer_unregister(hw->iio_devs[i]); + iio_kfifo_free(hw->iio_devs[i]->buffer); + } + + return 0; +} diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_core.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_core.c new file mode 100644 index 0000000000000000000000000000000000000000..dccd6bdca9ab47a918ccc8ad59524568dc1b21aa --- /dev/null +++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_core.c @@ -0,0 +1,1187 @@ +/* + * STMicroelectronics st_asm330lhh sensor driver + * + * Copyright 2018 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "st_asm330lhh.h" + +#define ST_ASM330LHH_REG_INT1_ADDR 0x0d +#define ST_ASM330LHH_REG_INT2_ADDR 0x0e +#define ST_ASM330LHH_REG_FIFO_CTRL4_ADDR 0x0a +#define ST_ASM330LHH_REG_FIFO_FTH_IRQ_MASK BIT(3) +#define ST_ASM330LHH_REG_WHOAMI_ADDR 0x0f +#define ST_ASM330LHH_WHOAMI_VAL 0x6b +#define ST_ASM330LHH_REG_CTRL1_XL_ADDR 0x10 +#define ST_ASM330LHH_REG_CTRL2_G_ADDR 0x11 +#define ST_ASM330LHH_REG_RESET_ADDR 0x12 +#define ST_ASM330LHH_REG_RESET_MASK BIT(0) +#define ST_ASM330LHH_REG_BDU_ADDR 0x12 +#define ST_ASM330LHH_REG_BDU_MASK BIT(6) +#define ST_ASM330LHH_REG_INT2_ON_INT1_ADDR 0x13 +#define ST_ASM330LHH_REG_INT2_ON_INT1_MASK BIT(5) +#define ST_ASM330LHH_REG_ROUNDING_ADDR 0x14 +#define ST_ASM330LHH_REG_ROUNDING_MASK GENMASK(6, 5) +#define ST_ASM330LHH_REG_TIMESTAMP_EN_ADDR 0x19 +#define ST_ASM330LHH_REG_TIMESTAMP_EN_MASK BIT(5) + +#define ST_ASM330LHH_REG_GYRO_OUT_X_L_ADDR 0x22 +#define ST_ASM330LHH_REG_GYRO_OUT_Y_L_ADDR 0x24 +#define ST_ASM330LHH_REG_GYRO_OUT_Z_L_ADDR 0x26 + +#define ST_ASM330LHH_REG_ACC_OUT_X_L_ADDR 0x28 +#define ST_ASM330LHH_REG_ACC_OUT_Y_L_ADDR 0x2a +#define ST_ASM330LHH_REG_ACC_OUT_Z_L_ADDR 0x2c + +#define ST_ASM330LHH_REG_LIR_ADDR 0x56 +#define ST_ASM330LHH_REG_LIR_MASK BIT(0) + +#define ST_ASM330LHH_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61) +#define ST_ASM330LHH_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122) +#define ST_ASM330LHH_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244) +#define ST_ASM330LHH_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488) + +#define ST_ASM330LHH_GYRO_FS_125_GAIN IIO_DEGREE_TO_RAD(4375) +#define ST_ASM330LHH_GYRO_FS_250_GAIN IIO_DEGREE_TO_RAD(8750) +#define ST_ASM330LHH_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(17500) +#define ST_ASM330LHH_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(35000) +#define ST_ASM330LHH_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000) +#define ST_ASM330LHH_GYRO_FS_4000_GAIN IIO_DEGREE_TO_RAD(140000) + +/* Temperature in uC */ +#define ST_ASM330LHH_TEMP_GAIN 256 +#define ST_ASM330LHH_TEMP_FS_GAIN (1000000 / ST_ASM330LHH_TEMP_GAIN) +#define ST_ASM330LHH_OFFSET (6400) + +struct st_asm330lhh_std_entry { + u16 odr; + u8 val; +}; + +/* Minimal number of sample to be discarded */ +struct st_asm330lhh_std_entry st_asm330lhh_std_table[] = { + { 13, 2 }, + { 26, 3 }, + { 52, 4 }, + { 104, 6 }, + { 208, 8 }, + { 416, 18 }, +}; + +static const struct st_asm330lhh_odr_table_entry st_asm330lhh_odr_table[] = { + [ST_ASM330LHH_ID_ACC] = { + .reg = { + .addr = ST_ASM330LHH_REG_CTRL1_XL_ADDR, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 0, 0x00 }, + .odr_avl[1] = { 13, 0x01 }, + .odr_avl[2] = { 26, 0x02 }, + .odr_avl[3] = { 52, 0x03 }, + .odr_avl[4] = { 104, 0x04 }, + .odr_avl[5] = { 208, 0x05 }, + .odr_avl[6] = { 416, 0x06 }, + }, + [ST_ASM330LHH_ID_GYRO] = { + .reg = { + .addr = ST_ASM330LHH_REG_CTRL2_G_ADDR, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 0, 0x00 }, + .odr_avl[1] = { 13, 0x01 }, + .odr_avl[2] = { 26, 0x02 }, + .odr_avl[3] = { 52, 0x03 }, + .odr_avl[4] = { 104, 0x04 }, + .odr_avl[5] = { 208, 0x05 }, + .odr_avl[6] = { 416, 0x06 }, + }, + [ST_ASM330LHH_ID_TEMP] = { + .odr_avl[0] = { 0, 0x00 }, + .odr_avl[1] = { 52, 0x01 }, + } +}; + +static const struct st_asm330lhh_fs_table_entry st_asm330lhh_fs_table[] = { + [ST_ASM330LHH_ID_ACC] = { + .reg = { + .addr = ST_ASM330LHH_REG_CTRL1_XL_ADDR, + .mask = GENMASK(3, 2), + }, + .size = ST_ASM330LHH_FS_ACC_LIST_SIZE, + .fs_avl[0] = { ST_ASM330LHH_ACC_FS_2G_GAIN, 0x0 }, + .fs_avl[1] = { ST_ASM330LHH_ACC_FS_4G_GAIN, 0x2 }, + .fs_avl[2] = { ST_ASM330LHH_ACC_FS_8G_GAIN, 0x3 }, + .fs_avl[3] = { ST_ASM330LHH_ACC_FS_16G_GAIN, 0x1 }, + }, + [ST_ASM330LHH_ID_GYRO] = { + .reg = { + .addr = ST_ASM330LHH_REG_CTRL2_G_ADDR, + .mask = GENMASK(3, 0), + }, + .size = ST_ASM330LHH_FS_GYRO_LIST_SIZE, + .fs_avl[0] = { ST_ASM330LHH_GYRO_FS_125_GAIN, 0x2 }, + .fs_avl[1] = { ST_ASM330LHH_GYRO_FS_250_GAIN, 0x0 }, + .fs_avl[2] = { ST_ASM330LHH_GYRO_FS_500_GAIN, 0x4 }, + .fs_avl[3] = { ST_ASM330LHH_GYRO_FS_1000_GAIN, 0x8 }, + .fs_avl[4] = { ST_ASM330LHH_GYRO_FS_2000_GAIN, 0xC }, + .fs_avl[5] = { ST_ASM330LHH_GYRO_FS_4000_GAIN, 0x1 }, + }, + [ST_ASM330LHH_ID_TEMP] = { + .size = ST_ASM330LHH_FS_TEMP_LIST_SIZE, + .fs_avl[0] = { ST_ASM330LHH_TEMP_FS_GAIN, 0x0 }, + } +}; + +static const struct iio_chan_spec st_asm330lhh_acc_channels[] = { + ST_ASM330LHH_CHANNEL(IIO_ACCEL, ST_ASM330LHH_REG_ACC_OUT_X_L_ADDR, + 1, IIO_MOD_X, 0, 16, 16, 's'), + ST_ASM330LHH_CHANNEL(IIO_ACCEL, ST_ASM330LHH_REG_ACC_OUT_Y_L_ADDR, + 1, IIO_MOD_Y, 1, 16, 16, 's'), + ST_ASM330LHH_CHANNEL(IIO_ACCEL, ST_ASM330LHH_REG_ACC_OUT_Z_L_ADDR, + 1, IIO_MOD_Z, 2, 16, 16, 's'), + ST_ASM330LHH_FLUSH_CHANNEL(IIO_ACCEL), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec st_asm330lhh_gyro_channels[] = { + ST_ASM330LHH_CHANNEL(IIO_ANGL_VEL, ST_ASM330LHH_REG_GYRO_OUT_X_L_ADDR, + 1, IIO_MOD_X, 0, 16, 16, 's'), + ST_ASM330LHH_CHANNEL(IIO_ANGL_VEL, ST_ASM330LHH_REG_GYRO_OUT_Y_L_ADDR, + 1, IIO_MOD_Y, 1, 16, 16, 's'), + ST_ASM330LHH_CHANNEL(IIO_ANGL_VEL, ST_ASM330LHH_REG_GYRO_OUT_Z_L_ADDR, + 1, IIO_MOD_Z, 2, 16, 16, 's'), + ST_ASM330LHH_FLUSH_CHANNEL(IIO_ANGL_VEL), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec st_asm330lhh_temp_channels[] = { + { + .type = IIO_TEMP, + .address = ST_ASM330LHH_REG_OUT_TEMP_L_ADDR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_OFFSET) + | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = -1, + }, +}; + +int st_asm330lhh_write_with_mask(struct st_asm330lhh_hw *hw, u8 addr, u8 mask, + u8 val) +{ + u8 data; + int err; + + mutex_lock(&hw->lock); + + err = hw->tf->read(hw->dev, addr, sizeof(data), &data); + if (err < 0) { + dev_err(hw->dev, "failed to read %02x register\n", addr); + goto out; + } + + data = (data & ~mask) | ((val << __ffs(mask)) & mask); + + err = hw->tf->write(hw->dev, addr, sizeof(data), &data); + if (err < 0) + dev_err(hw->dev, "failed to write %02x register\n", addr); + +out: + mutex_unlock(&hw->lock); + + return err; +} + +static int st_asm330lhh_check_whoami(struct st_asm330lhh_hw *hw) +{ + int err; + u8 data; + + err = hw->tf->read(hw->dev, ST_ASM330LHH_REG_WHOAMI_ADDR, sizeof(data), + &data); + if (err < 0) { + dev_err(hw->dev, "failed to read whoami register\n"); + return err; + } + + if (data != ST_ASM330LHH_WHOAMI_VAL) { + dev_err(hw->dev, "unsupported whoami [%02x]\n", data); + return -ENODEV; + } + + return 0; +} + +static int st_asm330lhh_set_full_scale(struct st_asm330lhh_sensor *sensor, + u32 gain) +{ + enum st_asm330lhh_sensor_id id = sensor->id; + int i, err; + u8 val; + + for (i = 0; i < st_asm330lhh_fs_table[id].size; i++) + if (st_asm330lhh_fs_table[id].fs_avl[i].gain == gain) + break; + + if (i == st_asm330lhh_fs_table[id].size) + return -EINVAL; + + val = st_asm330lhh_fs_table[id].fs_avl[i].val; + err = st_asm330lhh_write_with_mask(sensor->hw, + st_asm330lhh_fs_table[id].reg.addr, + st_asm330lhh_fs_table[id].reg.mask, + val); + if (err < 0) + return err; + + sensor->gain = gain; + + return 0; +} + +int st_asm330lhh_get_odr_val(enum st_asm330lhh_sensor_id id, u16 odr, u8 *val) +{ + int i; + + for (i = 0; i < ST_ASM330LHH_ODR_LIST_SIZE; i++) + if (st_asm330lhh_odr_table[id].odr_avl[i].hz >= odr) + break; + + if (i == ST_ASM330LHH_ODR_LIST_SIZE) + return -EINVAL; + + *val = st_asm330lhh_odr_table[id].odr_avl[i].val; + + return 0; +} + +static int st_asm330lhh_set_std_level(struct st_asm330lhh_sensor *sensor, + u16 odr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(st_asm330lhh_std_table); i++) + if (st_asm330lhh_std_table[i].odr == odr) + break; + + if (i == ARRAY_SIZE(st_asm330lhh_std_table)) + return -EINVAL; + + sensor->std_level = st_asm330lhh_std_table[i].val; + sensor->std_samples = 0; + + return 0; +} + +static int st_asm330lhh_set_odr(struct st_asm330lhh_sensor *sensor, u16 odr) +{ + struct st_asm330lhh_hw *hw = sensor->hw; + u8 val; + + if (st_asm330lhh_get_odr_val(sensor->id, odr, &val) < 0) + return -EINVAL; + + return st_asm330lhh_write_with_mask(hw, + st_asm330lhh_odr_table[sensor->id].reg.addr, + st_asm330lhh_odr_table[sensor->id].reg.mask, val); +} + +int st_asm330lhh_sensor_set_enable(struct st_asm330lhh_sensor *sensor, + bool enable) +{ + u16 odr = enable ? sensor->odr : 0; + int err; + + if (sensor->id != ST_ASM330LHH_ID_TEMP) { + err = st_asm330lhh_set_odr(sensor, odr); + if (err < 0) + return err; + } + + if (enable) + sensor->hw->enable_mask |= BIT(sensor->id); + else + sensor->hw->enable_mask &= ~BIT(sensor->id); + + return 0; +} + +static int st_asm330lhh_read_oneshot(struct st_asm330lhh_sensor *sensor, + u8 addr, int *val) +{ + int err, delay; + __le16 data = 0; + + if (sensor->id == ST_ASM330LHH_ID_TEMP) { + u8 status; + + mutex_lock(&sensor->hw->fifo_lock); + err = sensor->hw->tf->read(sensor->hw->dev, + ST_ASM330LHH_REG_STATUS_ADDR, sizeof(status), &status); + if (err < 0) + goto unlock; + + if (status & ST_ASM330LHH_REG_STATUS_TDA) { + err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data), + (u8 *)&data); + if (err < 0) + goto unlock; + + sensor->old_data = data; + } else + data = sensor->old_data; +unlock: + mutex_unlock(&sensor->hw->fifo_lock); + + } else { + err = st_asm330lhh_sensor_set_enable(sensor, true); + if (err < 0) + return err; + + delay = 1000000 / sensor->odr; + usleep_range(delay, 2 * delay); + + err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data), + (u8 *)&data); + if (err < 0) + return err; + + st_asm330lhh_sensor_set_enable(sensor, false); + } + + *val = (s16)data; + + return IIO_VAL_INT; +} + +static int st_asm330lhh_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&iio_dev->mlock); + if (iio_buffer_enabled(iio_dev)) { + ret = -EBUSY; + mutex_unlock(&iio_dev->mlock); + break; + } + ret = st_asm330lhh_read_oneshot(sensor, ch->address, val); + mutex_unlock(&iio_dev->mlock); + break; + case IIO_CHAN_INFO_OFFSET: + switch (ch->type) { + case IIO_TEMP: + *val = sensor->offset; + ret = IIO_VAL_INT; + break; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = sensor->odr; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + switch (ch->type) { + case IIO_TEMP: + *val = 1; + *val2 = ST_ASM330LHH_TEMP_GAIN; + ret = IIO_VAL_FRACTIONAL; + break; + case IIO_ACCEL: + case IIO_ANGL_VEL: + *val = 0; + *val2 = sensor->gain; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + return -EINVAL; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int st_asm330lhh_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev); + int err; + + if (asm330_check_acc_gyro_early_buff_enable_flag(sensor)) + return 0; + + mutex_lock(&iio_dev->mlock); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + err = st_asm330lhh_set_full_scale(sensor, val2); + break; + case IIO_CHAN_INFO_SAMP_FREQ: { + u8 data; + + err = st_asm330lhh_set_std_level(sensor, val); + if (err < 0) + break; + + err = st_asm330lhh_get_odr_val(sensor->id, val, &data); + if (!err) + sensor->odr = val; + + err = st_asm330lhh_set_odr(sensor, sensor->odr); + break; + } + default: + err = -EINVAL; + break; + } + + mutex_unlock(&iio_dev->mlock); + + return err; +} + +static ssize_t +st_asm330lhh_sysfs_sampling_frequency_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + enum st_asm330lhh_sensor_id id = sensor->id; + int i, len = 0; + + for (i = 1; i < ST_ASM330LHH_ODR_LIST_SIZE; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", + st_asm330lhh_odr_table[id].odr_avl[i].hz); + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t st_asm330lhh_sysfs_scale_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + enum st_asm330lhh_sensor_id id = sensor->id; + int i, len = 0; + + for (i = 0; i < st_asm330lhh_fs_table[id].size; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", + st_asm330lhh_fs_table[id].fs_avl[i].gain); + buf[len - 1] = '\n'; + + return len; +} +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING +static int asm_read_bootsampl(struct st_asm330lhh_sensor *sensor, + unsigned long enable_read) +{ + int i = 0; + + if (enable_read) { + sensor->buffer_asm_samples = false; + for (i = 0; i < sensor->bufsample_cnt; i++) { + dev_dbg(sensor->hw->dev, + "sensor:%d count:%d x=%d,y=%d,z=%d,tsec=%d,nsec=%lld\n", + sensor->id, i, sensor->asm_samplist[i]->xyz[0], + sensor->asm_samplist[i]->xyz[1], + sensor->asm_samplist[i]->xyz[2], + sensor->asm_samplist[i]->tsec, + sensor->asm_samplist[i]->tnsec); + input_report_abs(sensor->buf_dev, ABS_X, + sensor->asm_samplist[i]->xyz[0]); + input_report_abs(sensor->buf_dev, ABS_Y, + sensor->asm_samplist[i]->xyz[1]); + input_report_abs(sensor->buf_dev, ABS_Z, + sensor->asm_samplist[i]->xyz[2]); + input_report_abs(sensor->buf_dev, ABS_RX, + sensor->asm_samplist[i]->tsec); + input_report_abs(sensor->buf_dev, ABS_RY, + sensor->asm_samplist[i]->tnsec); + input_sync(sensor->buf_dev); + } + } else { + /* clean up */ + if (sensor->bufsample_cnt != 0) { + for (i = 0; i < ASM_MAXSAMPLE; i++) + kmem_cache_free(sensor->asm_cachepool, + sensor->asm_samplist[i]); + kmem_cache_destroy(sensor->asm_cachepool); + sensor->bufsample_cnt = 0; + } + + } + /*SYN_CONFIG indicates end of data*/ + input_event(sensor->buf_dev, EV_SYN, SYN_CONFIG, 0xFFFFFFFF); + input_sync(sensor->buf_dev); + dev_dbg(sensor->hw->dev, "End of gyro samples bufsample_cnt=%d\n", + sensor->bufsample_cnt); + return 0; +} +static ssize_t read_gyro_boot_sample_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + sensor->read_boot_sample); +} +static ssize_t read_gyro_boot_sample_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + unsigned long enable = 0; + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable > 1) { + err = dev_err(sensor->hw->dev, + "Invalid value of input, input=%ld\n", enable); + return -EINVAL; + } + err = asm_read_bootsampl(sensor, enable); + if (err) + return err; + sensor->read_boot_sample = enable; + return count; + +} + +static ssize_t read_acc_boot_sample_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + sensor->read_boot_sample); +} + +static ssize_t read_acc_boot_sample_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + + unsigned long enable = 0; + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable > 1) { + err = dev_err(sensor->hw->dev, + "Invalid value of input, input=%ld\n", enable); + return -EINVAL; + } + err = asm_read_bootsampl(sensor, enable); + if (err) + return err; + sensor->read_boot_sample = enable; + return count; +} +#endif + +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_asm330lhh_sysfs_sampling_frequency_avail); +static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, + st_asm330lhh_sysfs_scale_avail, NULL, 0); +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING +static IIO_DEVICE_ATTR(read_acc_boot_sample, 0444, + read_acc_boot_sample_show, read_acc_boot_sample_store, 0); +static IIO_DEVICE_ATTR(read_gyro_boot_sample, 0444, + read_gyro_boot_sample_show, read_gyro_boot_sample_store, 0); +#endif +static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444, + st_asm330lhh_sysfs_scale_avail, NULL, 0); +static IIO_DEVICE_ATTR(in_temp_scale_available, 0444, + st_asm330lhh_sysfs_scale_avail, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_watermark_max, 0444, + st_asm330lhh_get_max_watermark, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_flush, 0200, NULL, st_asm330lhh_flush_fifo, 0); +static IIO_DEVICE_ATTR(hwfifo_watermark, 0644, st_asm330lhh_get_watermark, + st_asm330lhh_set_watermark, 0); + +static struct attribute *st_asm330lhh_acc_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING + &iio_dev_attr_read_acc_boot_sample.dev_attr.attr, +#endif + &iio_dev_attr_in_accel_scale_available.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_flush.dev_attr.attr, + NULL, +}; + +static const struct attribute_group st_asm330lhh_acc_attribute_group = { + .attrs = st_asm330lhh_acc_attributes, +}; + +static const struct iio_info st_asm330lhh_acc_info = { + .driver_module = THIS_MODULE, + .attrs = &st_asm330lhh_acc_attribute_group, + .read_raw = st_asm330lhh_read_raw, + .write_raw = st_asm330lhh_write_raw, +}; + +static struct attribute *st_asm330lhh_gyro_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING + &iio_dev_attr_read_gyro_boot_sample.dev_attr.attr, +#endif + &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_flush.dev_attr.attr, + NULL, +}; + +static const struct attribute_group st_asm330lhh_gyro_attribute_group = { + .attrs = st_asm330lhh_gyro_attributes, +}; + +static const struct iio_info st_asm330lhh_gyro_info = { + .driver_module = THIS_MODULE, + .attrs = &st_asm330lhh_gyro_attribute_group, + .read_raw = st_asm330lhh_read_raw, + .write_raw = st_asm330lhh_write_raw, +}; + +static struct attribute *st_asm330lhh_temp_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_temp_scale_available.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_flush.dev_attr.attr, + NULL, +}; + +static const struct attribute_group st_asm330lhh_temp_attribute_group = { + .attrs = st_asm330lhh_temp_attributes, +}; + +static const struct iio_info st_asm330lhh_temp_info = { + .driver_module = THIS_MODULE, + .attrs = &st_asm330lhh_temp_attribute_group, + .read_raw = st_asm330lhh_read_raw, + .write_raw = st_asm330lhh_write_raw, +}; + +static const unsigned long st_asm330lhh_available_scan_masks[] = { 0x7, 0x0 }; + +static int st_asm330lhh_of_get_drdy_pin(struct st_asm330lhh_hw *hw, int *drdy_pin) +{ + struct device_node *np = hw->dev->of_node; + + if (!np) + return -EINVAL; + + return of_property_read_u32_array(np, "st,drdy-int-pin", drdy_pin, 1); +} + +static int st_asm330lhh_get_drdy_reg(struct st_asm330lhh_hw *hw, u8 *drdy_reg) +{ + int err = 0, drdy_pin; + + if (st_asm330lhh_of_get_drdy_pin(hw, &drdy_pin) < 0) { + struct st_sensors_platform_data *pdata; + struct device *dev = hw->dev; + + pdata = (struct st_sensors_platform_data *)dev->platform_data; + drdy_pin = pdata ? pdata->drdy_int_pin : 1; + } + + switch (drdy_pin) { + case 1: + *drdy_reg = ST_ASM330LHH_REG_INT1_ADDR; + break; + case 2: + *drdy_reg = ST_ASM330LHH_REG_INT2_ADDR; + break; + default: + dev_err(hw->dev, "unsupported data ready pin\n"); + err = -EINVAL; + break; + } + + return err; +} + +static int st_asm330lhh_init_device(struct st_asm330lhh_hw *hw) +{ + u8 drdy_int_reg; + int err; + + err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_RESET_ADDR, + ST_ASM330LHH_REG_RESET_MASK, 1); + if (err < 0) + return err; + + msleep(200); + + /* latch interrupts */ + err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_LIR_ADDR, + ST_ASM330LHH_REG_LIR_MASK, 1); + if (err < 0) + return err; + + /* enable Block Data Update */ + err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_BDU_ADDR, + ST_ASM330LHH_REG_BDU_MASK, 1); + if (err < 0) + return err; + + err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_ROUNDING_ADDR, + ST_ASM330LHH_REG_ROUNDING_MASK, 3); + if (err < 0) + return err; + + /* init timestamp engine */ + err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_TIMESTAMP_EN_ADDR, + ST_ASM330LHH_REG_TIMESTAMP_EN_MASK, 1); + if (err < 0) + return err; + + /* enable FIFO watermak interrupt */ + err = st_asm330lhh_get_drdy_reg(hw, &drdy_int_reg); + if (err < 0) + return err; + + return st_asm330lhh_write_with_mask(hw, drdy_int_reg, + ST_ASM330LHH_REG_FIFO_FTH_IRQ_MASK, 1); +} + +static struct iio_dev *st_asm330lhh_alloc_iiodev(struct st_asm330lhh_hw *hw, + enum st_asm330lhh_sensor_id id) +{ + struct st_asm330lhh_sensor *sensor; + struct iio_dev *iio_dev; + + iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); + if (!iio_dev) + return NULL; + + iio_dev->modes = INDIO_DIRECT_MODE; + iio_dev->dev.parent = hw->dev; + iio_dev->available_scan_masks = st_asm330lhh_available_scan_masks; + + sensor = iio_priv(iio_dev); + sensor->id = id; + sensor->hw = hw; + sensor->odr = st_asm330lhh_odr_table[id].odr_avl[1].hz; + sensor->gain = st_asm330lhh_fs_table[id].fs_avl[0].gain; + sensor->watermark = 1; + sensor->old_data = 0; + + switch (id) { + case ST_ASM330LHH_ID_ACC: + iio_dev->channels = st_asm330lhh_acc_channels; + iio_dev->num_channels = ARRAY_SIZE(st_asm330lhh_acc_channels); + iio_dev->name = "asm330lhh_accel"; + iio_dev->info = &st_asm330lhh_acc_info; + sensor->batch_addr = ST_ASM330LHH_REG_FIFO_BATCH_ADDR; + sensor->batch_mask = GENMASK(3, 0); + sensor->offset = 0; + break; + case ST_ASM330LHH_ID_GYRO: + iio_dev->channels = st_asm330lhh_gyro_channels; + iio_dev->num_channels = ARRAY_SIZE(st_asm330lhh_gyro_channels); + iio_dev->name = "asm330lhh_gyro"; + iio_dev->info = &st_asm330lhh_gyro_info; + sensor->batch_addr = ST_ASM330LHH_REG_FIFO_BATCH_ADDR; + sensor->batch_mask = GENMASK(7, 4); + sensor->offset = 0; + break; + case ST_ASM330LHH_ID_TEMP: + iio_dev->channels = st_asm330lhh_temp_channels; + iio_dev->num_channels = ARRAY_SIZE(st_asm330lhh_temp_channels); + iio_dev->name = "asm330lhh_temp"; + iio_dev->info = &st_asm330lhh_temp_info; + sensor->offset = ST_ASM330LHH_OFFSET; + break; + default: + return NULL; + } + + return iio_dev; +} +#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING +static void st_asm330lhh_enable_acc_gyro(struct st_asm330lhh_hw *hw) +{ + int i = 0; + struct st_asm330lhh_sensor *sensor; + int acc_gain = ST_ASM330LHH_ACC_FS_2G_GAIN; + int gyro_gain = ST_ASM330LHH_GYRO_FS_125_GAIN; + int delay; + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + if (!hw->iio_devs[i]) + continue; + sensor = iio_priv(hw->iio_devs[i]); + sensor->odr = 104; + sensor->watermark = 30; + delay = 1000000 / sensor->odr; + + if (sensor->id == ST_ASM330LHH_ID_ACC) { + st_asm330lhh_set_full_scale(sensor, acc_gain); + usleep_range(delay, 2 * delay); + st_asm330lhh_set_odr(sensor, sensor->odr); + usleep_range(delay, 2 * delay); + st_asm330lhh_update_watermark(sensor, + sensor->watermark); + usleep_range(delay, 2 * delay); + st_asm330lhh_update_fifo(hw->iio_devs[i], true); + usleep_range(delay, 2 * delay); + } else if (sensor->id == ST_ASM330LHH_ID_GYRO) { + st_asm330lhh_set_full_scale(sensor, gyro_gain); + usleep_range(delay, 2 * delay); + st_asm330lhh_set_odr(sensor, sensor->odr); + usleep_range(delay, 2 * delay); + st_asm330lhh_update_watermark(sensor, + sensor->watermark); + usleep_range(delay, 2 * delay); + st_asm330lhh_update_fifo(hw->iio_devs[i], true); + usleep_range(delay, 2 * delay); + } + } +} + +static int asm330_acc_gyro_early_buff_init(struct st_asm330lhh_hw *hw) +{ + int i = 0, err = 0; + struct st_asm330lhh_sensor *acc; + struct st_asm330lhh_sensor *gyro; + + acc = iio_priv(hw->iio_devs[ST_ASM330LHH_ID_ACC]); + gyro = iio_priv(hw->iio_devs[ST_ASM330LHH_ID_GYRO]); + + acc->bufsample_cnt = 0; + gyro->bufsample_cnt = 0; + acc->report_evt_cnt = 5; + gyro->report_evt_cnt = 5; + acc->max_buffer_time = 40; + gyro->max_buffer_time = 40; + + acc->asm_cachepool = kmem_cache_create("acc_sensor_sample", + sizeof(struct asm_sample), + 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!acc->asm_cachepool) { + dev_err(hw->dev, + "asm_acc_cachepool cache create failed\n"); + err = -ENOMEM; + return 0; + } + + for (i = 0; i < ASM_MAXSAMPLE; i++) { + acc->asm_samplist[i] = + kmem_cache_alloc(acc->asm_cachepool, + GFP_KERNEL); + if (!acc->asm_samplist[i]) { + err = -ENOMEM; + goto clean_exit1; + } + } + + gyro->asm_cachepool = kmem_cache_create("gyro_sensor_sample" + , sizeof(struct asm_sample), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!gyro->asm_cachepool) { + dev_err(hw->dev, + "asm_gyro_cachepool cache create failed\n"); + err = -ENOMEM; + goto clean_exit1; + } + + for (i = 0; i < ASM_MAXSAMPLE; i++) { + gyro->asm_samplist[i] = + kmem_cache_alloc(gyro->asm_cachepool, + GFP_KERNEL); + if (!gyro->asm_samplist[i]) { + err = -ENOMEM; + goto clean_exit2; + } + } + + acc->buf_dev = input_allocate_device(); + if (!acc->buf_dev) { + err = -ENOMEM; + dev_err(hw->dev, "input device allocation failed\n"); + goto clean_exit2; + } + acc->buf_dev->name = "asm_accbuf"; + acc->buf_dev->id.bustype = BUS_I2C; + input_set_events_per_packet(acc->buf_dev, + acc->report_evt_cnt * ASM_MAXSAMPLE); + set_bit(EV_ABS, acc->buf_dev->evbit); + input_set_abs_params(acc->buf_dev, ABS_X, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(acc->buf_dev, ABS_Y, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(acc->buf_dev, ABS_Z, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(acc->buf_dev, ABS_RX, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(acc->buf_dev, ABS_RY, + -G_MAX, G_MAX, 0, 0); + err = input_register_device(acc->buf_dev); + if (err) { + dev_err(hw->dev, + "unable to register input device %s\n", + acc->buf_dev->name); + goto clean_exit3; + } + + gyro->buf_dev = input_allocate_device(); + if (!gyro->buf_dev) { + err = -ENOMEM; + dev_err(hw->dev, "input device allocation failed\n"); + goto clean_exit4; + } + gyro->buf_dev->name = "asm_gyrobuf"; + gyro->buf_dev->id.bustype = BUS_I2C; + input_set_events_per_packet(gyro->buf_dev, + gyro->report_evt_cnt * ASM_MAXSAMPLE); + set_bit(EV_ABS, gyro->buf_dev->evbit); + input_set_abs_params(gyro->buf_dev, ABS_X, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(gyro->buf_dev, ABS_Y, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(gyro->buf_dev, ABS_Z, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(gyro->buf_dev, ABS_RX, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(gyro->buf_dev, ABS_RY, + -G_MAX, G_MAX, 0, 0); + err = input_register_device(gyro->buf_dev); + if (err) { + dev_err(hw->dev, + "unable to register input device %s\n", + gyro->buf_dev->name); + goto clean_exit5; + } + + acc->buffer_asm_samples = true; + gyro->buffer_asm_samples = true; + + return 1; +clean_exit5: + input_free_device(gyro->buf_dev); +clean_exit4: + input_unregister_device(acc->buf_dev); +clean_exit3: + input_free_device(acc->buf_dev); +clean_exit2: + for (i = 0; i < ASM_MAXSAMPLE; i++) + kmem_cache_free(gyro->asm_cachepool, + gyro->asm_samplist[i]); + kmem_cache_destroy(gyro->asm_cachepool); +clean_exit1: + for (i = 0; i < ASM_MAXSAMPLE; i++) + kmem_cache_free(acc->asm_cachepool, + acc->asm_samplist[i]); + kmem_cache_destroy(acc->asm_cachepool); + + return 0; +} +static void asm330_acc_gyro_input_cleanup( + struct st_asm330lhh_hw *hw) +{ + int i = 0; + struct st_asm330lhh_sensor *acc; + struct st_asm330lhh_sensor *gyro; + + acc = iio_priv(hw->iio_devs[ST_ASM330LHH_ID_ACC]); + gyro = iio_priv(hw->iio_devs[ST_ASM330LHH_ID_GYRO]); + + input_free_device(acc->buf_dev); + input_unregister_device(gyro->buf_dev); + input_free_device(gyro->buf_dev); + for (i = 0; i < ASM_MAXSAMPLE; i++) + kmem_cache_free(gyro->asm_cachepool, + gyro->asm_samplist[i]); + kmem_cache_destroy(gyro->asm_cachepool); + for (i = 0; i < ASM_MAXSAMPLE; i++) + kmem_cache_free(acc->asm_cachepool, + acc->asm_samplist[i]); + kmem_cache_destroy(acc->asm_cachepool); +} +#else +static void st_asm330lhh_enable_acc_gyro(struct st_asm330lhh_hw *hw) +{ +} +static int asm330_acc_gyro_early_buff_init(struct st_asm330lhh_hw *hw) +{ + return 1; +} +static void asm330_acc_gyro_input_cleanup(struct st_asm330lhh_hw *hw) +{ +} +#endif + + +int st_asm330lhh_probe(struct device *dev, int irq, + const struct st_asm330lhh_transfer_function *tf_ops) +{ + struct st_asm330lhh_hw *hw; + int i, err; + + hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return -ENOMEM; + + dev_set_drvdata(dev, (void *)hw); + + mutex_init(&hw->lock); + mutex_init(&hw->fifo_lock); + + hw->dev = dev; + hw->irq = irq; + hw->tf = tf_ops; + + dev_info(hw->dev, "Ver: %s\n", ST_ASM330LHH_VERSION); + err = st_asm330lhh_check_whoami(hw); + if (err < 0) + return err; + + err = st_asm330lhh_init_device(hw); + if (err < 0) + return err; + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + hw->iio_devs[i] = st_asm330lhh_alloc_iiodev(hw, i); + if (!hw->iio_devs[i]) + return -ENOMEM; + } + + if (hw->irq > 0) { + err = st_asm330lhh_fifo_setup(hw); + if (err < 0) + return err; + } + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + if (!hw->iio_devs[i]) + continue; + + err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); + if (err) { + if (hw->irq > 0) + st_asm330lhh_deallocate_fifo(hw); + return err; + } + } + + err = asm330_acc_gyro_early_buff_init(hw); + if (!err) + return err; + + st_asm330lhh_enable_acc_gyro(hw); + + dev_info(hw->dev, "probe ok\n"); + + return 0; +} + +EXPORT_SYMBOL(st_asm330lhh_probe); + +int st_asm330lhh_remove(struct device *dev) +{ + struct st_asm330lhh_hw *hw = dev_get_drvdata(dev); + + asm330_acc_gyro_input_cleanup(hw); + + return st_asm330lhh_deallocate_fifo(hw); +} +EXPORT_SYMBOL(st_asm330lhh_remove); + +static int __maybe_unused st_asm330lhh_suspend(struct device *dev) +{ + struct st_asm330lhh_hw *hw = dev_get_drvdata(dev); + struct st_asm330lhh_sensor *sensor; + int i, err = 0; + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + if (!hw->iio_devs[i]) + continue; + + sensor = iio_priv(hw->iio_devs[i]); + + if (!(hw->enable_mask & BIT(sensor->id))) + continue; + + err = st_asm330lhh_set_odr(sensor, 0); + if (err < 0) + return err; + } + + if (hw->enable_mask) + err = st_asm330lhh_suspend_fifo(hw); + + return err; +} + +static int __maybe_unused st_asm330lhh_resume(struct device *dev) +{ + struct st_asm330lhh_hw *hw = dev_get_drvdata(dev); + struct st_asm330lhh_sensor *sensor; + int i, err = 0; + + for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) { + if (!hw->iio_devs[i]) + continue; + + sensor = iio_priv(hw->iio_devs[i]); + + if (!(hw->enable_mask & BIT(sensor->id))) + continue; + + err = st_asm330lhh_set_odr(sensor, sensor->odr); + if (err < 0) + return err; + } + + if (hw->enable_mask) + err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_CONT); + + return err; +} + +const struct dev_pm_ops st_asm330lhh_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(st_asm330lhh_suspend, st_asm330lhh_resume) +}; +EXPORT_SYMBOL(st_asm330lhh_pm_ops); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("STMicroelectronics st_asm330lhh driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(ST_ASM330LHH_VERSION); diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_i2c.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..47284e814f7f877989e426360bdf0133f3f2b6e8 --- /dev/null +++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_i2c.c @@ -0,0 +1,100 @@ +/* + * STMicroelectronics st_asm330lhh i2c driver + * + * Copyright 2018 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include + +#include "st_asm330lhh.h" + +static int st_asm330lhh_i2c_read(struct device *dev, u8 addr, int len, u8 *data) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_msg msg[2]; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].len = 1; + msg[0].buf = &addr; + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].len = len; + msg[1].buf = data; + + return i2c_transfer(client->adapter, msg, 2); +} + +static int st_asm330lhh_i2c_write(struct device *dev, u8 addr, int len, u8 *data) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_msg msg; + u8 send[len + 1]; + + send[0] = addr; + memcpy(&send[1], data, len * sizeof(u8)); + + msg.addr = client->addr; + msg.flags = client->flags; + msg.len = len + 1; + msg.buf = send; + + return i2c_transfer(client->adapter, &msg, 1); +} + +static const struct st_asm330lhh_transfer_function st_asm330lhh_transfer_fn = { + .read = st_asm330lhh_i2c_read, + .write = st_asm330lhh_i2c_write, +}; + +static int st_asm330lhh_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return st_asm330lhh_probe(&client->dev, client->irq, + &st_asm330lhh_transfer_fn); +} + +static int st_asm330lhh_i2c_remove(struct i2c_client *client) +{ + return st_asm330lhh_remove(&client->dev); +} + +static const struct of_device_id st_asm330lhh_i2c_of_match[] = { + { + .compatible = "st,asm330lhh", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_asm330lhh_i2c_of_match); + +static const struct i2c_device_id st_asm330lhh_i2c_id_table[] = { + { ST_ASM330LHH_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, st_asm330lhh_i2c_id_table); + +static struct i2c_driver st_asm330lhh_driver = { + .driver = { + .name = "st_asm330lhh_i2c", + .pm = &st_asm330lhh_pm_ops, + .of_match_table = of_match_ptr(st_asm330lhh_i2c_of_match), + }, + .probe = st_asm330lhh_i2c_probe, + .remove = st_asm330lhh_i2c_remove, + .id_table = st_asm330lhh_i2c_id_table, +}; +module_i2c_driver(st_asm330lhh_driver); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("STMicroelectronics st_asm330lhh i2c driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(ST_ASM330LHH_VERSION); diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_spi.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..4a64a5e7a375fa6e1afdfae40bda20c78fec284c --- /dev/null +++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_spi.c @@ -0,0 +1,115 @@ +/* + * STMicroelectronics st_asm330lhh spi driver + * + * Copyright 2018 STMicroelectronics Inc. + * + * Lorenzo Bianconi + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include + +#include "st_asm330lhh.h" + +#define SENSORS_SPI_READ BIT(7) + +static int st_asm330lhh_spi_read(struct device *dev, u8 addr, int len, + u8 *data) +{ + struct spi_device *spi = to_spi_device(dev); + struct st_asm330lhh_hw *hw = spi_get_drvdata(spi); + int err; + + struct spi_transfer xfers[] = { + { + .tx_buf = hw->tb.tx_buf, + .bits_per_word = 8, + .len = 1, + }, + { + .rx_buf = hw->tb.rx_buf, + .bits_per_word = 8, + .len = len, + } + }; + + hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ; + + err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); + if (err < 0) + return err; + + memcpy(data, hw->tb.rx_buf, len * sizeof(u8)); + + return len; +} + +static int st_asm330lhh_spi_write(struct device *dev, u8 addr, int len, + u8 *data) +{ + struct st_asm330lhh_hw *hw; + struct spi_device *spi; + + if (len >= ST_ASM330LHH_TX_MAX_LENGTH) + return -ENOMEM; + + spi = to_spi_device(dev); + hw = spi_get_drvdata(spi); + + hw->tb.tx_buf[0] = addr; + memcpy(&hw->tb.tx_buf[1], data, len); + + return spi_write(spi, hw->tb.tx_buf, len + 1); +} + +static const struct st_asm330lhh_transfer_function st_asm330lhh_transfer_fn = { + .read = st_asm330lhh_spi_read, + .write = st_asm330lhh_spi_write, +}; + +static int st_asm330lhh_spi_probe(struct spi_device *spi) +{ + return st_asm330lhh_probe(&spi->dev, spi->irq, + &st_asm330lhh_transfer_fn); +} + +static int st_asm330lhh_spi_remove(struct spi_device *spi) +{ + return st_asm330lhh_remove(&spi->dev); +} + +static const struct of_device_id st_asm330lhh_spi_of_match[] = { + { + .compatible = "st,asm330lhh", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_asm330lhh_spi_of_match); + +static const struct spi_device_id st_asm330lhh_spi_id_table[] = { + { ST_ASM330LHH_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(spi, st_asm330lhh_spi_id_table); + +static struct spi_driver st_asm330lhh_driver = { + .driver = { + .name = "st_asm330lhh_spi", + .pm = &st_asm330lhh_pm_ops, + .of_match_table = of_match_ptr(st_asm330lhh_spi_of_match), + }, + .probe = st_asm330lhh_spi_probe, + .remove = st_asm330lhh_spi_remove, + .id_table = st_asm330lhh_spi_id_table, +}; +module_spi_driver(st_asm330lhh_driver); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("STMicroelectronics st_asm330lhh spi driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(ST_ASM330LHH_VERSION); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 25c68de393ad148eb36dc4bd5ed0a9476f7f1c4d..1f64457cc6bafc868e0a638df635155b9b31c71c 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -92,7 +92,7 @@ unsigned int iio_buffer_poll(struct file *filp, struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; - if (!indio_dev->info) + if (!indio_dev->info || rb == NULL) return 0; poll_wait(filp, &rb->pollq, wait); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 270381126e9e28c96322d57dc6f962903329b9e3..a9131ce67faad4dfeb1615023e0c61016e81f3c6 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -189,8 +189,10 @@ static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf, ret = indio_dev->info->debugfs_reg_access(indio_dev, indio_dev->cached_reg_addr, 0, &val); - if (ret) + if (ret) { dev_err(indio_dev->dev.parent, "%s: read failed\n", __func__); + return ret; + } len = snprintf(buf, sizeof(buf), "0x%X\n", val); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index a6143ea51dfcb1d906e1a28bc85e7b40f92d8163..d28685bec34eee233be48e147f5a39201b7a63db 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -49,8 +49,6 @@ static int st_magn_spi_remove(struct spi_device *spi) } static const struct spi_device_id st_magn_id_table[] = { - { LSM303DLHC_MAGN_DEV_NAME }, - { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, {}, }; diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 572bc6f02ca82987a9f3945bc073e4ab835effe9..e18f12b746100c0963c544598081b4cb2828e306 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -58,7 +58,7 @@ static int iio_interrupt_trigger_probe(struct platform_device *pdev) trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); if (!trig_info) { ret = -ENOMEM; - goto error_put_trigger; + goto error_free_trigger; } iio_trigger_set_drvdata(trig, trig_info); trig_info->irq = irq; @@ -83,8 +83,8 @@ error_release_irq: free_irq(irq, trig); error_free_trig_info: kfree(trig_info); -error_put_trigger: - iio_trigger_put(trig); +error_free_trigger: + iio_trigger_free(trig); error_ret: return ret; } @@ -99,7 +99,7 @@ static int iio_interrupt_trigger_remove(struct platform_device *pdev) iio_trigger_unregister(trig); free_irq(trig_info->irq, trig); kfree(trig_info); - iio_trigger_put(trig); + iio_trigger_free(trig); return 0; } diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c index 254c7e906127f6152a51d273e57b0a5daa0fa950..61ffbec048a70a60b19490d07006aab0dc702104 100644 --- a/drivers/iio/trigger/iio-trig-sysfs.c +++ b/drivers/iio/trigger/iio-trig-sysfs.c @@ -173,7 +173,7 @@ static int iio_sysfs_trigger_probe(int id) return 0; out2: - iio_trigger_put(t->trig); + iio_trigger_free(t->trig); free_t: kfree(t); out1: diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 77089399359b70bbcdccabc264c5e4e8089a1bdb..008123291b11f7bc35ff88a83c87e5ca2b51177b 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -33,6 +33,18 @@ config INFINIBAND_USER_ACCESS libibverbs, libibcm and a hardware driver library from . +config INFINIBAND_USER_ACCESS_UCM + bool "Userspace CM (UCM, DEPRECATED)" + depends on BROKEN + depends on INFINIBAND_USER_ACCESS + help + The UCM module has known security flaws, which no one is + interested to fix. The user-space part of this code was + dropped from the upstream a long time ago. + + This option is DEPRECATED and planned to be removed. + + config INFINIBAND_USER_MEM bool depends on INFINIBAND_USER_ACCESS != n diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index ffd0af6734af63120b78aa8402f2f48a1ec6fc20..070a895f3bd75c8a171037e7af11e029211add29 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -5,8 +5,8 @@ obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ ib_cm.o iw_cm.o ib_addr.o \ $(infiniband-y) obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o -obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \ - $(user_access-y) +obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o $(user_access-y) +obj-$(CONFIG_INFINIBAND_USER_ACCESS_UCM) += ib_ucm.o $(user_access-y) ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ device.o fmr_pool.o cache.o netlink.o diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 06441a43c3aacd1c6aecb22e15a17529b4a890a8..9ba24ed2845fa2b479c87cb17780fda30ebcbbb4 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -434,6 +434,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) dgid = (union ib_gid *) &addr->sib_addr; pkey = ntohs(addr->sib_pkey); + mutex_lock(&lock); list_for_each_entry(cur_dev, &dev_list, list) { if (rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB) continue; @@ -455,18 +456,19 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) cma_dev = cur_dev; sgid = gid; id_priv->id.port_num = p; + goto found; } } } } - - if (!cma_dev) - return -ENODEV; + mutex_unlock(&lock); + return -ENODEV; found: cma_attach_to_dev(id_priv, cma_dev); - addr = (struct sockaddr_ib *) cma_src_addr(id_priv); - memcpy(&addr->sib_addr, &sgid, sizeof sgid); + mutex_unlock(&lock); + addr = (struct sockaddr_ib *)cma_src_addr(id_priv); + memcpy(&addr->sib_addr, &sgid, sizeof(sgid)); cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); return 0; } @@ -3350,6 +3352,9 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, struct cma_multicast *mc; int ret; + if (!id->device) + return -EINVAL; + id_priv = container_of(id, struct rdma_id_private, id); if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) @@ -3632,7 +3637,7 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) goto out; if (ibnl_put_attr(skb, nlh, - rdma_addr_size(cma_src_addr(id_priv)), + rdma_addr_size(cma_dst_addr(id_priv)), cma_dst_addr(id_priv), RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) goto out; diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 74c30f4c557e015df74ec153417e09d626f8da2e..0c79b0626a6effdbcc35ee8c4759e7254ae8e1b7 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1466,7 +1466,8 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, mad_reg_req->oui, 3)) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(!*method); + if (!*method) + goto error3; goto check_in_use; } } @@ -1476,10 +1477,12 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, vclass]->oui[i])) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(*method); /* Allocate method table for this OUI */ - if ((ret = allocate_method_table(method))) - goto error3; + if (!*method) { + ret = allocate_method_table(method); + if (ret) + goto error3; + } memcpy((*vendor_table)->vendor_class[vclass]->oui[i], mad_reg_req->oui, 3); goto check_in_use; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 81dd84d0b68b545824788b9d7de99403b1befffe..a399d7da777463e59c8a00eb0a14467cb984496d 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -113,6 +113,8 @@ static DEFINE_MUTEX(mut); static DEFINE_IDR(ctx_idr); static DEFINE_IDR(multicast_idr); +static const struct file_operations ucma_fops; + static inline struct ucma_context *_ucma_find_context(int id, struct ucma_file *file) { @@ -180,7 +182,7 @@ static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) return NULL; mutex_lock(&mut); - mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL); + mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL); mutex_unlock(&mut); if (mc->id < 0) goto error; @@ -1262,6 +1264,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, goto err3; } + mutex_lock(&mut); + idr_replace(&multicast_idr, mc, mc->id); + mutex_unlock(&mut); + mutex_unlock(&file->mut); ucma_put_ctx(ctx); return 0; @@ -1412,6 +1418,10 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file, f = fdget(cmd.fd); if (!f.file) return -ENOENT; + if (f.file->f_op != &ucma_fops) { + ret = -EINVAL; + goto file_put; + } /* Validate current fd and prevent destruction of id. */ ctx = ucma_get_ctx(f.file->private_data, cmd.id); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 420ae23d064dbebae86c65d4a1c1504c58ea46e0..1ca8010ccb1f0b4081d610b88d681c05368d5bc7 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2348,9 +2348,8 @@ err_steer_free_bitmap: kfree(ibdev->ib_uc_qpns_bitmap); err_steer_qp_release: - if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) - mlx4_qp_release_range(dev, ibdev->steer_qpn_base, - ibdev->steer_qpn_count); + mlx4_qp_release_range(dev, ibdev->steer_qpn_base, + ibdev->steer_qpn_count); err_counter: for (; i; --i) if (ibdev->counters[i - 1] != -1) @@ -2452,11 +2451,9 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) ibdev->iboe.nb.notifier_call = NULL; } - if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) { - mlx4_qp_release_range(dev, ibdev->steer_qpn_base, - ibdev->steer_qpn_count); - kfree(ibdev->ib_uc_qpns_bitmap); - } + mlx4_qp_release_range(dev, ibdev->steer_qpn_base, + ibdev->steer_qpn_count); + kfree(ibdev->ib_uc_qpns_bitmap); if (ibdev->iboe.nb_inet.notifier_call) { if (unregister_inetaddr_notifier(&ibdev->iboe.nb_inet)) diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 33cbb7611d66d99f37e265efb78b4d67de388367..890bbf984748111f27f2391db277bc1d662bd33c 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1465,7 +1465,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, context->mtu_msgmax = (IB_MTU_4096 << 5) | ilog2(dev->dev->caps.max_gso_sz); else - context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; + context->mtu_msgmax = (IB_MTU_4096 << 5) | 13; } else if (attr_mask & IB_QP_PATH_MTU) { if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { pr_err("path MTU (%u) is invalid\n", diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 871823cd98256637b2959750ef6f0a48601e3f87..18645dcf58820cca3aec82cf8d8a762b05d6642c 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1099,6 +1099,8 @@ static int create_umr_res(struct mlx5_ib_dev *dev) qp->real_qp = qp; qp->uobject = NULL; qp->qp_type = MLX5_IB_QPT_REG_UMR; + qp->send_cq = init_attr->send_cq; + qp->recv_cq = init_attr->recv_cq; attr->qp_state = IB_QPS_INIT; attr->port_num = 1; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index e261a53f9a02a5edf18725cc75daaef3661fc64a..5edb09e674a628c52b7a6a23bbeb5e4401301c8d 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -174,7 +174,11 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, } else { if (ucmd) { qp->rq.wqe_cnt = ucmd->rq_wqe_count; + if (ucmd->rq_wqe_shift > BITS_PER_BYTE * sizeof(ucmd->rq_wqe_shift)) + return -EINVAL; qp->rq.wqe_shift = ucmd->rq_wqe_shift; + if ((1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) < qp->wq_sig) + return -EINVAL; qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig; qp->rq.max_post = qp->rq.wqe_cnt; } else { @@ -3028,12 +3032,9 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd) int err; err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn); - if (err) { + if (err) mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn); - return err; - } kfree(xrcd); - return 0; } diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 23ca2aca1ad66b020ee5069b9b4e9974bc49e6f7..5331f8683ef647fe7ca1bd87f266986a157ac9a0 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -7078,7 +7078,7 @@ static void qib_7322_txchk_change(struct qib_devdata *dd, u32 start, unsigned long flags; while (wait) { - unsigned long shadow; + unsigned long shadow = 0; int cstart, previ = -1; /* diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index cdf0a78e0c99867153c4dbb9f635a7873c36b78a..be5833e0306c8971260807ff40337924d5d64443 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -997,12 +997,14 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even skb_queue_head_init(&skqueue); + netif_tx_lock_bh(p->dev); spin_lock_irq(&priv->lock); set_bit(IPOIB_FLAG_OPER_UP, &p->flags); if (p->neigh) while ((skb = __skb_dequeue(&p->neigh->queue))) __skb_queue_tail(&skqueue, skb); spin_unlock_irq(&priv->lock); + netif_tx_unlock_bh(p->dev); while ((skb = __skb_dequeue(&skqueue))) { skb->dev = p->dev; @@ -1362,7 +1364,7 @@ static void ipoib_cm_tx_reap(struct work_struct *work) while (!list_empty(&priv->cm.reap_list)) { p = list_entry(priv->cm.reap_list.next, typeof(*p), list); - list_del(&p->list); + list_del_init(&p->list); spin_unlock_irqrestore(&priv->lock, flags); netif_tx_unlock_bh(dev); ipoib_cm_tx_destroy(p); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 72626c3481749b962fe96b79722d7c8e9c99c585..963cef55dc6039cefa5faa4692e6d829ea0cc520 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -955,6 +955,19 @@ static inline int update_parent_pkey(struct ipoib_dev_priv *priv) */ priv->dev->broadcast[8] = priv->pkey >> 8; priv->dev->broadcast[9] = priv->pkey & 0xff; + + /* + * Update the broadcast address in the priv->broadcast object, + * in case it already exists, otherwise no one will do that. + */ + if (priv->broadcast) { + spin_lock_irq(&priv->lock); + memcpy(priv->broadcast->mcmember.mgid.raw, + priv->dev->broadcast + 4, + sizeof(union ib_gid)); + spin_unlock_irq(&priv->lock); + } + return 0; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 5e08db6f9d8c595560523b3e15009836161bae57..0e58a705b37e8b002bd7195e03b8e7060b5383a7 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -488,6 +488,22 @@ static void path_rec_completion(int status, spin_lock_irqsave(&priv->lock, flags); if (!IS_ERR_OR_NULL(ah)) { + /* + * pathrec.dgid is used as the database key from the LLADDR, + * it must remain unchanged even if the SA returns a different + * GID to use in the AH. + */ + if (memcmp(pathrec->dgid.raw, path->pathrec.dgid.raw, + sizeof(union ib_gid))) { + ipoib_dbg( + priv, + "%s got PathRec for gid %pI6 while asked for %pI6\n", + dev->name, pathrec->dgid.raw, + path->pathrec.dgid.raw); + memcpy(pathrec->dgid.raw, path->pathrec.dgid.raw, + sizeof(union ib_gid)); + } + path->pathrec = *pathrec; old_ah = path->ah; @@ -958,7 +974,7 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) rcu_dereference_protected(neigh->hnext, lockdep_is_held(&priv->lock))); /* remove from path/mc list */ - list_del(&neigh->list); + list_del_init(&neigh->list); call_rcu(&neigh->rcu, ipoib_neigh_reclaim); } else { np = &neigh->hnext; @@ -1121,7 +1137,7 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh) rcu_dereference_protected(neigh->hnext, lockdep_is_held(&priv->lock))); /* remove from parent list */ - list_del(&neigh->list); + list_del_init(&neigh->list); call_rcu(&neigh->rcu, ipoib_neigh_reclaim); return; } else { @@ -1206,7 +1222,7 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) rcu_dereference_protected(neigh->hnext, lockdep_is_held(&priv->lock))); /* remove from parent list */ - list_del(&neigh->list); + list_del_init(&neigh->list); call_rcu(&neigh->rcu, ipoib_neigh_reclaim); } else { np = &neigh->hnext; @@ -1248,7 +1264,7 @@ static void ipoib_flush_neighs(struct ipoib_dev_priv *priv) rcu_dereference_protected(neigh->hnext, lockdep_is_held(&priv->lock))); /* remove from path/mc list */ - list_del(&neigh->list); + list_del_init(&neigh->list); call_rcu(&neigh->rcu, ipoib_neigh_reclaim); } } @@ -1628,6 +1644,9 @@ static struct net_device *ipoib_add_port(const char *format, goto event_failed; } + /* call event handler to ensure pkey in sync */ + queue_work(ipoib_workqueue, &priv->flush_heavy); + result = register_netdev(priv->dev); if (result) { printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n", diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index c995681befeeb4f83cec6b517bf162841284c087..67182d4e8138f34f1128a63e45385229fc6db311 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -162,11 +162,11 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) out: up_write(&ppriv->vlan_rwsem); + rtnl_unlock(); + if (result) free_netdev(priv->dev); - rtnl_unlock(); - return result; } @@ -187,7 +187,6 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { if (priv->pkey == pkey && priv->child_type == IPOIB_LEGACY_CHILD) { - unregister_netdevice(priv->dev); list_del(&priv->list); dev = priv->dev; break; @@ -195,6 +194,11 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) } up_write(&ppriv->vlan_rwsem); + if (dev) { + ipoib_dbg(ppriv, "delete child vlan %s\n", dev->name); + unregister_netdevice(dev); + } + rtnl_unlock(); if (dev) { diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 9fc0326c1da7dfce074e6cbfe4045632c30b9996..422e022dcbbb4c63910446a8cb6845833baa97fc 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -959,8 +959,7 @@ static int srpt_init_ch_qp(struct srpt_rdma_ch *ch, struct ib_qp *qp) return -ENOMEM; attr->qp_state = IB_QPS_INIT; - attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | - IB_ACCESS_REMOTE_WRITE; + attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; attr->port_num = ch->sport->port; attr->pkey_index = 0; @@ -2987,12 +2986,8 @@ static void srpt_queue_response(struct se_cmd *cmd) } spin_unlock_irqrestore(&ioctx->spinlock, flags); - if (unlikely(transport_check_aborted_status(&ioctx->cmd, false) - || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) { - atomic_inc(&ch->req_lim_delta); - srpt_abort_cmd(ioctx); + if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) return; - } dir = ioctx->cmd.data_direction; @@ -3522,7 +3517,7 @@ static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name) { const char *p; unsigned len, count, leading_zero_bytes; - int ret, rc; + int ret; p = name; if (strncasecmp(p, "0x", 2) == 0) @@ -3534,10 +3529,9 @@ static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name) count = min(len / 2, 16U); leading_zero_bytes = 16 - count; memset(i_port_id, 0, leading_zero_bytes); - rc = hex2bin(i_port_id + leading_zero_bytes, p, count); - if (rc < 0) - pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", rc); - ret = 0; + ret = hex2bin(i_port_id + leading_zero_bytes, p, count); + if (ret < 0) + pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", ret); out: return ret; } diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 9b12c334b8e24bb65db1b2cbbce29c61ce22cf2c..cf519aba1ec902e5f7d8b5b945843a941d91ef8e 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -208,6 +208,8 @@ source "drivers/input/touchscreen/Kconfig" source "drivers/input/misc/Kconfig" +source "drivers/input/sensors/smi130/Kconfig" + source "drivers/input/fingerprint/Kconfig" endif diff --git a/drivers/input/Makefile b/drivers/input/Makefile index d7fa8a6a795ff63b150da5b2adfbfdbc7403ac48..e26de1babc410af40cab51b1533d3c506b146392 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o obj-$(CONFIG_SENSORS_HALL) += hall_sensor.o +obj-y += sensors/smi130/ diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index e651fa692afef3959f0d48ee844a40c3ccb2aba0..176bdd1407699b38fbd768fc6cab638b64f6d624 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -216,8 +216,10 @@ static void matrix_keypad_stop(struct input_dev *dev) { struct matrix_keypad *keypad = input_get_drvdata(dev); + spin_lock_irq(&keypad->lock); keypad->stopped = true; - mb(); + spin_unlock_irq(&keypad->lock); + flush_work(&keypad->work.work); /* * matrix_keypad_scan() will leave IRQs enabled; diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 009c82256e895ec2383715a2ce706ed75133b0f3..671d202a94fa6113806a7c5604058f382ebe39c2 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -87,7 +87,8 @@ static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id) struct mpr121_touchkey *mpr121 = dev_id; struct i2c_client *client = mpr121->client; struct input_dev *input = mpr121->input_dev; - unsigned int key_num, key_val, pressed; + unsigned long bit_changed; + unsigned int key_num; int reg; reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR); @@ -105,18 +106,22 @@ static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id) reg &= TOUCH_STATUS_MASK; /* use old press bit to figure out which bit changed */ - key_num = ffs(reg ^ mpr121->statusbits) - 1; - pressed = reg & (1 << key_num); + bit_changed = reg ^ mpr121->statusbits; mpr121->statusbits = reg; + for_each_set_bit(key_num, &bit_changed, mpr121->keycount) { + unsigned int key_val, pressed; - key_val = mpr121->keycodes[key_num]; + pressed = reg & BIT(key_num); + key_val = mpr121->keycodes[key_num]; - input_event(input, EV_MSC, MSC_SCAN, key_num); - input_report_key(input, key_val, pressed); - input_sync(input); + input_event(input, EV_MSC, MSC_SCAN, key_num); + input_report_key(input, key_val, pressed); + + dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val, + pressed ? "pressed" : "released"); - dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val, - pressed ? "pressed" : "released"); + } + input_sync(input); out: return IRQ_HANDLED; @@ -230,6 +235,7 @@ static int mpr_touchkey_probe(struct i2c_client *client, input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_dev->keycode = mpr121->keycodes; input_dev->keycodesize = sizeof(mpr121->keycodes[0]); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 4069df138c055d6c4facfa92035e03a88de8503b..49d3ec06e8f32a95af659bb1ad795ed6ec752206 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -372,6 +372,18 @@ config INPUT_KEYCHORD To compile this driver as a module, choose M here: the module will be called keychord. + +config STMVL53L0X + tristate "STM VL53L0X Ranging Sensor" + depends on I2C + help + Say Y here if you want to enable the key chord driver + This is a Time-of-Flight (ToF) laser-ranging sensor, provide + the distance from obstacle. + + To compile this driver as a module, choose M here: the module will + be called vl5310x. + config INPUT_KEYSPAN_REMOTE tristate "Keyspan DMR USB remote control" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 1456a017577f554991cdb947334aaf9122441a9d..2eca2a12957cb31ed16afe2564da49b91d37da1f 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -85,3 +85,4 @@ ifeq ($(CONFIG_BOSCH_BMA2X2_ENABLE_INT2),y) endif obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH) += ots_pat9125/ +obj-$(CONFIG_STMVL53L0X) += vl53l0x/ diff --git a/drivers/input/misc/bma2x2.c b/drivers/input/misc/bma2x2.c index 513c4c27b250666dcd3284eacfb00b2b496502ec..7b526277a8622d07ce0fdb9e820b7c36ecae1bd3 100644 --- a/drivers/input/misc/bma2x2.c +++ b/drivers/input/misc/bma2x2.c @@ -8957,4 +8957,3 @@ MODULE_LICENSE("GPL v2"); module_init(BMA2X2_init); module_exit(BMA2X2_exit); - diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index f4e8fbec6a942a8ea7a48e268b1e96f9fe458369..b5304e26488154d347921db9952282b1c49cd60c 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -1635,13 +1635,25 @@ ims_pcu_get_cdc_union_desc(struct usb_interface *intf) return NULL; } - while (buflen > 0) { + while (buflen >= sizeof(*union_desc)) { union_desc = (struct usb_cdc_union_desc *)buf; + if (union_desc->bLength > buflen) { + dev_err(&intf->dev, "Too large descriptor\n"); + return NULL; + } + if (union_desc->bDescriptorType == USB_DT_CS_INTERFACE && union_desc->bDescriptorSubType == USB_CDC_UNION_TYPE) { dev_dbg(&intf->dev, "Found union header\n"); - return union_desc; + + if (union_desc->bLength >= sizeof(*union_desc)) + return union_desc; + + dev_err(&intf->dev, + "Union descriptor to short (%d vs %zd\n)", + union_desc->bLength, sizeof(*union_desc)); + return NULL; } buflen -= union_desc->bLength; diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c index fdcc14653b64c7bafd4d4fb52ccd2068291dfdd0..82fefdff366a236df578318e5345343850459666 100644 --- a/drivers/input/misc/keychord.c +++ b/drivers/input/misc/keychord.c @@ -276,7 +276,7 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, size_t resid = count; size_t key_bytes; - if (count < sizeof(struct input_keychord)) + if (count < sizeof(struct input_keychord) || count > PAGE_SIZE) return -EINVAL; keychords = kzalloc(count, GFP_KERNEL); if (!keychords) diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 960ef2a709100836eb1dc752d89e4743f3afae89..c434a8521d657b02305798910891adc8b64ba6b9 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -180,12 +180,15 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, twl4030_vibra_suspend, twl4030_vibra_resume); static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata, - struct device_node *node) + struct device_node *parent) { + struct device_node *node; + if (pdata && pdata->coexist) return true; - if (of_find_node_by_name(node, "codec")) { + node = of_get_child_by_name(parent, "codec"); + if (node) { of_node_put(node); return true; } diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 6d26eecc278c7e63d4e251ebbdbe3d03fdcf7de1..7eb23e644fac67f5a9860eddb08b773ae815116f 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -264,7 +264,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev) int vddvibr_uV = 0; int error; - twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node, + twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node, "vibra"); if (!twl6040_core_node) { dev_err(&pdev->dev, "parent of node is missing?\n"); diff --git a/drivers/input/misc/vl53l0x/Makefile b/drivers/input/misc/vl53l0x/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..af00414d93f5065c349b1ed52640504a63f5391b --- /dev/null +++ b/drivers/input/misc/vl53l0x/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for the vl53L0X drivers. +# + +# Each configuration option enables a list of files. +FEATURE_USE_CCI := false +#FEATURE_USE_CCI := true + +ifeq ($(FEATURE_USE_CCI), true) +ccflags-y += -Idrivers/input/misc/vl53l0x/inc -DCAMERA_CCI +else +ccflags-y += -Idrivers/input/misc/vl53l0x/inc -DSTM_TEST +endif + +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/common +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +obj-$(CONFIG_STMVL53L0X) += stmvl53l0x.o +stmvl53l0x-objs := stmvl53l0x_module.o stmvl53l0x_module-i2c.o stmvl53l0x_module-cci.o src/vl53l0x_api_calibration.o src/vl53l0x_api_core.o src/vl53l0x_api_ranging.o src/vl53l0x_api_strings.o src/vl53l0x_api.o src/vl53l0x_platform.o src/vl53l0x_i2c_platform.o src/vl53l0x_port_i2c.o diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b0e7f06e4811108bb95d7d50a21ffb48888b54a6 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h @@ -0,0 +1,1943 @@ +/* + * vl53l0x_api.h - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +#ifndef _VL_API_H_ +#define _VL_API_H_ + +#include "vl53l0x_api_strings.h" +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef _MSC_VER +# ifdef VL_API_EXPORTS +# define VL_API __declspec(dllexport) +# else +# define VL_API +# endif +#else +# define VL_API +#endif + +/** @defgroup VL_cut11_group VL53L0X cut1.1 Function Definition + * @brief VL53L0X cut1.1 Function Definition + * @{ + */ + +/** @defgroup VL_general_group VL53L0X General Functions + * @brief General functions and definitions + * @{ + */ + +/** + * @brief Return the VL53L0X PAL Implementation Version + * + * @note This function doesn't access to the device + * + * @param pVersion Pointer to current PAL Implementation Version + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetVersion(struct VL_Version_t *pVersion); + +/** + * @brief Return the PAL Specification Version used for the current + * implementation. + * + * @note This function doesn't access to the device + * + * @param pPalSpecVersion Pointer to current PAL Specification Version + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalSpecVersion( + struct VL_Version_t *pPalSpecVersion); + +/** + * @brief Reads the Product Revision for a for given Device + * This function can be used to distinguish cut1.0 from cut1.1. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pProductRevisionMajor Pointer to Product Revision Major + * for a given Device + * @param pProductRevisionMinor Pointer to Product Revision Minor + * for a given Device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetProductRevision(struct vl_data *Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor); + +/** + * @brief Reads the Device information for given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVL_DeviceInfo Pointer to current device info for a given + * Device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceInfo(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo); + +/** + * @brief Read current status of the error register for the selected device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pDeviceErrorStatus Pointer to current error code of the device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev, + uint8_t *pDeviceErrorStatus); + +/** + * @brief Human readable Range Status string for a given RangeStatus + * + * @note This function doesn't access to the device + * + * @param RangeStatus The RangeStatus code as stored on + * @a struct VL_RangingMeasurementData_t + * @param pRangeStatusString The returned RangeStatus string. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Human readable error string for a given Error Code + * + * @note This function doesn't access to the device + * + * @param ErrorCode The error code as stored on ::uint8_t + * @param pDeviceErrorString The error string corresponding to the ErrorCode + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceErrorString( + uint8_t ErrorCode, char *pDeviceErrorString); + +/** + * @brief Human readable error string for current PAL error status + * + * @note This function doesn't access to the device + * + * @param PalErrorCode The error code as stored on @a int8_t + * @param pPalErrorString The error string corresponding to the + * PalErrorCode + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalErrorString(int8_t PalErrorCode, + char *pPalErrorString); + +/** + * @brief Human readable PAL State string + * + * @note This function doesn't access to the device + * + * @param PalStateCode The State code as stored on @a uint8_t + * @param pPalStateString The State string corresponding to the + * PalStateCode + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalStateString(uint8_t PalStateCode, + char *pPalStateString); + +/** + * @brief Reads the internal state of the PAL for a given Device + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pPalState Pointer to current state of the PAL for a + * given Device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalState(struct vl_data *Dev, + uint8_t *pPalState); + +/** + * @brief Set the power mode for a given Device + * The power mode can be Standby or Idle. Different level of both Standby and + * Idle can exists. + * This function should not be used when device is in Ranging state. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param PowerMode The value of the power mode to set. + * see ::uint8_t + * Valid values are: + * VL_POWERMODE_STANDBY_LEVEL1, + * VL_POWERMODE_IDLE_LEVEL1 + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when PowerMode + * is not in the supported list + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetPowerMode(struct vl_data *Dev, + uint8_t PowerMode); + +/** + * @brief Get the power mode for a given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pPowerMode Pointer to the current value of the power + * mode. see ::uint8_t + * Valid values are: + * VL_POWERMODE_STANDBY_LEVEL1, + * VL_POWERMODE_IDLE_LEVEL1 + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPowerMode(struct vl_data *Dev, + uint8_t *pPowerMode); + +/** + * Set or over-hide part to part calibration offset + * \sa VL_DataInit() VL_GetOffsetCalibrationDataMicroMeter() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param OffsetCalibrationDataMicroMeter Offset (microns) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetOffsetCalibrationDataMicroMeter( + struct vl_data *Dev, int32_t OffsetCalibrationDataMicroMeter); + +/** + * @brief Get part to part calibration offset + * + * @par Function Description + * Should only be used after a successful call to @a VL_DataInit to backup + * device NVM value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pOffsetCalibrationDataMicroMeter Return part to part + * calibration offset from device (microns) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetOffsetCalibrationDataMicroMeter( + struct vl_data *Dev, int32_t *pOffsetCalibrationDataMicroMeter); + +/** + * Set the linearity corrective gain + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LinearityCorrectiveGain Linearity corrective + * gain in x1000 + * if value is 1000 then no modification is applied. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev, + int16_t LinearityCorrectiveGain); + +/** + * @brief Get the linearity corrective gain + * + * @par Function Description + * Should only be used after a successful call to @a VL_DataInit to backup + * device NVM value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pLinearityCorrectiveGain Pointer to the linearity + * corrective gain in x1000 + * if value is 1000 then no modification is applied. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev, + uint16_t *pLinearityCorrectiveGain); + +/** + * Set Group parameter Hold state + * + * @par Function Description + * Set or remove device internal group parameter hold + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param GroupParamHold Group parameter Hold state to be set (on/off) + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_SetGroupParamHold(struct vl_data *Dev, + uint8_t GroupParamHold); + +/** + * @brief Get the maximal distance for actual setup + * @par Function Description + * Device must be initialized through @a VL_SetParameters() prior calling + * this function. + * + * Any range value more than the value returned is to be considered as + * "no target detected" or + * "no target in detectable range"\n + * @warning The maximal distance depends on the setup + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param pUpperLimitMilliMeter The maximal range limit for actual setup + * (in millimeter) + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev, + uint16_t *pUpperLimitMilliMeter); + + +/** + * @brief Get the Total Signal Rate + * @par Function Description + * This function will return the Total Signal Rate after a good ranging is done. + * + * @note This function access to Device + * + * @param Dev Device Handle + * @param pTotalSignalRate Total Signal Rate value in Mega count per second + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_GetTotalSignalRate(struct vl_data *Dev, + unsigned int *pTotalSignalRate); + +/** @} VL_general_group */ + +/** @defgroup VL_init_group VL53L0X Init Functions + * @brief VL53L0X Init Functions + * @{ + */ + +/** + * @brief Set new device address + * + * After completion the device will answer to the new address programmed. + * This function should be called when several devices are used in parallel + * before start programming the sensor. + * When a single device us used, there is no need to call this function. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param DeviceAddress The new Device address + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetDeviceAddress(struct vl_data *Dev, + uint8_t DeviceAddress); + +/** + * + * @brief One time device initialization + * + * To be called once and only once after device is brought out of reset + * (Chip enable) and booted see @a VL_WaitDeviceBooted() + * + * @par Function Description + * When not used after a fresh device "power up" or reset, it may return + * @a #VL_ERROR_CALIBRATION_WARNING meaning wrong calibration data + * may have been fetched from device that can result in ranging offset error\n + * If application cannot execute device reset or need to run VL_DataInit + * multiple time then it must ensure proper offset calibration saving and + * restore on its own by using @a VL_GetOffsetCalibrationData() on first + * power up and then @a VL_SetOffsetCalibrationData() in all subsequent + * init. + * This function will change the uint8_t from VL_STATE_POWERDOWN to + * VL_STATE_WAIT_STATICINIT. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_DataInit(struct vl_data *Dev); + +/** + * @brief Set the tuning settings pointer + * + * This function is used to specify the Tuning settings buffer to be used + * for a given device. The buffer contains all the necessary data to permit + * the API to write tuning settings. + * This function permit to force the usage of either external or internal + * tuning settings. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pTuningSettingBuffer Pointer to tuning settings buffer. + * @param UseInternalTuningSettings Use internal tuning settings value. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings); + +/** + * @brief Get the tuning settings pointer and the internal external switch + * value. + * + * This function is used to get the Tuning settings buffer pointer and the + * value. + * of the switch to select either external or internal tuning settings. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param ppTuningSettingBuffer Pointer to tuning settings buffer. + * @param pUseInternalTuningSettings Pointer to store Use internal tuning + * settings value. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev, + uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings); + +/** + * @brief Do basic device init (and eventually patch loading) + * This function will change the uint8_t from + * VL_STATE_WAIT_STATICINIT to VL_STATE_IDLE. + * In this stage all default setting will be applied. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_StaticInit(struct vl_data *Dev); + +/** + * @brief Wait for device booted after chip enable (hardware standby) + * This function can be run only when uint8_t is VL_STATE_POWERDOWN. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + * + */ +VL_API int8_t VL_WaitDeviceBooted(struct vl_data *Dev); + +/** + * @brief Do an hard reset or soft reset (depending on implementation) of the + * device \nAfter call of this function, device must be in same state as right + * after a power-up sequence.This function will change the uint8_t to + * VL_STATE_POWERDOWN. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_ResetDevice(struct vl_data *Dev); + +/** @} VL_init_group */ + +/** @defgroup VL_parameters_group VL53L0X Parameters Functions + * @brief Functions used to prepare and setup the device + * @{ + */ + +/** + * @brief Prepare device for operation + * @par Function Description + * Update device with provided parameters + * @li Then start ranging operation. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pDeviceParameters Pointer to store current device parameters. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetDeviceParameters(struct vl_data *Dev, + const struct VL_DeviceParameters_t *pDeviceParameters); + +/** + * @brief Retrieve current device parameters + * @par Function Description + * Get actual parameters of the device + * @li Then start ranging operation. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pDeviceParameters Pointer to store current device parameters. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceParameters(struct vl_data *Dev, + struct VL_DeviceParameters_t *pDeviceParameters); + +/** + * @brief Set a new device mode + * @par Function Description + * Set device to a new mode (ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param DeviceMode New device mode to apply + * Valid values are: + * VL_DEVICEMODE_SINGLE_RANGING + * VL_DEVICEMODE_CONTINUOUS_RANGING + * VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING + * VL_DEVICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when DeviceMode is + * not in the supported list + */ +VL_API int8_t VL_SetDeviceMode(struct vl_data *Dev, + uint8_t DeviceMode); + +/** + * @brief Get current new device mode + * @par Function Description + * Get actual mode of the device(ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pDeviceMode Pointer to current apply mode value + * Valid values are: + * VL_DEVICEMODE_SINGLE_RANGING + * VL_DEVICEMODE_CONTINUOUS_RANGING + * VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING + * VL_DEVICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode is not in the supported list + */ +VL_API int8_t VL_GetDeviceMode(struct vl_data *Dev, + uint8_t *pDeviceMode); + +/** + * @brief Sets the resolution of range measurements. + * @par Function Description + * Set resolution of range measurements to either 0.25mm if + * fraction enabled or 1mm if not enabled. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param Enable Enable high resolution + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetRangeFractionEnable(struct vl_data *Dev, + uint8_t Enable); + +/** + * @brief Gets the fraction enable parameter indicating the resolution of + * range measurements. + * + * @par Function Description + * Gets the fraction enable state, which translates to the resolution of + * range measurements as follows :Enabled:=0.25mm resolution, + * Not Enabled:=1mm resolution. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pEnable Output Parameter reporting the fraction enable state. + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetFractionEnable(struct vl_data *Dev, + uint8_t *pEnable); + +/** + * @brief Set a new Histogram mode + * @par Function Description + * Set device to a new Histogram mode + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param HistogramMode New device mode to apply + * Valid values are: + * VL_HISTOGRAMMODE_DISABLED + * struct vl_data *ICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when + * HistogramMode is not in the supported list + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetHistogramMode(struct vl_data *Dev, + uint8_t HistogramMode); + +/** + * @brief Get current new device mode + * @par Function Description + * Get current Histogram mode of a Device + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pHistogramMode Pointer to current Histogram Mode value + * Valid values are: + * VL_HISTOGRAMMODE_DISABLED + * struct vl_data *ICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetHistogramMode(struct vl_data *Dev, + uint8_t *pHistogramMode); + +/** + * @brief Set Ranging Timing Budget in microseconds + * + * @par Function Description + * Defines the maximum time allowed by the user to the device to run a + * full ranging sequence for the current mode (ranging, histogram, ASL ...) + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param MeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * Valid values are: + * >= 17000 microsecs when wraparound enabled + * >= 12000 microsecs when wraparound disabled + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned if + MeasurementTimingBudgetMicroSeconds out of range + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetMeasurementTimingBudgetMicroSeconds( + struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +/** + * @brief Get Ranging Timing Budget in microseconds + * + * @par Function Description + * Returns the programmed the maximum time allowed by the user to the + * device to run a full ranging sequence for the current mode + * (ranging, histogram, ASL ...) + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * Valid values are: + * >= 17000 microsecs when wraparound enabled + * >= 12000 microsecs when wraparound disabled + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetMeasurementTimingBudgetMicroSeconds( + struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + +/** + * @brief Gets the VCSEL pulse period. + * + * @par Function Description + * This function retrieves the VCSEL pulse period for the given period type. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param VcselPeriodType VCSEL period identifier (pre-range|final). + * @param pVCSELPulsePeriod Pointer to VCSEL period value. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriod); + +/** + * @brief Sets the VCSEL pulse period. + * + * @par Function Description + * This function retrieves the VCSEL pulse period for the given period type. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param VcselPeriodType VCSEL period identifier (pre-range|final). + * @param VCSELPulsePeriod VCSEL period value + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriod); + +/** + * @brief Sets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function enables/disables a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param SequenceStepEnabled Demanded state {0=Off,1=On} + * is enabled. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t SequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function retrieves the state of a requested sequence step, i.e. on/off. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepEnabled Out parameter reporting if the sequence step + * is enabled {0=Off,1=On}. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of all sequence steps. + * + * @par Function Description + * This function retrieves the state of all sequence step in the scheduler. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pSchedulerSequenceSteps Pointer to struct containing result. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepEnables(struct vl_data *Dev, + struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps); + +/** + * @brief Sets the timeout of a requested sequence step. + * + * @par Function Description + * This function sets the timeout of a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param TimeOutMilliSecs Demanded timeout + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, unsigned int TimeOutMilliSecs); + +/** + * @brief Gets the timeout of a requested sequence step. + * + * @par Function Description + * This function retrieves the timeout of a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pTimeOutMilliSecs Timeout value. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int *pTimeOutMilliSecs); + +/** + * @brief Gets number of sequence steps managed by the API. + * + * @par Function Description + * This function retrieves the number of sequence steps currently managed + * by the API + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pNumberOfSequenceSteps Out parameter reporting the number of + * sequence steps. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev, + uint8_t *pNumberOfSequenceSteps); + +/** + * @brief Gets the name of a given sequence step. + * + * @par Function Description + * This function retrieves the name of sequence steps corresponding to + * SequenceStepId. + * + * @note This function doesn't Accesses the device + * + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepsString Pointer to Info string + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepsInfo( + uint8_t SequenceStepId, char *pSequenceStepsString); + +/** + * Program continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetInterMeasurementPeriodMilliSeconds( + struct vl_data *Dev, uint32_t InterMeasurementPeriodMilliSeconds); + +/** + * Get continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed + * Inter-Measurement Period in milliseconds. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetInterMeasurementPeriodMilliSeconds( + struct vl_data *Dev, uint32_t *pInterMeasurementPeriodMilliSeconds); + +/** + * @brief Enable/Disable Cross talk compensation feature + * + * @note This function is not Implemented. + * Enable/Disable Cross Talk by set to zero the Cross Talk value + * by using @a VL_SetXTalkCompensationRateMegaCps(). + * + * @param Dev Device Handle + * @param XTalkCompensationEnable Cross talk compensation + * to be set 0=disabled else = enabled + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t XTalkCompensationEnable); + +/** + * @brief Get Cross talk compensation rate + * + * @note This function is not Implemented. + * Enable/Disable Cross Talk by set to zero the Cross Talk value by + * using @a VL_SetXTalkCompensationRateMegaCps(). + * + * @param Dev Device Handle + * @param pXTalkCompensationEnable Pointer to the Cross talk compensation + * state 0=disabled or 1 = enabled + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t *pXTalkCompensationEnable); + +/** + * @brief Set Cross talk compensation rate + * + * @par Function Description + * Set Cross talk compensation rate. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param XTalkCompensationRateMegaCps Compensation rate in + * Mega counts per second (16.16 fix point) see datasheet for details + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetXTalkCompensationRateMegaCps( + struct vl_data *Dev, unsigned int XTalkCompensationRateMegaCps); + +/** + * @brief Get Cross talk compensation rate + * + * @par Function Description + * Get Cross talk compensation rate. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pXTalkCompensationRateMegaCps Pointer to Compensation rate + in Mega counts per second (16.16 fix point) see datasheet for details + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetXTalkCompensationRateMegaCps( + struct vl_data *Dev, unsigned int *pXTalkCompensationRateMegaCps); + +/** + * @brief Set Reference Calibration Parameters + * + * @par Function Description + * Set Reference Calibration Parameters. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param VhvSettings Parameter for VHV + * @param PhaseCal Parameter for PhaseCal + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetRefCalibration(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal); + +/** + * @brief Get Reference Calibration Parameters + * + * @par Function Description + * Get Reference Calibration Parameters. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVhvSettings Pointer to VHV parameter + * @param pPhaseCal Pointer to PhaseCal Parameter + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetRefCalibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + +/** + * @brief Get the number of the check limit managed by a given Device + * + * @par Function Description + * This function give the number of the check limit managed by the Device + * + * @note This function doesn't Access to the device + * + * @param pNumberOfLimitCheck Pointer to the number of check limit. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetNumberOfLimitCheck( + uint16_t *pNumberOfLimitCheck); + +/** + * @brief Return a description string for a given limit check number + * + * @par Function Description + * This function returns a description string for a given limit check number. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckString Pointer to the + description string of the given check limit. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is + returned when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckInfo(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString); + +/** + * @brief Return a the Status of the specified check limit + * + * @par Function Description + * This function returns the Status of the specified check limit. + * The value indicate if the check is fail or not. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckStatus Pointer to the + Limit Check Status of the given check limit. + * LimitCheckStatus : + * 0 the check is not fail + * 1 the check if fail or not enabled + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is + returned when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckStatus(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus); + +/** + * @brief Enable/Disable a specific limit check + * + * @par Function Description + * This function Enable/Disable a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param LimitCheckEnable if 1 the check limit + * corresponding to LimitCheckId is Enabled + * if 0 the check limit + * corresponding to LimitCheckId is disabled + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable); + +/** + * @brief Get specific limit check enable state + * + * @par Function Description + * This function get the enable state of a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckEnable Pointer to the check limit enable + * value. + * if 1 the check limit + * corresponding to LimitCheckId is Enabled + * if 0 the check limit + * corresponding to LimitCheckId is disabled + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + +/** + * @brief Set a specific limit check value + * + * @par Function Description + * This function set a specific limit check value. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param LimitCheckValue Limit check Value for a given + * LimitCheckId + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned when either + * LimitCheckId or LimitCheckValue value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetLimitCheckValue(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int LimitCheckValue); + +/** + * @brief Get a specific limit check value + * + * @par Function Description + * This function get a specific limit check value from device then it updates + * internal values and check enables. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckValue Pointer to Limit + * check Value for a given LimitCheckId. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckValue(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckValue); + +/** + * @brief Get the current value of the signal used for the limit check + * + * @par Function Description + * This function get a the current value of the signal used for the limit check. + * To obtain the latest value you should run a ranging before. + * The value reported is linked to the limit check identified with the + * LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckCurrent Pointer to current Value for a + * given LimitCheckId. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned when + * LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent); + +/** + * @brief Enable (or disable) Wrap around Check + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param WrapAroundCheckEnable Wrap around Check to be set + * 0=disabled, other = enabled + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t WrapAroundCheckEnable); + +/** + * @brief Get setup of Wrap around Check + * + * @par Function Description + * This function get the wrapAround check enable parameters + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pWrapAroundCheckEnable Pointer to the Wrap around Check state + * 0=disabled or 1 = enabled + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t *pWrapAroundCheckEnable); + +/** + * @brief Set Dmax Calibration Parameters for a given device + * When one of the parameter is zero, this function will get parameter + * from NVM. + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param RangeMilliMeter Calibration Distance + * @param SignalRateRtnMegaCps Signal rate return read at CalDistance + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetDmaxCalParameters(struct vl_data *Dev, + uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps); + +/** + * @brief Get Dmax Calibration Parameters for a given device + * + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pRangeMilliMeter Pointer to Calibration Distance + * @param pSignalRateRtnMegaCps Pointer to Signal rate return + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDmaxCalParameters(struct vl_data *Dev, + uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps); + +/** @} VL_parameters_group */ + +/** @defgroup VL_measurement_group VL53L0X Measurement Functions + * @brief Functions used for the measurements + * @{ + */ + +/** + * @brief Single shot measurement. + * + * @par Function Description + * Perform simple measurement sequence (Start measure, Wait measure to end, + * and returns when measurement is done). + * Once function returns, user can get valid data by calling + * VL_GetRangingMeasurement or VL_GetHistogramMeasurement + * depending on defined measurement mode + * User should Clear the interrupt in case this are enabled by using the + * function VL_ClearInterruptMask(). + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformSingleMeasurement(struct vl_data *Dev); + +/** + * @brief Perform Reference Calibration + * + * @details Perform a reference calibration of the Device. + * This function should be run from time to time before doing + * a ranging measurement. + * This function will launch a special ranging measurement, so + * if interrupt are enable an interrupt will be done. + * This function will clear the interrupt generated automatically. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVhvSettings Pointer to vhv settings parameter. + * @param pPhaseCal Pointer to PhaseCal parameter. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformRefCalibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + +/** + * @brief Perform XTalk Measurement + * + * @details Measures the current cross talk from glass in front + * of the sensor. + * This functions performs a histogram measurement and uses the results + * to measure the crosstalk. For the function to be successful, there + * must be no target in front of the sensor. + * + * @warning This function is a blocking function + * + * @warning This function is not supported when the final range + * vcsel clock period is set below 10 PCLKS. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param TimeoutMs Histogram measurement duration. + * @param pXtalkPerSpad Output parameter containing the crosstalk + * measurement result, in MCPS/Spad. Format fixpoint 16:16. + * @param pAmbientTooHigh Output parameter which indicate that + * pXtalkPerSpad is not good if the Ambient is too high. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS vcsel clock period not supported + * for this operation. Must not be less than 10PCLKS. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev, + uint32_t TimeoutMs, unsigned int *pXtalkPerSpad, + uint8_t *pAmbientTooHigh); + +/** + * @brief Perform XTalk Calibration + * + * @details Perform a XTalk calibration of the Device. + * This function will launch a ranging measurement, if interrupts + * are enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the XTalk compensation + * and it will enable the cross talk before exit. + * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @note This function change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING + * + * @param Dev Device Handle + * @param XTalkCalDistance XTalkCalDistance value used for the XTalk + * computation. + * @param pXTalkCompensationRateMegaCps Pointer to new + * XTalkCompensation value. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformXTalkCalibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps); + +/** + * @brief Perform Offset Calibration + * + * @details Perform a Offset calibration of the Device. + * This function will launch a ranging measurement, if interrupts are + * enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the Offset calibration value + * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @note This function does not change the device mode. + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * @param pOffsetMicroMeter Pointer to new Offset value computed by the + * function. + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformOffsetCalibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter); + +/** + * @brief Start device measurement + * + * @details Started measurement will depend on device parameters set through + * @a VL_SetParameters() + * This is a non-blocking function. + * This function will change the uint8_t from VL_STATE_IDLE to + * VL_STATE_RUNNING. + * + * @note This function Access to the device + * + + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode programmed with @a VL_SetDeviceMode is not in the supported + * list: + * Supported mode are: + * struct vl_data *ICEMODE_SINGLE_RANGING, + * struct vl_data *ICEMODE_CONTINUOUS_RANGING, + * struct vl_data *ICEMODE_CONTINUOUS_TIMED_RANGING + * @return VL_ERROR_TIME_OUT Time out on start measurement + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_StartMeasurement(struct vl_data *Dev); + +/** + * @brief Stop device measurement + * + * @details Will set the device in standby mode at end of current measurement\n + * Not necessary in single mode as device shall return automatically + * in standby mode at end of measurement. + * This function will change the uint8_t from + * VL_STATE_RUNNING to VL_STATE_IDLE. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_StopMeasurement(struct vl_data *Dev); + +/** + * @brief Return Measurement Data Ready + * + * @par Function Description + * This function indicate that a measurement data is ready. + * This function check if interrupt mode is used then check is done accordingly. + * If perform function clear the interrupt, this function will not work, + * like in case of @a VL_PerformSingleRangingMeasurement(). + * The previous function is blocking function, VL_GetMeasurementDataReady + * is used for non-blocking capture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementDataReady Pointer to Measurement Data Ready. + * 0=data not ready, 1 = data ready + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetMeasurementDataReady(struct vl_data *Dev, + uint8_t *pMeasurementDataReady); + +/** + * @brief Wait for device ready for a new measurement command. + * Blocking function. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param MaxLoop Max Number of polling loop (timeout). + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_WaitDeviceReadyForNewMeasurement( + struct vl_data *Dev, uint32_t MaxLoop); + +/** + * @brief Retrieve the Reference Signal after a measurements + * + * @par Function Description + * Get Reference Signal from last successful Ranging measurement + * This function return a valid value after that you call the + * @a VL_GetRangingMeasurementData(). + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementRefSignal Pointer to the Ref Signal to fill up. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev, + unsigned int *pMeasurementRefSignal); + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + * @warning USER should take care about @a VL_GetNumberOfROIZones() + * before get data. + * PAL will fill a NumberOfROIZones times the corresponding data + * structure used in the measurement function. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetRangingMeasurementData(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Histogram measurement + * @warning USER should take care about @a VL_GetNumberOfROIZones() + * before get data. + * PAL will fill a NumberOfROIZones times the corresponding data structure + * used in the measurement function. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param pHistogramMeasurementData Pointer to the histogram data structure. + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + +/** + * @brief Performs a single ranging measurement and retrieve the ranging + * measurement data + * + * @par Function Description + * This function will change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING with @a VL_SetDeviceMode(), + * It performs measurement with @a VL_PerformSingleMeasurement() + * It get data from last successful Ranging measurement with + * @a VL_GetRangingMeasurementData. + * Finally it clear the interrupt with @a VL_ClearInterruptMask(). + * + * @note This function Access to the device + * + * @note This function change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformSingleRangingMeasurement( + struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Performs a single histogram measurement and retrieve the histogram + * measurement data + * Is equivalent to VL_PerformSingleMeasurement + + * VL_GetHistogramMeasurementData + * + * @par Function Description + * Get data from last successful Ranging measurement. + * This function will clear the interrupt in case of these are enabled. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param pHistogramMeasurementData Pointer to the data structure to fill up. + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_PerformSingleHistogramMeasurement( + struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + +/** + * @brief Set the number of ROI Zones to be used for a specific Device + * + * @par Function Description + * Set the number of ROI Zones to be used for a specific Device. + * The programmed value should be less than the max number of ROI Zones given + * with @a VL_GetMaxNumberOfROIZones(). + * This version of API manage only one zone. + * + * @param Dev Device Handle + * @param NumberOfROIZones Number of ROI Zones to be used for a + * specific Device. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned if + * NumberOfROIZones != 1 + */ +VL_API int8_t VL_SetNumberOfROIZones(struct vl_data *Dev, + uint8_t NumberOfROIZones); + +/** + * @brief Get the number of ROI Zones managed by the Device + * + * @par Function Description + * Get number of ROI Zones managed by the Device + * USER should take care about @a VL_GetNumberOfROIZones() + * before get data after a perform measurement. + * PAL will fill a NumberOfROIZones times the corresponding data + * structure used in the measurement function. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pNumberOfROIZones Pointer to the Number of ROI Zones value. + * @return VL_ERROR_NONE Success + */ +VL_API int8_t VL_GetNumberOfROIZones(struct vl_data *Dev, + uint8_t *pNumberOfROIZones); + +/** + * @brief Get the Maximum number of ROI Zones managed by the Device + * + * @par Function Description + * Get Maximum number of ROI Zones managed by the Device. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pMaxNumberOfROIZones Pointer to the Maximum Number + * of ROI Zones value. + * @return VL_ERROR_NONE Success + */ +VL_API int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev, + uint8_t *pMaxNumberOfROIZones); + +/** @} VL_measurement_group */ + +/** @defgroup VL_interrupt_group VL53L0X Interrupt Functions + * @brief Functions used for interrupt managements + * @{ + */ + +/** + * @brief Set the configuration of GPIO pin for a given device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param Pin ID of the GPIO Pin + * @param Functionality Select Pin functionality. + * Refer to ::uint8_t + * @param DeviceMode Device Mode associated to the Gpio. + * @param Polarity Set interrupt polarity. Active high + * or active low see ::uint8_t + * @return VL_ERROR_NONE Success + * @return VL_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted. + * @return VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs + * when Functionality programmed is not in the supported list: + * Supported value are: + * VL_GPIOFUNCTIONALITY_OFF, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH, + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT, + * VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t DeviceMode, uint8_t Functionality, + uint8_t Polarity); + +/** + * @brief Get current configuration for GPIO pin for a given device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param Pin ID of the GPIO Pin + * @param pDeviceMode Pointer to Device Mode associated to the Gpio. + * @param pFunctionality Pointer to Pin functionality. + * Refer to ::uint8_t + * @param pPolarity Pointer to interrupt polarity. + * Active high or active low see ::uint8_t + * @return VL_ERROR_NONE Success + * @return VL_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted. + * @return VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs + * when Functionality programmed is not in the supported list: + * Supported value are: + * VL_GPIOFUNCTIONALITY_OFF, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT, + * VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t *pDeviceMode, + uint8_t *pFunctionality, + uint8_t *pPolarity); + +/** + * @brief Set low and high Interrupt thresholds for a given mode + * (ranging, ALS, ...) for a given device + * + * @par Function Description + * Set low and high Interrupt thresholds for a given mode (ranging, ALS, ...) + * for a given device + * + * @note This function Access to the device + * + * @note DeviceMode is ignored for the current device + * + * @param Dev Device Handle + * @param DeviceMode Device Mode for which change thresholds + * @param ThresholdLow Low threshold (mm, lux ..., depending on the mode) + * @param ThresholdHigh High threshold (mm, lux ..., depending on the mode) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int ThresholdLow, + unsigned int ThresholdHigh); + +/** + * @brief Get high and low Interrupt thresholds for a given mode + * (ranging, ALS, ...) for a given device + * + * @par Function Description + * Get high and low Interrupt thresholds for a given mode (ranging, ALS, ...) + * for a given device + * + * @note This function Access to the device + * + * @note DeviceMode is ignored for the current device + * + * @param Dev Device Handle + * @param DeviceMode Device Mode from which read thresholds + * @param pThresholdLow Low threshold (mm, lux ..., depending on the mode) + * @param pThresholdHigh High threshold (mm, lux ..., depending on the mode) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int *pThresholdLow, + unsigned int *pThresholdHigh); + +/** + * @brief Return device stop completion status + * + * @par Function Description + * Returns stop completiob status. + * User shall call this function after a stop command + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pStopStatus Pointer to status variable to update + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetStopCompletedStatus(struct vl_data *Dev, + uint32_t *pStopStatus); + + +/** + * @brief Clear given system interrupt condition + * + * @par Function Description + * Clear given interrupt(s). + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param InterruptMask Mask of interrupts to clear + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INTERRUPT_NOT_CLEARED Cannot clear interrupts + * + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_ClearInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask); + +/** + * @brief Return device interrupt status + * + * @par Function Description + * Returns currently raised interrupts by the device. + * User shall be able to activate/deactivate interrupts through + * @a VL_SetGpioConfig() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pInterruptMaskStatus Pointer to status variable to update + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev, + uint32_t *pInterruptMaskStatus); + +/** + * @brief Configure ranging interrupt reported to system + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param InterruptMask Mask of interrupt to Enable/disable + * (0:interrupt disabled or 1: interrupt enabled) + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_EnableInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask); + +/** @} VL_interrupt_group */ + +/** @defgroup VL_SPADfunctions_group VL53L0X SPAD Functions + * @brief Functions used for SPAD managements + * @{ + */ + +/** + * @brief Set the SPAD Ambient Damper Threshold value + * + * @par Function Description + * This function set the SPAD Ambient Damper Threshold value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param SpadAmbientDamperThreshold SPAD Ambient Damper Threshold value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t SpadAmbientDamperThreshold); + +/** + * @brief Get the current SPAD Ambient Damper Threshold value + * + * @par Function Description + * This function get the SPAD Ambient Damper Threshold value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pSpadAmbientDamperThreshold Pointer to programmed + * SPAD Ambient Damper Threshold value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperThreshold); + +/** + * @brief Set the SPAD Ambient Damper Factor value + * + * @par Function Description + * This function set the SPAD Ambient Damper Factor value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param SpadAmbientDamperFactor SPAD Ambient Damper Factor value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t SpadAmbientDamperFactor); + +/** + * @brief Get the current SPAD Ambient Damper Factor value + * + * @par Function Description + * This function get the SPAD Ambient Damper Factor value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pSpadAmbientDamperFactor Pointer to programmed SPAD Ambient + * Damper Factor value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperFactor); + +/** + * @brief Performs Reference Spad Management + * + * @par Function Description + * The reference SPAD initialization procedure determines the minimum amount + * of reference spads to be enables to achieve a target reference signal rate + * and should be performed once during initialization. + * + * @note This function Access to the device + * + * @note This function change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING + * + * @param Dev Device Handle + * @param refSpadCount Reports ref Spad Count + * @param isApertureSpads Reports if spads are of type + * aperture or non-aperture. + * 1:=aperture, 0:=Non-Aperture + * @return VL_ERROR_NONE Success + * @return VL_ERROR_REF_SPAD_INIT Error in the Ref Spad procedure. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformRefSpadManagement(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + +/** + * @brief Applies Reference SPAD configuration + * + * @par Function Description + * This function applies a given number of reference spads, identified as + * either Aperture or Non-Aperture. + * The requested spad count and type are stored within the device specific + * parameters data for access by the host. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param refSpadCount Number of ref spads. + * @param isApertureSpads Defines if spads are of type + * aperture or non-aperture. + * 1:=aperture, 0:=Non-Aperture + * @return VL_ERROR_NONE Success + * @return VL_ERROR_REF_SPAD_INIT Error in the in the reference + * spad configuration. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetReferenceSpads(struct vl_data *Dev, + uint32_t refSpadCount, uint8_t isApertureSpads); + +/** + * @brief Retrieves SPAD configuration + * + * @par Function Description + * This function retrieves the current number of applied reference spads + * and also their type : Aperture or Non-Aperture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param refSpadCount Number ref Spad Count + * @param isApertureSpads Reports if spads are of type + * aperture or non-aperture. + * 1:=aperture, 0:=Non-Aperture + * @return VL_ERROR_NONE Success + * @return VL_ERROR_REF_SPAD_INIT Error in the in the reference + * spad configuration. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetReferenceSpads(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + +/** @} VL_SPADfunctions_group */ + +/** @} VL_cut11_group */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h new file mode 100644 index 0000000000000000000000000000000000000000..556a25b494f3e869d3d5f3ad20a5ace9e7df531a --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h @@ -0,0 +1,76 @@ +/* + * vl53l0x_api_calibration.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#ifndef _VL_API_CALIBRATION_H_ +#define _VL_API_CALIBRATION_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +int8_t VL_perform_xtalk_calibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps); + +int8_t VL_perform_offset_calibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, + int32_t *pOffsetMicroMeter); + +int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter); + +int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter); + +int8_t VL_apply_offset_adjustment(struct vl_data *Dev); + +int8_t VL_perform_ref_spad_management(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + +int8_t VL_set_reference_spads(struct vl_data *Dev, + uint32_t count, uint8_t isApertureSpads); + +int8_t VL_get_reference_spads(struct vl_data *Dev, + uint32_t *pSpadCount, uint8_t *pIsApertureSpads); + +int8_t VL_perform_phase_calibration(struct vl_data *Dev, + uint8_t *pPhaseCal, const uint8_t get_data_enable, + const uint8_t restore_config); + +int8_t VL_perform_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable); + +int8_t VL_set_ref_calibration(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal); + +int8_t VL_get_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + + + + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_CALIBRATION_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h new file mode 100644 index 0000000000000000000000000000000000000000..a21ec47a69b0e8a4547786757a128a85ad9db84a --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h @@ -0,0 +1,100 @@ +/* + * vl53l0x_api_calibration.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +#ifndef _VL_API_CORE_H_ +#define _VL_API_CORE_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +int8_t VL_reverse_bytes(uint8_t *data, uint32_t size); + +int8_t VL_measurement_poll_for_completion(struct vl_data *Dev); + +uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks); + +uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg); + +uint32_t VL_isqrt(uint32_t num); + +uint32_t VL_quadrature_sum(uint32_t a, uint32_t b); + +int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option); + +int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK); + +int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK); + +uint32_t VL_decode_timeout(uint16_t encoded_timeout); + +int8_t get_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t *pTimeOutMicroSecs); + +int8_t set_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t TimeOutMicroSecs); + +int8_t VL_set_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +int8_t VL_get_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + +int8_t VL_load_tuning_settings(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer); + +int8_t VL_calc_sigma_estimate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *pSigmaEstimate, uint32_t *pDmax_mm); + +int8_t VL_get_total_xtalk_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_xtalk_rate_mcps); + +int8_t VL_get_total_signal_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_signal_rate_mcps); + +int8_t VL_get_pal_range_status(struct vl_data *Dev, + uint8_t DeviceRangeStatus, + unsigned int SignalRate, + uint16_t EffectiveSpadRtnCount, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + uint8_t *pPalRangeStatus); + +uint32_t VL_calc_timeout_mclks(struct vl_data *Dev, + uint32_t timeout_period_us, uint8_t vcsel_period_pclks); + +uint16_t VL_encode_timeout(uint32_t timeout_macro_clks); + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_CORE_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h new file mode 100644 index 0000000000000000000000000000000000000000..6009d1ad8d16e572abdcf936a413453cadbc9bfc --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h @@ -0,0 +1,38 @@ +/* + * vl53l0x_api_ranging.h - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#ifndef _VL_API_RANGING_H_ +#define _VL_API_RANGING_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_RANGING_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h new file mode 100644 index 0000000000000000000000000000000000000000..33b40233e1422a77a30f4865138f9859fd8d499a --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h @@ -0,0 +1,269 @@ +/* + * vl53l0x_api_string.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +#ifndef VL_API_STRINGS_H_ +#define VL_API_STRINGS_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +int8_t VL_get_device_info(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo); + +int8_t VL_get_device_error_string(uint8_t ErrorCode, + char *pDeviceErrorString); + +int8_t VL_get_range_status_string(uint8_t RangeStatus, + char *pRangeStatusString); + +int8_t VL_get_pal_error_string(int8_t PalErrorCode, + char *pPalErrorString); + +int8_t VL_get_pal_state_string(uint8_t PalStateCode, + char *pPalStateString); + +int8_t VL_get_sequence_steps_info( + uint8_t SequenceStepId, + char *pSequenceStepsString); + +int8_t VL_get_limit_check_info(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString); + + +#ifdef USE_EMPTY_STRING + #define VL_STRING_DEVICE_INFO_NAME "" + #define VL_STRING_DEVICE_INFO_NAME_TS0 "" + #define VL_STRING_DEVICE_INFO_NAME_TS1 "" + #define VL_STRING_DEVICE_INFO_NAME_TS2 "" + #define VL_STRING_DEVICE_INFO_NAME_ES1 "" + #define VL_STRING_DEVICE_INFO_TYPE "" + + /* PAL ERROR strings */ + #define VL_STRING_ERROR_NONE "" + #define VL_STRING_ERROR_CALIBRATION_WARNING "" + #define VL_STRING_ERROR_MIN_CLIPPED "" + #define VL_STRING_ERROR_UNDEFINED "" + #define VL_STRING_ERROR_INVALID_PARAMS "" + #define VL_STRING_ERROR_NOT_SUPPORTED "" + #define VL_STRING_ERROR_RANGE_ERROR "" + #define VL_STRING_ERROR_TIME_OUT "" + #define VL_STRING_ERROR_MODE_NOT_SUPPORTED "" + #define VL_STRING_ERROR_BUFFER_TOO_SMALL "" + #define VL_STRING_ERROR_GPIO_NOT_EXISTING "" + #define VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED "" + #define VL_STRING_ERROR_CONTROL_INTERFACE "" + #define VL_STRING_ERROR_INVALID_COMMAND "" + #define VL_STRING_ERROR_DIVISION_BY_ZERO "" + #define VL_STRING_ERROR_REF_SPAD_INIT "" + #define VL_STRING_ERROR_NOT_IMPLEMENTED "" + + #define VL_STRING_UNKNOWN_ERROR_CODE "" + + + + /* Range Status */ + #define VL_STRING_RANGESTATUS_NONE "" + #define VL_STRING_RANGESTATUS_RANGEVALID "" + #define VL_STRING_RANGESTATUS_SIGMA "" + #define VL_STRING_RANGESTATUS_SIGNAL "" + #define VL_STRING_RANGESTATUS_MINRANGE "" + #define VL_STRING_RANGESTATUS_PHASE "" + #define VL_STRING_RANGESTATUS_HW "" + + + /* Range Status */ + #define VL_STRING_STATE_POWERDOWN "" + #define VL_STRING_STATE_WAIT_STATICINIT "" + #define VL_STRING_STATE_STANDBY "" + #define VL_STRING_STATE_IDLE "" + #define VL_STRING_STATE_RUNNING "" + #define VL_STRING_STATE_UNKNOWN "" + #define VL_STRING_STATE_ERROR "" + + + /* Device Specific */ + #define VL_STRING_DEVICEERROR_NONE "" + #define VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE "" + #define VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE "" + #define VL_STRING_DEVICEERROR_NOVHVVALUEFOUND "" + #define VL_STRING_DEVICEERROR_MSRCNOTARGET "" + #define VL_STRING_DEVICEERROR_SNRCHECK "" + #define VL_STRING_DEVICEERROR_RANGEPHASECHECK "" + #define VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK "" + #define VL_STRING_DEVICEERROR_TCC "" + #define VL_STRING_DEVICEERROR_PHASECONSISTENCY "" + #define VL_STRING_DEVICEERROR_MINCLIP "" + #define VL_STRING_DEVICEERROR_RANGECOMPLETE "" + #define VL_STRING_DEVICEERROR_ALGOUNDERFLOW "" + #define VL_STRING_DEVICEERROR_ALGOOVERFLOW "" + #define VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD "" + #define VL_STRING_DEVICEERROR_UNKNOWN "" + + /* Check Enable */ + #define VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE "" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE "" + #define VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP "" + #define VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD "" + + /* Sequence Step */ + #define VL_STRING_SEQUENCESTEP_TCC "" + #define VL_STRING_SEQUENCESTEP_DSS "" + #define VL_STRING_SEQUENCESTEP_MSRC "" + #define VL_STRING_SEQUENCESTEP_PRE_RANGE "" + #define VL_STRING_SEQUENCESTEP_FINAL_RANGE "" +#else + #define VL_STRING_DEVICE_INFO_NAME "VL53L0X cut1.0" + #define VL_STRING_DEVICE_INFO_NAME_TS0 "VL53L0X TS0" + #define VL_STRING_DEVICE_INFO_NAME_TS1 "VL53L0X TS1" + #define VL_STRING_DEVICE_INFO_NAME_TS2 "VL53L0X TS2" + #define VL_STRING_DEVICE_INFO_NAME_ES1 "VL53L0X ES1 or later" + #define VL_STRING_DEVICE_INFO_TYPE "VL53L0X" + + /* PAL ERROR strings */ + #define VL_STRING_ERROR_NONE \ + "No Error" + #define VL_STRING_ERROR_CALIBRATION_WARNING \ + "Calibration Warning Error" + #define VL_STRING_ERROR_MIN_CLIPPED \ + "Min clipped error" + #define VL_STRING_ERROR_UNDEFINED \ + "Undefined error" + #define VL_STRING_ERROR_INVALID_PARAMS \ + "Invalid parameters error" + #define VL_STRING_ERROR_NOT_SUPPORTED \ + "Not supported error" + #define VL_STRING_ERROR_RANGE_ERROR \ + "Range error" + #define VL_STRING_ERROR_TIME_OUT \ + "Time out error" + #define VL_STRING_ERROR_MODE_NOT_SUPPORTED \ + "Mode not supported error" + #define VL_STRING_ERROR_BUFFER_TOO_SMALL \ + "Buffer too small" + #define VL_STRING_ERROR_GPIO_NOT_EXISTING \ + "GPIO not existing" + #define VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \ + "GPIO funct not supported" + #define VL_STRING_ERROR_INTERRUPT_NOT_CLEARED \ + "Interrupt not Cleared" + #define VL_STRING_ERROR_CONTROL_INTERFACE \ + "Control Interface Error" + #define VL_STRING_ERROR_INVALID_COMMAND \ + "Invalid Command Error" + #define VL_STRING_ERROR_DIVISION_BY_ZERO \ + "Division by zero Error" + #define VL_STRING_ERROR_REF_SPAD_INIT \ + "Reference Spad Init Error" + #define VL_STRING_ERROR_NOT_IMPLEMENTED \ + "Not implemented error" + + #define VL_STRING_UNKNOWN_ERROR_CODE \ + "Unknown Error Code" + + + + /* Range Status */ + #define VL_STRING_RANGESTATUS_NONE "No Update" + #define VL_STRING_RANGESTATUS_RANGEVALID "Range Valid" + #define VL_STRING_RANGESTATUS_SIGMA "Sigma Fail" + #define VL_STRING_RANGESTATUS_SIGNAL "Signal Fail" + #define VL_STRING_RANGESTATUS_MINRANGE "Min Range Fail" + #define VL_STRING_RANGESTATUS_PHASE "Phase Fail" + #define VL_STRING_RANGESTATUS_HW "Hardware Fail" + + + /* Range Status */ + #define VL_STRING_STATE_POWERDOWN "POWERDOWN State" + #define VL_STRING_STATE_WAIT_STATICINIT \ + "Wait for staticinit State" + #define VL_STRING_STATE_STANDBY "STANDBY State" + #define VL_STRING_STATE_IDLE "IDLE State" + #define VL_STRING_STATE_RUNNING "RUNNING State" + #define VL_STRING_STATE_UNKNOWN "UNKNOWN State" + #define VL_STRING_STATE_ERROR "ERROR State" + + + /* Device Specific */ + #define VL_STRING_DEVICEERROR_NONE "No Update" + #define VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \ + "VCSEL Continuity Test Failure" + #define VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \ + "VCSEL Watchdog Test Failure" + #define VL_STRING_DEVICEERROR_NOVHVVALUEFOUND \ + "No VHV Value found" + #define VL_STRING_DEVICEERROR_MSRCNOTARGET \ + "MSRC No Target Error" + #define VL_STRING_DEVICEERROR_SNRCHECK \ + "SNR Check Exit" + #define VL_STRING_DEVICEERROR_RANGEPHASECHECK \ + "Range Phase Check Error" + #define VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK \ + "Sigma Threshold Check Error" + #define VL_STRING_DEVICEERROR_TCC \ + "TCC Error" + #define VL_STRING_DEVICEERROR_PHASECONSISTENCY \ + "Phase Consistency Error" + #define VL_STRING_DEVICEERROR_MINCLIP \ + "Min Clip Error" + #define VL_STRING_DEVICEERROR_RANGECOMPLETE \ + "Range Complete" + #define VL_STRING_DEVICEERROR_ALGOUNDERFLOW \ + "Range Algo Underflow Error" + #define VL_STRING_DEVICEERROR_ALGOOVERFLOW \ + "Range Algo Overlow Error" + #define VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD \ + "Range Ignore Threshold Error" + #define VL_STRING_DEVICEERROR_UNKNOWN \ + "Unknown error code" + + /* Check Enable */ + #define VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \ + "SIGMA FINAL RANGE" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \ + "SIGNAL RATE FINAL RANGE" + #define VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP \ + "SIGNAL REF CLIP" + #define VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \ + "RANGE IGNORE THRESHOLD" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC \ + "SIGNAL RATE MSRC" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE \ + "SIGNAL RATE PRE RANGE" + + /* Sequence Step */ + #define VL_STRING_SEQUENCESTEP_TCC "TCC" + #define VL_STRING_SEQUENCESTEP_DSS "DSS" + #define VL_STRING_SEQUENCESTEP_MSRC "MSRC" + #define VL_STRING_SEQUENCESTEP_PRE_RANGE "PRE RANGE" + #define VL_STRING_SEQUENCESTEP_FINAL_RANGE "FINAL RANGE" +#endif /* USE_EMPTY_STRING */ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h new file mode 100644 index 0000000000000000000000000000000000000000..4a94a97c8b7fdbc54d81d4abe36f1ab0dc8b93ab --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h @@ -0,0 +1,621 @@ +/* + * vl53l0x_api_def.h - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +/** + * @file VL_def.h + * + * @brief Type definitions for VL53L0X API. + * + */ + + +#ifndef _VL_DEF_H_ +#define _VL_DEF_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup VL_globaldefine_group VL53L0X Defines + * @brief VL53L0X Defines + * @{ + */ + + +/** PAL SPECIFICATION major version */ +#define VL53L0X10_SPECIFICATION_VER_MAJOR 1 +/** PAL SPECIFICATION minor version */ +#define VL53L0X10_SPECIFICATION_VER_MINOR 2 +/** PAL SPECIFICATION sub version */ +#define VL53L0X10_SPECIFICATION_VER_SUB 7 +/** PAL SPECIFICATION sub version */ +#define VL53L0X10_SPECIFICATION_VER_REVISION 1440 + +/** VL53L0X PAL IMPLEMENTATION major version */ +#define VL53L0X10_IMPLEMENTATION_VER_MAJOR 1 +/** VL53L0X PAL IMPLEMENTATION minor version */ +#define VL53L0X10_IMPLEMENTATION_VER_MINOR 0 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL53L0X10_IMPLEMENTATION_VER_SUB 9 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL53L0X10_IMPLEMENTATION_VER_REVISION 3673 + +/** PAL SPECIFICATION major version */ +#define VL_SPECIFICATION_VER_MAJOR 1 +/** PAL SPECIFICATION minor version */ +#define VL_SPECIFICATION_VER_MINOR 2 +/** PAL SPECIFICATION sub version */ +#define VL_SPECIFICATION_VER_SUB 7 +/** PAL SPECIFICATION sub version */ +#define VL_SPECIFICATION_VER_REVISION 1440 + +/** VL53L0X PAL IMPLEMENTATION major version */ +#define VL_IMPLEMENTATION_VER_MAJOR 1 +/** VL53L0X PAL IMPLEMENTATION minor version */ +#define VL_IMPLEMENTATION_VER_MINOR 0 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL_IMPLEMENTATION_VER_SUB 2 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL_IMPLEMENTATION_VER_REVISION 4823 +#define VL_DEFAULT_MAX_LOOP 2000 +#define VL_MAX_STRING_LENGTH 32 + + +#include "vl53l0x_device.h" +#include "vl53l0x_types.h" + + +/**************************************** + * PRIVATE define do not edit + ****************************************/ + +/** @brief Defines the parameters of the Get Version Functions + */ +struct VL_Version_t { + uint32_t revision; /*!< revision number */ + uint8_t major; /*!< major number */ + uint8_t minor; /*!< minor number */ + uint8_t build; /*!< build number */ +}; + + +/** @brief Defines the parameters of the Get Device Info Functions + */ +struct VL_DeviceInfo_t { + char Name[VL_MAX_STRING_LENGTH]; + /*!< Name of the Device e.g. Left_Distance */ + char Type[VL_MAX_STRING_LENGTH]; + /*!< Type of the Device e.g VL53L0X */ + char ProductId[VL_MAX_STRING_LENGTH]; + /*!< Product Identifier String */ + uint8_t ProductType; + /*!< Product Type, VL53L0X = 1, VL53L1 = 2 */ + uint8_t ProductRevisionMajor; + /*!< Product revision major */ + uint8_t ProductRevisionMinor; + /*!< Product revision minor */ +}; + + +/** @defgroup VL_define_Error_group Error and Warning code returned by API + * The following DEFINE are used to identify the PAL ERROR + * @{ + */ + +#define VL_ERROR_NONE ((int8_t) 0) +#define VL_ERROR_CALIBRATION_WARNING ((int8_t) -1) + /*!< Warning invalid calibration data may be in used + \a VL_InitData() + \a VL_GetOffsetCalibrationData + \a VL_SetOffsetCalibrationData */ +#define VL_ERROR_MIN_CLIPPED ((int8_t) -2) + /*!< Warning parameter passed was clipped to min before to be applied */ + +#define VL_ERROR_UNDEFINED ((int8_t) -3) + /*!< Unqualified error */ +#define VL_ERROR_INVALID_PARAMS ((int8_t) -4) + /*!< Parameter passed is invalid or out of range */ +#define VL_ERROR_NOT_SUPPORTED ((int8_t) -5) + /*!< Function is not supported in current mode or configuration */ +#define VL_ERROR_RANGE_ERROR ((int8_t) -6) + /*!< Device report a ranging error interrupt status */ +#define VL_ERROR_TIME_OUT ((int8_t) -7) + /*!< Aborted due to time out */ +#define VL_ERROR_MODE_NOT_SUPPORTED ((int8_t) -8) + /*!< Asked mode is not supported by the device */ +#define VL_ERROR_BUFFER_TOO_SMALL ((int8_t) -9) + /*!< ... */ +#define VL_ERROR_GPIO_NOT_EXISTING ((int8_t) -10) + /*!< User tried to setup a non-existing GPIO pin */ +#define VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((int8_t) -11) + /*!< unsupported GPIO functionality */ +#define VL_ERROR_INTERRUPT_NOT_CLEARED ((int8_t) -12) + /*!< Error during interrupt clear */ +#define VL_ERROR_CONTROL_INTERFACE ((int8_t) -20) + /*!< error reported from IO functions */ +#define VL_ERROR_INVALID_COMMAND ((int8_t) -30) + /*!< The command is not allowed in the current device state + * (power down) */ +#define VL_ERROR_DIVISION_BY_ZERO ((int8_t) -40) + /*!< In the function a division by zero occurs */ +#define VL_ERROR_REF_SPAD_INIT ((int8_t) -50) + /*!< Error during reference SPAD initialization */ +#define VL_ERROR_NOT_IMPLEMENTED ((int8_t) -99) + /*!< Tells requested functionality has not been implemented yet or + * not compatible with the device */ +/** @} VL_define_Error_group */ + + +/** @defgroup VL_define_DeviceModes_group Defines Device modes + * Defines all possible modes for the device + * @{ + */ + +#define VL_DEVICEMODE_SINGLE_RANGING ((uint8_t) 0) +#define VL_DEVICEMODE_CONTINUOUS_RANGING ((uint8_t) 1) +#define VL_DEVICEMODE_SINGLE_HISTOGRAM ((uint8_t) 2) +#define VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING ((uint8_t) 3) +#define VL_DEVICEMODE_SINGLE_ALS ((uint8_t) 10) +#define VL_DEVICEMODE_GPIO_DRIVE ((uint8_t) 20) +#define VL_DEVICEMODE_GPIO_OSC ((uint8_t) 21) + /* ... Modes to be added depending on device */ +/** @} VL_define_DeviceModes_group */ + + + +/** @defgroup VL_define_HistogramModes_group Defines Histogram modes + * Defines all possible Histogram modes for the device + * @{ + */ + +#define VL_HISTOGRAMMODE_DISABLED ((uint8_t) 0) + /*!< Histogram Disabled */ +#define VL_HISTOGRAMMODE_REFERENCE_ONLY ((uint8_t) 1) + /*!< Histogram Reference array only */ +#define VL_HISTOGRAMMODE_RETURN_ONLY ((uint8_t) 2) + /*!< Histogram Return array only */ +#define VL_HISTOGRAMMODE_BOTH ((uint8_t) 3) + /*!< Histogram both Reference and Return Arrays */ + /* ... Modes to be added depending on device */ +/** @} VL_define_HistogramModes_group */ + + +/** @defgroup VL_define_PowerModes_group List of available Power Modes + * List of available Power Modes + * @{ + */ + +#define VL_POWERMODE_STANDBY_LEVEL1 ((uint8_t) 0) + /*!< Standby level 1 */ +#define VL_POWERMODE_STANDBY_LEVEL2 ((uint8_t) 1) + /*!< Standby level 2 */ +#define VL_POWERMODE_IDLE_LEVEL1 ((uint8_t) 2) + /*!< Idle level 1 */ +#define VL_POWERMODE_IDLE_LEVEL2 ((uint8_t) 3) + /*!< Idle level 2 */ + +/** @} VL_define_PowerModes_group */ + + +/** @brief Defines all parameters for the device + */ +struct VL_DeviceParameters_t { + uint8_t DeviceMode; + /*!< Defines type of measurement to be done for the next measure */ + uint8_t HistogramMode; + /*!< Defines type of histogram measurement to be done for the next + * measure */ + uint32_t MeasurementTimingBudgetMicroSeconds; + /*!< Defines the allowed total time for a single measurement */ + uint32_t InterMeasurementPeriodMilliSeconds; + /*!< Defines time between two consecutive measurements (between two + * measurement starts). If set to 0 means back-to-back mode */ + uint8_t XTalkCompensationEnable; + /*!< Tells if Crosstalk compensation shall be enable or not */ + uint16_t XTalkCompensationRangeMilliMeter; + /*!< CrossTalk compensation range in millimeter */ + unsigned int XTalkCompensationRateMegaCps; + /*!< CrossTalk compensation rate in Mega counts per seconds. + * Expressed in 16.16 fixed point format. */ + int32_t RangeOffsetMicroMeters; + /*!< Range offset adjustment (mm). */ + + uint8_t LimitChecksEnable[VL_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check enable for this device. */ + uint8_t LimitChecksStatus[VL_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Status of the check linked to last + * measurement. */ + unsigned int LimitChecksValue[VL_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check value for this device */ + + uint8_t WrapAroundCheckEnable; + /*!< Tells if Wrap Around Check shall be enable or not */ +}; + + +/** @defgroup VL_define_State_group Defines the current status + * of the device Defines the current status of the device + * @{ + */ + +#define VL_STATE_POWERDOWN ((uint8_t) 0) + /*!< Device is in HW reset */ +#define VL_STATE_WAIT_STATICINIT ((uint8_t) 1) + /*!< Device is initialized and wait for static initialization */ +#define VL_STATE_STANDBY ((uint8_t) 2) + /*!< Device is in Low power Standby mode */ +#define VL_STATE_IDLE ((uint8_t) 3) + /*!< Device has been initialized and ready to do measurements */ +#define VL_STATE_RUNNING ((uint8_t) 4) + /*!< Device is performing measurement */ +#define VL_STATE_UNKNOWN ((uint8_t) 98) + /*!< Device is in unknown state and need to be rebooted */ +#define VL_STATE_ERROR ((uint8_t) 99) + /*!< Device is in error state and need to be rebooted */ + +/** @} VL_define_State_group */ + + +/** @brief Structure containing the Dmax computation parameters and data + */ +struct VL_DMaxData_t { + int32_t AmbTuningWindowFactor_K; + /*!< internal algo tuning (*1000) */ + int32_t RetSignalAt0mm; + /*!< intermediate dmax computation value caching */ +}; + +/** + * @struct VL_RangeData_t + * @brief Range measurement data. + */ +struct VL_RangingMeasurementData_t { + uint32_t TimeStamp; /*!< 32-bit time stamp. */ + uint32_t MeasurementTimeUsec; + /*!< Give the Measurement time needed by the device to do the + * measurement.*/ + + + uint16_t RangeMilliMeter; /*!< range distance in millimeter. */ + + uint16_t RangeDMaxMilliMeter; + /*!< Tells what is the maximum detection distance of the device + * in current setup and environment conditions (Filled when + * applicable) */ + + unsigned int SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance.*/ + unsigned int AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light.*/ + + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 */ + + uint8_t ZoneId; + /*!< Denotes which zone and range scheduler stage the range + * data relates to. */ + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * FixPoint168 value. */ + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + * See \ref RangeStatusPage */ +}; + + +#define VL_HISTOGRAM_BUFFER_SIZE 24 + +/** + * @struct VL_HistogramData_t + * @brief Histogram measurement data. + */ +struct VL_HistogramMeasurementData_t { + /* Histogram Measurement data */ + uint32_t HistogramData[VL_HISTOGRAM_BUFFER_SIZE]; + /*!< Histogram data */ + uint8_t HistogramType; /*!< Indicate the types of histogram data : + Return only, Reference only, both Return and Reference */ + uint8_t FirstBin; /*!< First Bin value */ + uint8_t BufferSize; /*!< Buffer Size - Set by the user.*/ + uint8_t NumberOfBins; + /*!< Number of bins filled by the histogram measurement */ + + uint8_t ErrorStatus; + /*!< Error status of the current measurement. \n + see @a ::uint8_t @a VL_GetStatusErrorString() */ +}; + +#define VL_REF_SPAD_BUFFER_SIZE 6 + +/** + * @struct VL_SpadData_t + * @brief Spad Configuration Data. + */ +struct VL_SpadData_t { + uint8_t RefSpadEnables[VL_REF_SPAD_BUFFER_SIZE]; + /*!< Reference Spad Enables */ + uint8_t RefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE]; + /*!< Reference Spad Good Spad Map */ +}; + +struct VL_DeviceSpecificParameters_t { + unsigned int OscFrequencyMHz; /* Frequency used */ + + uint16_t LastEncodedTimeout; + /* last encoded Time out used for timing budget*/ + + uint8_t Pin0GpioFunctionality; + /* store the functionality of the GPIO: pin0 */ + + uint32_t FinalRangeTimeoutMicroSecs; + /*!< Execution time of the final range*/ + uint8_t FinalRangeVcselPulsePeriod; + /*!< Vcsel pulse period (pll clocks) for the final range measurement*/ + uint32_t PreRangeTimeoutMicroSecs; + /*!< Execution time of the final range*/ + uint8_t PreRangeVcselPulsePeriod; + /*!< Vcsel pulse period (pll clocks) for the pre-range measurement*/ + + uint16_t SigmaEstRefArray; + /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */ + uint16_t SigmaEstEffPulseWidth; + /*!< Effective Pulse width for sigma estimate in 1/100th + * of ns e.g. 900 = 9.0ns */ + uint16_t SigmaEstEffAmbWidth; + /*!< Effective Ambient width for sigma estimate in 1/100th of ns + * e.g. 500 = 5.0ns */ + + + uint8_t ReadDataFromDeviceDone; /* Indicate if read from device has + been done (==1) or not (==0) */ + uint8_t ModuleId; /* Module ID */ + uint8_t Revision; /* test Revision */ + char ProductId[VL_MAX_STRING_LENGTH]; + /* Product Identifier String */ + uint8_t ReferenceSpadCount; /* used for ref spad management */ + uint8_t ReferenceSpadType; /* used for ref spad management */ + uint8_t RefSpadsInitialised; /* reports if ref spads are initialised. */ + uint32_t PartUIDUpper; /*!< Unique Part ID Upper */ + uint32_t PartUIDLower; /*!< Unique Part ID Lower */ + unsigned int SignalRateMeasFixed400mm; /*!< Peek Signal rate + at 400 mm*/ + +}; + +/** + * @struct VL_DevData_t + * + * @brief VL53L0X PAL device ST private data structure \n + * End user should never access any of these field directly + * + * These must never access directly but only via macro + */ +struct VL_DevData_t { + struct VL_DMaxData_t DMaxData; + /*!< Dmax Data */ + int32_t Part2PartOffsetNVMMicroMeter; + /*!< backed up NVM value */ + int32_t Part2PartOffsetAdjustmentNVMMicroMeter; + /*!< backed up NVM value representing additional offset adjustment */ + struct VL_DeviceParameters_t CurrentParameters; + /*!< Current Device Parameter */ + struct VL_RangingMeasurementData_t LastRangeMeasure; + /*!< Ranging Data */ + struct VL_HistogramMeasurementData_t LastHistogramMeasure; + /*!< Histogram Data */ + struct VL_DeviceSpecificParameters_t DeviceSpecificParameters; + /*!< Parameters specific to the device */ + struct VL_SpadData_t SpadData; + /*!< Spad Data */ + uint8_t SequenceConfig; + /*!< Internal value for the sequence config */ + uint8_t RangeFractionalEnable; + /*!< Enable/Disable fractional part of ranging data */ + uint8_t PalState; + /*!< Current state of the PAL for this device */ + uint8_t PowerMode; + /*!< Current Power Mode */ + uint16_t SigmaEstRefArray; + /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */ + uint16_t SigmaEstEffPulseWidth; + /*!< Effective Pulse width for sigma estimate in 1/100th + * of ns e.g. 900 = 9.0ns */ + uint16_t SigmaEstEffAmbWidth; + /*!< Effective Ambient width for sigma estimate in 1/100th of ns + * e.g. 500 = 5.0ns */ + uint8_t StopVariable; + /*!< StopVariable used during the stop sequence */ + uint16_t targetRefRate; + /*!< Target Ambient Rate for Ref spad management */ + unsigned int SigmaEstimate; + /*!< Sigma Estimate - based on ambient & VCSEL rates and + * signal_total_events */ + unsigned int SignalEstimate; + /*!< Signal Estimate - based on ambient & VCSEL rates and cross talk */ + unsigned int LastSignalRefMcps; + /*!< Latest Signal ref in Mcps */ + uint8_t *pTuningSettingsPointer; + /*!< Pointer for Tuning Settings table */ + uint8_t UseInternalTuningSettings; + /*!< Indicate if we use Tuning Settings table */ + uint16_t LinearityCorrectiveGain; + /*!< Linearity Corrective Gain value in x1000 */ + uint16_t DmaxCalRangeMilliMeter; + /*!< Dmax Calibration Range millimeter */ + unsigned int DmaxCalSignalRateRtnMegaCps; + /*!< Dmax Calibration Signal Rate Return MegaCps */ + +}; + + +/** @defgroup VL_define_InterruptPolarity_group Defines the Polarity + * of the Interrupt + * Defines the Polarity of the Interrupt + * @{ + */ + +#define VL_INTERRUPTPOLARITY_LOW ((uint8_t) 0) +/*!< Set active low polarity best setup for falling edge. */ +#define VL_INTERRUPTPOLARITY_HIGH ((uint8_t) 1) +/*!< Set active high polarity best setup for rising edge. */ + +/** @} VL_define_InterruptPolarity_group */ + + +/** @defgroup VL_define_VcselPeriod_group Vcsel Period Defines + * Defines the range measurement for which to access the vcsel period. + * @{ + */ + +#define VL_VCSEL_PERIOD_PRE_RANGE ((uint8_t) 0) +/*!>9)&0xFFFF) +#define VL_FIXPOINT97TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<9) + +#define VL_FIXPOINT1616TOFIXPOINT88(Value) \ + (uint16_t)((Value>>8)&0xFFFF) +#define VL_FIXPOINT88TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<8) + +#define VL_FIXPOINT1616TOFIXPOINT412(Value) \ + (uint16_t)((Value>>4)&0xFFFF) +#define VL_FIXPOINT412TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<4) + +#define VL_FIXPOINT1616TOFIXPOINT313(Value) \ + (uint16_t)((Value>>3)&0xFFFF) +#define VL_FIXPOINT313TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<3) + +#define VL_FIXPOINT1616TOFIXPOINT08(Value) \ + (uint8_t)((Value>>8)&0x00FF) +#define VL_FIXPOINT08TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<8) + +#define VL_FIXPOINT1616TOFIXPOINT53(Value) \ + (uint8_t)((Value>>13)&0x00FF) +#define VL_FIXPOINT53TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<13) + +#define VL_FIXPOINT1616TOFIXPOINT102(Value) \ + (uint16_t)((Value>>14)&0x0FFF) +#define VL_FIXPOINT102TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<12) + +#define VL_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \ + (uint16_t)lsb) + +/** @} VL_define_GeneralMacro_group */ + +/** @} VL_globaldefine_group */ + + + + + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL_DEF_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h new file mode 100644 index 0000000000000000000000000000000000000000..a4347df75459915eee79b22a1b5490342a6b0234 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h @@ -0,0 +1,248 @@ +/* + * vl53l0x_device.h - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +/** + * Device specific defines. To be adapted by implementer for the targeted + * device. + */ + +#ifndef _VL_DEVICE_H_ +#define _VL_DEVICE_H_ + +#include "vl53l0x_types.h" + + +/** @defgroup VL_DevSpecDefines_group VL53L0X cut1.1 + * Device Specific Defines + * @brief VL53L0X cut1.1 Device Specific Defines + * @{ + */ + + +/** @defgroup uint8_t_group Device Error + * @brief Device Error code + * + * This enum is Device specific it should be updated in the implementation + * Use @a VL_GetStatusErrorString() to get the string. + * It is related to Status Register of the Device. + * @{ + */ + +#define VL_DEVICEERROR_NONE ((uint8_t) 0) + /*!< 0 NoError */ +#define VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE ((uint8_t) 1) +#define VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE ((uint8_t) 2) +#define VL_DEVICEERROR_NOVHVVALUEFOUND ((uint8_t) 3) +#define VL_DEVICEERROR_MSRCNOTARGET ((uint8_t) 4) +#define VL_DEVICEERROR_SNRCHECK ((uint8_t) 5) +#define VL_DEVICEERROR_RANGEPHASECHECK ((uint8_t) 6) +#define VL_DEVICEERROR_SIGMATHRESHOLDCHECK ((uint8_t) 7) +#define VL_DEVICEERROR_TCC ((uint8_t) 8) +#define VL_DEVICEERROR_PHASECONSISTENCY ((uint8_t) 9) +#define VL_DEVICEERROR_MINCLIP ((uint8_t) 10) +#define VL_DEVICEERROR_RANGECOMPLETE ((uint8_t) 11) +#define VL_DEVICEERROR_ALGOUNDERFLOW ((uint8_t) 12) +#define VL_DEVICEERROR_ALGOOVERFLOW ((uint8_t) 13) +#define VL_DEVICEERROR_RANGEIGNORETHRESHOLD ((uint8_t) 14) + +/** @} end of uint8_t_group */ + + +/** @defgroup VL_CheckEnable_group Check Enable list + * @brief Check Enable code + * + * Define used to specify the LimitCheckId. + * Use @a VL_GetLimitCheckInfo() to get the string. + * @{ + */ + +#define VL_CHECKENABLE_SIGMA_FINAL_RANGE 0 +#define VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1 +#define VL_CHECKENABLE_SIGNAL_REF_CLIP 2 +#define VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD 3 +#define VL_CHECKENABLE_SIGNAL_RATE_MSRC 4 +#define VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE 5 + +#define VL_CHECKENABLE_NUMBER_OF_CHECKS 6 + +/** @} end of VL_CheckEnable_group */ + + +/** @defgroup uint8_t_group Gpio Functionality + * @brief Defines the different functionalities for the device GPIO(s) + * @{ + */ + +#define VL_GPIOFUNCTIONALITY_OFF \ + ((uint8_t) 0) /*!< NO Interrupt */ +#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW \ + ((uint8_t) 1) /*!< Level Low (value < thresh_low) */ +#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH \ + ((uint8_t) 2)/*!< Level High (value > thresh_high)*/ +#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT \ + ((uint8_t) 3) + /*!< Out Of Window (value < thresh_low OR value > thresh_high) */ +#define VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY \ + ((uint8_t) 4) /*!< New Sample Ready */ + +/** @} end of uint8_t_group */ + + +/* Device register map */ + +/** @defgroup VL_DefineRegisters_group Define Registers + * @brief List of all the defined registers + * @{ + */ +#define VL_REG_SYSRANGE_START 0x000 + /** mask existing bit in #VL_REG_SYSRANGE_START*/ + #define VL_REG_SYSRANGE_MODE_MASK 0x0F + /** bit 0 in #VL_REG_SYSRANGE_START write 1 toggle state in + * continuous mode and arm next shot in single shot mode */ + #define VL_REG_SYSRANGE_MODE_START_STOP 0x01 + /** bit 1 write 0 in #VL_REG_SYSRANGE_START set single shot mode */ + #define VL_REG_SYSRANGE_MODE_SINGLESHOT 0x00 + /** bit 1 write 1 in #VL_REG_SYSRANGE_START set back-to-back + * operation mode */ + #define VL_REG_SYSRANGE_MODE_BACKTOBACK 0x02 + /** bit 2 write 1 in #VL_REG_SYSRANGE_START set timed operation + * mode */ + #define VL_REG_SYSRANGE_MODE_TIMED 0x04 + /** bit 3 write 1 in #VL_REG_SYSRANGE_START set histogram operation + * mode */ + #define VL_REG_SYSRANGE_MODE_HISTOGRAM 0x08 + + +#define VL_REG_SYSTEM_THRESH_HIGH 0x000C +#define VL_REG_SYSTEM_THRESH_LOW 0x000E + + +#define VL_REG_SYSTEM_SEQUENCE_CONFIG 0x0001 +#define VL_REG_SYSTEM_RANGE_CONFIG 0x0009 +#define VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x0004 + + +#define VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x000A + #define VL_REG_SYSTEM_INTERRUPT_GPIO_DISABLED 0x00 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_LOW 0x01 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_HIGH 0x02 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_OUT_OF_WINDOW 0x03 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY 0x04 + +#define VL_REG_GPIO_HV_MUX_ACTIVE_HIGH 0x0084 + + +#define VL_REG_SYSTEM_INTERRUPT_CLEAR 0x000B + +/* Result registers */ +#define VL_REG_RESULT_INTERRUPT_STATUS 0x0013 +#define VL_REG_RESULT_RANGE_STATUS 0x0014 + +#define VL_REG_RESULT_CORE_PAGE 1 +#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN 0x00BC +#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN 0x00C0 +#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF 0x00D0 +#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF 0x00D4 +#define VL_REG_RESULT_PEAK_SIGNAL_RATE_REF 0x00B6 + +/* Algo register */ + +#define VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM 0x0028 + +#define VL_REG_I2C_SLAVE_DEVICE_ADDRESS 0x008a + +/* Check Limit registers */ +#define VL_REG_MSRC_CONFIG_CONTROL 0x0060 + +#define VL_REG_PRE_RANGE_CONFIG_MIN_SNR 0X0027 +#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW 0x0056 +#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH 0x0057 +#define VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT 0x0064 + +#define VL_REG_FINAL_RANGE_CONFIG_MIN_SNR 0X0067 +#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW 0x0047 +#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH 0x0048 +#define VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT 0x0044 + + +#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_HI 0X0061 +#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_LO 0X0062 + +/* PRE RANGE registers */ +#define VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x0050 +#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0051 +#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0052 + +#define VL_REG_SYSTEM_HISTOGRAM_BIN 0x0081 +#define VL_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT 0x0033 +#define VL_REG_HISTOGRAM_CONFIG_READOUT_CTRL 0x0055 + +#define VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x0070 +#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0071 +#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0072 +#define VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS 0x0020 + +#define VL_REG_MSRC_CONFIG_TIMEOUT_MACROP 0x0046 + + +#define VL_REG_SOFT_RESET_GO2_SOFT_RESET_N 0x00bf +#define VL_REG_IDENTIFICATION_MODEL_ID 0x00c0 +#define VL_REG_IDENTIFICATION_REVISION_ID 0x00c2 + +#define VL_REG_OSC_CALIBRATE_VAL 0x00f8 + + +#define VL_SIGMA_ESTIMATE_MAX_VALUE 65535 +/* equivalent to a range sigma of 655.35mm */ + +#define VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH 0x032 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 0x0B0 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 0x0B1 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 0x0B2 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 0x0B3 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 0x0B4 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 0x0B5 + +#define VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT 0xB6 +#define VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD 0x4E /* 0x14E */ +#define VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET 0x4F /* 0x14F */ +#define VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE 0x80 + +/* + * Speed of light in um per 1E-10 Seconds + */ + +#define VL_SPEED_OF_LIGHT_IN_AIR 2997 + +#define VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV 0x0089 + +#define VL_REG_ALGO_PHASECAL_LIM 0x0030 /* 0x130 */ +#define VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT 0x0030 + +/** @} VL_DefineRegisters_group */ + +/** @} VL_DevSpecDefines_group */ + + +#endif + +/* _VL_DEVICE_H_ */ + + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h new file mode 100644 index 0000000000000000000000000000000000000000..7fb292e418cc3f3d5c08004ff391180cc70877f5 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h @@ -0,0 +1,399 @@ +/* + * vl53l0x_i2c_platform.h - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +/** + * @file VL_i2c_platform.h + * @brief Function prototype definitions for EWOK Platform layer. + * + */ + + +#ifndef _VL_I2C_PLATFORM_H_ +#define _VL_I2C_PLATFORM_H_ + +#include "vl53l0x_def.h" + + +/** Maximum buffer size to be used in i2c */ +#define VL_MAX_I2C_XFER_SIZE 64 + +/** + * @brief Typedef defining .\n + * The developer should modify this to suit the platform being deployed. + * + */ + +/** + * @brief Typedef defining 8 bit unsigned char type.\n + * The developer should modify this to suit the platform being deployed. + * + */ +#define I2C 0x01 +#define SPI 0x00 + +#define COMMS_BUFFER_SIZE 64 +/*MUST be the same size as the SV task buffer */ + +#define BYTES_PER_WORD 2 +#define BYTES_PER_DWORD 4 + +#define VL_MAX_STRING_LENGTH_PLT 256 + +/** + * @brief Initialise platform comms. + * + * @param comms_type - selects between I2C and SPI + * @param comms_speed_khz - unsigned short containing the I2C speed in kHz + * + * @return status - status 0 = ok, 1 = error + * + */ + +int32_t VL_comms_initialise(uint8_t comms_type, + uint16_t comms_speed_khz); + +/** + * @brief Close platform comms. + * + * @return status - status 0 = ok, 1 = error + * + */ + +int32_t VL_comms_close(void); + +/** + * @brief Cycle Power to Device + * + * @return status - status 0 = ok, 1 = error + * + */ + +int32_t VL_cycle_power(void); + +int32_t VL_set_page(struct vl_data *dev, uint8_t page_data); + +/** + * @brief Writes the supplied byte buffer to the device + * + * Wrapper for SystemVerilog Write Multi task + * + * @code + * + * Example: + * + * uint8_t *spad_enables; + * + * int status = VL_write_multi(RET_SPAD_EN_0, spad_enables, 36); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint8_t buffer containing the data to be written + * @param count - number of bytes in the supplied byte buffer + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count); + + +/** + * @brief Reads the requested number of bytes from the device + * + * Wrapper for SystemVerilog Read Multi task + * + * @code + * + * Example: + * + * uint8_t buffer[COMMS_BUFFER_SIZE]; + * + * int status = status = VL_read_multi(DEVICE_ID, buffer, 2) + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to the uint8_t buffer to store read data + * @param count - number of uint8_t's to read + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count); + + +/** + * @brief Writes a single byte to the device + * + * Wrapper for SystemVerilog Write Byte task + * + * @code + * + * Example: + * + * uint8_t page_number = MAIN_SELECT_PAGE; + * + * int status = VL_write_byte(PAGE_SELECT, page_number); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param data - uint8_t data value to write + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_byte(struct vl_data *dev, uint8_t index, uint8_t data); + + +/** + * @brief Writes a single word (16-bit unsigned) to the device + * + * Manages the big-endian nature of the device (first byte written is the + * MS byte). + * Uses SystemVerilog Write Multi task. + * + * @code + * + * Example: + * + * uint16_t nvm_ctrl_pulse_width = 0x0004; + * + * int status = VL_write_word(NVM_CTRL__PULSE_WIDTH_MSB, + * nvm_ctrl_pulse_width); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param data - uin16_t data value write + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_word(struct vl_data *dev, uint8_t index, uint16_t data); + + +/** + * @brief Writes a single dword (32-bit unsigned) to the device + * + * Manages the big-endian nature of the device (first byte written is the + * MS byte). + * Uses SystemVerilog Write Multi task. + * + * @code + * + * Example: + * + * uint32_t nvm_data = 0x0004; + * + * int status = VL_write_dword(NVM_CTRL__DATAIN_MMM, nvm_data); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param data - uint32_t data value to write + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t data); + + + +/** + * @brief Reads a single byte from the device + * + * Uses SystemVerilog Read Byte task. + * + * @code + * + * Example: + * + * uint8_t device_status = 0; + * + * int status = VL_read_byte(STATUS, &device_status); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint8_t data value + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_byte(struct vl_data *dev, uint8_t index, uint8_t *pdata); + + +/** + * @brief Reads a single word (16-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * Uses SystemVerilog Read Multi task. + * + * @code + * + * Example: + * + * uint16_t timeout = 0; + * + * int status = VL_read_word(TIMEOUT_OVERALL_PERIODS_MSB, &timeout); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint16_t data value + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_word(struct vl_data *dev, uint8_t index, uint16_t *pdata); + + +/** + * @brief Reads a single dword (32-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * Uses SystemVerilog Read Multi task. + * + * @code + * + * Example: + * + * uint32_t range_1 = 0; + * + * int status = VL_read_dword(RANGE_1_MMM, &range_1); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint32_t data value + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata); + + +/** + * @brief Implements a programmable wait in us + * + * Wrapper for SystemVerilog Wait in micro seconds task + * + * @param wait_us - integer wait in micro seconds + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_platform_wait_us(int32_t wait_us); + + +/** + * @brief Implements a programmable wait in ms + * + * Wrapper for SystemVerilog Wait in milli seconds task + * + * @param wait_ms - integer wait in milli seconds + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_wait_ms(int32_t wait_ms); + + +/** + * @brief Set GPIO value + * + * @param level - input level - either 0 or 1 + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_set_gpio(uint8_t level); + + +/** + * @brief Get GPIO value + * + * @param plevel - uint8_t pointer to store GPIO level (0 or 1) + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_get_gpio(uint8_t *plevel); + +/** + * @brief Release force on GPIO + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_release_gpio(void); + + +/** +* @brief Get the frequency of the timer used for ranging results time stamps +* +* @param[out] ptimer_freq_hz : pointer for timer frequency +* +* @return status : 0 = ok, 1 = error +* +*/ + +int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz); + +/** +* @brief Get the timer value in units of timer_freq_hz +* (see VL_get_timestamp_frequency()) +* +* @param[out] ptimer_count : pointer for timer count value +* +* @return status : 0 = ok, 1 = error +* +*/ + +int32_t VL_get_timer_value(int32_t *ptimer_count); +int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len); +int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len); + +#endif /* _VL_I2C_PLATFORM_H_ */ + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h new file mode 100644 index 0000000000000000000000000000000000000000..24a33ee13a8e4b25b0607dfa973129b52e3d2d2a --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h @@ -0,0 +1,186 @@ +/* + * vl53l0x_interrupt_threshold_setting.h - Linux kernel modules + * for STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + + +#ifndef _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ +#define _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +uint8_t InterruptThresholdSettings[] = { + + /* Start of Interrupt Threshold Settings */ + 0x1, 0xff, 0x00, + 0x1, 0x80, 0x01, + 0x1, 0xff, 0x01, + 0x1, 0x00, 0x00, + 0x1, 0xff, 0x01, + 0x1, 0x4f, 0x02, + 0x1, 0xFF, 0x0E, + 0x1, 0x00, 0x03, + 0x1, 0x01, 0x84, + 0x1, 0x02, 0x0A, + 0x1, 0x03, 0x03, + 0x1, 0x04, 0x08, + 0x1, 0x05, 0xC8, + 0x1, 0x06, 0x03, + 0x1, 0x07, 0x8D, + 0x1, 0x08, 0x08, + 0x1, 0x09, 0xC6, + 0x1, 0x0A, 0x01, + 0x1, 0x0B, 0x02, + 0x1, 0x0C, 0x00, + 0x1, 0x0D, 0xD5, + 0x1, 0x0E, 0x18, + 0x1, 0x0F, 0x12, + 0x1, 0x10, 0x01, + 0x1, 0x11, 0x82, + 0x1, 0x12, 0x00, + 0x1, 0x13, 0xD5, + 0x1, 0x14, 0x18, + 0x1, 0x15, 0x13, + 0x1, 0x16, 0x03, + 0x1, 0x17, 0x86, + 0x1, 0x18, 0x0A, + 0x1, 0x19, 0x09, + 0x1, 0x1A, 0x08, + 0x1, 0x1B, 0xC2, + 0x1, 0x1C, 0x03, + 0x1, 0x1D, 0x8F, + 0x1, 0x1E, 0x0A, + 0x1, 0x1F, 0x06, + 0x1, 0x20, 0x01, + 0x1, 0x21, 0x02, + 0x1, 0x22, 0x00, + 0x1, 0x23, 0xD5, + 0x1, 0x24, 0x18, + 0x1, 0x25, 0x22, + 0x1, 0x26, 0x01, + 0x1, 0x27, 0x82, + 0x1, 0x28, 0x00, + 0x1, 0x29, 0xD5, + 0x1, 0x2A, 0x18, + 0x1, 0x2B, 0x0B, + 0x1, 0x2C, 0x28, + 0x1, 0x2D, 0x78, + 0x1, 0x2E, 0x28, + 0x1, 0x2F, 0x91, + 0x1, 0x30, 0x00, + 0x1, 0x31, 0x0B, + 0x1, 0x32, 0x00, + 0x1, 0x33, 0x0B, + 0x1, 0x34, 0x00, + 0x1, 0x35, 0xA1, + 0x1, 0x36, 0x00, + 0x1, 0x37, 0xA0, + 0x1, 0x38, 0x00, + 0x1, 0x39, 0x04, + 0x1, 0x3A, 0x28, + 0x1, 0x3B, 0x30, + 0x1, 0x3C, 0x0C, + 0x1, 0x3D, 0x04, + 0x1, 0x3E, 0x0F, + 0x1, 0x3F, 0x79, + 0x1, 0x40, 0x28, + 0x1, 0x41, 0x1E, + 0x1, 0x42, 0x2F, + 0x1, 0x43, 0x87, + 0x1, 0x44, 0x00, + 0x1, 0x45, 0x0B, + 0x1, 0x46, 0x00, + 0x1, 0x47, 0x0B, + 0x1, 0x48, 0x00, + 0x1, 0x49, 0xA7, + 0x1, 0x4A, 0x00, + 0x1, 0x4B, 0xA6, + 0x1, 0x4C, 0x00, + 0x1, 0x4D, 0x04, + 0x1, 0x4E, 0x01, + 0x1, 0x4F, 0x00, + 0x1, 0x50, 0x00, + 0x1, 0x51, 0x80, + 0x1, 0x52, 0x09, + 0x1, 0x53, 0x08, + 0x1, 0x54, 0x01, + 0x1, 0x55, 0x00, + 0x1, 0x56, 0x0F, + 0x1, 0x57, 0x79, + 0x1, 0x58, 0x09, + 0x1, 0x59, 0x05, + 0x1, 0x5A, 0x00, + 0x1, 0x5B, 0x60, + 0x1, 0x5C, 0x05, + 0x1, 0x5D, 0xD1, + 0x1, 0x5E, 0x0C, + 0x1, 0x5F, 0x3C, + 0x1, 0x60, 0x00, + 0x1, 0x61, 0xD0, + 0x1, 0x62, 0x0B, + 0x1, 0x63, 0x03, + 0x1, 0x64, 0x28, + 0x1, 0x65, 0x10, + 0x1, 0x66, 0x2A, + 0x1, 0x67, 0x39, + 0x1, 0x68, 0x0B, + 0x1, 0x69, 0x02, + 0x1, 0x6A, 0x28, + 0x1, 0x6B, 0x10, + 0x1, 0x6C, 0x2A, + 0x1, 0x6D, 0x61, + 0x1, 0x6E, 0x0C, + 0x1, 0x6F, 0x00, + 0x1, 0x70, 0x0F, + 0x1, 0x71, 0x79, + 0x1, 0x72, 0x00, + 0x1, 0x73, 0x0B, + 0x1, 0x74, 0x00, + 0x1, 0x75, 0x0B, + 0x1, 0x76, 0x00, + 0x1, 0x77, 0xA1, + 0x1, 0x78, 0x00, + 0x1, 0x79, 0xA0, + 0x1, 0x7A, 0x00, + 0x1, 0x7B, 0x04, + 0x1, 0xFF, 0x04, + 0x1, 0x79, 0x1D, + 0x1, 0x7B, 0x27, + 0x1, 0x96, 0x0E, + 0x1, 0x97, 0xFE, + 0x1, 0x98, 0x03, + 0x1, 0x99, 0xEF, + 0x1, 0x9A, 0x02, + 0x1, 0x9B, 0x44, + 0x1, 0x73, 0x07, + 0x1, 0x70, 0x01, + 0x1, 0xff, 0x01, + 0x1, 0x00, 0x01, + 0x1, 0xff, 0x00, + 0x00, 0x00, 0x00 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h new file mode 100644 index 0000000000000000000000000000000000000000..d018ed2fe62393a4f0e2f3909478244a6552eab2 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h @@ -0,0 +1,212 @@ +/* + * vl53l0x_platform.h - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +#ifndef _VL_PLATFORM_H_ +#define _VL_PLATFORM_H_ + +#include +#include "vl53l0x_def.h" +#include "vl53l0x_platform_log.h" + +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" +#include "stmvl53l0x.h" + +/** + * @file vl53l0x_platform.h + * + * @brief All end user OS/platform/application porting + */ + +/** + * @defgroup VL_platform_group VL53L0 Platform Functions + * @brief VL53L0 Platform Functions + * @{ + */ + +/** + * @def PALDevDataGet + * @brief Get ST private structure @a struct VL_DevData_t data access + * + * @param Dev Device Handle + * @param field ST structure field name + * It maybe used and as real data "ref" not just as "get" for sub-structure item + * like PALDevDataGet(FilterData.field)[i] or + * PALDevDataGet(FilterData.MeasurementIndex)++ + */ +#define PALDevDataGet(Dev, field) (Dev->Data.field) + +/** + * @def PALDevDataSet(Dev, field, data) + * @brief Set ST private structure @a struct VL_DevData_t data field + * @param Dev Device Handle + * @param field ST structure field na*me + * @param data Data to be set + */ +#define PALDevDataSet(Dev, field, data) ((Dev->Data.field) = (data)) + + +/** + * @defgroup VL_registerAccess_group PAL Register Access Functions + * @brief PAL Register Access Functions + * @{ + */ + +/** + * Lock comms interface to serialize all commands to a shared I2C interface for a specific device + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_LockSequenceAccess(struct vl_data *Dev); + +/** + * Unlock comms interface to serialize all commands to a shared I2C interface for a specific device + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_UnlockSequenceAccess(struct vl_data *Dev); + + +/** + * Writes the supplied byte buffer to the device + * @param Dev Device Handle + * @param index The register index + * @param pdata Pointer to uint8_t buffer containing the data to be written + * @param count Number of bytes in the supplied byte buffer + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count); + +/** + * Reads the requested number of bytes from the device + * @param Dev Device Handle + * @param index The register index + * @param pdata Pointer to the uint8_t buffer to store read data + * @param count Number of uint8_t's to read + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count); + +/** + * Write single byte register + * @param Dev Device Handle + * @param index The register index + * @param data 8 bit register data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data); + +/** + * Write word register + * @param Dev Device Handle + * @param index The register index + * @param data 16 bit register data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data); + +/** + * Write double word (4 byte) register + * @param Dev Device Handle + * @param index The register index + * @param data 32 bit register data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data); + +/** + * Read single byte register + * @param Dev Device Handle + * @param index The register index + * @param data pointer to 8 bit data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data); + +/** + * Read word (2byte) register + * @param Dev Device Handle + * @param index The register index + * @param data pointer to 16 bit data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data); + +/** + * Read dword (4byte) register + * @param Dev Device Handle + * @param index The register index + * @param data pointer to 32 bit data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data); + +/** + * Threat safe Update (read/modify/write) single byte register + * + * Final_reg = (Initial_reg & and_data) |or_data + * + * @param Dev Device Handle + * @param index The register index + * @param AndData 8 bit and data + * @param OrData 8 bit or data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index, + uint8_t AndData, uint8_t OrData); + +/** @} end of VL_registerAccess_group */ + + +/** + * @brief execute delay in all polling API call + * + * A typical multi-thread or RTOs implementation is to sleep the task for + * some 5ms (with 100Hz max rate faster polling is not needed) + * if nothing specific is need you can define it as an empty/void macro + * @code + * #define VL_PollingDelay(...) (void)0 + * @endcode + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_PollingDelay(struct vl_data *Dev); +/* usually best implemented as a real function */ + +/** @} end of VL_platform_group */ + +#endif /* _VL_PLATFORM_H_ */ + + + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h new file mode 100644 index 0000000000000000000000000000000000000000..e15303a71f9432537b6741395f3bd9c1b6405184 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h @@ -0,0 +1,115 @@ +/* + * vl53l0x_platform_log.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + + +#ifndef _VL_PLATFORM_LOG_H_ +#define _VL_PLATFORM_LOG_H_ + +#include +/* LOG Functions */ + + +/** + * @file vl53l0x_platform_log.h + * + * @brief platform log function definition + */ + +/* #define VL_LOG_ENABLE */ + +enum { + TRACE_LEVEL_NONE, + TRACE_LEVEL_ERRORS, + TRACE_LEVEL_WARNING, + TRACE_LEVEL_INFO, + TRACE_LEVEL_DEBUG, + TRACE_LEVEL_ALL, + TRACE_LEVEL_IGNORE +}; + +enum { + TRACE_FUNCTION_NONE = 0, + TRACE_FUNCTION_I2C = 1, + TRACE_FUNCTION_ALL = 0x7fffffff /* all bits except sign */ +}; + +enum { + TRACE_MODULE_NONE = 0x0, + TRACE_MODULE_API = 0x1, + TRACE_MODULE_PLATFORM = 0x2, + TRACE_MODULE_ALL = 0x7fffffff /* all bits except sign */ +}; + + +#ifdef VL_LOG_ENABLE + +#include + + +extern uint32_t _trace_level; + + + +int32_t VL_trace_config(char *filename, uint32_t modules, + uint32_t level, uint32_t functions); + +#define trace_print_module_function(...) + +#define LOG_GET_TIME() (int)0 +/* +#define _LOG_FUNCTION_START(module, fmt, ...) \ + dbg(KERN_INFO"beg %s start @%d\t" fmt "\n", \ + __func__, LOG_GET_TIME(), ##__VA_ARGS__) + +#define _LOG_FUNCTION_END(module, status, ...)\ + dbg(KERN_INFO"end %s @%d %d\n", \ + __func__, LOG_GET_TIME(), (int)status) + +#define _LOG_FUNCTION_END_FMT(module, status, fmt, ...)\ + dbg(KERN_INFO"End %s @%d %d\t"fmt"\n" , \ + __func__, LOG_GET_TIME(), (int)status, ##__VA_ARGS__) +*/ +#define _LOG_FUNCTION_START(module, fmt, ...) \ + dbg("beg %s start @%d\t" fmt "\n", \ + __func__, LOG_GET_TIME(), ##__VA_ARGS__) + +#define _LOG_FUNCTION_END(module, status, ...)\ + dbg("end %s start @%d Status %d\n", \ + __func__, LOG_GET_TIME(), (int)status) + +#define _LOG_FUNCTION_END_FMT(module, status, fmt, ...)\ + dbg("End %s @%d %d\t"fmt"\n" , \ + __func__, LOG_GET_TIME(), (int)status, ##__VA_ARGS__) + + +#else /* VL_LOG_ENABLE no logging */ + #define VL_ErrLog(...) (void)0 + #define _LOG_FUNCTION_START(module, fmt, ...) (void)0 + #define _LOG_FUNCTION_END(module, status, ...) (void)0 + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) (void)0 +#endif /* else */ + +#define VL_COPYSTRING(str, ...) strlcpy(str, ##__VA_ARGS__, sizeof(str)) + + +#endif /* _VL_PLATFORM_LOG_H_ */ + + + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h new file mode 100644 index 0000000000000000000000000000000000000000..5c04a26ff2d0ff773f3d7b59573b7b5f750ba988 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h @@ -0,0 +1,138 @@ +/* + * vl53l0x_tuning.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + + +#ifndef _VL_TUNING_H_ +#define _VL_TUNING_H_ + +#include "vl53l0x_def.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +uint8_t DefaultTuningSettings[] = { + + /* update 02/11/2015_v36 */ + 0x01, 0xFF, 0x01, + 0x01, 0x00, 0x00, + + 0x01, 0xFF, 0x00, + 0x01, 0x09, 0x00, + 0x01, 0x10, 0x00, + 0x01, 0x11, 0x00, + + 0x01, 0x24, 0x01, + 0x01, 0x25, 0xff, + 0x01, 0x75, 0x00, + + 0x01, 0xFF, 0x01, + 0x01, 0x4e, 0x2c, + 0x01, 0x48, 0x00, + 0x01, 0x30, 0x20, + + 0x01, 0xFF, 0x00, + 0x01, 0x30, 0x09, /* mja changed from 0x64. */ + 0x01, 0x54, 0x00, + 0x01, 0x31, 0x04, + 0x01, 0x32, 0x03, + 0x01, 0x40, 0x83, + 0x01, 0x46, 0x25, + 0x01, 0x60, 0x00, + 0x01, 0x27, 0x00, + 0x01, 0x50, 0x06, + 0x01, 0x51, 0x00, + 0x01, 0x52, 0x96, + 0x01, 0x56, 0x08, + 0x01, 0x57, 0x30, + 0x01, 0x61, 0x00, + 0x01, 0x62, 0x00, + 0x01, 0x64, 0x00, + 0x01, 0x65, 0x00, + 0x01, 0x66, 0xa0, + + 0x01, 0xFF, 0x01, + 0x01, 0x22, 0x32, + 0x01, 0x47, 0x14, + 0x01, 0x49, 0xff, + 0x01, 0x4a, 0x00, + + 0x01, 0xFF, 0x00, + 0x01, 0x7a, 0x0a, + 0x01, 0x7b, 0x00, + 0x01, 0x78, 0x21, + + 0x01, 0xFF, 0x01, + 0x01, 0x23, 0x34, + 0x01, 0x42, 0x00, + 0x01, 0x44, 0xff, + 0x01, 0x45, 0x26, + 0x01, 0x46, 0x05, + 0x01, 0x40, 0x40, + 0x01, 0x0E, 0x06, + 0x01, 0x20, 0x1a, + 0x01, 0x43, 0x40, + + 0x01, 0xFF, 0x00, + 0x01, 0x34, 0x03, + 0x01, 0x35, 0x44, + + 0x01, 0xFF, 0x01, + 0x01, 0x31, 0x04, + 0x01, 0x4b, 0x09, + 0x01, 0x4c, 0x05, + 0x01, 0x4d, 0x04, + + + 0x01, 0xFF, 0x00, + 0x01, 0x44, 0x00, + 0x01, 0x45, 0x20, + 0x01, 0x47, 0x08, + 0x01, 0x48, 0x28, + 0x01, 0x67, 0x00, + 0x01, 0x70, 0x04, + 0x01, 0x71, 0x01, + 0x01, 0x72, 0xfe, + 0x01, 0x76, 0x00, + 0x01, 0x77, 0x00, + + 0x01, 0xFF, 0x01, + 0x01, 0x0d, 0x01, + + 0x01, 0xFF, 0x00, + 0x01, 0x80, 0x01, + 0x01, 0x01, 0xF8, + + 0x01, 0xFF, 0x01, + 0x01, 0x8e, 0x01, + 0x01, 0x00, 0x01, + 0x01, 0xFF, 0x00, + 0x01, 0x80, 0x00, + + 0x00, 0x00, 0x00 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_TUNING_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h new file mode 100644 index 0000000000000000000000000000000000000000..8afe9974100ff539dc9461aed96decc43dd9deba --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h @@ -0,0 +1,55 @@ +/* + * vl53l0x_types.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#ifndef VL_TYPES_H_ +#define VL_TYPES_H_ + +#include + +#ifndef NULL +#error "TODO review NULL definition or add required include " +#define NULL 0 +#endif + +#if !defined(STDINT_H) && !defined(_GCC_STDINT_H) \ + && !defined(_STDINT_H) && !defined(_LINUX_TYPES_H) + +#pragma message( +"Review type definition of STDINT define for your platform and add to above") + +/* +* target platform do not provide stdint or use a different #define than above +* to avoid seeing the message below addapt the #define list above or implement +* all type and delete these pragma +*/ + +unsigned int uint32_t; +int int32_t; + +unsigned short uint16_t; +short int16_t; + +unsigned char uint8_t; + +signed char int8_t; + + +#endif /* _STDINT_H */ + +#endif /* VL_TYPES_H_ */ diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c new file mode 100644 index 0000000000000000000000000000000000000000..6180ac0cad7bd58bb8237c2985ca10a91f480dc9 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c @@ -0,0 +1,3099 @@ +/* + * vl53l0x_api.c - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#include "vl53l0x_api.h" +#include "vl53l0x_tuning.h" +#include "vl53l0x_interrupt_threshold_settings.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_calibration.h" +#include "vl53l0x_api_strings.h" + +#ifndef __KERNEL__ +#include +#endif +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + +#ifdef VL_LOG_ENABLE +#define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_API, \ + level, TRACE_FUNCTION_NONE, ##__VA_ARGS__) +#endif + +/* Group PAL General Functions */ + +int8_t VL_GetVersion(struct VL_Version_t *pVersion) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pVersion->major = VL_IMPLEMENTATION_VER_MAJOR; + pVersion->minor = VL_IMPLEMENTATION_VER_MINOR; + pVersion->build = VL_IMPLEMENTATION_VER_SUB; + + pVersion->revision = VL_IMPLEMENTATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalSpecVersion(struct VL_Version_t *pPalSpecVersion) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pPalSpecVersion->major = VL_SPECIFICATION_VER_MAJOR; + pPalSpecVersion->minor = VL_SPECIFICATION_VER_MINOR; + pPalSpecVersion->build = VL_SPECIFICATION_VER_SUB; + + pPalSpecVersion->revision = VL_SPECIFICATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetProductRevision(struct vl_data *Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t revision_id; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_IDENTIFICATION_REVISION_ID, + &revision_id); + *pProductRevisionMajor = 1; + *pProductRevisionMinor = (revision_id & 0xF0) >> 4; + + LOG_FUNCTION_END(Status); + return Status; + +} + +int8_t VL_GetDeviceInfo(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_device_info(Dev, pVL_DeviceInfo); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev, + uint8_t *pDeviceErrorStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t RangeStatus; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS, + &RangeStatus); + + *pDeviceErrorStatus = (uint8_t)((RangeStatus & 0x78) >> 3); + + LOG_FUNCTION_END(Status); + return Status; +} + + +int8_t VL_GetDeviceErrorString(uint8_t ErrorCode, + char *pDeviceErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_device_error_string(ErrorCode, pDeviceErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_range_status_string(RangeStatus, + pRangeStatusString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalErrorString(int8_t PalErrorCode, + char *pPalErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_pal_error_string(PalErrorCode, pPalErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalStateString(uint8_t PalStateCode, + char *pPalStateString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_pal_state_string(PalStateCode, pPalStateString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalState(struct vl_data *Dev, uint8_t *pPalState) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPalState = PALDevDataGet(Dev, PalState); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetPowerMode(struct vl_data *Dev, + uint8_t PowerMode) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + /* Only level1 of Power mode exists */ + if ((PowerMode != VL_POWERMODE_STANDBY_LEVEL1) + && (PowerMode != VL_POWERMODE_IDLE_LEVEL1)) { + Status = VL_ERROR_MODE_NOT_SUPPORTED; + } else if (PowerMode == VL_POWERMODE_STANDBY_LEVEL1) { + /* set the standby level1 of power mode */ + Status = VL_WrByte(Dev, 0x80, 0x00); + if (Status == VL_ERROR_NONE) { + /* Set PAL State to standby */ + PALDevDataSet(Dev, PalState, VL_STATE_STANDBY); + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_STANDBY_LEVEL1); + } + + } else { + /* VL_POWERMODE_IDLE_LEVEL1 */ + Status = VL_WrByte(Dev, 0x80, 0x00); + if (Status == VL_ERROR_NONE) + Status = VL_StaticInit(Dev); + + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_IDLE_LEVEL1); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPowerMode(struct vl_data *Dev, + uint8_t *pPowerMode) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + /* Only level1 of Power mode exists */ + Status = VL_RdByte(Dev, 0x80, &Byte); + + if (Status == VL_ERROR_NONE) { + if (Byte == 1) { + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_IDLE_LEVEL1); + } else { + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_STANDBY_LEVEL1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetOffsetCalibrationDataMicroMeter(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_offset_calibration_data_micro_meter(Dev, + OffsetCalibrationDataMicroMeter); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetOffsetCalibrationDataMicroMeter(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_offset_calibration_data_micro_meter(Dev, + pOffsetCalibrationDataMicroMeter); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev, + int16_t LinearityCorrectiveGain) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if ((LinearityCorrectiveGain < 0) || (LinearityCorrectiveGain > 1000)) + Status = VL_ERROR_INVALID_PARAMS; + else { + PALDevDataSet(Dev, LinearityCorrectiveGain, + LinearityCorrectiveGain); + + if (LinearityCorrectiveGain != 1000) { + /* Disable FW Xtalk */ + Status = VL_WrWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, 0); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev, + uint16_t *pLinearityCorrectiveGain) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pLinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetGroupParamHold(struct vl_data *Dev, uint8_t GroupParamHold) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev, + uint16_t *pUpperLimitMilliMeter) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetTotalSignalRate(struct vl_data *Dev, + unsigned int *pTotalSignalRate) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_RangingMeasurementData_t LastRangeDataBuffer; + + LOG_FUNCTION_START(""); + + LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure); + + Status = VL_get_total_signal_rate( + Dev, &LastRangeDataBuffer, pTotalSignalRate); + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL General Functions */ + +/* Group PAL Init Functions */ +int8_t VL_SetDeviceAddress(struct vl_data *Dev, uint8_t DeviceAddress) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, VL_REG_I2C_SLAVE_DEVICE_ADDRESS, + DeviceAddress / 2); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_DataInit(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_DeviceParameters_t CurrentParameters; + int i; + uint8_t StopVariable; + + LOG_FUNCTION_START(""); + + /* by default the I2C is running at 1V8 if you want to change it you + * need to include this define at compilation level. */ +#ifdef USE_I2C_2V8 + Status = VL_UpdateByte(Dev, + VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV, + 0xFE, + 0x01); +#endif + + /* Set I2C standard mode */ + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0x88, 0x00); + + VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone, 0); + +#ifdef USE_IQC_STATION + if (Status == VL_ERROR_NONE) + Status = VL_apply_offset_adjustment(Dev); +#endif + + /* Default value is 1000 for Linearity Corrective Gain */ + PALDevDataSet(Dev, LinearityCorrectiveGain, 1000); + + /* Dmax default Parameter */ + PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400); + PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps, + (unsigned int)((0x00016B85))); /* 1.42 No Cover Glass*/ + + /* Set Default static parameters + *set first temporary values 9.44MHz * 65536 = 618660 */ + VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, 618660); + + /* Set Default XTalkCompensationRateMegaCps to 0 */ + VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, 0); + + /* Get default parameters */ + Status = VL_GetDeviceParameters(Dev, &CurrentParameters); + if (Status == VL_ERROR_NONE) { + /* initialize PAL values */ + CurrentParameters.DeviceMode = VL_DEVICEMODE_SINGLE_RANGING; + CurrentParameters.HistogramMode = VL_HISTOGRAMMODE_DISABLED; + PALDevDataSet(Dev, CurrentParameters, CurrentParameters); + } + + /* Sigma estimator variable */ + PALDevDataSet(Dev, SigmaEstRefArray, 100); + PALDevDataSet(Dev, SigmaEstEffPulseWidth, 900); + PALDevDataSet(Dev, SigmaEstEffAmbWidth, 500); + PALDevDataSet(Dev, targetRefRate, 0x0A00); /* 20 MCPS in 9:7 format */ + + /* Use internal default settings */ + PALDevDataSet(Dev, UseInternalTuningSettings, 1); + + Status |= VL_WrByte(Dev, 0x80, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + Status |= VL_RdByte(Dev, 0x91, &StopVariable); + PALDevDataSet(Dev, StopVariable, StopVariable); + Status |= VL_WrByte(Dev, 0x00, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x00); + + /* Enable all check */ + for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL_ERROR_NONE) + Status |= VL_SetLimitCheckEnable(Dev, i, 1); + else + break; + + } + + /* Disable the following checks */ + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_RATE_MSRC, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE, 0); + + /* Limit default values */ + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + (unsigned int)(18 * 65536)); + } + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (unsigned int)(25 * 65536 / 100)); + /* 0.25 * 65536 */ + } + + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + (unsigned int)(35 * 65536)); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + (unsigned int)(0 * 65536)); + } + + if (Status == VL_ERROR_NONE) { + + PALDevDataSet(Dev, SequenceConfig, 0xFF); + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + 0xFF); + + /* Set PAL state to tell that we are waiting for call to + * VL_StaticInit */ + PALDevDataSet(Dev, PalState, VL_STATE_WAIT_STATICINIT); + } + + if (Status == VL_ERROR_NONE) + VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 0); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (UseInternalTuningSettings == 1) { + /* Force use internal settings */ + PALDevDataSet(Dev, UseInternalTuningSettings, 1); + } else { + + /* check that the first byte is not 0 */ + if (*pTuningSettingBuffer != 0) { + PALDevDataSet(Dev, pTuningSettingsPointer, + pTuningSettingBuffer); + PALDevDataSet(Dev, UseInternalTuningSettings, 0); + + } else { + Status = VL_ERROR_INVALID_PARAMS; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev, + uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *ppTuningSettingBuffer = PALDevDataGet(Dev, pTuningSettingsPointer); + *pUseInternalTuningSettings = PALDevDataGet(Dev, + UseInternalTuningSettings); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_StaticInit(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_DeviceParameters_t CurrentParameters = {0}; + uint8_t *pTuningSettingBuffer; + uint16_t tempword = 0; + uint8_t tempbyte = 0; + uint8_t UseInternalTuningSettings = 0; + uint32_t count = 0; + uint8_t isApertureSpads = 0; + uint32_t refSpadCount = 0; + uint8_t ApertureSpads = 0; + uint8_t vcselPulsePeriodPCLK; + uint32_t seqTimeoutMicroSecs; + + LOG_FUNCTION_START(""); + + Status = VL_get_info_from_device(Dev, 1); + + /* set the ref spad from NVM */ + count = (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount); + ApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType); + + /* NVM value invalid */ + if ((ApertureSpads > 1) || + ((ApertureSpads == 1) && (count > 32)) || + ((ApertureSpads == 0) && (count > 12))) + Status = VL_perform_ref_spad_management(Dev, &refSpadCount, + &isApertureSpads); + else + Status = VL_set_reference_spads(Dev, count, ApertureSpads); + + + /* Initialize tuning settings buffer to prevent compiler warning. */ + pTuningSettingBuffer = DefaultTuningSettings; + + if (Status == VL_ERROR_NONE) { + UseInternalTuningSettings = PALDevDataGet(Dev, + UseInternalTuningSettings); + + if (UseInternalTuningSettings == 0) + pTuningSettingBuffer = PALDevDataGet(Dev, + pTuningSettingsPointer); + else + pTuningSettingBuffer = DefaultTuningSettings; + + } + + if (Status == VL_ERROR_NONE) + Status = VL_load_tuning_settings(Dev, + pTuningSettingBuffer); + + + /* Set interrupt config to new sample ready */ + if (Status == VL_ERROR_NONE) { + Status = VL_SetGpioConfig(Dev, 0, 0, + VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY, + VL_INTERRUPTPOLARITY_LOW); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_RdWord(Dev, 0x84, &tempword); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, + VL_FIXPOINT412TOFIXPOINT1616(tempword)); + } + + /* After static init, some device parameters may be changed, + * so update them */ + if (Status == VL_ERROR_NONE) + Status = VL_GetDeviceParameters(Dev, &CurrentParameters); + + + if (Status == VL_ERROR_NONE) { + Status = VL_GetFractionEnable(Dev, &tempbyte); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, RangeFractionalEnable, tempbyte); + + } + + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, CurrentParameters, CurrentParameters); + + + /* read the sequence config and save it */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_SYSTEM_SEQUENCE_CONFIG, &tempbyte); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, tempbyte); + + } + + /* Disable MSRC and TCC by default */ + if (Status == VL_ERROR_NONE) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, 0); + + + if (Status == VL_ERROR_NONE) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_MSRC, 0); + + + /* Set PAL State to standby */ + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, PalState, VL_STATE_IDLE); + + + + /* Store pre-range vcsel period */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetVcselPulsePeriod( + Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &vcselPulsePeriodPCLK); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + PreRangeVcselPulsePeriod, + vcselPulsePeriodPCLK); + } + + /* Store final-range vcsel period */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetVcselPulsePeriod( + Dev, + VL_VCSEL_PERIOD_FINAL_RANGE, + &vcselPulsePeriodPCLK); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + FinalRangeVcselPulsePeriod, + vcselPulsePeriodPCLK); + } + + /* Store pre-range timeout */ + if (Status == VL_ERROR_NONE) { + Status = get_sequence_step_timeout( + Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &seqTimeoutMicroSecs); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + PreRangeTimeoutMicroSecs, + seqTimeoutMicroSecs); + } + + /* Store final-range timeout */ + if (Status == VL_ERROR_NONE) { + Status = get_sequence_step_timeout( + Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + &seqTimeoutMicroSecs); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + FinalRangeTimeoutMicroSecs, + seqTimeoutMicroSecs); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_WaitDeviceBooted(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_ResetDevice(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + /* Set reset bit */ + Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N, + 0x00); + + /* Wait for some time */ + if (Status == VL_ERROR_NONE) { + do { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_MODEL_ID, &Byte); + } while (Byte != 0x00); + } + + VL_PollingDelay(Dev); + + /* Release reset */ + Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N, + 0x01); + + /* Wait until correct boot-up of the device */ + if (Status == VL_ERROR_NONE) { + do { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_MODEL_ID, &Byte); + } while (Byte == 0x00); + } + + VL_PollingDelay(Dev); + + /* Set PAL State to VL_STATE_POWERDOWN */ + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, PalState, VL_STATE_POWERDOWN); + + + LOG_FUNCTION_END(Status); + return Status; +} +/* End Group PAL Init Functions */ + +/* Group PAL Parameters Functions */ +int8_t VL_SetDeviceParameters(struct vl_data *Dev, + const struct VL_DeviceParameters_t *pDeviceParameters) +{ + int8_t Status = VL_ERROR_NONE; + int i; + + LOG_FUNCTION_START(""); + Status = VL_SetDeviceMode(Dev, pDeviceParameters->DeviceMode); + + if (Status == VL_ERROR_NONE) + Status = VL_SetInterMeasurementPeriodMilliSeconds(Dev, + pDeviceParameters->InterMeasurementPeriodMilliSeconds); + + + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationRateMegaCps(Dev, + pDeviceParameters->XTalkCompensationRateMegaCps); + + + if (Status == VL_ERROR_NONE) + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, + pDeviceParameters->RangeOffsetMicroMeters); + + + for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL_ERROR_NONE) + Status |= VL_SetLimitCheckEnable(Dev, i, + pDeviceParameters->LimitChecksEnable[i]); + else + break; + + if (Status == VL_ERROR_NONE) + Status |= VL_SetLimitCheckValue(Dev, i, + pDeviceParameters->LimitChecksValue[i]); + else + break; + + } + + if (Status == VL_ERROR_NONE) + Status = VL_SetWrapAroundCheckEnable(Dev, + pDeviceParameters->WrapAroundCheckEnable); + + if (Status == VL_ERROR_NONE) + Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + pDeviceParameters->MeasurementTimingBudgetMicroSeconds); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDeviceParameters(struct vl_data *Dev, + struct VL_DeviceParameters_t *pDeviceParameters) +{ + int8_t Status = VL_ERROR_NONE; + int i; + + LOG_FUNCTION_START(""); + + Status = VL_GetDeviceMode(Dev, &(pDeviceParameters->DeviceMode)); + + if (Status == VL_ERROR_NONE) + Status = VL_GetInterMeasurementPeriodMilliSeconds(Dev, + &(pDeviceParameters->InterMeasurementPeriodMilliSeconds)); + + + if (Status == VL_ERROR_NONE) + pDeviceParameters->XTalkCompensationEnable = 0; + + if (Status == VL_ERROR_NONE) + Status = VL_GetXTalkCompensationRateMegaCps(Dev, + &(pDeviceParameters->XTalkCompensationRateMegaCps)); + + + if (Status == VL_ERROR_NONE) + Status = VL_GetOffsetCalibrationDataMicroMeter(Dev, + &(pDeviceParameters->RangeOffsetMicroMeters)); + + + if (Status == VL_ERROR_NONE) { + for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + /* get first the values, then the enables. + * VL_GetLimitCheckValue will modify the enable + * flags + */ + if (Status == VL_ERROR_NONE) { + Status |= VL_GetLimitCheckValue(Dev, i, + &(pDeviceParameters->LimitChecksValue[i])); + } else { + break; + } + if (Status == VL_ERROR_NONE) { + Status |= VL_GetLimitCheckEnable(Dev, i, + &(pDeviceParameters->LimitChecksEnable[i])); + } else { + break; + } + } + } + + if (Status == VL_ERROR_NONE) { + Status = VL_GetWrapAroundCheckEnable(Dev, + &(pDeviceParameters->WrapAroundCheckEnable)); + } + + /* Need to be done at the end as it uses VCSELPulsePeriod */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetMeasurementTimingBudgetMicroSeconds(Dev, + &(pDeviceParameters->MeasurementTimingBudgetMicroSeconds)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetDeviceMode(struct vl_data *Dev, + uint8_t DeviceMode) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START("%d", (int)DeviceMode); + + switch (DeviceMode) { + case VL_DEVICEMODE_SINGLE_RANGING: + case VL_DEVICEMODE_CONTINUOUS_RANGING: + case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING: + case VL_DEVICEMODE_GPIO_DRIVE: + case VL_DEVICEMODE_GPIO_OSC: + /* Supported modes */ + VL_SETPARAMETERFIELD(Dev, DeviceMode, DeviceMode); + break; + default: + /* Unsupported mode */ + Status = VL_ERROR_MODE_NOT_SUPPORTED; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDeviceMode(struct vl_data *Dev, + uint8_t *pDeviceMode) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, DeviceMode, *pDeviceMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetRangeFractionEnable(struct vl_data *Dev, uint8_t Enable) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START("%d", (int)Enable); + + Status = VL_WrByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, Enable); + + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, RangeFractionalEnable, Enable); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetFractionEnable(struct vl_data *Dev, uint8_t *pEnabled) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, pEnabled); + + if (Status == VL_ERROR_NONE) + *pEnabled = (*pEnabled & 1); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetHistogramMode(struct vl_data *Dev, + uint8_t HistogramMode) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetHistogramMode(struct vl_data *Dev, + uint8_t *pHistogramMode) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev, + uint32_t MeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_measurement_timing_budget_micro_seconds(Dev, + MeasurementTimingBudgetMicroSeconds); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_measurement_timing_budget_micro_seconds(Dev, + pMeasurementTimingBudgetMicroSeconds); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_vcsel_pulse_period(Dev, VcselPeriodType, + VCSELPulsePeriodPCLK); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_vcsel_pulse_period(Dev, VcselPeriodType, + pVCSELPulsePeriodPCLK); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t SequenceStepEnabled) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + uint8_t SequenceConfigNew = 0; + uint32_t MeasurementTimingBudgetMicroSeconds; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + &SequenceConfig); + + SequenceConfigNew = SequenceConfig; + + if (Status == VL_ERROR_NONE) { + if (SequenceStepEnabled == 1) { + + /* Enable requested sequence step + */ + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + SequenceConfigNew |= 0x10; + break; + case VL_SEQUENCESTEP_DSS: + SequenceConfigNew |= 0x28; + break; + case VL_SEQUENCESTEP_MSRC: + SequenceConfigNew |= 0x04; + break; + case VL_SEQUENCESTEP_PRE_RANGE: + SequenceConfigNew |= 0x40; + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + SequenceConfigNew |= 0x80; + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } else { + /* Disable requested sequence step + */ + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + SequenceConfigNew &= 0xef; + break; + case VL_SEQUENCESTEP_DSS: + SequenceConfigNew &= 0xd7; + break; + case VL_SEQUENCESTEP_MSRC: + SequenceConfigNew &= 0xfb; + break; + case VL_SEQUENCESTEP_PRE_RANGE: + SequenceConfigNew &= 0xbf; + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + SequenceConfigNew &= 0x7f; + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } + } + + if (SequenceConfigNew != SequenceConfig) { + /* Apply New Setting */ + if (Status == VL_ERROR_NONE) { + Status = VL_WrByte(Dev, + VL_REG_SYSTEM_SEQUENCE_CONFIG, SequenceConfigNew); + } + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfigNew); + + + /* Recalculate timing budget */ + if (Status == VL_ERROR_NONE) { + VL_GETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + + VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + } + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t sequence_step_enabled(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t SequenceConfig, + uint8_t *pSequenceStepEnabled) +{ + int8_t Status = VL_ERROR_NONE; + *pSequenceStepEnabled = 0; + + LOG_FUNCTION_START(""); + + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + *pSequenceStepEnabled = (SequenceConfig & 0x10) >> 4; + break; + case VL_SEQUENCESTEP_DSS: + *pSequenceStepEnabled = (SequenceConfig & 0x08) >> 3; + break; + case VL_SEQUENCESTEP_MSRC: + *pSequenceStepEnabled = (SequenceConfig & 0x04) >> 2; + break; + case VL_SEQUENCESTEP_PRE_RANGE: + *pSequenceStepEnabled = (SequenceConfig & 0x40) >> 6; + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + *pSequenceStepEnabled = (SequenceConfig & 0x80) >> 7; + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + &SequenceConfig); + + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, SequenceStepId, + SequenceConfig, pSequenceStepEnabled); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSequenceStepEnables(struct vl_data *Dev, + struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + &SequenceConfig); + + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_TCC, SequenceConfig, + &pSchedulerSequenceSteps->TccOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_DSS, SequenceConfig, + &pSchedulerSequenceSteps->DssOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_MSRC, SequenceConfig, + &pSchedulerSequenceSteps->MsrcOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_PRE_RANGE, SequenceConfig, + &pSchedulerSequenceSteps->PreRangeOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, SequenceConfig, + &pSchedulerSequenceSteps->FinalRangeOn); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev, + uint8_t *pNumberOfSequenceSteps) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfSequenceSteps = VL_SEQUENCESTEP_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSequenceStepsInfo( + uint8_t SequenceStepId, char *pSequenceStepsString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_sequence_steps_info( + SequenceStepId, + pSequenceStepsString); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, unsigned int TimeOutMilliSecs) +{ + int8_t Status = VL_ERROR_NONE; + int8_t Status1 = VL_ERROR_NONE; + uint32_t TimeoutMicroSeconds = ((TimeOutMilliSecs * 1000) + 0x8000) + >> 16; + uint32_t MeasurementTimingBudgetMicroSeconds; + unsigned int OldTimeOutMicroSeconds; + + LOG_FUNCTION_START(""); + + /* Read back the current value in case we need to revert back to this. + */ + Status = get_sequence_step_timeout(Dev, SequenceStepId, + &OldTimeOutMicroSeconds); + + if (Status == VL_ERROR_NONE) { + Status = set_sequence_step_timeout(Dev, SequenceStepId, + TimeoutMicroSeconds); + } + + if (Status == VL_ERROR_NONE) { + VL_GETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + + /* At this point we don't know if the requested value is valid, + therefore proceed to update the entire timing budget and + if this fails, revert back to the previous value. + */ + Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + + if (Status != VL_ERROR_NONE) { + Status1 = set_sequence_step_timeout(Dev, SequenceStepId, + OldTimeOutMicroSeconds); + + if (Status1 == VL_ERROR_NONE) { + Status1 = + VL_SetMeasurementTimingBudgetMicroSeconds( + Dev, + MeasurementTimingBudgetMicroSeconds); + } + + Status = Status1; + } + } + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int *pTimeOutMilliSecs) +{ + int8_t Status = VL_ERROR_NONE; + uint32_t TimeoutMicroSeconds; + + LOG_FUNCTION_START(""); + + Status = get_sequence_step_timeout(Dev, SequenceStepId, + &TimeoutMicroSeconds); + if (Status == VL_ERROR_NONE) { + TimeoutMicroSeconds <<= 8; + *pTimeOutMilliSecs = (TimeoutMicroSeconds + 500)/1000; + *pTimeOutMilliSecs <<= 8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev, + uint32_t InterMeasurementPeriodMilliSeconds) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t osc_calibrate_val; + uint32_t IMPeriodMilliSeconds; + + LOG_FUNCTION_START(""); + + Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL, + &osc_calibrate_val); + + if (Status == VL_ERROR_NONE) { + if (osc_calibrate_val != 0) { + IMPeriodMilliSeconds = + InterMeasurementPeriodMilliSeconds + * osc_calibrate_val; + } else { + IMPeriodMilliSeconds = + InterMeasurementPeriodMilliSeconds; + } + Status = VL_WrDWord(Dev, + VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD, + IMPeriodMilliSeconds); + } + + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, + InterMeasurementPeriodMilliSeconds, + InterMeasurementPeriodMilliSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t osc_calibrate_val; + uint32_t IMPeriodMilliSeconds; + + LOG_FUNCTION_START(""); + + Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL, + &osc_calibrate_val); + + if (Status == VL_ERROR_NONE) { + Status = VL_RdDWord(Dev, + VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD, + &IMPeriodMilliSeconds); + } + + if (Status == VL_ERROR_NONE) { + if (osc_calibrate_val != 0) { + *pInterMeasurementPeriodMilliSeconds = + IMPeriodMilliSeconds / osc_calibrate_val; + } + VL_SETPARAMETERFIELD(Dev, + InterMeasurementPeriodMilliSeconds, + *pInterMeasurementPeriodMilliSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t XTalkCompensationEnable) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int TempFix1616; + uint16_t LinearityCorrectiveGain; + + LOG_FUNCTION_START(""); + + LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain); + + if ((XTalkCompensationEnable == 0) + || (LinearityCorrectiveGain != 1000)) { + TempFix1616 = 0; + } else { + VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, + TempFix1616); + } + + /* the following register has a format 3.13 */ + Status = VL_WrWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, + VL_FIXPOINT1616TOFIXPOINT313(TempFix1616)); + + if (Status == VL_ERROR_NONE) { + if (XTalkCompensationEnable == 0) { + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 0); + } else { + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t *pXTalkCompensationEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8); + *pXTalkCompensationEnable = Temp8; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetXTalkCompensationRateMegaCps(struct vl_data *Dev, + unsigned int XTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + uint16_t LinearityCorrectiveGain; + uint16_t data; + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8); + LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain); + + if (Temp8 == 0) { /* disabled write only internal value */ + VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, + XTalkCompensationRateMegaCps); + } else { + /* the following register has a format 3.13 */ + if (LinearityCorrectiveGain == 1000) { + data = VL_FIXPOINT1616TOFIXPOINT313( + XTalkCompensationRateMegaCps); + } else { + data = 0; + } + + Status = VL_WrWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, data); + + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, + XTalkCompensationRateMegaCps); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetXTalkCompensationRateMegaCps(struct vl_data *Dev, + unsigned int *pXTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t Value; + unsigned int TempFix1616; + + LOG_FUNCTION_START(""); + + Status = VL_RdWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, (uint16_t *)&Value); + if (Status == VL_ERROR_NONE) { + if (Value == 0) { + /* the Xtalk is disabled return value from memory */ + VL_GETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, TempFix1616); + *pXTalkCompensationRateMegaCps = TempFix1616; + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 0); + } else { + TempFix1616 = VL_FIXPOINT313TOFIXPOINT1616(Value); + *pXTalkCompensationRateMegaCps = TempFix1616; + VL_SETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, TempFix1616); + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetRefCalibration(struct vl_data *Dev, uint8_t VhvSettings, + uint8_t PhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_ref_calibration(Dev, VhvSettings, PhaseCal); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetRefCalibration(struct vl_data *Dev, uint8_t *pVhvSettings, + uint8_t *pPhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_ref_calibration(Dev, pVhvSettings, pPhaseCal); + + LOG_FUNCTION_END(Status); + return Status; +} + +/* + * CHECK LIMIT FUNCTIONS + */ + +int8_t VL_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfLimitCheck = VL_CHECKENABLE_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckInfo(struct vl_data *Dev, uint16_t LimitCheckId, + char *pLimitCheckString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_limit_check_info(Dev, LimitCheckId, + pLimitCheckString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckStatus(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + } else { + + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + LimitCheckId, Temp8); + + *pLimitCheckStatus = Temp8; + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int TempFix1616 = 0; + uint8_t LimitCheckEnableInt = 0; + uint8_t LimitCheckDisable = 0; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + } else { + if (LimitCheckEnable == 0) { + TempFix1616 = 0; + LimitCheckEnableInt = 0; + LimitCheckDisable = 1; + + } else { + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, TempFix1616); + LimitCheckDisable = 0; + /* this to be sure to have either 0 or 1 */ + LimitCheckEnableInt = 1; + } + + switch (LimitCheckId) { + + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + LimitCheckEnableInt); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + + Status = VL_WrWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, + VL_FIXPOINT1616TOFIXPOINT97(TempFix1616)); + + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + LimitCheckEnableInt); + + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + LimitCheckEnableInt); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + + Temp8 = (uint8_t)(LimitCheckDisable << 1); + Status = VL_UpdateByte(Dev, + VL_REG_MSRC_CONFIG_CONTROL, + 0xFE, Temp8); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + + Temp8 = (uint8_t)(LimitCheckDisable << 4); + Status = VL_UpdateByte(Dev, + VL_REG_MSRC_CONFIG_CONTROL, + 0xEF, Temp8); + + break; + + + default: + Status = VL_ERROR_INVALID_PARAMS; + + } + + } + + if (Status == VL_ERROR_NONE) { + if (LimitCheckEnable == 0) { + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, 0); + } else { + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, 1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + *pLimitCheckEnable = 0; + } else { + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, Temp8); + *pLimitCheckEnable = Temp8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId, + unsigned int LimitCheckValue) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, LimitCheckId, + Temp8); + + if (Temp8 == 0) { /* disabled write only internal value */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } else { + + switch (LimitCheckId) { + + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + LimitCheckValue); + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + + Status = VL_WrWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, + VL_FIXPOINT1616TOFIXPOINT97( + LimitCheckValue)); + + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + LimitCheckValue); + + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + LimitCheckValue); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + + Status = VL_WrWord(Dev, + VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT, + VL_FIXPOINT1616TOFIXPOINT97( + LimitCheckValue)); + + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + + } + + if (Status == VL_ERROR_NONE) { + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId, + unsigned int *pLimitCheckValue) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t EnableZeroValue = 0; + uint16_t Temp16; + unsigned int TempFix1616; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* internal computation: */ + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, TempFix1616); + EnableZeroValue = 0; + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + Status = VL_RdWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, + &Temp16); + if (Status == VL_ERROR_NONE) + TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16); + + + EnableZeroValue = 1; + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + /* internal computation: */ + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGNAL_REF_CLIP, TempFix1616); + EnableZeroValue = 0; + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + /* internal computation: */ + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, TempFix1616); + EnableZeroValue = 0; + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + Status = VL_RdWord(Dev, + VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT, + &Temp16); + if (Status == VL_ERROR_NONE) + TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16); + + + EnableZeroValue = 0; + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + + } + + if (Status == VL_ERROR_NONE) { + + if (EnableZeroValue == 1) { + + if (TempFix1616 == 0) { + /* disabled: return value from memory */ + VL_GETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + *pLimitCheckValue = TempFix1616; + VL_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 0); + } else { + *pLimitCheckValue = TempFix1616; + VL_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + VL_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 1); + } + } else { + *pLimitCheckValue = TempFix1616; + } + } + + LOG_FUNCTION_END(Status); + return Status; + +} + +int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_RangingMeasurementData_t LastRangeDataBuffer; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + } else { + switch (LimitCheckId) { + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* Need to run a ranging to have the latest values */ + *pLimitCheckCurrent = PALDevDataGet(Dev, SigmaEstimate); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + /* Need to run a ranging to have the latest values */ + *pLimitCheckCurrent = PALDevDataGet(Dev, + LastSignalRefMcps); + + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } + + LOG_FUNCTION_END(Status); + return Status; + +} + +/* + * WRAPAROUND Check + */ +int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t WrapAroundCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + uint8_t WrapAroundCheckEnableInt; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &Byte); + if (WrapAroundCheckEnable == 0) { + /* Disable wraparound */ + Byte = Byte & 0x7F; + WrapAroundCheckEnableInt = 0; + } else { + /*Enable wraparound */ + Byte = Byte | 0x80; + WrapAroundCheckEnableInt = 1; + } + + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, Byte); + + if (Status == VL_ERROR_NONE) { + PALDevDataSet(Dev, SequenceConfig, Byte); + VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable, + WrapAroundCheckEnableInt); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t *pWrapAroundCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t data; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &data); + if (Status == VL_ERROR_NONE) { + PALDevDataSet(Dev, SequenceConfig, data); + if (data & (0x01 << 7)) + *pWrapAroundCheckEnable = 0x01; + else + *pWrapAroundCheckEnable = 0x00; + } + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable, + *pWrapAroundCheckEnable); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetDmaxCalParameters(struct vl_data *Dev, + uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int SignalRateRtnMegaCpsTemp = 0; + + LOG_FUNCTION_START(""); + + /* Check if one of input parameter is zero, in that case the + * value are get from NVM */ + if ((RangeMilliMeter == 0) || (SignalRateRtnMegaCps == 0)) { + /* NVM parameters */ + /* Run VL_get_info_from_device wit option 4 to get + * signal rate at 400 mm if the value have been already + * get this function will return with no access to device */ + VL_get_info_from_device(Dev, 4); + + SignalRateRtnMegaCpsTemp = VL_GETDEVICESPECIFICPARAMETER( + Dev, SignalRateMeasFixed400mm); + + PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400); + PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps, + SignalRateRtnMegaCpsTemp); + } else { + /* User parameters */ + PALDevDataSet(Dev, DmaxCalRangeMilliMeter, RangeMilliMeter); + PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps, + SignalRateRtnMegaCps); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDmaxCalParameters(struct vl_data *Dev, + uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pRangeMilliMeter = PALDevDataGet(Dev, DmaxCalRangeMilliMeter); + *pSignalRateRtnMegaCps = PALDevDataGet(Dev, + DmaxCalSignalRateRtnMegaCps); + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL Parameters Functions */ + +/* Group PAL Measurement Functions */ +int8_t VL_PerformSingleMeasurement(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t DeviceMode; + + LOG_FUNCTION_START(""); + + /* Get Current DeviceMode */ + Status = VL_GetDeviceMode(Dev, &DeviceMode); + + /* Start immediately to run a single ranging measurement in case of + * single ranging or single histogram */ + if (Status == VL_ERROR_NONE + && DeviceMode == VL_DEVICEMODE_SINGLE_RANGING) + Status = VL_StartMeasurement(Dev); + + + if (Status == VL_ERROR_NONE) + Status = VL_measurement_poll_for_completion(Dev); + + + /* Change PAL State in case of single ranging or single histogram */ + if (Status == VL_ERROR_NONE + && DeviceMode == VL_DEVICEMODE_SINGLE_RANGING) + PALDevDataSet(Dev, PalState, VL_STATE_IDLE); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformSingleHistogramMeasurement(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformRefCalibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_ref_calibration(Dev, pVhvSettings, + pPhaseCal, 1); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev, + uint32_t TimeoutMs, unsigned int *pXtalkPerSpad, + uint8_t *pAmbientTooHigh) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformXTalkCalibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_xtalk_calibration(Dev, XTalkCalDistance, + pXTalkCompensationRateMegaCps); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformOffsetCalibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_offset_calibration(Dev, CalDistanceMilliMeter, + pOffsetMicroMeter); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_CheckAndLoadInterruptSettings(struct vl_data *Dev, + uint8_t StartNotStopFlag) +{ + uint8_t InterruptConfig; + unsigned int ThresholdLow; + unsigned int ThresholdHigh; + int8_t Status = VL_ERROR_NONE; + + InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev, + Pin0GpioFunctionality); + + if ((InterruptConfig == + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW) || + (InterruptConfig == + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH) || + (InterruptConfig == + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT)) { + + Status = VL_GetInterruptThresholds(Dev, + VL_DEVICEMODE_CONTINUOUS_RANGING, + &ThresholdLow, &ThresholdHigh); + + if (((ThresholdLow > 255*65536) || + (ThresholdHigh > 255*65536)) && + (Status == VL_ERROR_NONE)) { + + if (StartNotStopFlag != 0) { + Status = VL_load_tuning_settings(Dev, + InterruptThresholdSettings); + } else { + Status |= VL_WrByte(Dev, 0xFF, 0x04); + Status |= VL_WrByte(Dev, 0x70, 0x00); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x00); + } + + } + + + } + + return Status; + +} + + +int8_t VL_StartMeasurement(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t DeviceMode; + uint8_t Byte; + uint8_t StartStopByte = VL_REG_SYSRANGE_MODE_START_STOP; + uint32_t LoopNb; + + LOG_FUNCTION_START(""); + + /* Get Current DeviceMode */ + VL_GetDeviceMode(Dev, &DeviceMode); + + Status = VL_WrByte(Dev, 0x80, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status = VL_WrByte(Dev, 0x00, 0x00); + Status = VL_WrByte(Dev, 0x91, PALDevDataGet(Dev, StopVariable)); + Status = VL_WrByte(Dev, 0x00, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x00); + Status = VL_WrByte(Dev, 0x80, 0x00); + + switch (DeviceMode) { + case VL_DEVICEMODE_SINGLE_RANGING: + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x01); + + Byte = StartStopByte; + if (Status == VL_ERROR_NONE) { + /* Wait until start bit has been cleared */ + LoopNb = 0; + do { + if (LoopNb > 0) + Status = VL_RdByte(Dev, + VL_REG_SYSRANGE_START, &Byte); + LoopNb = LoopNb + 1; + } while (((Byte & StartStopByte) == StartStopByte) + && (Status == VL_ERROR_NONE) + && (LoopNb < VL_DEFAULT_MAX_LOOP)); + + if (LoopNb >= VL_DEFAULT_MAX_LOOP) + Status = VL_ERROR_TIME_OUT; + + } + + break; + case VL_DEVICEMODE_CONTINUOUS_RANGING: + /* Back-to-back mode */ + + /* Check if need to apply interrupt settings */ + if (Status == VL_ERROR_NONE) + Status = VL_CheckAndLoadInterruptSettings(Dev, 1); + + Status = VL_WrByte(Dev, + VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_BACKTOBACK); + if (Status == VL_ERROR_NONE) { + /* Set PAL State to Running */ + PALDevDataSet(Dev, PalState, VL_STATE_RUNNING); + } + break; + case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING: + /* Continuous mode */ + /* Check if need to apply interrupt settings */ + if (Status == VL_ERROR_NONE) + Status = VL_CheckAndLoadInterruptSettings(Dev, 1); + + Status = VL_WrByte(Dev, + VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_TIMED); + + if (Status == VL_ERROR_NONE) { + /* Set PAL State to Running */ + PALDevDataSet(Dev, PalState, VL_STATE_RUNNING); + } + break; + default: + /* Selected mode not supported */ + Status = VL_ERROR_MODE_NOT_SUPPORTED; + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_StopMeasurement(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_SINGLESHOT); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status = VL_WrByte(Dev, 0x00, 0x00); + Status = VL_WrByte(Dev, 0x91, 0x00); + Status = VL_WrByte(Dev, 0x00, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x00); + + if (Status == VL_ERROR_NONE) { + /* Set PAL State to Idle */ + PALDevDataSet(Dev, PalState, VL_STATE_IDLE); + } + + /* Check if need to apply interrupt settings */ + if (Status == VL_ERROR_NONE) + Status = VL_CheckAndLoadInterruptSettings(Dev, 0); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetMeasurementDataReady(struct vl_data *Dev, + uint8_t *pMeasurementDataReady) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SysRangeStatusRegister; + uint8_t InterruptConfig; + uint32_t InterruptMask; + + LOG_FUNCTION_START(""); + + InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev, + Pin0GpioFunctionality); + + if (InterruptConfig == + VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) { + Status = VL_GetInterruptMaskStatus(Dev, &InterruptMask); + if (InterruptMask == + VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) + *pMeasurementDataReady = 1; + else + *pMeasurementDataReady = 0; + } else { + Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS, + &SysRangeStatusRegister); + if (Status == VL_ERROR_NONE) { + if (SysRangeStatusRegister & 0x01) + *pMeasurementDataReady = 1; + else + *pMeasurementDataReady = 0; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_WaitDeviceReadyForNewMeasurement(struct vl_data *Dev, + uint32_t MaxLoop) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented for VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + + +int8_t VL_GetRangingMeasurementData(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t DeviceRangeStatus; + uint8_t RangeFractionalEnable; + uint8_t PalRangeStatus; + uint8_t XTalkCompensationEnable; + uint16_t AmbientRate; + unsigned int SignalRate; + uint16_t XTalkCompensationRateMegaCps; + uint16_t EffectiveSpadRtnCount; + uint16_t tmpuint16; + uint16_t XtalkRangeMilliMeter; + uint16_t LinearityCorrectiveGain; + uint8_t localBuffer[12]; + struct VL_RangingMeasurementData_t LastRangeDataBuffer; + + LOG_FUNCTION_START(""); + + /* + * use multi read even if some registers are not useful, result will + * be more efficient + * start reading at 0x14 dec20 + * end reading at 0x21 dec33 total 14 bytes to read + */ + Status = VL_ReadMulti(Dev, 0x14, localBuffer, 12); + + if (Status == VL_ERROR_NONE) { + + pRangingMeasurementData->ZoneId = 0; /* Only one zone */ + pRangingMeasurementData->TimeStamp = 0; /* Not Implemented */ + + tmpuint16 = VL_MAKEUINT16(localBuffer[11], + localBuffer[10]); + /* cut1.1 if SYSTEM__RANGE_CONFIG if 1 range is 2bits fractional + *(format 11.2) else no fractional + */ + + pRangingMeasurementData->MeasurementTimeUsec = 0; + + SignalRate = VL_FIXPOINT97TOFIXPOINT1616( + VL_MAKEUINT16(localBuffer[7], localBuffer[6])); + /* peak_signal_count_rate_rtn_mcps */ + pRangingMeasurementData->SignalRateRtnMegaCps = SignalRate; + + AmbientRate = VL_MAKEUINT16(localBuffer[9], + localBuffer[8]); + pRangingMeasurementData->AmbientRateRtnMegaCps = + VL_FIXPOINT97TOFIXPOINT1616(AmbientRate); + + EffectiveSpadRtnCount = VL_MAKEUINT16(localBuffer[3], + localBuffer[2]); + /* EffectiveSpadRtnCount is 8.8 format */ + pRangingMeasurementData->EffectiveSpadRtnCount = + EffectiveSpadRtnCount; + + DeviceRangeStatus = localBuffer[0]; + + /* Get Linearity Corrective Gain */ + LinearityCorrectiveGain = PALDevDataGet(Dev, + LinearityCorrectiveGain); + + /* Get ranging configuration */ + RangeFractionalEnable = PALDevDataGet(Dev, + RangeFractionalEnable); + + if (LinearityCorrectiveGain != 1000) { + + tmpuint16 = (uint16_t)((LinearityCorrectiveGain + * tmpuint16 + 500) / 1000); + + /* Implement Xtalk */ + VL_GETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, + XTalkCompensationRateMegaCps); + VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, + XTalkCompensationEnable); + + if (XTalkCompensationEnable) { + + if ((SignalRate + - ((XTalkCompensationRateMegaCps + * EffectiveSpadRtnCount) >> 8)) + <= 0) { + if (RangeFractionalEnable) + XtalkRangeMilliMeter = 8888; + else + XtalkRangeMilliMeter = 8888 + << 2; + } else { + XtalkRangeMilliMeter = + (tmpuint16 * SignalRate) + / (SignalRate + - ((XTalkCompensationRateMegaCps + * EffectiveSpadRtnCount) + >> 8)); + } + + tmpuint16 = XtalkRangeMilliMeter; + } + + } + + if (RangeFractionalEnable) { + pRangingMeasurementData->RangeMilliMeter = + (uint16_t)((tmpuint16) >> 2); + pRangingMeasurementData->RangeFractionalPart = + (uint8_t)((tmpuint16 & 0x03) << 6); + } else { + pRangingMeasurementData->RangeMilliMeter = tmpuint16; + pRangingMeasurementData->RangeFractionalPart = 0; + } + + /* + * For a standard definition of RangeStatus, this should + * return 0 in case of good result after a ranging + * The range status depends on the device so call a device + * specific function to obtain the right Status. + */ + Status |= VL_get_pal_range_status(Dev, DeviceRangeStatus, + SignalRate, EffectiveSpadRtnCount, + pRangingMeasurementData, &PalRangeStatus); + + if (Status == VL_ERROR_NONE) + pRangingMeasurementData->RangeStatus = PalRangeStatus; + + } + + if (Status == VL_ERROR_NONE) { + /* Copy last read data into Dev buffer */ + LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure); + + LastRangeDataBuffer.RangeMilliMeter = + pRangingMeasurementData->RangeMilliMeter; + LastRangeDataBuffer.RangeFractionalPart = + pRangingMeasurementData->RangeFractionalPart; + LastRangeDataBuffer.RangeDMaxMilliMeter = + pRangingMeasurementData->RangeDMaxMilliMeter; + LastRangeDataBuffer.MeasurementTimeUsec = + pRangingMeasurementData->MeasurementTimeUsec; + LastRangeDataBuffer.SignalRateRtnMegaCps = + pRangingMeasurementData->SignalRateRtnMegaCps; + LastRangeDataBuffer.AmbientRateRtnMegaCps = + pRangingMeasurementData->AmbientRateRtnMegaCps; + LastRangeDataBuffer.EffectiveSpadRtnCount = + pRangingMeasurementData->EffectiveSpadRtnCount; + LastRangeDataBuffer.RangeStatus = + pRangingMeasurementData->RangeStatus; + + PALDevDataSet(Dev, LastRangeMeasure, LastRangeDataBuffer); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev, + unsigned int *pMeasurementRefSignal) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SignalRefClipLimitCheckEnable = 0; + + LOG_FUNCTION_START(""); + + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + &SignalRefClipLimitCheckEnable); + if (SignalRefClipLimitCheckEnable != 0) + *pMeasurementRefSignal = PALDevDataGet(Dev, LastSignalRefMcps); + else + Status = VL_ERROR_INVALID_COMMAND; + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformSingleRangingMeasurement(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + /* This function will do a complete single ranging + * Here we fix the mode! */ + Status = VL_SetDeviceMode(Dev, VL_DEVICEMODE_SINGLE_RANGING); + + if (Status == VL_ERROR_NONE) + Status = VL_PerformSingleMeasurement(Dev); + + + if (Status == VL_ERROR_NONE) + Status = VL_GetRangingMeasurementData(Dev, + pRangingMeasurementData); + + + if (Status == VL_ERROR_NONE) + Status = VL_ClearInterruptMask(Dev, 0); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetNumberOfROIZones(struct vl_data *Dev, + uint8_t NumberOfROIZones) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (NumberOfROIZones != 1) + Status = VL_ERROR_INVALID_PARAMS; + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetNumberOfROIZones(struct vl_data *Dev, + uint8_t *pNumberOfROIZones) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfROIZones = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev, + uint8_t *pMaxNumberOfROIZones) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pMaxNumberOfROIZones = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL Measurement Functions */ + +int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t DeviceMode, uint8_t Functionality, + uint8_t Polarity) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t data; + + LOG_FUNCTION_START(""); + + if (Pin != 0) { + Status = VL_ERROR_GPIO_NOT_EXISTING; + } else if (DeviceMode == VL_DEVICEMODE_GPIO_DRIVE) { + if (Polarity == VL_INTERRUPTPOLARITY_LOW) + data = 0x10; + else + data = 1; + + Status = VL_WrByte(Dev, + VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, data); + + } else if (DeviceMode == VL_DEVICEMODE_GPIO_OSC) { + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + + Status |= VL_WrByte(Dev, 0xff, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x01); + Status |= VL_WrByte(Dev, 0x85, 0x02); + + Status |= VL_WrByte(Dev, 0xff, 0x04); + Status |= VL_WrByte(Dev, 0xcd, 0x00); + Status |= VL_WrByte(Dev, 0xcc, 0x11); + + Status |= VL_WrByte(Dev, 0xff, 0x07); + Status |= VL_WrByte(Dev, 0xbe, 0x00); + + Status |= VL_WrByte(Dev, 0xff, 0x06); + Status |= VL_WrByte(Dev, 0xcc, 0x09); + + Status |= VL_WrByte(Dev, 0xff, 0x00); + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + + } else { + + if (Status == VL_ERROR_NONE) { + switch (Functionality) { + case VL_GPIOFUNCTIONALITY_OFF: + data = 0x00; + break; + case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW: + data = 0x01; + break; + case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH: + data = 0x02; + break; + case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT: + data = 0x03; + break; + case VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY: + data = 0x04; + break; + default: + Status = + VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED; + } + } + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, data); + + if (Status == VL_ERROR_NONE) { + if (Polarity == VL_INTERRUPTPOLARITY_LOW) + data = 0; + else + data = (uint8_t)(1 << 4); + + Status = VL_UpdateByte(Dev, + VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, 0xEF, data); + } + + if (Status == VL_ERROR_NONE) + VL_SETDEVICESPECIFICPARAMETER(Dev, + Pin0GpioFunctionality, Functionality); + + if (Status == VL_ERROR_NONE) + Status = VL_ClearInterruptMask(Dev, 0); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t *pDeviceMode, + uint8_t *pFunctionality, + uint8_t *pPolarity) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t GpioFunctionality; + uint8_t data; + + LOG_FUNCTION_START(""); + + /* pDeviceMode not managed by Ewok it return the current mode */ + + Status = VL_GetDeviceMode(Dev, pDeviceMode); + + if (Status == VL_ERROR_NONE) { + if (Pin != 0) { + Status = VL_ERROR_GPIO_NOT_EXISTING; + } else { + Status = VL_RdByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, &data); + } + } + + if (Status == VL_ERROR_NONE) { + switch (data & 0x07) { + case 0x00: + GpioFunctionality = VL_GPIOFUNCTIONALITY_OFF; + break; + case 0x01: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW; + break; + case 0x02: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH; + break; + case 0x03: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT; + break; + case 0x04: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY; + break; + default: + Status = VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED; + } + } + + if (Status == VL_ERROR_NONE) + Status = VL_RdByte(Dev, + VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, &data); + + if (Status == VL_ERROR_NONE) { + if ((data & (uint8_t)(1 << 4)) == 0) + *pPolarity = VL_INTERRUPTPOLARITY_LOW; + else + *pPolarity = VL_INTERRUPTPOLARITY_HIGH; + } + + if (Status == VL_ERROR_NONE) { + *pFunctionality = GpioFunctionality; + VL_SETDEVICESPECIFICPARAMETER(Dev, Pin0GpioFunctionality, + GpioFunctionality); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int ThresholdLow, + unsigned int ThresholdHigh) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t Threshold16; + + LOG_FUNCTION_START(""); + + /* no dependency on DeviceMode for Ewok */ + /* Need to divide by 2 because the FW will apply a x2 */ + Threshold16 = (uint16_t)((ThresholdLow >> 17) & 0x00fff); + Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_LOW, + Threshold16); + + if (Status == VL_ERROR_NONE) { + /* Need to divide by 2 because the FW will apply a x2 */ + Threshold16 = (uint16_t)((ThresholdHigh >> 17) & 0x00fff); + Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_HIGH, + Threshold16); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int *pThresholdLow, + unsigned int *pThresholdHigh) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t Threshold16; + + LOG_FUNCTION_START(""); + + /* no dependency on DeviceMode for Ewok */ + + Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_LOW, + &Threshold16); + /* Need to multiply by 2 because the FW will apply a x2 */ + *pThresholdLow = (unsigned int)((0x00fff & Threshold16) << 17); + + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_HIGH, + &Threshold16); + /* Need to multiply by 2 because the FW will apply a x2 */ + *pThresholdHigh = + (unsigned int)((0x00fff & Threshold16) << 17); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetStopCompletedStatus(struct vl_data *Dev, + uint32_t *pStopStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte = 0; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_RdByte(Dev, 0x04, &Byte); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x0); + + *pStopStatus = Byte; + + if (Byte == 0) { + Status = VL_WrByte(Dev, 0x80, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status = VL_WrByte(Dev, 0x00, 0x00); + Status = VL_WrByte(Dev, 0x91, + PALDevDataGet(Dev, StopVariable)); + Status = VL_WrByte(Dev, 0x00, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x00); + Status = VL_WrByte(Dev, 0x80, 0x00); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +/* Group PAL Interrupt Functions */ +int8_t VL_ClearInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t LoopCount; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + /* clear bit 0 range interrupt, bit 1 error interrupt */ + LoopCount = 0; + do { + Status = VL_WrByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x00); + Status |= VL_RdByte(Dev, + VL_REG_RESULT_INTERRUPT_STATUS, &Byte); + LoopCount++; + } while (((Byte & 0x07) != 0x00) + && (LoopCount < 3) + && (Status == VL_ERROR_NONE)); + + + if (LoopCount >= 3) + Status = VL_ERROR_INTERRUPT_NOT_CLEARED; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev, + uint32_t *pInterruptMaskStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_RESULT_INTERRUPT_STATUS, + &Byte); + *pInterruptMaskStatus = Byte & 0x07; + + if (Byte & 0x18) + Status = VL_ERROR_RANGE_ERROR; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_EnableInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented for VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL Interrupt Functions */ + +/* Group SPAD functions */ + +int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t SpadAmbientDamperThreshold) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrWord(Dev, 0x40, SpadAmbientDamperThreshold); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperThreshold) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_RdWord(Dev, 0x40, pSpadAmbientDamperThreshold); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t SpadAmbientDamperFactor) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + Byte = (uint8_t)(SpadAmbientDamperFactor & 0x00FF); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x42, Byte); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperFactor) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_RdByte(Dev, 0x42, &Byte); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + *pSpadAmbientDamperFactor = (uint16_t)Byte; + + LOG_FUNCTION_END(Status); + return Status; +} + +/* END Group SPAD functions */ + +/***************************************************************************** + * Internal functions + *****************************************************************************/ + +int8_t VL_SetReferenceSpads(struct vl_data *Dev, uint32_t count, + uint8_t isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_reference_spads(Dev, count, isApertureSpads); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetReferenceSpads(struct vl_data *Dev, uint32_t *pSpadCount, + uint8_t *pIsApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_reference_spads(Dev, pSpadCount, pIsApertureSpads); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_PerformRefSpadManagement(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_ref_spad_management(Dev, refSpadCount, + isApertureSpads); + + LOG_FUNCTION_END(Status); + + return Status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c new file mode 100644 index 0000000000000000000000000000000000000000..4d03089e8c30c74f94fa5185f1fd6f17aaaf473f --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c @@ -0,0 +1,1268 @@ +/* + * vl53l0x_api_calibration.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_calibration.h" + +#ifndef __KERNEL__ +#include +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + +#define REF_ARRAY_SPAD_0 0 +#define REF_ARRAY_SPAD_5 5 +#define REF_ARRAY_SPAD_10 10 + +uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5, + REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5 }; + +int8_t VL_perform_xtalk_calibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t sum_ranging = 0; + uint16_t sum_spads = 0; + unsigned int sum_signalRate = 0; + unsigned int total_count = 0; + uint8_t xtalk_meas = 0; + struct VL_RangingMeasurementData_t RangingMeasurementData; + unsigned int xTalkStoredMeanSignalRate; + unsigned int xTalkStoredMeanRange; + unsigned int xTalkStoredMeanRtnSpads; + uint32_t signalXTalkTotalPerSpad; + uint32_t xTalkStoredMeanRtnSpadsAsInt; + uint32_t xTalkCalDistanceAsInt; + unsigned int XTalkCompensationRateMegaCps; + + if (XTalkCalDistance <= 0) + Status = VL_ERROR_INVALID_PARAMS; + + /* Disable the XTalk compensation */ + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationEnable(Dev, 0); + + /* Disable the RIT */ + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0); + } + + /* Perform 50 measurements and compute the averages */ + if (Status == VL_ERROR_NONE) { + sum_ranging = 0; + sum_spads = 0; + sum_signalRate = 0; + total_count = 0; + for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) { + Status = VL_PerformSingleRangingMeasurement(Dev, + &RangingMeasurementData); + + if (Status != VL_ERROR_NONE) + break; + + /* The range is valid when RangeStatus = 0 */ + if (RangingMeasurementData.RangeStatus == 0) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + sum_signalRate = sum_signalRate + + RangingMeasurementData.SignalRateRtnMegaCps; + sum_spads = sum_spads + + RangingMeasurementData.EffectiveSpadRtnCount + / 256; + total_count = total_count + 1; + } + } + + /* no valid values found */ + if (total_count == 0) + Status = VL_ERROR_RANGE_ERROR; + + } + + + if (Status == VL_ERROR_NONE) { + /* unsigned int / uint16_t = unsigned int */ + xTalkStoredMeanSignalRate = sum_signalRate / total_count; + xTalkStoredMeanRange = (unsigned int)((uint32_t)( + sum_ranging << 16) / total_count); + xTalkStoredMeanRtnSpads = (unsigned int)((uint32_t)( + sum_spads << 16) / total_count); + + /* Round Mean Spads to Whole Number. + * Typically the calculated mean SPAD count is a whole number + * or very close to a whole + * number, therefore any truncation will not result in a + * significant loss in accuracy. + * Also, for a grey target at a typical distance of around + * 400mm, around 220 SPADs will + * be enabled, therefore, any truncation will result in a loss + * of accuracy of less than + * 0.5%. + */ + xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads + + 0x8000) >> 16; + + /* Round Cal Distance to Whole Number. + * Note that the cal distance is in mm, therefore no resolution + * is lost.*/ + xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16; + + if (xTalkStoredMeanRtnSpadsAsInt == 0 || + xTalkCalDistanceAsInt == 0 || + xTalkStoredMeanRange >= XTalkCalDistance) { + XTalkCompensationRateMegaCps = 0; + } else { + /* Round Cal Distance to Whole Number. + Note that the cal distance is in mm, therefore no + resolution is lost.*/ + xTalkCalDistanceAsInt = (XTalkCalDistance + + 0x8000) >> 16; + + /* Apply division by mean spad count early in the + * calculation to keep the numbers small. + * This ensures we can maintain a 32bit calculation. + * Fixed1616 / int := Fixed1616 */ + signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) / + xTalkStoredMeanRtnSpadsAsInt; + + /* Complete the calculation for total Signal XTalk per + * SPAD + * Fixed1616 * (Fixed1616 - Fixed1616/int) := + * (2^16 * Fixed1616) + */ + signalXTalkTotalPerSpad *= ((1 << 16) - + (xTalkStoredMeanRange / xTalkCalDistanceAsInt)); + + /* Round from 2^16 * Fixed1616, to Fixed1616. */ + XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad + + 0x8000) >> 16; + } + + *pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps; + + /* Enable the XTalk compensation */ + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationEnable(Dev, 1); + + /* Enable the XTalk compensation */ + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationRateMegaCps(Dev, + XTalkCompensationRateMegaCps); + + } + + return Status; +} + +int8_t VL_perform_offset_calibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, + int32_t *pOffsetMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t sum_ranging = 0; + unsigned int total_count = 0; + struct VL_RangingMeasurementData_t RangingMeasurementData; + unsigned int StoredMeanRange; + uint32_t StoredMeanRangeAsInt; + uint32_t CalDistanceAsInt_mm; + uint8_t SequenceStepEnabled; + int meas = 0; + + if (CalDistanceMilliMeter <= 0) + Status = VL_ERROR_INVALID_PARAMS; + + if (Status == VL_ERROR_NONE) + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, 0); + + + /* Get the value of the TCC */ + if (Status == VL_ERROR_NONE) + Status = VL_GetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, &SequenceStepEnabled); + + + /* Disable the TCC */ + if (Status == VL_ERROR_NONE) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, 0); + + + /* Disable the RIT */ + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0); + + /* Perform 50 measurements and compute the averages */ + if (Status == VL_ERROR_NONE) { + sum_ranging = 0; + total_count = 0; + for (meas = 0; meas < 50; meas++) { + Status = VL_PerformSingleRangingMeasurement(Dev, + &RangingMeasurementData); + + if (Status != VL_ERROR_NONE) + break; + + /* The range is valid when RangeStatus = 0 */ + if (RangingMeasurementData.RangeStatus == 0) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + total_count = total_count + 1; + } + } + + /* no valid values found */ + if (total_count == 0) + Status = VL_ERROR_RANGE_ERROR; + } + + + if (Status == VL_ERROR_NONE) { + /* unsigned int / uint16_t = unsigned int */ + StoredMeanRange = (unsigned int)((uint32_t)(sum_ranging << 16) + / total_count); + + StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16; + + /* Round Cal Distance to Whole Number. + * Note that the cal distance is in mm, therefore no resolution + * is lost.*/ + CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16; + + *pOffsetMicroMeter = (CalDistanceAsInt_mm - + StoredMeanRangeAsInt) * 1000; + + /* Apply the calculated offset */ + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters, + *pOffsetMicroMeter); + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, + *pOffsetMicroMeter); + } + + } + + /* Restore the TCC */ + if (Status == VL_ERROR_NONE) { + if (SequenceStepEnabled != 0) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, 1); + } + + return Status; +} + + +int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + int32_t cMaxOffsetMicroMeter = 511000; + int32_t cMinOffsetMicroMeter = -512000; + int16_t cOffsetRange = 4096; + uint32_t encodedOffsetVal; + + LOG_FUNCTION_START(""); + + if (OffsetCalibrationDataMicroMeter > cMaxOffsetMicroMeter) + OffsetCalibrationDataMicroMeter = cMaxOffsetMicroMeter; + else if (OffsetCalibrationDataMicroMeter < cMinOffsetMicroMeter) + OffsetCalibrationDataMicroMeter = cMinOffsetMicroMeter; + + /* The offset register is 10.2 format and units are mm + * therefore conversion is applied by a division of + * 250. + */ + if (OffsetCalibrationDataMicroMeter >= 0) { + encodedOffsetVal = + OffsetCalibrationDataMicroMeter/250; + } else { + encodedOffsetVal = + cOffsetRange + + OffsetCalibrationDataMicroMeter/250; + } + + Status = VL_WrWord(Dev, + VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM, + encodedOffsetVal); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t RangeOffsetRegister; + int16_t cMaxOffset = 2047; + int16_t cOffsetRange = 4096; + + /* Note that offset has 10.2 format */ + + Status = VL_RdWord(Dev, + VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM, + &RangeOffsetRegister); + + if (Status == VL_ERROR_NONE) { + RangeOffsetRegister = (RangeOffsetRegister & 0x0fff); + + /* Apply 12 bit 2's compliment conversion */ + if (RangeOffsetRegister > cMaxOffset) + *pOffsetCalibrationDataMicroMeter = + (int16_t)(RangeOffsetRegister - cOffsetRange) + * 250; + else + *pOffsetCalibrationDataMicroMeter = + (int16_t)RangeOffsetRegister * 250; + + } + + return Status; +} + + +int8_t VL_apply_offset_adjustment(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + int32_t CorrectedOffsetMicroMeters; + int32_t CurrentOffsetMicroMeters; + + /* if we run on this function we can read all the NVM info + * used by the API */ + Status = VL_get_info_from_device(Dev, 7); + + /* Read back current device offset */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetOffsetCalibrationDataMicroMeter(Dev, + &CurrentOffsetMicroMeters); + } + + /* Apply Offset Adjustment derived from 400mm measurements */ + if (Status == VL_ERROR_NONE) { + + /* Store initial device offset */ + PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter, + CurrentOffsetMicroMeters); + + CorrectedOffsetMicroMeters = CurrentOffsetMicroMeters + + (int32_t)PALDevDataGet(Dev, + Part2PartOffsetAdjustmentNVMMicroMeter); + + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, + CorrectedOffsetMicroMeters); + + /* store current, adjusted offset */ + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters, + CorrectedOffsetMicroMeters); + } + } + + return Status; +} + +void get_next_good_spad(uint8_t goodSpadArray[], uint32_t size, + uint32_t curr, int32_t *next) +{ + uint32_t startIndex; + uint32_t fineOffset; + uint32_t cSpadsPerByte = 8; + uint32_t coarseIndex; + uint32_t fineIndex; + uint8_t dataByte; + uint8_t success = 0; + + /* + * Starting with the current good spad, loop through the array to find + * the next. i.e. the next bit set in the sequence. + * + * The coarse index is the byte index of the array and the fine index is + * the index of the bit within each byte. + */ + + *next = -1; + + startIndex = curr / cSpadsPerByte; + fineOffset = curr % cSpadsPerByte; + + for (coarseIndex = startIndex; ((coarseIndex < size) && !success); + coarseIndex++) { + fineIndex = 0; + dataByte = goodSpadArray[coarseIndex]; + + if (coarseIndex == startIndex) { + /* locate the bit position of the provided current + * spad bit before iterating */ + dataByte >>= fineOffset; + fineIndex = fineOffset; + } + + while (fineIndex < cSpadsPerByte) { + if ((dataByte & 0x1) == 1) { + success = 1; + *next = coarseIndex * cSpadsPerByte + fineIndex; + break; + } + dataByte >>= 1; + fineIndex++; + } + } +} + + +uint8_t is_aperture(uint32_t spadIndex) +{ + /* + * This function reports if a given spad index is an aperture SPAD by + * deriving the quadrant. + */ + uint32_t quadrant; + uint8_t isAperture = 1; + + quadrant = spadIndex >> 6; + if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0) + isAperture = 0; + + return isAperture; +} + + +int8_t enable_spad_bit(uint8_t spadArray[], uint32_t size, + uint32_t spadIndex) +{ + int8_t status = VL_ERROR_NONE; + uint32_t cSpadsPerByte = 8; + uint32_t coarseIndex; + uint32_t fineIndex; + + coarseIndex = spadIndex / cSpadsPerByte; + fineIndex = spadIndex % cSpadsPerByte; + if (coarseIndex >= size) + status = VL_ERROR_REF_SPAD_INIT; + else + spadArray[coarseIndex] |= (1 << fineIndex); + + return status; +} + +int8_t count_enabled_spads(uint8_t spadArray[], + uint32_t byteCount, uint32_t maxSpads, + uint32_t *pTotalSpadsEnabled, uint8_t *pIsAperture) +{ + int8_t status = VL_ERROR_NONE; + uint32_t cSpadsPerByte = 8; + uint32_t lastByte; + uint32_t lastBit; + uint32_t byteIndex = 0; + uint32_t bitIndex = 0; + uint8_t tempByte; + uint8_t spadTypeIdentified = 0; + + /* The entire array will not be used for spads, therefore the last + * byte and last bit is determined from the max spads value. + */ + + lastByte = maxSpads / cSpadsPerByte; + lastBit = maxSpads % cSpadsPerByte; + + /* Check that the max spads value does not exceed the array bounds. */ + if (lastByte >= byteCount) + status = VL_ERROR_REF_SPAD_INIT; + + *pTotalSpadsEnabled = 0; + + /* Count the bits enabled in the whole bytes */ + for (byteIndex = 0; byteIndex <= (lastByte - 1); byteIndex++) { + tempByte = spadArray[byteIndex]; + + for (bitIndex = 0; bitIndex <= cSpadsPerByte; bitIndex++) { + if ((tempByte & 0x01) == 1) { + (*pTotalSpadsEnabled)++; + + if (!spadTypeIdentified) { + *pIsAperture = 1; + if ((byteIndex < 2) && (bitIndex < 4)) + *pIsAperture = 0; + spadTypeIdentified = 1; + } + } + tempByte >>= 1; + } + } + + /* Count the number of bits enabled in the last byte accounting + * for the fact that not all bits in the byte may be used. + */ + tempByte = spadArray[lastByte]; + + for (bitIndex = 0; bitIndex <= lastBit; bitIndex++) { + if ((tempByte & 0x01) == 1) + (*pTotalSpadsEnabled)++; + } + + return status; +} + +int8_t set_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray) +{ + int8_t status = VL_WriteMulti(Dev, + VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0, + refSpadArray, 6); + return status; +} + +int8_t get_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray) +{ + int8_t status = VL_ReadMulti(Dev, + VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0, + refSpadArray, + 6); + return status; +} + +int8_t enable_ref_spads(struct vl_data *Dev, + uint8_t apertureSpads, + uint8_t goodSpadArray[], + uint8_t spadArray[], + uint32_t size, + uint32_t start, + uint32_t offset, + uint32_t spadCount, + uint32_t *lastSpad) +{ + int8_t status = VL_ERROR_NONE; + uint32_t index; + uint32_t i; + int32_t nextGoodSpad = offset; + uint32_t currentSpad; + uint8_t checkSpadArray[6]; + + /* + * This function takes in a spad array which may or may not have SPADS + * already enabled and appends from a given offset a requested number + * of new SPAD enables. The 'good spad map' is applied to + * determine the next SPADs to enable. + * + * This function applies to only aperture or only non-aperture spads. + * Checks are performed to ensure this. + */ + + currentSpad = offset; + for (index = 0; index < spadCount; index++) { + get_next_good_spad(goodSpadArray, size, currentSpad, + &nextGoodSpad); + + if (nextGoodSpad == -1) { + status = VL_ERROR_REF_SPAD_INIT; + break; + } + + /* Confirm that the next good SPAD is non-aperture */ + if (is_aperture(start + nextGoodSpad) != apertureSpads) { + /* if we can't get the required number of good aperture + * spads from the current quadrant then this is an error + */ + status = VL_ERROR_REF_SPAD_INIT; + break; + } + currentSpad = (uint32_t)nextGoodSpad; + enable_spad_bit(spadArray, size, currentSpad); + currentSpad++; + } + *lastSpad = currentSpad; + + if (status == VL_ERROR_NONE) + status = set_ref_spad_map(Dev, spadArray); + + + if (status == VL_ERROR_NONE) { + status = get_ref_spad_map(Dev, checkSpadArray); + + i = 0; + + /* Compare spad maps. If not equal report error. */ + while (i < size) { + if (spadArray[i] != checkSpadArray[i]) { + status = VL_ERROR_REF_SPAD_INIT; + break; + } + i++; + } + } + return status; +} + + +int8_t perform_ref_signal_measurement(struct vl_data *Dev, + uint16_t *refSignalRate) +{ + int8_t status = VL_ERROR_NONE; + struct VL_RangingMeasurementData_t rangingMeasurementData; + + uint8_t SequenceConfig = 0; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* + * This function performs a reference signal rate measurement. + */ + if (status == VL_ERROR_NONE) + status = VL_WrByte(Dev, + VL_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0); + + if (status == VL_ERROR_NONE) + status = VL_PerformSingleRangingMeasurement(Dev, + &rangingMeasurementData); + + if (status == VL_ERROR_NONE) + status = VL_WrByte(Dev, 0xFF, 0x01); + + if (status == VL_ERROR_NONE) + status = VL_RdWord(Dev, + VL_REG_RESULT_PEAK_SIGNAL_RATE_REF, + refSignalRate); + + if (status == VL_ERROR_NONE) + status = VL_WrByte(Dev, 0xFF, 0x00); + + if (status == VL_ERROR_NONE) { + /* restore the previous Sequence Config */ + status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + } + + return status; +} + +int8_t VL_perform_ref_spad_management(struct vl_data *Dev, + uint32_t *refSpadCount, + uint8_t *isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t lastSpadArray[6]; + uint8_t startSelect = 0xB4; + uint32_t minimumSpadCount = 3; + uint32_t maxSpadCount = 44; + uint32_t currentSpadIndex = 0; + uint32_t lastSpadIndex = 0; + int32_t nextGoodSpad = 0; + uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */ + uint16_t peakSignalRateRef; + uint32_t needAptSpads = 0; + uint32_t index = 0; + uint32_t spadArraySize = 6; + uint32_t signalRateDiff = 0; + uint32_t lastSignalRateDiff = 0; + uint8_t complete = 0; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + uint32_t refSpadCount_int = 0; + uint8_t isApertureSpads_int = 0; + + /* + * The reference SPAD initialization procedure determines the minimum + * amount of reference spads to be enables to achieve a target reference + * signal rate and should be performed once during initialization. + * + * Either aperture or non-aperture spads are applied but never both. + * Firstly non-aperture spads are set, beginning with 5 spads, and + * increased one spad at a time until the closest measurement to the + * target rate is achieved. + * + * If the target rate is exceeded when 5 non-aperture spads are enabled, + * initialization is performed instead with aperture spads. + * + * When setting spads, a 'Good Spad Map' is applied. + * + * This procedure operates within a SPAD window of interest of a maximum + * 44 spads. + * The start point is currently fixed to 180, which lies towards the end + * of the non-aperture quadrant and runs in to the adjacent aperture + * quadrant. + */ + + + targetRefRate = PALDevDataGet(Dev, targetRefRate); + + /* + * Initialize Spad arrays. + * Currently the good spad map is initialised to 'All good'. + * This is a short term implementation. The good spad map will be + * provided as an input. + * Note that there are 6 bytes. Only the first 44 bits will be used to + * represent spads. + */ + for (index = 0; index < spadArraySize; index++) + Dev->Data.SpadData.RefSpadEnables[index] = 0; + + + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT, + startSelect); + + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0); + + /* Perform ref calibration */ + if (Status == VL_ERROR_NONE) + Status = VL_perform_ref_calibration(Dev, &VhvSettings, + &PhaseCal, 0); + + if (Status == VL_ERROR_NONE) { + /* Enable Minimum NON-APERTURE Spads */ + currentSpadIndex = 0; + lastSpadIndex = currentSpadIndex; + needAptSpads = 0; + Status = enable_ref_spads(Dev, + needAptSpads, + Dev->Data.SpadData.RefGoodSpadMap, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, + startSelect, + currentSpadIndex, + minimumSpadCount, + &lastSpadIndex); + } + + if (Status == VL_ERROR_NONE) { + currentSpadIndex = lastSpadIndex; + + Status = perform_ref_signal_measurement(Dev, + &peakSignalRateRef); + if ((Status == VL_ERROR_NONE) && + (peakSignalRateRef > targetRefRate)) { + /* Signal rate measurement too high, + * switch to APERTURE SPADs */ + + for (index = 0; index < spadArraySize; index++) + Dev->Data.SpadData.RefSpadEnables[index] = 0; + + + /* Increment to the first APERTURE spad */ + while ((is_aperture(startSelect + currentSpadIndex) + == 0) && (currentSpadIndex < maxSpadCount)) { + currentSpadIndex++; + } + + needAptSpads = 1; + + Status = enable_ref_spads(Dev, + needAptSpads, + Dev->Data.SpadData.RefGoodSpadMap, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, + startSelect, + currentSpadIndex, + minimumSpadCount, + &lastSpadIndex); + + if (Status == VL_ERROR_NONE) { + currentSpadIndex = lastSpadIndex; + Status = perform_ref_signal_measurement(Dev, + &peakSignalRateRef); + + if ((Status == VL_ERROR_NONE) && + (peakSignalRateRef > targetRefRate)) { + /* Signal rate still too high after + * setting the minimum number of + * APERTURE spads. Can do no more + * therefore set the min number of + * aperture spads as the result. + */ + isApertureSpads_int = 1; + refSpadCount_int = minimumSpadCount; + } + } + } else { + needAptSpads = 0; + } + } + + if ((Status == VL_ERROR_NONE) && + (peakSignalRateRef < targetRefRate)) { + /* At this point, the minimum number of either aperture + * or non-aperture spads have been set. Proceed to add + * spads and perform measurements until the target + * reference is reached. + */ + isApertureSpads_int = needAptSpads; + refSpadCount_int = minimumSpadCount; + + memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables, + spadArraySize); + lastSignalRateDiff = abs(peakSignalRateRef - + targetRefRate); + complete = 0; + + while (!complete) { + get_next_good_spad( + Dev->Data.SpadData.RefGoodSpadMap, + spadArraySize, currentSpadIndex, + &nextGoodSpad); + + if (nextGoodSpad == -1) { + Status = VL_ERROR_REF_SPAD_INIT; + break; + } + + /* Cannot combine Aperture and Non-Aperture spads, so + * ensure the current spad is of the correct type. + */ + if (is_aperture((uint32_t)startSelect + nextGoodSpad) != + needAptSpads) { + /* At this point we have enabled the maximum + * number of Aperture spads. + */ + complete = 1; + break; + } + + (refSpadCount_int)++; + + currentSpadIndex = nextGoodSpad; + Status = enable_spad_bit( + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, currentSpadIndex); + + if (Status == VL_ERROR_NONE) { + currentSpadIndex++; + /* Proceed to apply the additional spad and + * perform measurement. */ + Status = set_ref_spad_map(Dev, + Dev->Data.SpadData.RefSpadEnables); + } + + if (Status != VL_ERROR_NONE) + break; + + Status = perform_ref_signal_measurement(Dev, + &peakSignalRateRef); + + if (Status != VL_ERROR_NONE) + break; + + signalRateDiff = abs(peakSignalRateRef - targetRefRate); + + if (peakSignalRateRef > targetRefRate) { + /* Select the spad map that provides the + * measurement closest to the target rate, + * either above or below it. + */ + if (signalRateDiff > lastSignalRateDiff) { + /* Previous spad map produced a closer + * measurement, so choose this. */ + Status = set_ref_spad_map(Dev, + lastSpadArray); + memcpy( + Dev->Data.SpadData.RefSpadEnables, + lastSpadArray, spadArraySize); + + (refSpadCount_int)--; + } + complete = 1; + } else { + /* Continue to add spads */ + lastSignalRateDiff = signalRateDiff; + memcpy(lastSpadArray, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize); + } + + } /* while */ + } + + if (Status == VL_ERROR_NONE) { + *refSpadCount = refSpadCount_int; + *isApertureSpads = isApertureSpads_int; + + VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, (uint8_t)(*refSpadCount)); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, *isApertureSpads); + } + + return Status; +} + +int8_t VL_set_reference_spads(struct vl_data *Dev, + uint32_t count, uint8_t isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + uint32_t currentSpadIndex = 0; + uint8_t startSelect = 0xB4; + uint32_t spadArraySize = 6; + uint32_t maxSpadCount = 44; + uint32_t lastSpadIndex; + uint32_t index; + + /* + * This function applies a requested number of reference spads, either + * aperture or + * non-aperture, as requested. + * The good spad map will be applied. + */ + + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT, + startSelect); + + for (index = 0; index < spadArraySize; index++) + Dev->Data.SpadData.RefSpadEnables[index] = 0; + + if (isApertureSpads) { + /* Increment to the first APERTURE spad */ + while ((is_aperture(startSelect + currentSpadIndex) == 0) && + (currentSpadIndex < maxSpadCount)) { + currentSpadIndex++; + } + } + Status = enable_ref_spads(Dev, + isApertureSpads, + Dev->Data.SpadData.RefGoodSpadMap, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, + startSelect, + currentSpadIndex, + count, + &lastSpadIndex); + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, (uint8_t)(count)); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, isApertureSpads); + } + + return Status; +} + +int8_t VL_get_reference_spads(struct vl_data *Dev, + uint32_t *pSpadCount, uint8_t *pIsApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t refSpadsInitialised; + uint8_t refSpadArray[6]; + uint32_t cMaxSpadCount = 44; + uint32_t cSpadArraySize = 6; + uint32_t spadsEnabled; + uint8_t isApertureSpads = 0; + + refSpadsInitialised = VL_GETDEVICESPECIFICPARAMETER(Dev, + RefSpadsInitialised); + + if (refSpadsInitialised == 1) { + + *pSpadCount = (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount); + *pIsApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType); + } else { + + /* obtain spad info from device.*/ + Status = get_ref_spad_map(Dev, refSpadArray); + + if (Status == VL_ERROR_NONE) { + /* count enabled spads within spad map array and + * determine if Aperture or Non-Aperture. + */ + Status = count_enabled_spads(refSpadArray, + cSpadArraySize, + cMaxSpadCount, + &spadsEnabled, + &isApertureSpads); + + if (Status == VL_ERROR_NONE) { + + *pSpadCount = spadsEnabled; + *pIsApertureSpads = isApertureSpads; + + VL_SETDEVICESPECIFICPARAMETER(Dev, + RefSpadsInitialised, 1); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, + (uint8_t)spadsEnabled); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, isApertureSpads); + } + } + } + + return Status; +} + + +int8_t VL_perform_single_ref_calibration(struct vl_data *Dev, + uint8_t vhv_init_byte) +{ + int8_t Status = VL_ERROR_NONE; + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_START_STOP | + vhv_init_byte); + + if (Status == VL_ERROR_NONE) + Status = VL_measurement_poll_for_completion(Dev); + + if (Status == VL_ERROR_NONE) + Status = VL_ClearInterruptMask(Dev, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x00); + + return Status; +} + + +int8_t VL_ref_calibration_io(struct vl_data *Dev, + uint8_t read_not_write, uint8_t VhvSettings, uint8_t PhaseCal, + uint8_t *pVhvSettings, uint8_t *pPhaseCal, + const uint8_t vhv_enable, const uint8_t phase_enable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t PhaseCalint = 0; + + /* Read VHV from device */ + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + if (read_not_write) { + if (vhv_enable) + Status |= VL_RdByte(Dev, 0xCB, pVhvSettings); + if (phase_enable) + Status |= VL_RdByte(Dev, 0xEE, &PhaseCalint); + } else { + if (vhv_enable) + Status |= VL_WrByte(Dev, 0xCB, VhvSettings); + if (phase_enable) + Status |= VL_UpdateByte(Dev, 0xEE, 0x80, PhaseCal); + } + + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + *pPhaseCal = (uint8_t)(PhaseCalint&0xEF); + + return Status; +} + + +int8_t VL_perform_vhv_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, const uint8_t get_data_enable, + const uint8_t restore_config) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + uint8_t PhaseCalInt = 0; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + if (restore_config) + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* Run VHV */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_perform_single_ref_calibration(Dev, 0x40); + + /* Read VHV from device */ + if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) { + Status = VL_ref_calibration_io(Dev, 1, + VhvSettings, PhaseCal, /* Not used here */ + pVhvSettings, &PhaseCalInt, + 1, 0); + } else + *pVhvSettings = 0; + + + if ((Status == VL_ERROR_NONE) && restore_config) { + /* restore the previous Sequence Config */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + + } + + return Status; +} + +int8_t VL_perform_phase_calibration(struct vl_data *Dev, + uint8_t *pPhaseCal, const uint8_t get_data_enable, + const uint8_t restore_config) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + uint8_t VhvSettingsint; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + if (restore_config) + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* Run PhaseCal */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x02); + + if (Status == VL_ERROR_NONE) + Status = VL_perform_single_ref_calibration(Dev, 0x0); + + /* Read PhaseCal from device */ + if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) { + Status = VL_ref_calibration_io(Dev, 1, + VhvSettings, PhaseCal, /* Not used here */ + &VhvSettingsint, pPhaseCal, + 0, 1); + } else + *pPhaseCal = 0; + + + if ((Status == VL_ERROR_NONE) && restore_config) { + /* restore the previous Sequence Config */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + + } + + return Status; +} + +int8_t VL_perform_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* In the following function we don't save the config to optimize + * writes on device. Config is saved and restored only once. */ + Status = VL_perform_vhv_calibration( + Dev, pVhvSettings, get_data_enable, 0); + + + if (Status == VL_ERROR_NONE) + Status = VL_perform_phase_calibration( + Dev, pPhaseCal, get_data_enable, 0); + + + if (Status == VL_ERROR_NONE) { + /* restore the previous Sequence Config */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + + } + + return Status; +} + +int8_t VL_set_ref_calibration(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t pVhvSettings; + uint8_t pPhaseCal; + + Status = VL_ref_calibration_io(Dev, 0, + VhvSettings, PhaseCal, + &pVhvSettings, &pPhaseCal, + 1, 1); + + return Status; +} + +int8_t VL_get_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + + Status = VL_ref_calibration_io(Dev, 1, + VhvSettings, PhaseCal, + pVhvSettings, pPhaseCal, + 1, 1); + + return Status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c new file mode 100644 index 0000000000000000000000000000000000000000..2c42ad7923c769dc6ec4e74d01eaa5f6d992d475 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c @@ -0,0 +1,2237 @@ +/* + * vl53l0x_api_core.c - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_calibration.h" + + +#ifndef __KERNEL__ +#include +#endif +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + +int8_t VL_reverse_bytes(uint8_t *data, uint32_t size) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t tempData; + uint32_t mirrorIndex; + uint32_t middle = size/2; + uint32_t index; + + for (index = 0; index < middle; index++) { + mirrorIndex = size - index - 1; + tempData = data[index]; + data[index] = data[mirrorIndex]; + data[mirrorIndex] = tempData; + } + return Status; +} + +int8_t VL_measurement_poll_for_completion(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t NewDataReady = 0; + uint32_t LoopNb; + + LOG_FUNCTION_START(""); + + LoopNb = 0; + + do { + Status = VL_GetMeasurementDataReady(Dev, &NewDataReady); + if (Status != 0) + break; /* the error is set */ + + if (NewDataReady == 1) + break; /* done note that status == 0 */ + + LoopNb++; + if (LoopNb >= VL_DEFAULT_MAX_LOOP) { + Status = VL_ERROR_TIME_OUT; + break; + } + + VL_PollingDelay(Dev); + } while (1); + + LOG_FUNCTION_END(Status); + + return Status; +} + + +uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg) +{ + /*! + * Converts the encoded VCSEL period register value into the real + * period in PLL clocks + */ + + uint8_t vcsel_period_pclks = 0; + + vcsel_period_pclks = (vcsel_period_reg + 1) << 1; + + return vcsel_period_pclks; +} + +uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks) +{ + /*! + * Converts the encoded VCSEL period register value into the real period + * in PLL clocks + */ + + uint8_t vcsel_period_reg = 0; + + vcsel_period_reg = (vcsel_period_pclks >> 1) - 1; + + return vcsel_period_reg; +} + + +uint32_t VL_isqrt(uint32_t num) +{ + /* + * Implements an integer square root + * + * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots + */ + + uint32_t res = 0; + uint32_t bit = 1 << 30; + /* The second-to-top bit is set: + * 1 << 14 for 16-bits, 1 << 30 for 32 bits */ + + /* "bit" starts at the highest power of four <= the argument. */ + while (bit > num) + bit >>= 2; + + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else + res >>= 1; + + bit >>= 2; + } + + return res; +} + + +uint32_t VL_quadrature_sum(uint32_t a, uint32_t b) +{ + /* + * Implements a quadrature sum + * + * rea = sqrt(a^2 + b^2) + * + * Trap overflow case max input value is 65535 (16-bit value) + * as internal calc are 32-bit wide + * + * If overflow then seta output to maximum + */ + uint32_t res = 0; + + if (a > 65535 || b > 65535) + res = 65535; + else + res = VL_isqrt(a * a + b * b); + + return res; +} + + +int8_t VL_device_read_strobe(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t strobe; + uint32_t LoopNb; + + LOG_FUNCTION_START(""); + + Status |= VL_WrByte(Dev, 0x83, 0x00); + + /* polling + * use timeout to avoid deadlock*/ + if (Status == VL_ERROR_NONE) { + LoopNb = 0; + do { + Status = VL_RdByte(Dev, 0x83, &strobe); + if ((strobe != 0x00) || Status != VL_ERROR_NONE) + break; + + LoopNb = LoopNb + 1; + } while (LoopNb < VL_DEFAULT_MAX_LOOP); + + if (LoopNb >= VL_DEFAULT_MAX_LOOP) + Status = VL_ERROR_TIME_OUT; + + } + + Status |= VL_WrByte(Dev, 0x83, 0x01); + + LOG_FUNCTION_END(Status); + return Status; + +} + +int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option) +{ + + int8_t Status = VL_ERROR_NONE; + uint8_t byte; + uint32_t TmpDWord; + uint8_t ModuleId; + uint8_t Revision; + uint8_t ReferenceSpadCount = 0; + uint8_t ReferenceSpadType = 0; + uint32_t PartUIDUpper = 0; + uint32_t PartUIDLower = 0; + uint32_t OffsetFixed1104_mm = 0; + int16_t OffsetMicroMeters = 0; + uint32_t DistMeasTgtFixed1104_mm = 400 << 4; + uint32_t DistMeasFixed1104_400_mm = 0; + uint32_t SignalRateMeasFixed1104_400_mm = 0; + char ProductId[19]; + char *ProductId_tmp; + uint8_t ReadDataFromDeviceDone; + unsigned int SignalRateMeasFixed400mmFix = 0; + uint8_t NvmRefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE]; + int i; + + + LOG_FUNCTION_START(""); + + ReadDataFromDeviceDone = VL_GETDEVICESPECIFICPARAMETER(Dev, + ReadDataFromDeviceDone); + + /* This access is done only once after that a GetDeviceInfo or + * datainit is done*/ + if (ReadDataFromDeviceDone != 7) { + + Status |= VL_WrByte(Dev, 0x80, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + + Status |= VL_WrByte(Dev, 0xFF, 0x06); + Status |= VL_RdByte(Dev, 0x83, &byte); + Status |= VL_WrByte(Dev, 0x83, byte|4); + Status |= VL_WrByte(Dev, 0xFF, 0x07); + Status |= VL_WrByte(Dev, 0x81, 0x01); + + Status |= VL_PollingDelay(Dev); + + Status |= VL_WrByte(Dev, 0x80, 0x01); + + if (((option & 1) == 1) && + ((ReadDataFromDeviceDone & 1) == 0)) { + Status |= VL_WrByte(Dev, 0x94, 0x6b); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ReferenceSpadCount = (uint8_t)((TmpDWord >> 8) & 0x07f); + ReferenceSpadType = (uint8_t)((TmpDWord >> 15) & 0x01); + + Status |= VL_WrByte(Dev, 0x94, 0x24); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + + NvmRefGoodSpadMap[0] = (uint8_t)((TmpDWord >> 24) + & 0xff); + NvmRefGoodSpadMap[1] = (uint8_t)((TmpDWord >> 16) + & 0xff); + NvmRefGoodSpadMap[2] = (uint8_t)((TmpDWord >> 8) + & 0xff); + NvmRefGoodSpadMap[3] = (uint8_t)(TmpDWord & 0xff); + + Status |= VL_WrByte(Dev, 0x94, 0x25); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + NvmRefGoodSpadMap[4] = (uint8_t)((TmpDWord >> 24) + & 0xff); + NvmRefGoodSpadMap[5] = (uint8_t)((TmpDWord >> 16) + & 0xff); + } + + if (((option & 2) == 2) && + ((ReadDataFromDeviceDone & 2) == 0)) { + + Status |= VL_WrByte(Dev, 0x94, 0x02); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdByte(Dev, 0x90, &ModuleId); + + Status |= VL_WrByte(Dev, 0x94, 0x7B); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdByte(Dev, 0x90, &Revision); + + Status |= VL_WrByte(Dev, 0x94, 0x77); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[0] = (char)((TmpDWord >> 25) & 0x07f); + ProductId[1] = (char)((TmpDWord >> 18) & 0x07f); + ProductId[2] = (char)((TmpDWord >> 11) & 0x07f); + ProductId[3] = (char)((TmpDWord >> 4) & 0x07f); + + byte = (uint8_t)((TmpDWord & 0x00f) << 3); + + Status |= VL_WrByte(Dev, 0x94, 0x78); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[4] = (char)(byte + + ((TmpDWord >> 29) & 0x07f)); + ProductId[5] = (char)((TmpDWord >> 22) & 0x07f); + ProductId[6] = (char)((TmpDWord >> 15) & 0x07f); + ProductId[7] = (char)((TmpDWord >> 8) & 0x07f); + ProductId[8] = (char)((TmpDWord >> 1) & 0x07f); + + byte = (uint8_t)((TmpDWord & 0x001) << 6); + + Status |= VL_WrByte(Dev, 0x94, 0x79); + + Status |= VL_device_read_strobe(Dev); + + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[9] = (char)(byte + + ((TmpDWord >> 26) & 0x07f)); + ProductId[10] = (char)((TmpDWord >> 19) & 0x07f); + ProductId[11] = (char)((TmpDWord >> 12) & 0x07f); + ProductId[12] = (char)((TmpDWord >> 5) & 0x07f); + + byte = (uint8_t)((TmpDWord & 0x01f) << 2); + + Status |= VL_WrByte(Dev, 0x94, 0x7A); + + Status |= VL_device_read_strobe(Dev); + + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[13] = (char)(byte + + ((TmpDWord >> 30) & 0x07f)); + ProductId[14] = (char)((TmpDWord >> 23) & 0x07f); + ProductId[15] = (char)((TmpDWord >> 16) & 0x07f); + ProductId[16] = (char)((TmpDWord >> 9) & 0x07f); + ProductId[17] = (char)((TmpDWord >> 2) & 0x07f); + ProductId[18] = '\0'; + + } + + if (((option & 4) == 4) && + ((ReadDataFromDeviceDone & 4) == 0)) { + + Status |= VL_WrByte(Dev, 0x94, 0x7B); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &PartUIDUpper); + + Status |= VL_WrByte(Dev, 0x94, 0x7C); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &PartUIDLower); + + Status |= VL_WrByte(Dev, 0x94, 0x73); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + SignalRateMeasFixed1104_400_mm = (TmpDWord & + 0x0000000ff) << 8; + + Status |= VL_WrByte(Dev, 0x94, 0x74); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + SignalRateMeasFixed1104_400_mm |= ((TmpDWord & + 0xff000000) >> 24); + + Status |= VL_WrByte(Dev, 0x94, 0x75); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + DistMeasFixed1104_400_mm = (TmpDWord & 0x0000000ff) + << 8; + + Status |= VL_WrByte(Dev, 0x94, 0x76); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + DistMeasFixed1104_400_mm |= ((TmpDWord & 0xff000000) + >> 24); + } + + Status |= VL_WrByte(Dev, 0x81, 0x00); + Status |= VL_WrByte(Dev, 0xFF, 0x06); + Status |= VL_RdByte(Dev, 0x83, &byte); + Status |= VL_WrByte(Dev, 0x83, byte&0xfb); + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x01); + + Status |= VL_WrByte(Dev, 0xFF, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x00); + } + + if ((Status == VL_ERROR_NONE) && + (ReadDataFromDeviceDone != 7)) { + /* Assign to variable if status is ok */ + if (((option & 1) == 1) && + ((ReadDataFromDeviceDone & 1) == 0)) { + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, ReferenceSpadCount); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, ReferenceSpadType); + + for (i = 0; i < VL_REF_SPAD_BUFFER_SIZE; i++) { + Dev->Data.SpadData.RefGoodSpadMap[i] = + NvmRefGoodSpadMap[i]; + } + } + + if (((option & 2) == 2) && + ((ReadDataFromDeviceDone & 2) == 0)) { + VL_SETDEVICESPECIFICPARAMETER(Dev, + ModuleId, ModuleId); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + Revision, Revision); + + ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev, + ProductId); + VL_COPYSTRING(ProductId_tmp, ProductId); + + } + + if (((option & 4) == 4) && + ((ReadDataFromDeviceDone & 4) == 0)) { + VL_SETDEVICESPECIFICPARAMETER(Dev, + PartUIDUpper, PartUIDUpper); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + PartUIDLower, PartUIDLower); + + SignalRateMeasFixed400mmFix = + VL_FIXPOINT97TOFIXPOINT1616( + SignalRateMeasFixed1104_400_mm); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + SignalRateMeasFixed400mm, + SignalRateMeasFixed400mmFix); + + OffsetMicroMeters = 0; + if (DistMeasFixed1104_400_mm != 0) { + OffsetFixed1104_mm = + DistMeasFixed1104_400_mm - + DistMeasTgtFixed1104_mm; + OffsetMicroMeters = (OffsetFixed1104_mm + * 1000) >> 4; + OffsetMicroMeters *= -1; + } + + PALDevDataSet(Dev, + Part2PartOffsetAdjustmentNVMMicroMeter, + OffsetMicroMeters); + } + byte = (uint8_t)(ReadDataFromDeviceDone|option); + VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone, + byte); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +uint32_t VL_calc_macro_period_ps(struct vl_data *Dev, + uint8_t vcsel_period_pclks) +{ + uint64_t PLL_period_ps; + uint32_t macro_period_vclks; + uint32_t macro_period_ps; + + LOG_FUNCTION_START(""); + + /* The above calculation will produce rounding errors, + therefore set fixed value + */ + PLL_period_ps = 1655; + + macro_period_vclks = 2304; + macro_period_ps = (uint32_t)(macro_period_vclks + * vcsel_period_pclks * PLL_period_ps); + + LOG_FUNCTION_END(""); + return macro_period_ps; +} + +uint16_t VL_encode_timeout(uint32_t timeout_macro_clks) +{ + /*! + * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format + */ + + uint16_t encoded_timeout = 0; + uint32_t ls_byte = 0; + uint16_t ms_byte = 0; + + if (timeout_macro_clks > 0) { + ls_byte = timeout_macro_clks - 1; + + while ((ls_byte & 0xFFFFFF00) > 0) { + ls_byte = ls_byte >> 1; + ms_byte++; + } + + encoded_timeout = (ms_byte << 8) + + (uint16_t) (ls_byte & 0x000000FF); + } + + return encoded_timeout; + +} + +uint32_t VL_decode_timeout(uint16_t encoded_timeout) +{ + /*! + * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1 + */ + + uint32_t timeout_macro_clks = 0; + + timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF) + << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1; + + return timeout_macro_clks; +} + + +/* To convert ms into register value */ +uint32_t VL_calc_timeout_mclks(struct vl_data *Dev, + uint32_t timeout_period_us, + uint8_t vcsel_period_pclks) +{ + uint32_t macro_period_ps; + uint32_t macro_period_ns; + uint32_t timeout_period_mclks = 0; + + macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks); + macro_period_ns = (macro_period_ps + 500) / 1000; + + timeout_period_mclks = + (uint32_t) (((timeout_period_us * 1000) + + (macro_period_ns / 2)) / macro_period_ns); + + return timeout_period_mclks; +} + +/* To convert register value into us */ +uint32_t VL_calc_timeout_us(struct vl_data *Dev, + uint16_t timeout_period_mclks, + uint8_t vcsel_period_pclks) +{ + uint32_t macro_period_ps; + uint32_t macro_period_ns; + uint32_t actual_timeout_period_us = 0; + + macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks); + macro_period_ns = (macro_period_ps + 500) / 1000; + + actual_timeout_period_us = + ((timeout_period_mclks * macro_period_ns) + 500) / 1000; + + return actual_timeout_period_us; +} + + +int8_t get_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t *pTimeOutMicroSecs) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t CurrentVCSELPulsePeriodPClk; + uint8_t EncodedTimeOutByte = 0; + uint32_t TimeoutMicroSeconds = 0; + uint16_t PreRangeEncodedTimeOut = 0; + uint16_t MsrcTimeOutMClks; + uint16_t PreRangeTimeOutMClks; + uint16_t FinalRangeTimeOutMClks = 0; + uint16_t FinalRangeEncodedTimeOut; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + + if ((SequenceStepId == VL_SEQUENCESTEP_TCC) || + (SequenceStepId == VL_SEQUENCESTEP_DSS) || + (SequenceStepId == VL_SEQUENCESTEP_MSRC)) { + + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_MSRC_CONFIG_TIMEOUT_MACROP, + &EncodedTimeOutByte); + } + MsrcTimeOutMClks = VL_decode_timeout(EncodedTimeOutByte); + + TimeoutMicroSeconds = VL_calc_timeout_us(Dev, + MsrcTimeOutMClks, + CurrentVCSELPulsePeriodPClk); + } else if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) { + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + /* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */ + if (Status == VL_ERROR_NONE) { + + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, + VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, + &PreRangeEncodedTimeOut); + } + + PreRangeTimeOutMClks = VL_decode_timeout( + PreRangeEncodedTimeOut); + + TimeoutMicroSeconds = VL_calc_timeout_us(Dev, + PreRangeTimeOutMClks, + CurrentVCSELPulsePeriodPClk); + } + } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) { + + VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps); + PreRangeTimeOutMClks = 0; + + if (SchedulerSequenceSteps.PreRangeOn) { + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + /* Retrieve PRE-RANGE Timeout in Macro periods + * (MCLKS) */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, + VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, + &PreRangeEncodedTimeOut); + PreRangeTimeOutMClks = VL_decode_timeout( + PreRangeEncodedTimeOut); + } + } + + if (Status == VL_ERROR_NONE) { + /* Retrieve FINAL-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_FINAL_RANGE, + &CurrentVCSELPulsePeriodPClk); + } + + /* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, + &FinalRangeEncodedTimeOut); + FinalRangeTimeOutMClks = VL_decode_timeout( + FinalRangeEncodedTimeOut); + } + + FinalRangeTimeOutMClks -= PreRangeTimeOutMClks; + TimeoutMicroSeconds = VL_calc_timeout_us(Dev, + FinalRangeTimeOutMClks, + CurrentVCSELPulsePeriodPClk); + } + + *pTimeOutMicroSecs = TimeoutMicroSeconds; + + return Status; +} + + +int8_t set_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t TimeOutMicroSecs) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t CurrentVCSELPulsePeriodPClk; + uint8_t MsrcEncodedTimeOut; + uint16_t PreRangeEncodedTimeOut; + uint16_t PreRangeTimeOutMClks; + uint16_t MsrcRangeTimeOutMClks; + uint32_t FinalRangeTimeOutMClks; + uint16_t FinalRangeEncodedTimeOut; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + + if ((SequenceStepId == VL_SEQUENCESTEP_TCC) || + (SequenceStepId == VL_SEQUENCESTEP_DSS) || + (SequenceStepId == VL_SEQUENCESTEP_MSRC)) { + + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + if (Status == VL_ERROR_NONE) { + MsrcRangeTimeOutMClks = VL_calc_timeout_mclks(Dev, + TimeOutMicroSecs, + (uint8_t)CurrentVCSELPulsePeriodPClk); + + if (MsrcRangeTimeOutMClks > 256) + MsrcEncodedTimeOut = 255; + else + MsrcEncodedTimeOut = + (uint8_t)MsrcRangeTimeOutMClks - 1; + + VL_SETDEVICESPECIFICPARAMETER(Dev, + LastEncodedTimeout, + MsrcEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_WrByte(Dev, + VL_REG_MSRC_CONFIG_TIMEOUT_MACROP, + MsrcEncodedTimeOut); + } + } else { + + if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) { + + if (Status == VL_ERROR_NONE) { + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + PreRangeTimeOutMClks = + VL_calc_timeout_mclks(Dev, + TimeOutMicroSecs, + (uint8_t)CurrentVCSELPulsePeriodPClk); + PreRangeEncodedTimeOut = VL_encode_timeout( + PreRangeTimeOutMClks); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + LastEncodedTimeout, + PreRangeEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_WrWord(Dev, + VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, + PreRangeEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + PreRangeTimeoutMicroSecs, + TimeOutMicroSecs); + } + } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) { + + /* For the final range timeout, the pre-range timeout + * must be added. To do this both final and pre-range + * timeouts must be expressed in macro periods MClks + * because they have different vcsel periods. + */ + + VL_GetSequenceStepEnables(Dev, + &SchedulerSequenceSteps); + PreRangeTimeOutMClks = 0; + if (SchedulerSequenceSteps.PreRangeOn) { + + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + /* Retrieve PRE-RANGE Timeout in Macro periods + * (MCLKS) */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, 0x51, + &PreRangeEncodedTimeOut); + PreRangeTimeOutMClks = + VL_decode_timeout( + PreRangeEncodedTimeOut); + } + } + + /* Calculate FINAL RANGE Timeout in Macro Periods + * (MCLKS) and add PRE-RANGE value + */ + if (Status == VL_ERROR_NONE) { + + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_FINAL_RANGE, + &CurrentVCSELPulsePeriodPClk); + } + if (Status == VL_ERROR_NONE) { + + FinalRangeTimeOutMClks = + VL_calc_timeout_mclks(Dev, + TimeOutMicroSecs, + (uint8_t) CurrentVCSELPulsePeriodPClk); + + FinalRangeTimeOutMClks += PreRangeTimeOutMClks; + + FinalRangeEncodedTimeOut = + VL_encode_timeout(FinalRangeTimeOutMClks); + + if (Status == VL_ERROR_NONE) { + Status = VL_WrWord(Dev, 0x71, + FinalRangeEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + FinalRangeTimeoutMicroSecs, + TimeOutMicroSecs); + } + } + } else + Status = VL_ERROR_INVALID_PARAMS; + + } + return Status; +} + +int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t vcsel_period_reg; + uint8_t MinPreVcselPeriodPCLK = 12; + uint8_t MaxPreVcselPeriodPCLK = 18; + uint8_t MinFinalVcselPeriodPCLK = 8; + uint8_t MaxFinalVcselPeriodPCLK = 14; + uint32_t MeasurementTimingBudgetMicroSeconds; + uint32_t FinalRangeTimeoutMicroSeconds; + uint32_t PreRangeTimeoutMicroSeconds; + uint32_t MsrcTimeoutMicroSeconds; + uint8_t PhaseCalInt = 0; + + /* Check if valid clock period requested */ + + if ((VCSELPulsePeriodPCLK % 2) != 0) { + /* Value must be an even number */ + Status = VL_ERROR_INVALID_PARAMS; + } else if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE && + (VCSELPulsePeriodPCLK < MinPreVcselPeriodPCLK || + VCSELPulsePeriodPCLK > MaxPreVcselPeriodPCLK)) { + Status = VL_ERROR_INVALID_PARAMS; + } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE && + (VCSELPulsePeriodPCLK < MinFinalVcselPeriodPCLK || + VCSELPulsePeriodPCLK > MaxFinalVcselPeriodPCLK)) { + + Status = VL_ERROR_INVALID_PARAMS; + } + + /* Apply specific settings for the requested clock period */ + + if (Status != VL_ERROR_NONE) + return Status; + + + if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE) { + + /* Set phase check limits */ + if (VCSELPulsePeriodPCLK == 12) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x18); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } else if (VCSELPulsePeriodPCLK == 14) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x30); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } else if (VCSELPulsePeriodPCLK == 16) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x40); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } else if (VCSELPulsePeriodPCLK == 18) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x50); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } + } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE) { + + if (VCSELPulsePeriodPCLK == 8) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x10); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x30); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } else if (VCSELPulsePeriodPCLK == 10) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x28); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x20); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } else if (VCSELPulsePeriodPCLK == 12) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x38); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x20); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } else if (VCSELPulsePeriodPCLK == 14) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x048); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x20); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } + } + + + /* Re-calculate and apply timeouts, in macro periods */ + + if (Status == VL_ERROR_NONE) { + vcsel_period_reg = VL_encode_vcsel_period((uint8_t) + VCSELPulsePeriodPCLK); + + /* When the VCSEL period for the pre or final range is changed, + * the corresponding timeout must be read from the device using + * the current VCSEL period, then the new VCSEL period can be + * applied. The timeout then must be written back to the device + * using the new VCSEL period. + * + * For the MSRC timeout, the same applies - this timeout being + * dependent on the pre-range vcsel period. + */ + switch (VcselPeriodType) { + case VL_VCSEL_PERIOD_PRE_RANGE: + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &PreRangeTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + &MsrcTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD, + vcsel_period_reg); + + + if (Status == VL_ERROR_NONE) + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + PreRangeTimeoutMicroSeconds); + + + if (Status == VL_ERROR_NONE) + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + MsrcTimeoutMicroSeconds); + + VL_SETDEVICESPECIFICPARAMETER( + Dev, + PreRangeVcselPulsePeriod, + VCSELPulsePeriodPCLK); + break; + case VL_VCSEL_PERIOD_FINAL_RANGE: + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + &FinalRangeTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD, + vcsel_period_reg); + + + if (Status == VL_ERROR_NONE) + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + FinalRangeTimeoutMicroSeconds); + + VL_SETDEVICESPECIFICPARAMETER( + Dev, + FinalRangeVcselPulsePeriod, + VCSELPulsePeriodPCLK); + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } + + /* Finally, the timing budget must be re-applied */ + if (Status == VL_ERROR_NONE) { + VL_GETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + + Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + + /* Perform the phase calibration. This is needed after changing on + * vcsel period. + * get_data_enable = 0, restore_config = 1 */ + if (Status == VL_ERROR_NONE) + Status = VL_perform_phase_calibration( + Dev, &PhaseCalInt, 0, 1); + + return Status; +} + +int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t vcsel_period_reg; + + switch (VcselPeriodType) { + case VL_VCSEL_PERIOD_PRE_RANGE: + Status = VL_RdByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD, + &vcsel_period_reg); + break; + case VL_VCSEL_PERIOD_FINAL_RANGE: + Status = VL_RdByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD, + &vcsel_period_reg); + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + + if (Status == VL_ERROR_NONE) + *pVCSELPulsePeriodPCLK = + VL_decode_vcsel_period(vcsel_period_reg); + + return Status; +} + + + +int8_t VL_set_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + uint32_t FinalRangeTimingBudgetMicroSeconds; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + uint32_t MsrcDccTccTimeoutMicroSeconds = 2000; + uint32_t StartOverheadMicroSeconds = 1910; + uint32_t EndOverheadMicroSeconds = 960; + uint32_t MsrcOverheadMicroSeconds = 660; + uint32_t TccOverheadMicroSeconds = 590; + uint32_t DssOverheadMicroSeconds = 690; + uint32_t PreRangeOverheadMicroSeconds = 660; + uint32_t FinalRangeOverheadMicroSeconds = 550; + uint32_t PreRangeTimeoutMicroSeconds = 0; + uint32_t cMinTimingBudgetMicroSeconds = 20000; + uint32_t SubTimeout = 0; + + LOG_FUNCTION_START(""); + + if (MeasurementTimingBudgetMicroSeconds + < cMinTimingBudgetMicroSeconds) { + Status = VL_ERROR_INVALID_PARAMS; + return Status; + } + + FinalRangeTimingBudgetMicroSeconds = + MeasurementTimingBudgetMicroSeconds - + (StartOverheadMicroSeconds + EndOverheadMicroSeconds); + + Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps); + + if (Status == VL_ERROR_NONE && + (SchedulerSequenceSteps.TccOn || + SchedulerSequenceSteps.MsrcOn || + SchedulerSequenceSteps.DssOn)) { + + /* TCC, MSRC and DSS all share the same timeout */ + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + &MsrcDccTccTimeoutMicroSeconds); + + /* Subtract the TCC, MSRC and DSS timeouts if they are + * enabled. */ + + if (Status != VL_ERROR_NONE) + return Status; + + /* TCC */ + if (SchedulerSequenceSteps.TccOn) { + + SubTimeout = MsrcDccTccTimeoutMicroSeconds + + TccOverheadMicroSeconds; + + if (SubTimeout < + FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds -= + SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + /* DSS */ + if (SchedulerSequenceSteps.DssOn) { + + SubTimeout = 2 * (MsrcDccTccTimeoutMicroSeconds + + DssOverheadMicroSeconds); + + if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds + -= SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } else if (SchedulerSequenceSteps.MsrcOn) { + /* MSRC */ + SubTimeout = MsrcDccTccTimeoutMicroSeconds + + MsrcOverheadMicroSeconds; + + if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds + -= SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } + + } + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + if (SchedulerSequenceSteps.PreRangeOn) { + + /* Subtract the Pre-range timeout if enabled. */ + + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &PreRangeTimeoutMicroSeconds); + + SubTimeout = PreRangeTimeoutMicroSeconds + + PreRangeOverheadMicroSeconds; + + if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds -= SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } + + + if (Status == VL_ERROR_NONE && + SchedulerSequenceSteps.FinalRangeOn) { + + FinalRangeTimingBudgetMicroSeconds -= + FinalRangeOverheadMicroSeconds; + + /* Final Range Timeout + * Note that the final range timeout is determined by the timing + * budget and the sum of all other timeouts within the sequence. + * If there is no room for the final range timeout,then an error + * will be set. Otherwise the remaining time will be applied to + * the final range. + */ + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + FinalRangeTimingBudgetMicroSeconds); + + VL_SETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_get_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + uint32_t FinalRangeTimeoutMicroSeconds; + uint32_t MsrcDccTccTimeoutMicroSeconds = 2000; + uint32_t StartOverheadMicroSeconds = 1910; + uint32_t EndOverheadMicroSeconds = 960; + uint32_t MsrcOverheadMicroSeconds = 660; + uint32_t TccOverheadMicroSeconds = 590; + uint32_t DssOverheadMicroSeconds = 690; + uint32_t PreRangeOverheadMicroSeconds = 660; + uint32_t FinalRangeOverheadMicroSeconds = 550; + uint32_t PreRangeTimeoutMicroSeconds = 0; + + LOG_FUNCTION_START(""); + + /* Start and end overhead times always present */ + *pMeasurementTimingBudgetMicroSeconds + = StartOverheadMicroSeconds + EndOverheadMicroSeconds; + + Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps); + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + + if (SchedulerSequenceSteps.TccOn || + SchedulerSequenceSteps.MsrcOn || + SchedulerSequenceSteps.DssOn) { + + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + &MsrcDccTccTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) { + if (SchedulerSequenceSteps.TccOn) { + *pMeasurementTimingBudgetMicroSeconds += + MsrcDccTccTimeoutMicroSeconds + + TccOverheadMicroSeconds; + } + + if (SchedulerSequenceSteps.DssOn) { + *pMeasurementTimingBudgetMicroSeconds += + 2 * (MsrcDccTccTimeoutMicroSeconds + + DssOverheadMicroSeconds); + } else if (SchedulerSequenceSteps.MsrcOn) { + *pMeasurementTimingBudgetMicroSeconds += + MsrcDccTccTimeoutMicroSeconds + + MsrcOverheadMicroSeconds; + } + } + } + + if (Status == VL_ERROR_NONE) { + if (SchedulerSequenceSteps.PreRangeOn) { + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &PreRangeTimeoutMicroSeconds); + *pMeasurementTimingBudgetMicroSeconds += + PreRangeTimeoutMicroSeconds + + PreRangeOverheadMicroSeconds; + } + } + + if (Status == VL_ERROR_NONE) { + if (SchedulerSequenceSteps.FinalRangeOn) { + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + &FinalRangeTimeoutMicroSeconds); + *pMeasurementTimingBudgetMicroSeconds += + (FinalRangeTimeoutMicroSeconds + + FinalRangeOverheadMicroSeconds); + } + } + + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + *pMeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + +int8_t VL_load_tuning_settings(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer) +{ + int8_t Status = VL_ERROR_NONE; + int i; + int Index; + uint8_t msb; + uint8_t lsb; + uint8_t SelectParam; + uint8_t NumberOfWrites; + uint8_t Address; + uint8_t localBuffer[4]; /* max */ + uint16_t Temp16; + + LOG_FUNCTION_START(""); + + Index = 0; + + while ((*(pTuningSettingBuffer + Index) != 0) && + (Status == VL_ERROR_NONE)) { + NumberOfWrites = *(pTuningSettingBuffer + Index); + Index++; + if (NumberOfWrites == 0xFF) { + /* internal parameters */ + SelectParam = *(pTuningSettingBuffer + Index); + Index++; + switch (SelectParam) { + case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, SigmaEstRefArray, Temp16); + break; + case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, SigmaEstEffPulseWidth, + Temp16); + break; + case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, SigmaEstEffAmbWidth, Temp16); + break; + case 3: /* uint16_t targetRefRate -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, targetRefRate, Temp16); + break; + default: /* invalid parameter */ + Status = VL_ERROR_INVALID_PARAMS; + } + + } else if (NumberOfWrites <= 4) { + Address = *(pTuningSettingBuffer + Index); + Index++; + + for (i = 0; i < NumberOfWrites; i++) { + localBuffer[i] = *(pTuningSettingBuffer + + Index); + Index++; + } + + Status = VL_WriteMulti(Dev, Address, localBuffer, + NumberOfWrites); + + } else { + Status = VL_ERROR_INVALID_PARAMS; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_total_xtalk_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_xtalk_rate_mcps) +{ + int8_t Status = VL_ERROR_NONE; + + uint8_t xtalkCompEnable; + unsigned int totalXtalkMegaCps; + unsigned int xtalkPerSpadMegaCps; + + *ptotal_xtalk_rate_mcps = 0; + + Status = VL_GetXTalkCompensationEnable(Dev, &xtalkCompEnable); + if (Status == VL_ERROR_NONE) { + + if (xtalkCompEnable) { + + VL_GETPARAMETERFIELD( + Dev, + XTalkCompensationRateMegaCps, + xtalkPerSpadMegaCps); + + /* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */ + totalXtalkMegaCps = + pRangingMeasurementData->EffectiveSpadRtnCount * + xtalkPerSpadMegaCps; + + /* FixPoint0824 >> 8 = FixPoint1616 */ + *ptotal_xtalk_rate_mcps = + (totalXtalkMegaCps + 0x80) >> 8; + } + } + + return Status; +} + +int8_t VL_get_total_signal_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_signal_rate_mcps) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int totalXtalkMegaCps; + + LOG_FUNCTION_START(""); + + *ptotal_signal_rate_mcps = + pRangingMeasurementData->SignalRateRtnMegaCps; + + Status = VL_get_total_xtalk_rate( + Dev, pRangingMeasurementData, &totalXtalkMegaCps); + + if (Status == VL_ERROR_NONE) + *ptotal_signal_rate_mcps += totalXtalkMegaCps; + + return Status; +} + +int8_t VL_calc_dmax( + struct vl_data *Dev, + unsigned int totalSignalRate_mcps, + unsigned int totalCorrSignalRate_mcps, + unsigned int pwMult, + uint32_t sigmaEstimateP1, + unsigned int sigmaEstimateP2, + uint32_t peakVcselDuration_us, + uint32_t *pdmax_mm) +{ + const uint32_t cSigmaLimit = 18; + const unsigned int cSignalLimit = 0x4000; /* 0.25 */ + const unsigned int cSigmaEstRef = 0x00000042; /* 0.001 */ + const uint32_t cAmbEffWidthSigmaEst_ns = 6; + const uint32_t cAmbEffWidthDMax_ns = 7; + uint32_t dmaxCalRange_mm; + unsigned int dmaxCalSignalRateRtn_mcps; + unsigned int minSignalNeeded; + unsigned int minSignalNeeded_p1; + unsigned int minSignalNeeded_p2; + unsigned int minSignalNeeded_p3; + unsigned int minSignalNeeded_p4; + unsigned int sigmaLimitTmp; + unsigned int sigmaEstSqTmp; + unsigned int signalLimitTmp; + unsigned int SignalAt0mm; + unsigned int dmaxDark; + unsigned int dmaxAmbient; + unsigned int dmaxDarkTmp; + unsigned int sigmaEstP2Tmp; + uint32_t signalRateTemp_mcps; + + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + dmaxCalRange_mm = + PALDevDataGet(Dev, DmaxCalRangeMilliMeter); + + dmaxCalSignalRateRtn_mcps = + PALDevDataGet(Dev, DmaxCalSignalRateRtnMegaCps); + + /* uint32 * FixPoint1616 = FixPoint1616 */ + SignalAt0mm = dmaxCalRange_mm * dmaxCalSignalRateRtn_mcps; + + /* FixPoint1616 >> 8 = FixPoint2408 */ + SignalAt0mm = (SignalAt0mm + 0x80) >> 8; + SignalAt0mm *= dmaxCalRange_mm; + + minSignalNeeded_p1 = 0; + if (totalCorrSignalRate_mcps > 0) { + + /* Shift by 10 bits to increase resolution prior to the + * division */ + signalRateTemp_mcps = totalSignalRate_mcps << 10; + + /* Add rounding value prior to division */ + minSignalNeeded_p1 = signalRateTemp_mcps + + (totalCorrSignalRate_mcps/2); + + /* FixPoint0626/FixPoint1616 = FixPoint2210 */ + minSignalNeeded_p1 /= totalCorrSignalRate_mcps; + + /* Apply a factored version of the speed of light. + Correction to be applied at the end */ + minSignalNeeded_p1 *= 3; + + /* FixPoint2210 * FixPoint2210 = FixPoint1220 */ + minSignalNeeded_p1 *= minSignalNeeded_p1; + + /* FixPoint1220 >> 16 = FixPoint2804 */ + minSignalNeeded_p1 = (minSignalNeeded_p1 + 0x8000) >> 16; + } + + minSignalNeeded_p2 = pwMult * sigmaEstimateP1; + + /* FixPoint1616 >> 16 = uint32 */ + minSignalNeeded_p2 = (minSignalNeeded_p2 + 0x8000) >> 16; + + /* uint32 * uint32 = uint32 */ + minSignalNeeded_p2 *= minSignalNeeded_p2; + + /* Check sigmaEstimateP2 + * If this value is too high there is not enough signal rate + * to calculate dmax value so set a suitable value to ensure + * a very small dmax. + */ + sigmaEstP2Tmp = (sigmaEstimateP2 + 0x8000) >> 16; + sigmaEstP2Tmp = (sigmaEstP2Tmp + cAmbEffWidthSigmaEst_ns/2)/ + cAmbEffWidthSigmaEst_ns; + sigmaEstP2Tmp *= cAmbEffWidthDMax_ns; + + if (sigmaEstP2Tmp > 0xffff) { + minSignalNeeded_p3 = 0xfff00000; + } else { + + /* DMAX uses a different ambient width from sigma, so apply + * correction. + * Perform division before multiplication to prevent overflow. + */ + sigmaEstimateP2 = (sigmaEstimateP2 + cAmbEffWidthSigmaEst_ns/2)/ + cAmbEffWidthSigmaEst_ns; + sigmaEstimateP2 *= cAmbEffWidthDMax_ns; + + /* FixPoint1616 >> 16 = uint32 */ + minSignalNeeded_p3 = (sigmaEstimateP2 + 0x8000) >> 16; + + minSignalNeeded_p3 *= minSignalNeeded_p3; + + } + + /* FixPoint1814 / uint32 = FixPoint1814 */ + sigmaLimitTmp = ((cSigmaLimit << 14) + 500) / 1000; + + /* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */ + sigmaLimitTmp *= sigmaLimitTmp; + + /* FixPoint1616 * FixPoint1616 = FixPoint3232 */ + sigmaEstSqTmp = cSigmaEstRef * cSigmaEstRef; + + /* FixPoint3232 >> 4 = FixPoint0428 */ + sigmaEstSqTmp = (sigmaEstSqTmp + 0x08) >> 4; + + /* FixPoint0428 - FixPoint0428 = FixPoint0428 */ + sigmaLimitTmp -= sigmaEstSqTmp; + + /* uint32_t * FixPoint0428 = FixPoint0428 */ + minSignalNeeded_p4 = 4 * 12 * sigmaLimitTmp; + + /* FixPoint0428 >> 14 = FixPoint1814 */ + minSignalNeeded_p4 = (minSignalNeeded_p4 + 0x2000) >> 14; + + /* uint32 + uint32 = uint32 */ + minSignalNeeded = (minSignalNeeded_p2 + minSignalNeeded_p3); + + /* uint32 / uint32 = uint32 */ + minSignalNeeded += (peakVcselDuration_us/2); + minSignalNeeded /= peakVcselDuration_us; + + /* uint32 << 14 = FixPoint1814 */ + minSignalNeeded <<= 14; + + /* FixPoint1814 / FixPoint1814 = uint32 */ + minSignalNeeded += (minSignalNeeded_p4/2); + minSignalNeeded /= minSignalNeeded_p4; + + /* FixPoint3200 * FixPoint2804 := FixPoint2804*/ + minSignalNeeded *= minSignalNeeded_p1; + + /* Apply correction by dividing by 1000000. + * This assumes 10E16 on the numerator of the equation + * and 10E-22 on the denominator. + * We do this because 32bit fix point calculation can't + * handle the larger and smaller elements of this equation, + * i.e. speed of light and pulse widths. + */ + minSignalNeeded = (minSignalNeeded + 500) / 1000; + minSignalNeeded <<= 4; + + minSignalNeeded = (minSignalNeeded + 500) / 1000; + + /* FixPoint1616 >> 8 = FixPoint2408 */ + signalLimitTmp = (cSignalLimit + 0x80) >> 8; + + /* FixPoint2408/FixPoint2408 = uint32 */ + if (signalLimitTmp != 0) + dmaxDarkTmp = (SignalAt0mm + (signalLimitTmp / 2)) + / signalLimitTmp; + else + dmaxDarkTmp = 0; + + dmaxDark = VL_isqrt(dmaxDarkTmp); + + /* FixPoint2408/FixPoint2408 = uint32 */ + if (minSignalNeeded != 0) + dmaxAmbient = (SignalAt0mm + minSignalNeeded/2) + / minSignalNeeded; + else + dmaxAmbient = 0; + + dmaxAmbient = VL_isqrt(dmaxAmbient); + + *pdmax_mm = dmaxDark; + if (dmaxDark > dmaxAmbient) + *pdmax_mm = dmaxAmbient; + + LOG_FUNCTION_END(Status); + + return Status; +} + + +int8_t VL_calc_sigma_estimate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *pSigmaEstimate, + uint32_t *pDmax_mm) +{ + /* Expressed in 100ths of a ns, i.e. centi-ns */ + const uint32_t cPulseEffectiveWidth_centi_ns = 800; + /* Expressed in 100ths of a ns, i.e. centi-ns */ + const uint32_t cAmbientEffectiveWidth_centi_ns = 600; + /* 25ms */ + const unsigned int cDfltFinalRangeIntegrationTimeMilliSecs = + 0x00190000; + const uint32_t cVcselPulseWidth_ps = 4700; /* pico secs */ + const unsigned int cSigmaEstMax = 0x028F87AE; + const unsigned int cSigmaEstRtnMax = 0xF000; + const unsigned int cAmbToSignalRatioMax = 0xF0000000/ + cAmbientEffectiveWidth_centi_ns; + /* Time Of Flight per mm (6.6 pico secs) */ + const unsigned int cTOF_per_mm_ps = 0x0006999A; + const uint32_t c16BitRoundingParam = 0x00008000; + const unsigned int cMaxXTalk_kcps = 0x00320000; + const uint32_t cPllPeriod_ps = 1655; + + uint32_t vcselTotalEventsRtn; + uint32_t finalRangeTimeoutMicroSecs; + uint32_t preRangeTimeoutMicroSecs; + uint32_t finalRangeIntegrationTimeMilliSecs; + unsigned int sigmaEstimateP1; + unsigned int sigmaEstimateP2; + unsigned int sigmaEstimateP3; + unsigned int deltaT_ps; + unsigned int pwMult; + unsigned int sigmaEstRtn; + unsigned int sigmaEstimate; + unsigned int xTalkCorrection; + unsigned int ambientRate_kcps; + unsigned int peakSignalRate_kcps; + unsigned int xTalkCompRate_mcps; + uint32_t xTalkCompRate_kcps; + int8_t Status = VL_ERROR_NONE; + unsigned int diff1_mcps; + unsigned int diff2_mcps; + unsigned int sqr1; + unsigned int sqr2; + unsigned int sqrSum; + unsigned int sqrtResult_centi_ns; + unsigned int sqrtResult; + unsigned int totalSignalRate_mcps; + unsigned int correctedSignalRate_mcps; + unsigned int sigmaEstRef; + uint32_t vcselWidth; + uint32_t finalRangeMacroPCLKS; + uint32_t preRangeMacroPCLKS; + uint32_t peakVcselDuration_us; + uint8_t finalRangeVcselPCLKS; + uint8_t preRangeVcselPCLKS; + /*! \addtogroup calc_sigma_estimate + * @{ + * + * Estimates the range sigma + */ + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, + xTalkCompRate_mcps); + + /* + * We work in kcps rather than mcps as this helps keep within the + * confines of the 32 Fix1616 type. + */ + + ambientRate_kcps = + (pRangingMeasurementData->AmbientRateRtnMegaCps * 1000) >> 16; + + correctedSignalRate_mcps = + pRangingMeasurementData->SignalRateRtnMegaCps; + + + Status = VL_get_total_signal_rate( + Dev, pRangingMeasurementData, &totalSignalRate_mcps); + Status = VL_get_total_xtalk_rate( + Dev, pRangingMeasurementData, &xTalkCompRate_mcps); + + + /* Signal rate measurement provided by device is the + * peak signal rate, not average. + */ + peakSignalRate_kcps = (totalSignalRate_mcps * 1000); + peakSignalRate_kcps = (peakSignalRate_kcps + 0x8000) >> 16; + + xTalkCompRate_kcps = xTalkCompRate_mcps * 1000; + + if (xTalkCompRate_kcps > cMaxXTalk_kcps) + xTalkCompRate_kcps = cMaxXTalk_kcps; + + if (Status == VL_ERROR_NONE) { + + /* Calculate final range macro periods */ + finalRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER( + Dev, FinalRangeTimeoutMicroSecs); + + finalRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER( + Dev, FinalRangeVcselPulsePeriod); + + finalRangeMacroPCLKS = VL_calc_timeout_mclks( + Dev, finalRangeTimeoutMicroSecs, finalRangeVcselPCLKS); + + /* Calculate pre-range macro periods */ + preRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER( + Dev, PreRangeTimeoutMicroSecs); + + preRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER( + Dev, PreRangeVcselPulsePeriod); + + preRangeMacroPCLKS = VL_calc_timeout_mclks( + Dev, preRangeTimeoutMicroSecs, preRangeVcselPCLKS); + + vcselWidth = 3; + if (finalRangeVcselPCLKS == 8) + vcselWidth = 2; + + + peakVcselDuration_us = vcselWidth * 2048 * + (preRangeMacroPCLKS + finalRangeMacroPCLKS); + peakVcselDuration_us = (peakVcselDuration_us + 500)/1000; + peakVcselDuration_us *= cPllPeriod_ps; + peakVcselDuration_us = (peakVcselDuration_us + 500)/1000; + + /* Fix1616 >> 8 = Fix2408 */ + totalSignalRate_mcps = (totalSignalRate_mcps + 0x80) >> 8; + + /* Fix2408 * uint32 = Fix2408 */ + vcselTotalEventsRtn = totalSignalRate_mcps * + peakVcselDuration_us; + + /* Fix2408 >> 8 = uint32 */ + vcselTotalEventsRtn = (vcselTotalEventsRtn + 0x80) >> 8; + + /* Fix2408 << 8 = Fix1616 = */ + totalSignalRate_mcps <<= 8; + } + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + if (peakSignalRate_kcps == 0) { + *pSigmaEstimate = cSigmaEstMax; + PALDevDataSet(Dev, SigmaEstimate, cSigmaEstMax); + *pDmax_mm = 0; + } else { + if (vcselTotalEventsRtn < 1) + vcselTotalEventsRtn = 1; + + sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns; + + /* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */ + sigmaEstimateP2 = (ambientRate_kcps << 16)/peakSignalRate_kcps; + if (sigmaEstimateP2 > cAmbToSignalRatioMax) { + /* Clip to prevent overflow. Will ensure safe + * max result. */ + sigmaEstimateP2 = cAmbToSignalRatioMax; + } + sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns; + + sigmaEstimateP3 = 2 * VL_isqrt(vcselTotalEventsRtn * 12); + + /* uint32 * FixPoint1616 = FixPoint1616 */ + deltaT_ps = pRangingMeasurementData->RangeMilliMeter * + cTOF_per_mm_ps; + + /* + * vcselRate - xtalkCompRate + * (uint32 << 16) - FixPoint1616 = FixPoint1616. + * Divide result by 1000 to convert to mcps. + * 500 is added to ensure rounding when integer division + * truncates. + */ + diff1_mcps = (((peakSignalRate_kcps << 16) - + 2 * xTalkCompRate_kcps) + 500)/1000; + + /* vcselRate + xtalkCompRate */ + diff2_mcps = ((peakSignalRate_kcps << 16) + 500)/1000; + + /* Shift by 8 bits to increase resolution prior to the + * division */ + diff1_mcps <<= 8; + + /* FixPoint0824/FixPoint1616 = FixPoint2408 */ + xTalkCorrection = abs(diff1_mcps/diff2_mcps); + + /* FixPoint2408 << 8 = FixPoint1616 */ + xTalkCorrection <<= 8; + + if (pRangingMeasurementData->RangeStatus != 0) { + pwMult = 1 << 16; + } else { + /* FixPoint1616/uint32 = FixPoint1616 *i/ + /* smaller than 1.0f */ + pwMult = deltaT_ps/cVcselPulseWidth_ps; + + /* + * FixPoint1616 * FixPoint1616 = FixPoint3232, however both + * values are small enough such that32 bits will not be + * exceeded. + */ + pwMult *= ((1 << 16) - xTalkCorrection); + + /* (FixPoint3232 >> 16) = FixPoint1616 */ + pwMult = (pwMult + c16BitRoundingParam) >> 16; + + /* FixPoint1616 + FixPoint1616 = FixPoint1616 */ + pwMult += (1 << 16); + + /* + * At this point the value will be 1.xx, therefore if we square + * the value this will exceed 32 bits. To address this perform + * a single shift to the right before the multiplication. + */ + pwMult >>= 1; + /* FixPoint1715 * FixPoint1715 = FixPoint3430 */ + pwMult = pwMult * pwMult; + + /* (FixPoint3430 >> 14) = Fix1616 */ + pwMult >>= 14; + } + + /* FixPoint1616 * uint32 = FixPoint1616 */ + sqr1 = pwMult * sigmaEstimateP1; + + /* (FixPoint1616 >> 16) = FixPoint3200 */ + sqr1 = (sqr1 + 0x8000) >> 16; + + /* FixPoint3200 * FixPoint3200 = FixPoint6400 */ + sqr1 *= sqr1; + + sqr2 = sigmaEstimateP2; + + /* (FixPoint1616 >> 16) = FixPoint3200 */ + sqr2 = (sqr2 + 0x8000) >> 16; + + /* FixPoint3200 * FixPoint3200 = FixPoint6400 */ + sqr2 *= sqr2; + + /* FixPoint64000 + FixPoint6400 = FixPoint6400 */ + sqrSum = sqr1 + sqr2; + + /* SQRT(FixPoin6400) = FixPoint3200 */ + sqrtResult_centi_ns = VL_isqrt(sqrSum); + + /* (FixPoint3200 << 16) = FixPoint1616 */ + sqrtResult_centi_ns <<= 16; + + /* + * Note that the Speed Of Light is expressed in um per 1E-10 + * seconds (2997) Therefore to get mm/ns we have to divide by + * 10000 + */ + sigmaEstRtn = (((sqrtResult_centi_ns+50)/100) / + sigmaEstimateP3); + sigmaEstRtn *= VL_SPEED_OF_LIGHT_IN_AIR; + + /* Add 5000 before dividing by 10000 to ensure rounding. */ + sigmaEstRtn += 5000; + sigmaEstRtn /= 10000; + + if (sigmaEstRtn > cSigmaEstRtnMax) { + /* Clip to prevent overflow. Will ensure safe + * max result. */ + sigmaEstRtn = cSigmaEstRtnMax; + } + finalRangeIntegrationTimeMilliSecs = + (finalRangeTimeoutMicroSecs + + preRangeTimeoutMicroSecs + 500)/1000; + + /* sigmaEstRef = 1mm * 25ms/final range integration time + * (inc pre-range) sqrt(FixPoint1616/int) = FixPoint2408) + */ + sigmaEstRef = + VL_isqrt((cDfltFinalRangeIntegrationTimeMilliSecs + + finalRangeIntegrationTimeMilliSecs/2)/ + finalRangeIntegrationTimeMilliSecs); + + /* FixPoint2408 << 8 = FixPoint1616 */ + sigmaEstRef <<= 8; + sigmaEstRef = (sigmaEstRef + 500)/1000; + + /* FixPoint1616 * FixPoint1616 = FixPoint3232 */ + sqr1 = sigmaEstRtn * sigmaEstRtn; + /* FixPoint1616 * FixPoint1616 = FixPoint3232 */ + sqr2 = sigmaEstRef * sigmaEstRef; + + /* sqrt(FixPoint3232) = FixPoint1616 */ + sqrtResult = VL_isqrt((sqr1 + sqr2)); + /* + * Note that the Shift by 4 bits increases resolution prior to + * the sqrt, therefore the result must be shifted by 2 bits to + * the right to revert back to the FixPoint1616 format. + */ + + sigmaEstimate = 1000 * sqrtResult; + + if ((peakSignalRate_kcps < 1) || (vcselTotalEventsRtn < 1) || + (sigmaEstimate > cSigmaEstMax)) { + sigmaEstimate = cSigmaEstMax; + } + + *pSigmaEstimate = (uint32_t)(sigmaEstimate); + PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate); + Status = VL_calc_dmax( + Dev, + totalSignalRate_mcps, + correctedSignalRate_mcps, + pwMult, + sigmaEstimateP1, + sigmaEstimateP2, + peakVcselDuration_us, + pDmax_mm); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_pal_range_status(struct vl_data *Dev, + uint8_t DeviceRangeStatus, + unsigned int SignalRate, + uint16_t EffectiveSpadRtnCount, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + uint8_t *pPalRangeStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t NoneFlag; + uint8_t SigmaLimitflag = 0; + uint8_t SignalRefClipflag = 0; + uint8_t RangeIgnoreThresholdflag = 0; + uint8_t SigmaLimitCheckEnable = 0; + uint8_t SignalRateFinalRangeLimitCheckEnable = 0; + uint8_t SignalRefClipLimitCheckEnable = 0; + uint8_t RangeIgnoreThresholdLimitCheckEnable = 0; + unsigned int SigmaEstimate; + unsigned int SigmaLimitValue; + unsigned int SignalRefClipValue; + unsigned int RangeIgnoreThresholdValue; + unsigned int SignalRatePerSpad; + uint8_t DeviceRangeStatusInternal = 0; + uint16_t tmpWord = 0; + uint8_t Temp8; + uint32_t Dmax_mm = 0; + unsigned int LastSignalRefMcps; + + LOG_FUNCTION_START(""); + + + /* + * VL53L0X has a good ranging when the value of the + * DeviceRangeStatus = 11. This function will replace the value 0 with + * the value 11 in the DeviceRangeStatus. + * In addition, the SigmaEstimator is not included in the VL53L0X + * DeviceRangeStatus, this will be added in the PalRangeStatus. + */ + + DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3); + + if (DeviceRangeStatusInternal == 0 || + DeviceRangeStatusInternal == 5 || + DeviceRangeStatusInternal == 7 || + DeviceRangeStatusInternal == 12 || + DeviceRangeStatusInternal == 13 || + DeviceRangeStatusInternal == 14 || + DeviceRangeStatusInternal == 15 + ) { + NoneFlag = 1; + } else { + NoneFlag = 0; + } + + /* + * Check if Sigma limit is enabled, if yes then do comparison with limit + * value and put the result back into pPalRangeStatus. + */ + if (Status == VL_ERROR_NONE) + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + &SigmaLimitCheckEnable); + + if ((SigmaLimitCheckEnable != 0) && (Status == VL_ERROR_NONE)) { + /* + * compute the Sigma and check with limit + */ + Status = VL_calc_sigma_estimate( + Dev, + pRangingMeasurementData, + &SigmaEstimate, + &Dmax_mm); + if (Status == VL_ERROR_NONE) + pRangingMeasurementData->RangeDMaxMilliMeter = Dmax_mm; + + if (Status == VL_ERROR_NONE) { + Status = VL_GetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + &SigmaLimitValue); + + if ((SigmaLimitValue > 0) && + (SigmaEstimate > SigmaLimitValue)) + /* Limit Fail */ + SigmaLimitflag = 1; + } + } + + /* + * Check if Signal ref clip limit is enabled, if yes then do comparison + * with limit value and put the result back into pPalRangeStatus. + */ + if (Status == VL_ERROR_NONE) + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + &SignalRefClipLimitCheckEnable); + + if ((SignalRefClipLimitCheckEnable != 0) && + (Status == VL_ERROR_NONE)) { + + Status = VL_GetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + &SignalRefClipValue); + + /* Read LastSignalRefMcps from device */ + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_RdWord(Dev, + VL_REG_RESULT_PEAK_SIGNAL_RATE_REF, + &tmpWord); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x00); + + LastSignalRefMcps = VL_FIXPOINT97TOFIXPOINT1616(tmpWord); + PALDevDataSet(Dev, LastSignalRefMcps, LastSignalRefMcps); + + if ((SignalRefClipValue > 0) && + (LastSignalRefMcps > SignalRefClipValue)) { + /* Limit Fail */ + SignalRefClipflag = 1; + } + } + + /* + * Check if Signal ref clip limit is enabled, if yes then do comparison + * with limit value and put the result back into pPalRangeStatus. + * EffectiveSpadRtnCount has a format 8.8 + * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL + */ + if (Status == VL_ERROR_NONE) + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + &RangeIgnoreThresholdLimitCheckEnable); + + if ((RangeIgnoreThresholdLimitCheckEnable != 0) && + (Status == VL_ERROR_NONE)) { + + /* Compute the signal rate per spad */ + if (EffectiveSpadRtnCount == 0) { + SignalRatePerSpad = 0; + } else { + SignalRatePerSpad = (unsigned int)((256 * SignalRate) + / EffectiveSpadRtnCount); + } + + Status = VL_GetLimitCheckValue(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + &RangeIgnoreThresholdValue); + + if ((RangeIgnoreThresholdValue > 0) && + (SignalRatePerSpad < RangeIgnoreThresholdValue)) { + /* Limit Fail add 2^6 to range status */ + RangeIgnoreThresholdflag = 1; + } + } + + if (Status == VL_ERROR_NONE) { + if (NoneFlag == 1) { + *pPalRangeStatus = 255; /* NONE */ + } else if (DeviceRangeStatusInternal == 1 || + DeviceRangeStatusInternal == 2 || + DeviceRangeStatusInternal == 3) { + *pPalRangeStatus = 5; /* HW fail */ + } else if (DeviceRangeStatusInternal == 6 || + DeviceRangeStatusInternal == 9) { + *pPalRangeStatus = 4; /* Phase fail */ + } else if (DeviceRangeStatusInternal == 8 || + DeviceRangeStatusInternal == 10 || + SignalRefClipflag == 1) { + *pPalRangeStatus = 3; /* Min range */ + } else if (DeviceRangeStatusInternal == 4 || + RangeIgnoreThresholdflag == 1) { + *pPalRangeStatus = 2; /* Signal Fail */ + } else if (SigmaLimitflag == 1) { + *pPalRangeStatus = 1; /* Sigma Fail */ + } else { + *pPalRangeStatus = 0; /* Range Valid */ + } + } + + /* DMAX only relevant during range error */ + if (*pPalRangeStatus == 0) + pRangingMeasurementData->RangeDMaxMilliMeter = 0; + + /* fill the Limit Check Status */ + + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &SignalRateFinalRangeLimitCheckEnable); + + if (Status == VL_ERROR_NONE) { + if ((SigmaLimitCheckEnable == 0) || (SigmaLimitflag == 1)) + Temp8 = 1; + else + Temp8 = 0; + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + if ((DeviceRangeStatusInternal == 4) || + (SignalRateFinalRangeLimitCheckEnable == 0)) + Temp8 = 1; + else + Temp8 = 0; + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + Temp8); + + if ((SignalRefClipLimitCheckEnable == 0) || + (SignalRefClipflag == 1)) + Temp8 = 1; + else + Temp8 = 0; + + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_SIGNAL_REF_CLIP, Temp8); + + if ((RangeIgnoreThresholdLimitCheckEnable == 0) || + (RangeIgnoreThresholdflag == 1)) + Temp8 = 1; + else + Temp8 = 0; + + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + Temp8); + } + + LOG_FUNCTION_END(Status); + return Status; + +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c new file mode 100644 index 0000000000000000000000000000000000000000..9b5b2baa7faed4caadb392b4c9471f4590bb42e2 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c @@ -0,0 +1,34 @@ +/* + * vl53l0x_api_ranging.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" + + +#ifndef __KERNEL__ +#include +#endif +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c new file mode 100644 index 0000000000000000000000000000000000000000..90832f5a546188ded6b3bd1aabc8a192e9709f34 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c @@ -0,0 +1,456 @@ +/* + * vl53l0x_api_string.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_strings.h" + +#ifndef __KERNEL__ +#include +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + + +int8_t VL_check_part_used(struct vl_data *Dev, + uint8_t *Revision, + struct VL_DeviceInfo_t *pVL_DeviceInfo) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t ModuleIdInt; + char *ProductId_tmp; + + LOG_FUNCTION_START(""); + + Status = VL_get_info_from_device(Dev, 2); + + if (Status == VL_ERROR_NONE) { + ModuleIdInt = VL_GETDEVICESPECIFICPARAMETER(Dev, ModuleId); + + if (ModuleIdInt == 0) { + *Revision = 0; + VL_COPYSTRING(pVL_DeviceInfo->ProductId, ""); + } else { + *Revision = VL_GETDEVICESPECIFICPARAMETER(Dev, Revision); + ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev, + ProductId); + VL_COPYSTRING(pVL_DeviceInfo->ProductId, + ProductId_tmp); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +int8_t VL_get_device_info(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t revision_id; + uint8_t Revision; + + Status = VL_check_part_used(Dev, &Revision, pVL_DeviceInfo); + + if (Status == VL_ERROR_NONE) { + if (Revision == 0) { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_TS0); + } else if ((Revision <= 34) && (Revision != 32)) { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_TS1); + } else if (Revision < 39) { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_TS2); + } else { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_ES1); + } + + VL_COPYSTRING(pVL_DeviceInfo->Type, + VL_STRING_DEVICE_INFO_TYPE); + + } + + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_MODEL_ID, + &pVL_DeviceInfo->ProductType); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_REVISION_ID, + &revision_id); + pVL_DeviceInfo->ProductRevisionMajor = 1; + pVL_DeviceInfo->ProductRevisionMinor = + (revision_id & 0xF0) >> 4; + } + + return Status; +} + + +int8_t VL_get_device_error_string(uint8_t ErrorCode, + char *pDeviceErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (ErrorCode) { + case VL_DEVICEERROR_NONE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_NONE); + break; + case VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE); + break; + case VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE); + break; + case VL_DEVICEERROR_NOVHVVALUEFOUND: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_NOVHVVALUEFOUND); + break; + case VL_DEVICEERROR_MSRCNOTARGET: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_MSRCNOTARGET); + break; + case VL_DEVICEERROR_SNRCHECK: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_SNRCHECK); + break; + case VL_DEVICEERROR_RANGEPHASECHECK: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_RANGEPHASECHECK); + break; + case VL_DEVICEERROR_SIGMATHRESHOLDCHECK: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK); + break; + case VL_DEVICEERROR_TCC: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_TCC); + break; + case VL_DEVICEERROR_PHASECONSISTENCY: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_PHASECONSISTENCY); + break; + case VL_DEVICEERROR_MINCLIP: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_MINCLIP); + break; + case VL_DEVICEERROR_RANGECOMPLETE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_RANGECOMPLETE); + break; + case VL_DEVICEERROR_ALGOUNDERFLOW: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_ALGOUNDERFLOW); + break; + case VL_DEVICEERROR_ALGOOVERFLOW: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_ALGOOVERFLOW); + break; + case VL_DEVICEERROR_RANGEIGNORETHRESHOLD: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD); + break; + + default: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_UNKNOWN_ERROR_CODE); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_range_status_string(uint8_t RangeStatus, + char *pRangeStatusString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (RangeStatus) { + case 0: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_RANGEVALID); + break; + case 1: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_SIGMA); + break; + case 2: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_SIGNAL); + break; + case 3: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_MINRANGE); + break; + case 4: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_PHASE); + break; + case 5: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_HW); + break; + + default: /**/ + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_NONE); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_pal_error_string(int8_t PalErrorCode, + char *pPalErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (PalErrorCode) { + case VL_ERROR_NONE: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_NONE); + break; + case VL_ERROR_CALIBRATION_WARNING: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_CALIBRATION_WARNING); + break; + case VL_ERROR_MIN_CLIPPED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_MIN_CLIPPED); + break; + case VL_ERROR_UNDEFINED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_UNDEFINED); + break; + case VL_ERROR_INVALID_PARAMS: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_INVALID_PARAMS); + break; + case VL_ERROR_NOT_SUPPORTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_NOT_SUPPORTED); + break; + case VL_ERROR_INTERRUPT_NOT_CLEARED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_INTERRUPT_NOT_CLEARED); + break; + case VL_ERROR_RANGE_ERROR: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_RANGE_ERROR); + break; + case VL_ERROR_TIME_OUT: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_TIME_OUT); + break; + case VL_ERROR_MODE_NOT_SUPPORTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_MODE_NOT_SUPPORTED); + break; + case VL_ERROR_BUFFER_TOO_SMALL: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_BUFFER_TOO_SMALL); + break; + case VL_ERROR_GPIO_NOT_EXISTING: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_GPIO_NOT_EXISTING); + break; + case VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED); + break; + case VL_ERROR_CONTROL_INTERFACE: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_CONTROL_INTERFACE); + break; + case VL_ERROR_INVALID_COMMAND: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_INVALID_COMMAND); + break; + case VL_ERROR_DIVISION_BY_ZERO: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_DIVISION_BY_ZERO); + break; + case VL_ERROR_REF_SPAD_INIT: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_REF_SPAD_INIT); + break; + case VL_ERROR_NOT_IMPLEMENTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_NOT_IMPLEMENTED); + break; + + default: + VL_COPYSTRING(pPalErrorString, + VL_STRING_UNKNOWN_ERROR_CODE); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_pal_state_string(uint8_t PalStateCode, + char *pPalStateString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (PalStateCode) { + case VL_STATE_POWERDOWN: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_POWERDOWN); + break; + case VL_STATE_WAIT_STATICINIT: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_WAIT_STATICINIT); + break; + case VL_STATE_STANDBY: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_STANDBY); + break; + case VL_STATE_IDLE: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_IDLE); + break; + case VL_STATE_RUNNING: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_RUNNING); + break; + case VL_STATE_UNKNOWN: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_UNKNOWN); + break; + case VL_STATE_ERROR: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_ERROR); + break; + + default: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_UNKNOWN); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_sequence_steps_info( + uint8_t SequenceStepId, + char *pSequenceStepsString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_TCC); + break; + case VL_SEQUENCESTEP_DSS: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_DSS); + break; + case VL_SEQUENCESTEP_MSRC: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_MSRC); + break; + case VL_SEQUENCESTEP_PRE_RANGE: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_PRE_RANGE); + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_FINAL_RANGE); + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + + return Status; +} + + +int8_t VL_get_limit_check_info(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE); + break; + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE); + break; + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP); + break; + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD); + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC); + break; + + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE); + break; + + default: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_UNKNOWN_ERROR_CODE); + + } + + LOG_FUNCTION_END(Status); + return Status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c new file mode 100644 index 0000000000000000000000000000000000000000..cdc004c0ef5c95a78787a2b1a0cc8f6145988020 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c @@ -0,0 +1,385 @@ +/* + * vl53l0x_i2c_platform.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +/*! + * \file VL_platform.c + * \brief Code function defintions for EWOK Platform Layer + * + */ + + +#include +#include +#include +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" + +#include "vl53l0x_platform.h" +#include "vl53l0x_i2c_platform.h" +#include "vl53l0x_def.h" + +#include "vl53l0x_platform_log.h" + +#ifdef VL_LOG_ENABLE +#define trace_print(level, ...) \ + trace_print_module_function(TRACE_MODULE_PLATFORM, level,\ + TRACE_FUNCTION_NONE, ##__VA_ARGS__) +#define trace_i2c(...) \ + trace_print_module_function(TRACE_MODULE_NONE, \ + TRACE_LEVEL_NONE, TRACE_FUNCTION_I2C, ##__VA_ARGS__) +#endif + +/** + * @def I2C_BUFFER_CONFIG + * + * @brief Configure Device register I2C access + * + * @li 0 : one GLOBAL buffer \n + * Use one global buffer of MAX_I2C_XFER_SIZE byte in data space \n + * This solution is not multi-Device compliant nor multi-thread cpu safe \n + * It can be the best option for small 8/16 bit MCU without stack and limited + * ram (STM8s, 80C51 ...) + * + * @li 1 : ON_STACK/local \n + * Use local variable (on stack) buffer \n + * This solution is multi-thread with use of i2c resource lock or mutex see + * VL6180x_GetI2CAccess() \n + * + * @li 2 : User defined \n + * Per Device potentially dynamic allocated. Requires VL6180x_GetI2cBuffer() + * to be implemented. + * @ingroup Configuration + */ +#define I2C_BUFFER_CONFIG 1 + +#if I2C_BUFFER_CONFIG == 0 + /* GLOBAL config buffer */ + uint8_t i2c_global_buffer[VL_MAX_I2C_XFER_SIZE]; + + #define DECL_I2C_BUFFER + #define VL_GetLocalBuffer(Dev, n_byte) i2c_global_buffer + +#elif I2C_BUFFER_CONFIG == 1 + /* ON STACK */ + uint8_t LocBuffer[VL_MAX_I2C_XFER_SIZE]; + #define VL_GetLocalBuffer(Dev, n_byte) LocBuffer +#elif I2C_BUFFER_CONFIG == 2 + /* user define buffer type declare DECL_I2C_BUFFER as access via + VL_GetLocalBuffer */ + #define DECL_I2C_BUFFER +#else +#error "invalid I2C_BUFFER_CONFIG " +#endif + + +#define VL_I2C_USER_VAR /* none but could be for a flag var to + get/pass to mutex interruptible return flags and try again */ +#define VL_GetI2CAccess(Dev) /* todo mutex acquire */ +#define VL_DoneI2CAcces(Dev) /* todo mutex release */ + + +char debug_string[VL_MAX_STRING_LENGTH_PLT]; + + +#define MIN_COMMS_VERSION_MAJOR 1 +#define MIN_COMMS_VERSION_MINOR 8 +#define MIN_COMMS_VERSION_BUILD 1 +#define MIN_COMMS_VERSION_REVISION 0 + +#define STATUS_OK 0x00 +#define STATUS_FAIL 0x01 + +bool _check_min_version(void) +{ + bool min_version_comms_dll = false; + + min_version_comms_dll = true; + + return min_version_comms_dll; +} + +int32_t VL_comms_initialise(uint8_t comms_type, uint16_t comms_speed_khz) +{ + int32_t status = STATUS_OK; + + return status; +} + +int32_t VL_comms_close(void) +{ + int32_t status = STATUS_OK; + + + return status; +} + +int32_t VL_set_page(struct vl_data *dev, uint8_t page_data) +{ + int32_t status = STATUS_OK; + uint16_t page_index = 0xFF; + uint8_t *buffer; + + buffer = VL_GetLocalBuffer(dev, 3); + buffer[0] = page_index >> 8; + buffer[1] = page_index & 0xff; + buffer[2] = page_data; + + status = VL_I2CWrite(dev, buffer, (uint8_t) 3); + return status; +} + +int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count) +{ + int32_t status = STATUS_OK; + uint8_t *buffer; + +#ifdef VL_LOG_ENABLE + int32_t i = 0; + char value_as_str[VL_MAX_STRING_LENGTH_PLT]; + char *pvalue_as_str; + + pvalue_as_str = value_as_str; + + for (i = 0 ; i < count ; i++) { + snprintf(pvalue_as_str, sizeof(pvalue_as_str), + "%02X", *(pdata + i)); + + pvalue_as_str += 2; + } + trace_i2c("Write reg : 0x%04X, Val : 0x%s\n", index, value_as_str); +#endif + if ((count + 1) > VL_MAX_I2C_XFER_SIZE) + return STATUS_FAIL; + buffer = VL_GetLocalBuffer(dev, (count+1)); + buffer[0] = index; + memcpy(&buffer[1], pdata, count); + status = VL_I2CWrite(dev, buffer, (count+1)); + + return status; +} + +int32_t VL_read_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count) +{ + int32_t status = STATUS_OK; + uint8_t *buffer; + +#ifdef VL_LOG_ENABLE + int32_t i = 0; + char value_as_str[VL_MAX_STRING_LENGTH_PLT]; + char *pvalue_as_str; +#endif + + if ((count + 1) > VL_MAX_I2C_XFER_SIZE) + return STATUS_FAIL; + + buffer = VL_GetLocalBuffer(dev, 1); + buffer[0] = index; + status = VL_I2CWrite(dev, (uint8_t *)buffer, (uint8_t)1); + if (!status) { + pdata[0] = index; + status = VL_I2CRead(dev, pdata, count); + } + +#ifdef VL_LOG_ENABLE + pvalue_as_str = value_as_str; + + for (i = 0 ; i < count ; i++) { + snprintf(pvalue_as_str, sizeof(value_as_str), + "%02X", *(pdata+i)); + pvalue_as_str += 2; + } + + trace_i2c("Read reg : 0x%04X, Val : 0x%s\n", index, value_as_str); +#endif + + return status; +} + + +int32_t VL_write_byte(struct vl_data *dev, uint8_t index, uint8_t data) +{ + int32_t status = STATUS_OK; + const int32_t cbyte_count = 1; + + status = VL_write_multi(dev, index, &data, cbyte_count); + + return status; + +} + + +int32_t VL_write_word(struct vl_data *dev, uint8_t index, uint16_t data) +{ + int32_t status = STATUS_OK; + + uint8_t buffer[BYTES_PER_WORD]; + + /* Split 16-bit word into MS and LS uint8_t */ + buffer[0] = (uint8_t)(data >> 8); + buffer[1] = (uint8_t)(data & 0x00FF); + + status = VL_write_multi(dev, index, buffer, BYTES_PER_WORD); + + return status; + +} + + +int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t data) +{ + int32_t status = STATUS_OK; + uint8_t buffer[BYTES_PER_DWORD]; + + /* Split 32-bit word into MS ... LS bytes */ + buffer[0] = (uint8_t) (data >> 24); + buffer[1] = (uint8_t)((data & 0x00FF0000) >> 16); + buffer[2] = (uint8_t)((data & 0x0000FF00) >> 8); + buffer[3] = (uint8_t) (data & 0x000000FF); + + status = VL_write_multi(dev, index, buffer, BYTES_PER_DWORD); + + return status; + +} + + +int32_t VL_read_byte(struct vl_data *dev, uint8_t index, uint8_t *pdata) +{ + int32_t status = STATUS_OK; + int32_t cbyte_count = 1; + + status = VL_read_multi(dev, index, pdata, cbyte_count); + + return status; + +} + + +int32_t VL_read_word(struct vl_data *dev, uint8_t index, uint16_t *pdata) +{ + int32_t status = STATUS_OK; + uint8_t buffer[BYTES_PER_WORD]; + + status = VL_read_multi(dev, index, buffer, BYTES_PER_WORD); + *pdata = ((uint16_t)buffer[0]<<8) + (uint16_t)buffer[1]; + + return status; + +} + +int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata) +{ + int32_t status = STATUS_OK; + uint8_t buffer[BYTES_PER_DWORD]; + + status = VL_read_multi(dev, index, buffer, BYTES_PER_DWORD); + *pdata = ((uint32_t)buffer[0]<<24) + ((uint32_t)buffer[1]<<16) + + ((uint32_t)buffer[2]<<8) + (uint32_t)buffer[3]; + + return status; + +} + +int32_t VL_platform_wait_us(int32_t wait_us) +{ + int32_t status = STATUS_OK; + + msleep((wait_us/1000)); + +#ifdef VL_LOG_ENABLE + trace_i2c("Wait us : %6d\n", wait_us); +#endif + + return status; + +} + + +int32_t VL_wait_ms(int32_t wait_ms) +{ + int32_t status = STATUS_OK; + + msleep(wait_ms); + +#ifdef VL_LOG_ENABLE + trace_i2c("Wait ms : %6d\n", wait_ms); +#endif + + return status; + +} + + +int32_t VL_set_gpio(uint8_t level) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// Set GPIO = %d;\n", level); +#endif + + return status; + +} + + +int32_t VL_get_gpio(uint8_t *plevel) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// Get GPIO = %d;\n", *plevel); +#endif + return status; +} + + +int32_t VL_release_gpio(void) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// Releasing force on GPIO\n"); +#endif + return status; + +} + +int32_t VL_cycle_power(void) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// cycle sensor power\n"); +#endif + + return status; +} + + +int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz) +{ + *ptimer_freq_hz = 0; + return STATUS_FAIL; +} + + +int32_t VL_get_timer_value(int32_t *ptimer_count) +{ + *ptimer_count = 0; + return STATUS_FAIL; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c new file mode 100644 index 0000000000000000000000000000000000000000..560d6b1ece6fdaeaf2b387547f39c0da3268c156 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c @@ -0,0 +1,233 @@ +/* + * vl53l0x_platform.c - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +/** + * @file VL_i2c.c + * + * Copyright (C) 2014 ST MicroElectronics + * + * provide variable word size byte/Word/dword VL6180x register access via i2c + * + */ +#include "vl53l0x_platform.h" +#include "vl53l0x_i2c_platform.h" +#include "vl53l0x_api.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_PLATFORM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_PLATFORM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...)\ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_PLATFORM, status,\ + fmt, ##__VA_ARGS__) + + + +int8_t VL_LockSequenceAccess(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + + return Status; +} + +int8_t VL_UnlockSequenceAccess(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + + return Status; +} + +/* the ranging_sensor_comms.dll will take care of the page selection */ +int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count) +{ + + int8_t Status = VL_ERROR_NONE; + int32_t status_int = 0; + uint8_t deviceAddress; + + if (count >= VL_MAX_I2C_XFER_SIZE) + Status = VL_ERROR_INVALID_PARAMS; + + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_multi(Dev, index, pdata, count); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +/* the ranging_sensor_comms.dll will take care of the page selection */ +int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + if (count >= VL_MAX_I2C_XFER_SIZE) + Status = VL_ERROR_INVALID_PARAMS; + + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_multi(Dev, index, pdata, count); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + + +int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_byte(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_word(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_dword(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index, + uint8_t AndData, uint8_t OrData) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + uint8_t data; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_byte(Dev, index, &data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + if (Status == VL_ERROR_NONE) { + data = (data & AndData) | OrData; + status_int = VL_write_byte(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + } + + return Status; +} + +int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_byte(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_word(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_dword(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +#define VL_POLLINGDELAY_LOOPNB 250 +int8_t VL_PollingDelay(struct vl_data *Dev) +{ + int8_t status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + usleep_range(1000, 1001); + LOG_FUNCTION_END(status); + return status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..2380c0857cee16282aa0c373a223e5d58c485e18 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c @@ -0,0 +1,170 @@ +/* + * vl53l0x_port_i2c.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + + +#include +#include +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" +#include "vl53l0x_platform.h" +#include "vl53l0x_i2c_platform.h" +#include "stmvl53l0x.h" + +#define I2C_M_WR 0x00 +#define STATUS_OK 0x00 +#define STATUS_FAIL (-1) +/** int VL_I2CWrite(VL_Dev_t dev, void *buff, uint8_t len); + * @brief Write data buffer to VL53L0 device via i2c + * @param dev The device to write to + * @param buff The data buffer + * @param len The length of the transaction in byte + * @return 0 on success + */ +int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len) +{ + + + int err = 0; + + if (dev->bus_type == CCI_BUS) { +#ifdef CAMERA_CCI + uint16_t index; + struct cci_data *cci_client_obj = + (struct cci_data *)dev->client_object; + struct msm_camera_i2c_client *client = cci_client_obj->client; + + index = buff[0]; + /*dbg("%s: index: %d len: %d\n", __func__, index, len); */ + + if (len == 2) { + uint8_t data; + + data = buff[1]; + /* for byte access */ + err = client->i2c_func_tbl->i2c_write(client, index, + data, MSM_CAMERA_I2C_BYTE_DATA); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } + } else if (len == 3) { + uint16_t data; + + data = ((uint16_t)buff[1] << 8) | (uint16_t)buff[2]; + err = client->i2c_func_tbl->i2c_write(client, index, + data, MSM_CAMERA_I2C_WORD_DATA); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } + } else if (len >= 5) { + err = client->i2c_func_tbl->i2c_write_seq(client, + index, &buff[1], (len-1)); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } + + } +#endif +#ifndef CAMERA_CCI + } else { + struct i2c_msg msg[1]; + struct i2c_data *i2c_client_obj = + (struct i2c_data *)dev->client_object; + struct i2c_client *client = + (struct i2c_client *)i2c_client_obj->client; + + msg[0].addr = client->addr; + msg[0].flags = I2C_M_WR; + msg[0].buf = buff; + msg[0].len = len; + + err = i2c_transfer(client->adapter, msg, 1); + /* return the actual messages transfer */ + if (err != 1) { + dbg("%s: i2c_transfer err:%d, addr:0x%x, reg:0x%x\n", + __func__, err, client->addr, + (buff[0] << 8 | buff[1])); + return STATUS_FAIL; + } +#endif + } + + return 0; +} + + +/** int VL_I2CRead(VL_Dev_t dev, void *buff, uint8_t len); + * @brief Read data buffer from VL53L0 device via i2c + * @param dev The device to read from + * @param buff The data buffer to fill + * @param len The length of the transaction in byte + * @return transaction status + */ +int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len) +{ + + int err = 0; + + if (dev->bus_type == CCI_BUS) { +#ifdef CAMERA_CCI + uint16_t index; + struct cci_data *cci_client_obj = + (struct cci_data *)dev->client_object; + struct msm_camera_i2c_client *client = cci_client_obj->client; + + index = buff[0]; + /* dbg("%s: index: %d\n", __func__, index); */ + err = client->i2c_func_tbl->i2c_read_seq(client, + index, buff, len); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } +#endif + } else { +#ifndef CAMERA_CCI + struct i2c_msg msg[1]; + struct i2c_data *i2c_client_obj = + (struct i2c_data *)dev->client_object; + struct i2c_client *client = + (struct i2c_client *) i2c_client_obj->client; + + msg[0].addr = client->addr; + msg[0].flags = I2C_M_RD|client->flags; + msg[0].buf = buff; + msg[0].len = len; + + err = i2c_transfer(client->adapter, &msg[0], 1); + /* return the actual message transfer */ + if (err != 1) { + dbg("%s: Read i2c_transfer err:%d, addr:0x%x\n", + __func__, err, client->addr); + return STATUS_FAIL; + } +#endif + } + + return 0; +} diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h new file mode 100644 index 0000000000000000000000000000000000000000..6dc4a08bc7d45a63bea071355ea6faea04425c16 --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h @@ -0,0 +1,57 @@ +/* + * stmvl53l0-cci.h - Linux kernel modules for STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#ifndef STMVL_CCI_H +#define STMVL_CCI_H +#include + +#ifdef CAMERA_CCI +#include +#include "msm_camera_i2c.h" +#include "msm_camera_dt_util.h" +#include "msm_camera_io_util.h" +#include "msm_cci.h" + +#define MSM_TOF_MAX_VREGS (10) + +struct msm_tof_vreg { + struct camera_vreg_t *cam_vreg; + void *data[MSM_TOF_MAX_VREGS]; + int num_vreg; +}; + +struct cci_data { + struct msm_camera_i2c_client g_client; + struct msm_camera_i2c_client *client; + struct platform_device *pdev; + enum msm_camera_device_type_t device_type; + enum cci_i2c_master_t cci_master; + struct msm_tof_vreg vreg_cfg; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *subdev_ops; + char subdev_initialized; + uint32_t subdev_id; + uint8_t power_up; +}; +int stmvl53l0x_init_cci(void); +void stmvl53l0x_exit_cci(void *); +int stmvl53l0x_power_down_cci(void *); +int stmvl53l0x_power_up_cci(void *, unsigned int *); +#endif /* CAMERA_CCI */ +#endif /* STMVL_CCI_H */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..a7a890fe6fa5a77913d0a78b41367c665b9f4142 --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h @@ -0,0 +1,35 @@ +/* + * stmvl53l0-i2c.h - Linux kernel modules for STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#ifndef STMVL_I2C_H +#define STMVL_I2C_H +#include + +#ifndef CAMERA_CCI +struct i2c_data { + struct i2c_client *client; + struct regulator *vana; + uint8_t power_up; +}; +int stmvl53l0x_init_i2c(void); +void stmvl53l0x_exit_i2c(void *); +int stmvl53l0x_power_up_i2c(void *, unsigned int *); +int stmvl53l0x_power_down_i2c(void *); + +#endif /* NOT CAMERA_CCI */ +#endif /* STMVL_I2C_H */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x.h b/drivers/input/misc/vl53l0x/stmvl53l0x.h new file mode 100644 index 0000000000000000000000000000000000000000..feb7b368ea4ae685960e4251b70800e2a86ed3c2 --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x.h @@ -0,0 +1,187 @@ +/* + * stmvl53l0.h - Linux kernel modules for STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + +#ifndef STMVL_H +#define STMVL_H + +#include +#include +#include +#include +#include + + +#define STMVL_DRV_NAME "stmvl53l0" +#define STMVL_SLAVE_ADDR (0x52>>1) + +#define DRIVER_VERSION "1.0.5" +#define I2C_M_WR 0x00 +/* #define INT_POLLING_DELAY 20 */ + +/* if don't want to have output from dbg, comment out #DEBUG macro */ +#ifdef DEBUG +#define dbg(fmt, ...) \ + printk(fmt, ##__VA_ARGS__) +#else +#define dbg(fmt, ...) +#endif + +#define err(fmt, ...) \ + printk(fmt, ##__VA_ARGS__) + +#define VL_VDD_MIN 2600000 +#define VL_VDD_MAX 3000000 + +enum init_mode_e { + NORMAL_MODE = 0, + OFFSETCALIB_MODE = 1, + XTALKCALIB_MODE = 2, +}; + +enum parameter_name_e { + OFFSET_PAR = 0, + XTALKRATE_PAR = 1, + XTALKENABLE_PAR = 2, + GPIOFUNC_PAR = 3, + LOWTHRESH_PAR = 4, + HIGHTHRESH_PAR = 5, + DEVICEMODE_PAR = 6, + INTERMEASUREMENT_PAR = 7, + REFERENCESPADS_PAR = 8, + REFCALIBRATION_PAR = 9, +}; + +enum { + CCI_BUS = 0, + I2C_BUS = 1, +}; + +/* + * IOCTL register data structs + */ +struct stmvl53l0x_register { + uint32_t is_read; /*1: read 0: write*/ + uint32_t reg_index; + uint32_t reg_bytes; + uint32_t reg_data; + int32_t status; +}; + +/* + * IOCTL parameter structs + */ +struct stmvl53l0x_parameter { + uint32_t is_read; /*1: Get 0: Set*/ + enum parameter_name_e name; + int32_t value; + int32_t value2; + int32_t status; +}; + +/* + * driver data structs + */ +struct vl_data { + + struct VL_DevData_t Data; /* ! +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * power specific includes + */ +#include +#include +#include +#include +#include +/* + * API includes + */ +#include "vl53l0x_api.h" +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" +#include "stmvl53l0x-cci.h" +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x.h" + +#ifdef CAMERA_CCI +/* + * Global data + */ +static struct v4l2_file_operations msm_tof_v4l2_subdev_fops; +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_seq = msm_camera_cci_i2c_write_seq, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; +static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data); + +/* + * QCOM specific functions + */ +static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data) +{ + int rc = 0; + + dbg("Enter\n"); + + if (dev->of_node) { + struct device_node *of_node = dev->of_node; + struct msm_tof_vreg *vreg_cfg; + + if (!of_node) { + err("failed %d\n", __LINE__); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, + "cell-index", &data->pdev->id); + if (rc < 0) { + err("failed %d\n", __LINE__); + return rc; + } + dbg("cell-index: %d\n", data->pdev->id); + rc = of_property_read_u32(of_node, "qcom,cci-master", + &data->cci_master); + if (rc < 0) { + err("failed %d\n", __LINE__); + /* Set default master 0 */ + data->cci_master = MASTER_0; + rc = 0; + } + dbg("cci_master: %d\n", data->cci_master); + if (of_find_property(of_node, "qcom,cam-vreg-name", NULL)) { + vreg_cfg = &data->vreg_cfg; + rc = msm_camera_get_dt_vreg_data(of_node, + &vreg_cfg->cam_vreg, &vreg_cfg->num_vreg); + if (rc < 0) { + err("failed %d\n", __LINE__); + return rc; + } + } + dbg("vreg-name: %s min_volt: %d max_volt: %d", + vreg_cfg->cam_vreg->reg_name, + vreg_cfg->cam_vreg->min_voltage, + vreg_cfg->cam_vreg->max_voltage); + } + dbg("End rc =%d\n", rc); + + return rc; +} + +static int32_t stmvl53l0x_vreg_control(struct cci_data *data, int config) +{ + int rc = 0, i, cnt; + struct msm_tof_vreg *vreg_cfg; + + dbg("Enter\n"); + + vreg_cfg = &data->vreg_cfg; + cnt = vreg_cfg->num_vreg; + dbg("num_vreg: %d\n", cnt); + if (!cnt) { + err("failed %d\n", __LINE__); + return 0; + } + + if (cnt >= MSM_TOF_MAX_VREGS) { + err("failed %d cnt %d\n", __LINE__, cnt); + return -EINVAL; + } + + for (i = 0; i < cnt; i++) { + rc = msm_camera_config_single_vreg(&(data->pdev->dev), + &vreg_cfg->cam_vreg[i], + (struct regulator **)&vreg_cfg->data[i], + config); + } + + dbg("EXIT rc =%d\n", rc); + return rc; +} + + +static int msm_tof_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; +/* + struct msm_tof_ctrl_t *tof_ctrl = v4l2_get_subdevdata(sd); + if (!tof_ctrl) { + dbg("failed\n"); + return -EINVAL; + } + if (tof_ctrl->tof_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = tof_ctrl->i2c_client.i2c_func_tbl->i2c_util( + &tof_ctrl->i2c_client, MSM_CCI_RELEASE); + if (rc < 0) + dbg("cci_init failed\n"); + } + tof_ctrl->i2c_state = TOF_I2C_RELEASE; +*/ + return rc; +} + + +static const struct v4l2_subdev_internal_ops msm_tof_internal_ops = { + .close = msm_tof_close, +}; + +static long msm_tof_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + dbg("Subdev_ioctl not handled\n"); + return 0; +} + +static int32_t msm_tof_power(struct v4l2_subdev *sd, int on) +{ + dbg("TOF power called\n"); + return 0; +} + +static struct v4l2_subdev_core_ops msm_tof_subdev_core_ops = { + .ioctl = msm_tof_subdev_ioctl, + .s_power = msm_tof_power, +}; + +static struct v4l2_subdev_ops msm_tof_subdev_ops = { + .core = &msm_tof_subdev_core_ops, +}; + +static int stmvl53l0x_cci_init(struct cci_data *data) +{ + int rc = 0; + struct msm_camera_cci_client *cci_client = data->client->cci_client; + + if (FALSE == data->subdev_initialized) { + data->client->i2c_func_tbl = &msm_sensor_cci_func_tbl; + data->client->cci_client = + kzalloc(sizeof(struct msm_camera_cci_client), + GFP_KERNEL); + if (!data->client->cci_client) { + err("%d, failed no memory\n", __LINE__); + return -ENOMEM; + } + cci_client = data->client->cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = data->cci_master; + v4l2_subdev_init(&data->msm_sd.sd, data->subdev_ops); + v4l2_set_subdevdata(&data->msm_sd.sd, data); + data->msm_sd.sd.internal_ops = &msm_tof_internal_ops; + data->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(data->msm_sd.sd.name, ARRAY_SIZE(data->msm_sd.sd.name), + "msm_tof"); + media_entity_init(&data->msm_sd.sd.entity, 0, NULL, 0); + data->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + data->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_TOF; + data->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; + msm_sd_register(&data->msm_sd); + msm_tof_v4l2_subdev_fops = v4l2_subdev_fops; + data->msm_sd.sd.devnode->fops = &msm_tof_v4l2_subdev_fops; + data->subdev_initialized = TRUE; + } + + cci_client->sid = 0x29; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->cci_i2c_master = data->cci_master; + rc = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_INIT); + if (rc < 0) { + err("%d: CCI Init failed\n", __LINE__); + return rc; + } + dbg("CCI Init Succeeded\n"); + + data->client->addr_type = MSM_CAMERA_I2C_BYTE_ADDR; + + return 0; +} + +static int32_t stmvl53l0x_platform_probe(struct platform_device *pdev) +{ + struct vl_data *vl53l0x_data = NULL; + struct cci_data *cci_object = NULL; + int32_t rc = 0; + + dbg("Enter\n"); + + if (!pdev->dev.of_node) { + err("of_node NULL\n"); + return -EINVAL; + } + + vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL); + if (!vl53l0x_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l0x_data) { + vl53l0x_data->client_object = + kzalloc(sizeof(struct cci_data), GFP_KERNEL); + cci_object = (struct cci_data *)vl53l0x_data->client_object; + } + cci_object->client = + (struct msm_camera_i2c_client *)&cci_object->g_client; + + /* setup bus type */ + vl53l0x_data->bus_type = CCI_BUS; + + /* Set platform device handle */ + cci_object->subdev_ops = &msm_tof_subdev_ops; + cci_object->pdev = pdev; + rc = stmvl53l0x_get_dt_data(&pdev->dev, cci_object); + if (rc < 0) { + err("%d, failed rc %d\n", __LINE__, rc); + return rc; + } + cci_object->subdev_id = pdev->id; + + /* Set device type as platform device */ + cci_object->device_type = MSM_CAMERA_PLATFORM_DEVICE; + cci_object->subdev_initialized = FALSE; + + /* setup device name */ + vl53l0x_data->dev_name = dev_name(&pdev->dev); + + /* setup device data */ + dev_set_drvdata(&pdev->dev, vl53l0x_data); + + /* setup other stuff */ + rc = stmvl53l0x_setup(vl53l0x_data); + + /* init default value */ + cci_object->power_up = 0; + + dbg("End\n"); + + return rc; + +} + +static int32_t stmvl53l0x_platform_remove(struct platform_device *pdev) +{ + struct vl_data *vl53l0x_data = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + kfree(vl53l0x_data->client_object); + kfree(vl53l0x_data); + + return 0; +} + +static const struct of_device_id st_stmvl53l0x_dt_match[] = { + { .compatible = "st,stmvl53l0", }, + { }, +}; + +static struct platform_driver stmvl53l0x_platform_driver = { + .probe = stmvl53l0x_platform_probe, + .remove = stmvl53l0x_platform_remove, + .driver = { + .name = STMVL_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l0x_dt_match, + }, +}; + +int stmvl53l0x_power_up_cci(void *cci_object, unsigned int *preset_flag) +{ + int ret = 0; + struct cci_data *data = (struct cci_data *)cci_object; + + dbg("Enter"); + + /* need to init cci first */ + ret = stmvl53l0x_cci_init(data); + if (ret) { + err("stmvl53l0x_cci_init failed %d\n", __LINE__); + return ret; + } + /* actual power up */ + if (data && data->device_type == MSM_CAMERA_PLATFORM_DEVICE) { + ret = stmvl53l0x_vreg_control(data, 1); + if (ret < 0) { + err("stmvl53l0x_vreg_control failed %d\n", + __LINE__); + return ret; + } + } + data->power_up = 1; + *preset_flag = 1; + dbg("End\n"); + + return ret; +} + +int stmvl53l0x_power_down_cci(void *cci_object) +{ + int ret = 0; + struct cci_data *data = (struct cci_data *)cci_object; + + dbg("Enter\n"); + if (data->power_up) { + /* need to release cci first */ + ret = data->client->i2c_func_tbl->i2c_util(data->client, + MSM_CCI_RELEASE); + if (ret < 0) + err("CCI Release failed rc %d\n", ret); + + /* actual power down */ + if (data->device_type == MSM_CAMERA_PLATFORM_DEVICE) { + ret = stmvl53l0x_vreg_control(data, 0); + if (ret < 0) { + err( + "stmvl53l0x_vreg_control failed %d\n", + __LINE__); + return ret; + } + } + } + data->power_up = 0; + dbg("End\n"); + return ret; +} + +int stmvl53l0x_init_cci(void) +{ + int ret = 0; + + dbg("Enter\n"); + + /* register as a platform device */ + ret = platform_driver_register(&stmvl53l0x_platform_driver); + if (ret) + err("%d, error ret:%d\n", __LINE__, ret); + + dbg("End\n"); + + return ret; +} + +void stmvl53l0x_exit_cci(void *cci_object) +{ + struct cci_data *data = (struct cci_data *)cci_object; + + dbg("Enter\n"); + + if (data && data->client->cci_client) + kfree(data->client->cci_client); + + dbg("End\n"); +} +#endif /* end of CAMERA_CCI */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..57c0c0627e6758bc601d799be42b9b9b5ff0fb9d --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c @@ -0,0 +1,247 @@ +/* + * stmvl53l0x_module-i2c.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * power specific includes + */ +#include +#include +#include +#include +#include +/* + * API includes + */ +#include "vl53l0x_api.h" +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" +#include "stmvl53l0x.h" +#ifndef CAMERA_CCI + +/* + * Global data + */ +static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data); + +/* + * QCOM specific functions + */ +static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data) +{ + int ret = 0; + + dbg("Enter\n"); + + if (dev->of_node) { + data->vana = regulator_get(dev, "vdd"); + if (IS_ERR(data->vana)) { + err("vdd supply is not provided\n"); + ret = -1; + } + } + dbg("End\n"); + + return ret; +} + +static int stmvl53l0x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct vl_data *vl53l0x_data = NULL; + struct i2c_data *i2c_object = NULL; + + dbg("Enter\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + rc = -EIO; + return rc; + } + + vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL); + if (!vl53l0x_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l0x_data) { + vl53l0x_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + i2c_object = (struct i2c_data *)vl53l0x_data->client_object; + } + i2c_object->client = client; + + /* setup bus type */ + vl53l0x_data->bus_type = I2C_BUS; + + /* setup regulator */ + stmvl53l0x_parse_vdd(&i2c_object->client->dev, i2c_object); + + /* setup device name */ + vl53l0x_data->dev_name = dev_name(&client->dev); + + /* setup device data */ + dev_set_drvdata(&client->dev, vl53l0x_data); + + /* setup client data */ + i2c_set_clientdata(client, vl53l0x_data); + + /* setup other stuff */ + rc = stmvl53l0x_setup(vl53l0x_data); + + /* init default value */ + i2c_object->power_up = 0; + + dbg("End\n"); + return rc; +} + +static int stmvl53l0x_remove(struct i2c_client *client) +{ + struct vl_data *data = i2c_get_clientdata(client); + + dbg("Enter\n"); + + /* Power down the device */ + stmvl53l0x_power_down_i2c(data->client_object); + kfree(data->client_object); + kfree(data); + dbg("End\n"); + return 0; +} + +static const struct i2c_device_id stmvl53l0x_id[] = { + { STMVL_DRV_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, stmvl53l0x_id); + +static const struct of_device_id st_stmvl53l0x_dt_match[] = { + { .compatible = "st,stmvl53l0", }, + { }, +}; + +static struct i2c_driver stmvl53l0x_driver = { + .driver = { + .name = STMVL_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l0x_dt_match, + }, + .probe = stmvl53l0x_probe, + .remove = stmvl53l0x_remove, + .id_table = stmvl53l0x_id, + +}; + +int stmvl53l0x_power_up_i2c(void *i2c_object, unsigned int *preset_flag) +{ + int ret = 0; +#ifndef STM_TEST + struct i2c_data *data = (struct i2c_data *)i2c_object; +#endif + + dbg("Enter\n"); + + /* actual power on */ +#ifndef STM_TEST + ret = regulator_set_voltage(data->vana, + VL_VDD_MIN, VL_VDD_MAX); + if (ret < 0) { + err("set_vol(%p) fail %d\n", data->vana , ret); + return ret; + } + ret = regulator_enable(data->vana); + usleep_range(3000, 3001); + if (ret < 0) { + err("reg enable(%p) failed.rc=%d\n", + data->vana, ret); + return ret; + } + data->power_up = 1; + *preset_flag = 1; +#endif + + dbg("End\n"); + return ret; +} + +int stmvl53l0x_power_down_i2c(void *i2c_object) +{ + int ret = 0; +#ifndef STM_TEST + struct i2c_data *data = (struct i2c_data *)i2c_object; +#endif + + dbg("Enter\n"); +#ifndef STM_TEST + msleep(30); + ret = regulator_disable(data->vana); + if (ret < 0) + err("reg disable(%p) failed.rc=%d\n", + data->vana, ret); + + data->power_up = 0; +#endif + + dbg("End\n"); + return ret; +} + +int stmvl53l0x_init_i2c(void) +{ + int ret = 0; + + dbg("Enter\n"); + + /* register as a i2c client device */ + ret = i2c_add_driver(&stmvl53l0x_driver); + if (ret) + err("%d erro ret:%d\n", __LINE__, ret); + + dbg("End with rc:%d\n", ret); + + return ret; +} + +void stmvl53l0x_exit_i2c(void *i2c_object) +{ + dbg("Enter\n"); + i2c_del_driver(&stmvl53l0x_driver); + + dbg("End\n"); +} + +#endif /* end of NOT CAMERA_CCI */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c new file mode 100644 index 0000000000000000000000000000000000000000..5130b910b2e214ca2c46a61a5886f95c76e9770a --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c @@ -0,0 +1,1898 @@ +/* + * stmvl53l0x_module.c - Linux kernel modules for STM VL53L0 FlightSense TOF + * sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * API includes + */ +#include "vl53l0x_api.h" + +#define IRQ_NUM 59 +#ifdef DEBUG_TIME_LOG +struct timeval start_tv, stop_tv; +#endif + +/* + * Global data + */ + +#ifdef CAMERA_CCI +static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = { + .init = stmvl53l0x_init_cci, + .deinit = stmvl53l0x_exit_cci, + .power_up = stmvl53l0x_power_up_cci, + .power_down = stmvl53l0x_power_down_cci, +}; +#else +static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = { + .init = stmvl53l0x_init_i2c, + .deinit = stmvl53l0x_exit_i2c, + .power_up = stmvl53l0x_power_up_i2c, + .power_down = stmvl53l0x_power_down_i2c, +}; +#endif +struct stmvl53l0x_module_fn_t *pmodule_func_tbl; + +struct stmvl53l0x_api_fn_t { + int8_t (*GetVersion)(struct VL_Version_t *pVersion); + int8_t (*GetPalSpecVersion)(struct VL_Version_t *pPalSpecVersion); + + int8_t (*GetProductRevision)(struct vl_data *Dev, + uint8_t *pProductRevisionMajor, + uint8_t *pProductRevisionMinor); + int8_t (*GetDeviceInfo)(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo); + int8_t (*GetDeviceErrorStatus)(struct vl_data *Dev, + uint8_t *pDeviceErrorStatus); + int8_t (*GetRangeStatusString)(uint8_t RangeStatus, + char *pRangeStatusString); + int8_t (*GetDeviceErrorString)(uint8_t ErrorCode, + char *pDeviceErrorString); + int8_t (*GetPalErrorString)(int8_t PalErrorCode, + char *pPalErrorString); + int8_t (*GetPalStateString)(uint8_t PalStateCode, + char *pPalStateString); + int8_t (*GetPalState)(struct vl_data *Dev, uint8_t *pPalState); + int8_t (*SetPowerMode)(struct vl_data *Dev, + uint8_t PowerMode); + int8_t (*GetPowerMode)(struct vl_data *Dev, + uint8_t *pPowerMode); + int8_t (*SetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter); + int8_t (*GetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter); + int8_t (*SetLinearityCorrectiveGain)(struct vl_data *Dev, + int16_t LinearityCorrectiveGain); + int8_t (*GetLinearityCorrectiveGain)(struct vl_data *Dev, + uint16_t *pLinearityCorrectiveGain); + int8_t (*SetGroupParamHold)(struct vl_data *Dev, + uint8_t GroupParamHold); + int8_t (*GetUpperLimitMilliMeter)(struct vl_data *Dev, + uint16_t *pUpperLimitMilliMeter); + int8_t (*SetDeviceAddress)(struct vl_data *Dev, + uint8_t DeviceAddress); + int8_t (*DataInit)(struct vl_data *Dev); + int8_t (*SetTuningSettingBuffer)(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer, + uint8_t UseInternalTuningSettings); + int8_t (*GetTuningSettingBuffer)(struct vl_data *Dev, + uint8_t **pTuningSettingBuffer, + uint8_t *pUseInternalTuningSettings); + int8_t (*StaticInit)(struct vl_data *Dev); + int8_t (*WaitDeviceBooted)(struct vl_data *Dev); + int8_t (*ResetDevice)(struct vl_data *Dev); + int8_t (*SetDeviceParameters)(struct vl_data *Dev, + const struct VL_DeviceParameters_t *pDeviceParameters); + int8_t (*GetDeviceParameters)(struct vl_data *Dev, + struct VL_DeviceParameters_t *pDeviceParameters); + int8_t (*SetDeviceMode)(struct vl_data *Dev, + uint8_t DeviceMode); + int8_t (*GetDeviceMode)(struct vl_data *Dev, + uint8_t *pDeviceMode); + int8_t (*SetHistogramMode)(struct vl_data *Dev, + uint8_t HistogramMode); + int8_t (*GetHistogramMode)(struct vl_data *Dev, + uint8_t *pHistogramMode); + int8_t (*SetMeasurementTimingBudgetMicroSeconds)(struct vl_data *Dev, + uint32_t MeasurementTimingBudgetMicroSeconds); + int8_t (*GetMeasurementTimingBudgetMicroSeconds)( + struct vl_data *Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds); + int8_t (*GetVcselPulsePeriod)(struct vl_data *Dev, + uint8_t VcselPeriodType, + uint8_t *pVCSELPulsePeriod); + int8_t (*SetVcselPulsePeriod)(struct vl_data *Dev, + uint8_t VcselPeriodType, + uint8_t VCSELPulsePeriod); + int8_t (*SetSequenceStepEnable)(struct vl_data *Dev, + uint8_t SequenceStepId, + uint8_t SequenceStepEnabled); + int8_t (*GetSequenceStepEnable)(struct vl_data *Dev, + uint8_t SequenceStepId, + uint8_t *pSequenceStepEnabled); + int8_t (*GetSequenceStepEnables)(struct vl_data *Dev, + struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps); + int8_t (*SetSequenceStepTimeout)(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int TimeOutMilliSecs); + int8_t (*GetSequenceStepTimeout)(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int *pTimeOutMilliSecs); + int8_t (*GetNumberOfSequenceSteps)(struct vl_data *Dev, + uint8_t *pNumberOfSequenceSteps); + int8_t (*GetSequenceStepsInfo)( + uint8_t SequenceStepId, + char *pSequenceStepsString); + int8_t (*SetInterMeasurementPeriodMilliSeconds)( + struct vl_data *Dev, + uint32_t InterMeasurementPeriodMilliSeconds); + int8_t (*GetInterMeasurementPeriodMilliSeconds)( + struct vl_data *Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds); + int8_t (*SetXTalkCompensationEnable)(struct vl_data *Dev, + uint8_t XTalkCompensationEnable); + int8_t (*GetXTalkCompensationEnable)(struct vl_data *Dev, + uint8_t *pXTalkCompensationEnable); + int8_t (*SetXTalkCompensationRateMegaCps)( + struct vl_data *Dev, + unsigned int XTalkCompensationRateMegaCps); + int8_t (*GetXTalkCompensationRateMegaCps)( + struct vl_data *Dev, + unsigned int *pXTalkCompensationRateMegaCps); + int8_t (*GetNumberOfLimitCheck)( + uint16_t *pNumberOfLimitCheck); + int8_t (*GetLimitCheckInfo)(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString); + int8_t (*SetLimitCheckEnable)(struct vl_data *Dev, + uint16_t LimitCheckId, + uint8_t LimitCheckEnable); + int8_t (*GetLimitCheckEnable)(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + int8_t (*SetLimitCheckValue)(struct vl_data *Dev, + uint16_t LimitCheckId, + unsigned int LimitCheckValue); + int8_t (*GetLimitCheckValue)(struct vl_data *Dev, + uint16_t LimitCheckId, + unsigned int *pLimitCheckValue); + int8_t (*GetLimitCheckCurrent)(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent); + int8_t (*SetWrapAroundCheckEnable)(struct vl_data *Dev, + uint8_t WrapAroundCheckEnable); + int8_t (*GetWrapAroundCheckEnable)(struct vl_data *Dev, + uint8_t *pWrapAroundCheckEnable); + int8_t (*PerformSingleMeasurement)(struct vl_data *Dev); + int8_t (*PerformRefCalibration)(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + int8_t (*SetRefCalibration)(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal); + int8_t (*GetRefCalibration)(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + int8_t (*PerformXTalkCalibration)(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps); + int8_t (*PerformOffsetCalibration)(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, + int32_t *pOffsetMicroMeter); + int8_t (*StartMeasurement)(struct vl_data *Dev); + int8_t (*StopMeasurement)(struct vl_data *Dev); + int8_t (*GetMeasurementDataReady)(struct vl_data *Dev, + uint8_t *pMeasurementDataReady); + int8_t (*WaitDeviceReadyForNewMeasurement)(struct vl_data *Dev, + uint32_t MaxLoop); + int8_t (*GetRangingMeasurementData)(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + int8_t (*GetHistogramMeasurementData)(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + int8_t (*PerformSingleRangingMeasurement)(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + int8_t (*PerformSingleHistogramMeasurement)(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + int8_t (*SetNumberOfROIZones)(struct vl_data *Dev, + uint8_t NumberOfROIZones); + int8_t (*GetNumberOfROIZones)(struct vl_data *Dev, + uint8_t *pNumberOfROIZones); + int8_t (*GetMaxNumberOfROIZones)(struct vl_data *Dev, + uint8_t *pMaxNumberOfROIZones); + int8_t (*SetGpioConfig)(struct vl_data *Dev, + uint8_t Pin, + uint8_t DeviceMode, + uint8_t Functionality, + uint8_t Polarity); + int8_t (*GetGpioConfig)(struct vl_data *Dev, + uint8_t Pin, + uint8_t *pDeviceMode, + uint8_t *pFunctionality, + uint8_t *pPolarity); + int8_t (*SetInterruptThresholds)(struct vl_data *Dev, + uint8_t DeviceMode, + unsigned int ThresholdLow, + unsigned int ThresholdHigh); + int8_t (*GetInterruptThresholds)(struct vl_data *Dev, + uint8_t DeviceMode, + unsigned int *pThresholdLow, + unsigned int *pThresholdHigh); + int8_t (*ClearInterruptMask)(struct vl_data *Dev, + uint32_t InterruptMask); + int8_t (*GetInterruptMaskStatus)(struct vl_data *Dev, + uint32_t *pInterruptMaskStatus); + int8_t (*EnableInterruptMask)(struct vl_data *Dev, + uint32_t InterruptMask); + int8_t (*SetSpadAmbientDamperThreshold)(struct vl_data *Dev, + uint16_t SpadAmbientDamperThreshold); + int8_t (*GetSpadAmbientDamperThreshold)(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperThreshold); + int8_t (*SetSpadAmbientDamperFactor)(struct vl_data *Dev, + uint16_t SpadAmbientDamperFactor); + int8_t (*GetSpadAmbientDamperFactor)(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperFactor); + int8_t (*PerformRefSpadManagement)(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + int8_t (*SetReferenceSpads)(struct vl_data *Dev, + uint32_t count, uint8_t isApertureSpads); + int8_t (*GetReferenceSpads)(struct vl_data *Dev, + uint32_t *pSpadCount, uint8_t *pIsApertureSpads); +}; + +static struct stmvl53l0x_api_fn_t stmvl53l0x_api_func_tbl = { + .GetVersion = VL_GetVersion, + .GetPalSpecVersion = VL_GetPalSpecVersion, + .GetProductRevision = VL_GetProductRevision, + .GetDeviceInfo = VL_GetDeviceInfo, + .GetDeviceErrorStatus = VL_GetDeviceErrorStatus, + .GetRangeStatusString = VL_GetRangeStatusString, + .GetDeviceErrorString = VL_GetDeviceErrorString, + .GetPalErrorString = VL_GetPalErrorString, + .GetPalState = VL_GetPalState, + .SetPowerMode = VL_SetPowerMode, + .GetPowerMode = VL_GetPowerMode, + .SetOffsetCalibrationDataMicroMeter = + VL_SetOffsetCalibrationDataMicroMeter, + .SetLinearityCorrectiveGain = + VL_SetLinearityCorrectiveGain, + .GetLinearityCorrectiveGain = + VL_GetLinearityCorrectiveGain, + .GetOffsetCalibrationDataMicroMeter = + VL_GetOffsetCalibrationDataMicroMeter, + .SetGroupParamHold = VL_SetGroupParamHold, + .GetUpperLimitMilliMeter = VL_GetUpperLimitMilliMeter, + .SetDeviceAddress = VL_SetDeviceAddress, + .DataInit = VL_DataInit, + .SetTuningSettingBuffer = VL_SetTuningSettingBuffer, + .GetTuningSettingBuffer = VL_GetTuningSettingBuffer, + .StaticInit = VL_StaticInit, + .WaitDeviceBooted = VL_WaitDeviceBooted, + .ResetDevice = VL_ResetDevice, + .SetDeviceParameters = VL_SetDeviceParameters, + .SetDeviceMode = VL_SetDeviceMode, + .GetDeviceMode = VL_GetDeviceMode, + .SetHistogramMode = VL_SetHistogramMode, + .GetHistogramMode = VL_GetHistogramMode, + .SetMeasurementTimingBudgetMicroSeconds = + VL_SetMeasurementTimingBudgetMicroSeconds, + .GetMeasurementTimingBudgetMicroSeconds = + VL_GetMeasurementTimingBudgetMicroSeconds, + .GetVcselPulsePeriod = VL_GetVcselPulsePeriod, + .SetVcselPulsePeriod = VL_SetVcselPulsePeriod, + .SetSequenceStepEnable = VL_SetSequenceStepEnable, + .GetSequenceStepEnable = VL_GetSequenceStepEnable, + .GetSequenceStepEnables = VL_GetSequenceStepEnables, + .SetSequenceStepTimeout = VL_SetSequenceStepTimeout, + .GetSequenceStepTimeout = VL_GetSequenceStepTimeout, + .GetNumberOfSequenceSteps = VL_GetNumberOfSequenceSteps, + .GetSequenceStepsInfo = VL_GetSequenceStepsInfo, + .SetInterMeasurementPeriodMilliSeconds = + VL_SetInterMeasurementPeriodMilliSeconds, + .GetInterMeasurementPeriodMilliSeconds = + VL_GetInterMeasurementPeriodMilliSeconds, + .SetXTalkCompensationEnable = VL_SetXTalkCompensationEnable, + .GetXTalkCompensationEnable = VL_GetXTalkCompensationEnable, + .SetXTalkCompensationRateMegaCps = + VL_SetXTalkCompensationRateMegaCps, + .GetXTalkCompensationRateMegaCps = + VL_GetXTalkCompensationRateMegaCps, + .GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck, + .GetLimitCheckInfo = VL_GetLimitCheckInfo, + .SetLimitCheckEnable = VL_SetLimitCheckEnable, + .GetLimitCheckEnable = VL_GetLimitCheckEnable, + .SetLimitCheckValue = VL_SetLimitCheckValue, + .GetLimitCheckValue = VL_GetLimitCheckValue, + .GetLimitCheckCurrent = VL_GetLimitCheckCurrent, + .SetWrapAroundCheckEnable = VL_SetWrapAroundCheckEnable, + .GetWrapAroundCheckEnable = VL_GetWrapAroundCheckEnable, + .PerformSingleMeasurement = VL_PerformSingleMeasurement, + .PerformRefCalibration = VL_PerformRefCalibration, + .SetRefCalibration = VL_SetRefCalibration, + .GetRefCalibration = VL_GetRefCalibration, + .PerformXTalkCalibration = VL_PerformXTalkCalibration, + .PerformOffsetCalibration = VL_PerformOffsetCalibration, + .StartMeasurement = VL_StartMeasurement, + .StopMeasurement = VL_StopMeasurement, + .GetMeasurementDataReady = VL_GetMeasurementDataReady, + .WaitDeviceReadyForNewMeasurement = + VL_WaitDeviceReadyForNewMeasurement, + .GetRangingMeasurementData = VL_GetRangingMeasurementData, + .GetHistogramMeasurementData = VL_GetHistogramMeasurementData, + .PerformSingleRangingMeasurement = + VL_PerformSingleRangingMeasurement, + .PerformSingleHistogramMeasurement = + VL_PerformSingleHistogramMeasurement, + .SetNumberOfROIZones = VL_SetNumberOfROIZones, + .GetNumberOfROIZones = VL_GetNumberOfROIZones, + .GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones, + .SetGpioConfig = VL_SetGpioConfig, + .GetGpioConfig = VL_GetGpioConfig, + .SetInterruptThresholds = VL_SetInterruptThresholds, + .GetInterruptThresholds = VL_GetInterruptThresholds, + .ClearInterruptMask = VL_ClearInterruptMask, + .GetInterruptMaskStatus = VL_GetInterruptMaskStatus, + .EnableInterruptMask = VL_EnableInterruptMask, + .SetSpadAmbientDamperThreshold = VL_SetSpadAmbientDamperThreshold, + .GetSpadAmbientDamperThreshold = VL_GetSpadAmbientDamperThreshold, + .SetSpadAmbientDamperFactor = VL_SetSpadAmbientDamperFactor, + .GetSpadAmbientDamperFactor = VL_GetSpadAmbientDamperFactor, + .PerformRefSpadManagement = VL_PerformRefSpadManagement, + .SetReferenceSpads = VL_SetReferenceSpads, + .GetReferenceSpads = VL_GetReferenceSpads, + +}; +struct stmvl53l0x_api_fn_t *papi_func_tbl; + +/* + * IOCTL definitions + */ +#define VL_IOCTL_INIT _IO('p', 0x01) +#define VL_IOCTL_XTALKCALB _IOW('p', 0x02, unsigned int) +#define VL_IOCTL_OFFCALB _IOW('p', 0x03, unsigned int) +#define VL_IOCTL_STOP _IO('p', 0x05) +#define VL_IOCTL_SETXTALK _IOW('p', 0x06, unsigned int) +#define VL_IOCTL_SETOFFSET _IOW('p', 0x07, int8_t) +#define VL_IOCTL_GETDATAS \ + _IOR('p', 0x0b, struct VL_RangingMeasurementData_t) +#define VL_IOCTL_REGISTER \ + _IOWR('p', 0x0c, struct stmvl53l0x_register) +#define VL_IOCTL_PARAMETER \ + _IOWR('p', 0x0d, struct stmvl53l0x_parameter) + +static long stmvl53l0x_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +/*static int stmvl53l0x_flush(struct file *file, fl_owner_t id);*/ +static int stmvl53l0x_open(struct inode *inode, struct file *file); +static int stmvl53l0x_init_client(struct vl_data *data); +static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling, + enum init_mode_e mode); +static int stmvl53l0x_stop(struct vl_data *data); + +#ifdef DEBUG_TIME_LOG +static void stmvl53l0x_DebugTimeGet(struct timeval *ptv) +{ + do_gettimeofday(ptv); +} + +static void stmvl53l0x_DebugTimeDuration(struct timeval *pstart_tv, + struct timeval *pstop_tv) +{ + long total_sec, total_msec; + + total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec; + total_msec = (pstop_tv->tv_usec - pstart_tv->tv_usec)/1000; + total_msec += total_sec * 1000; + dbg("elapsedTime:%ld\n", total_msec); +} +#endif + +static void stmvl53l0x_setupAPIFunctions(void) +{ + + /*cut 1.1*/ + err("to setup API cut 1.1\n"); + papi_func_tbl->GetVersion = VL_GetVersion; + papi_func_tbl->GetPalSpecVersion = VL_GetPalSpecVersion; + papi_func_tbl->GetProductRevision = VL_GetProductRevision; + papi_func_tbl->GetDeviceInfo = VL_GetDeviceInfo; + papi_func_tbl->GetDeviceErrorStatus = VL_GetDeviceErrorStatus; + papi_func_tbl->GetRangeStatusString = VL_GetRangeStatusString; + papi_func_tbl->GetDeviceErrorString = VL_GetDeviceErrorString; + papi_func_tbl->GetPalErrorString = VL_GetPalErrorString; + papi_func_tbl->GetPalState = VL_GetPalState; + papi_func_tbl->SetPowerMode = VL_SetPowerMode; + papi_func_tbl->GetPowerMode = VL_GetPowerMode; + papi_func_tbl->SetOffsetCalibrationDataMicroMeter = + VL_SetOffsetCalibrationDataMicroMeter; + papi_func_tbl->GetOffsetCalibrationDataMicroMeter = + VL_GetOffsetCalibrationDataMicroMeter; + papi_func_tbl->SetLinearityCorrectiveGain = + VL_SetLinearityCorrectiveGain; + papi_func_tbl->GetLinearityCorrectiveGain = + VL_GetLinearityCorrectiveGain; + papi_func_tbl->SetGroupParamHold = VL_SetGroupParamHold; + papi_func_tbl->GetUpperLimitMilliMeter = + VL_GetUpperLimitMilliMeter; + papi_func_tbl->SetDeviceAddress = VL_SetDeviceAddress; + papi_func_tbl->DataInit = VL_DataInit; + papi_func_tbl->SetTuningSettingBuffer = VL_SetTuningSettingBuffer; + papi_func_tbl->GetTuningSettingBuffer = VL_GetTuningSettingBuffer; + papi_func_tbl->StaticInit = VL_StaticInit; + papi_func_tbl->WaitDeviceBooted = VL_WaitDeviceBooted; + papi_func_tbl->ResetDevice = VL_ResetDevice; + papi_func_tbl->SetDeviceParameters = VL_SetDeviceParameters; + papi_func_tbl->SetDeviceMode = VL_SetDeviceMode; + papi_func_tbl->GetDeviceMode = VL_GetDeviceMode; + papi_func_tbl->SetHistogramMode = VL_SetHistogramMode; + papi_func_tbl->GetHistogramMode = VL_GetHistogramMode; + papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds = + VL_SetMeasurementTimingBudgetMicroSeconds; + papi_func_tbl->GetMeasurementTimingBudgetMicroSeconds = + VL_GetMeasurementTimingBudgetMicroSeconds; + papi_func_tbl->GetVcselPulsePeriod = VL_GetVcselPulsePeriod; + papi_func_tbl->SetVcselPulsePeriod = VL_SetVcselPulsePeriod; + papi_func_tbl->SetSequenceStepEnable = VL_SetSequenceStepEnable; + papi_func_tbl->GetSequenceStepEnable = VL_GetSequenceStepEnable; + papi_func_tbl->GetSequenceStepEnables = VL_GetSequenceStepEnables; + papi_func_tbl->SetSequenceStepTimeout = VL_SetSequenceStepTimeout; + papi_func_tbl->GetSequenceStepTimeout = VL_GetSequenceStepTimeout; + papi_func_tbl->GetNumberOfSequenceSteps = + VL_GetNumberOfSequenceSteps; + papi_func_tbl->GetSequenceStepsInfo = VL_GetSequenceStepsInfo; + papi_func_tbl->SetInterMeasurementPeriodMilliSeconds = + VL_SetInterMeasurementPeriodMilliSeconds; + papi_func_tbl->GetInterMeasurementPeriodMilliSeconds = + VL_GetInterMeasurementPeriodMilliSeconds; + papi_func_tbl->SetXTalkCompensationEnable = + VL_SetXTalkCompensationEnable; + papi_func_tbl->GetXTalkCompensationEnable = + VL_GetXTalkCompensationEnable; + papi_func_tbl->SetXTalkCompensationRateMegaCps = + VL_SetXTalkCompensationRateMegaCps; + papi_func_tbl->GetXTalkCompensationRateMegaCps = + VL_GetXTalkCompensationRateMegaCps; + papi_func_tbl->GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck; + papi_func_tbl->GetLimitCheckInfo = VL_GetLimitCheckInfo; + papi_func_tbl->SetLimitCheckEnable = VL_SetLimitCheckEnable; + papi_func_tbl->GetLimitCheckEnable = VL_GetLimitCheckEnable; + papi_func_tbl->SetLimitCheckValue = VL_SetLimitCheckValue; + papi_func_tbl->GetLimitCheckValue = VL_GetLimitCheckValue; + papi_func_tbl->GetLimitCheckCurrent = VL_GetLimitCheckCurrent; + papi_func_tbl->SetWrapAroundCheckEnable = + VL_SetWrapAroundCheckEnable; + papi_func_tbl->GetWrapAroundCheckEnable = + VL_GetWrapAroundCheckEnable; + papi_func_tbl->PerformSingleMeasurement = + VL_PerformSingleMeasurement; + papi_func_tbl->PerformRefCalibration = VL_PerformRefCalibration; + papi_func_tbl->SetRefCalibration = VL_SetRefCalibration; + papi_func_tbl->GetRefCalibration = VL_GetRefCalibration; + papi_func_tbl->PerformXTalkCalibration = + VL_PerformXTalkCalibration; + papi_func_tbl->PerformOffsetCalibration = + VL_PerformOffsetCalibration; + papi_func_tbl->StartMeasurement = VL_StartMeasurement; + papi_func_tbl->StopMeasurement = VL_StopMeasurement; + papi_func_tbl->GetMeasurementDataReady = + VL_GetMeasurementDataReady; + papi_func_tbl->WaitDeviceReadyForNewMeasurement = + VL_WaitDeviceReadyForNewMeasurement; + papi_func_tbl->GetRangingMeasurementData = + VL_GetRangingMeasurementData; + papi_func_tbl->GetHistogramMeasurementData = + VL_GetHistogramMeasurementData; + papi_func_tbl->PerformSingleRangingMeasurement = + VL_PerformSingleRangingMeasurement; + papi_func_tbl->PerformSingleHistogramMeasurement = + VL_PerformSingleHistogramMeasurement; + papi_func_tbl->SetNumberOfROIZones = VL_SetNumberOfROIZones; + papi_func_tbl->GetNumberOfROIZones = VL_GetNumberOfROIZones; + papi_func_tbl->GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones; + papi_func_tbl->SetGpioConfig = VL_SetGpioConfig; + papi_func_tbl->GetGpioConfig = VL_GetGpioConfig; + papi_func_tbl->SetInterruptThresholds = VL_SetInterruptThresholds; + papi_func_tbl->GetInterruptThresholds = VL_GetInterruptThresholds; + papi_func_tbl->ClearInterruptMask = VL_ClearInterruptMask; + papi_func_tbl->GetInterruptMaskStatus = VL_GetInterruptMaskStatus; + papi_func_tbl->EnableInterruptMask = VL_EnableInterruptMask; + papi_func_tbl->SetSpadAmbientDamperThreshold = + VL_SetSpadAmbientDamperThreshold; + papi_func_tbl->GetSpadAmbientDamperThreshold = + VL_GetSpadAmbientDamperThreshold; + papi_func_tbl->SetSpadAmbientDamperFactor = + VL_SetSpadAmbientDamperFactor; + papi_func_tbl->GetSpadAmbientDamperFactor = + VL_GetSpadAmbientDamperFactor; + papi_func_tbl->PerformRefSpadManagement = + VL_PerformRefSpadManagement; + papi_func_tbl->SetReferenceSpads = VL_SetReferenceSpads; + papi_func_tbl->GetReferenceSpads = VL_GetReferenceSpads; + +} + +static void stmvl53l0x_ps_read_measurement(struct vl_data *data) +{ + struct timeval tv; + struct vl_data *vl53l0x_dev = data; + int8_t Status = VL_ERROR_NONE; + unsigned int LimitCheckCurrent; + + do_gettimeofday(&tv); + + data->ps_data = data->rangeData.RangeMilliMeter; + input_report_abs(data->input_dev_ps, ABS_DISTANCE, + (int)(data->ps_data + 5) / 10); + input_report_abs(data->input_dev_ps, ABS_HAT0X, tv.tv_sec); + input_report_abs(data->input_dev_ps, ABS_HAT0Y, tv.tv_usec); + input_report_abs(data->input_dev_ps, ABS_HAT1X, + data->rangeData.RangeMilliMeter); + input_report_abs(data->input_dev_ps, ABS_HAT1Y, + data->rangeData.RangeStatus); + input_report_abs(data->input_dev_ps, ABS_HAT2X, + data->rangeData.SignalRateRtnMegaCps); + input_report_abs(data->input_dev_ps, ABS_HAT2Y, + data->rangeData.AmbientRateRtnMegaCps); + input_report_abs(data->input_dev_ps, ABS_HAT3X, + data->rangeData.MeasurementTimeUsec); + input_report_abs(data->input_dev_ps, ABS_HAT3Y, + data->rangeData.RangeDMaxMilliMeter); + Status = papi_func_tbl->GetLimitCheckCurrent(vl53l0x_dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckCurrent); + if (Status == VL_ERROR_NONE) { + input_report_abs(data->input_dev_ps, ABS_WHEEL, + LimitCheckCurrent); + } + input_report_abs(data->input_dev_ps, ABS_PRESSURE, + data->rangeData.EffectiveSpadRtnCount); + input_sync(data->input_dev_ps); + + if (data->enableDebug) + err("range:%d, RtnRateMcps:%d,err:0x%x\n", + data->rangeData.RangeMilliMeter, + data->rangeData.SignalRateRtnMegaCps, + data->rangeData.RangeStatus); + err("Dmax:%d,rtnambr:%d,time:%d,Spad:%d,SigmaLimit:%d\n", + data->rangeData.RangeDMaxMilliMeter, + data->rangeData.AmbientRateRtnMegaCps, + data->rangeData.MeasurementTimeUsec, + data->rangeData.EffectiveSpadRtnCount, + LimitCheckCurrent); + + +} + +static void stmvl53l0x_cancel_handler(struct vl_data *data) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&data->update_lock.wait_lock, flags); + /* + * If work is already scheduled then subsequent schedules will not + * change the scheduled time that's why we have to cancel it first. + */ + ret = cancel_delayed_work(&data->dwork); + if (ret == 0) + err("cancel_delayed_work return FALSE\n"); + + spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); + +} + +void stmvl53l0x_schedule_handler(struct vl_data *data) +{ + unsigned long flags; + + spin_lock_irqsave(&data->update_lock.wait_lock, flags); + /* + * If work is already scheduled then subsequent schedules will not + * change the scheduled time that's why we have to cancel it first. + */ + cancel_delayed_work(&data->dwork); + schedule_delayed_work(&data->dwork, 0); + spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); + +} + +/* Flag used to exit the thread when kthread_stop() is invoked */ +static int poll_thread_exit; +int stmvl53l0x_poll_thread(void *data) +{ + struct vl_data *vl53l0x_dev = data; + int8_t Status = VL_ERROR_NONE; + uint32_t sleep_time = 0; + uint32_t interruptStatus = 0; + + dbg("Starting Polling thread\n"); + + while (!kthread_should_stop()) { + /* Check if enable_ps_sensor is true or + exit request is made. If not block */ + wait_event(vl53l0x_dev->poll_thread_wq, + (vl53l0x_dev->enable_ps_sensor || poll_thread_exit)); + if (poll_thread_exit) { + dbg("Exiting the poll thread\n"); + break; + } + + mutex_lock(&vl53l0x_dev->work_mutex); + + sleep_time = vl53l0x_dev->delay_ms; + Status = VL_GetInterruptMaskStatus(vl53l0x_dev, + &interruptStatus); + if (Status == VL_ERROR_NONE && + interruptStatus && + interruptStatus != vl53l0x_dev->interruptStatus) { + vl53l0x_dev->interruptStatus = interruptStatus; + vl53l0x_dev->noInterruptCount = 0; + stmvl53l0x_schedule_handler(vl53l0x_dev); + + } else { + vl53l0x_dev->noInterruptCount++; + } + + /* Force Clear interrupt mask and restart if no interrupt + after twice the timingBudget */ + if ((vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms) > + (vl53l0x_dev->timingBudget * 2)) { + dbg("No interrupt after (%u) msec(TimingBudget = %u)\n", + (vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms), + vl53l0x_dev->timingBudget); + Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0); + if (vl53l0x_dev->deviceMode == + VL_DEVICEMODE_SINGLE_RANGING) { + Status = papi_func_tbl->StartMeasurement(vl53l0x_dev); + if (Status != VL_ERROR_NONE) + dbg("Status = %d\n", Status); + } + } + + mutex_unlock(&vl53l0x_dev->work_mutex); + + msleep(sleep_time); + } + + return 0; +} + +/* work handler */ +static void stmvl53l0x_work_handler(struct work_struct *work) +{ + struct vl_data *data = container_of(work, + struct vl_data, dwork.work); + + struct vl_data *vl53l0x_dev = data; + + int8_t Status = VL_ERROR_NONE; + + mutex_lock(&data->work_mutex); + /* dbg("Enter\n"); */ + + + if (vl53l0x_dev->enable_ps_sensor == 1) { +#ifdef DEBUG_TIME_LOG + stmvl53l0x_DebugTimeGet(&stop_tv); + stmvl53l0x_DebugTimeDuration(&start_tv, &stop_tv); +#endif + /* ISR has scheduled this function */ + if (vl53l0x_dev->interrupt_received == 1) { + Status = papi_func_tbl->GetInterruptMaskStatus( + vl53l0x_dev, &vl53l0x_dev->interruptStatus); + if (Status != VL_ERROR_NONE) { + dbg("%s(%d) : Status = %d\n", + __func__, __LINE__, Status); + } + vl53l0x_dev->interrupt_received = 0; + } + if (data->enableDebug) + dbg("interruptStatus:0x%x, interrupt_received:%d\n", + vl53l0x_dev->interruptStatus, + vl53l0x_dev->interrupt_received); + + if (vl53l0x_dev->interruptStatus == + vl53l0x_dev->gpio_function) { + Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev, + 0); + if (Status != VL_ERROR_NONE) { + dbg("%s(%d) : Status = %d\n", + __func__, __LINE__, Status); + } else { + Status = + papi_func_tbl->GetRangingMeasurementData( + vl53l0x_dev, &(data->rangeData)); + /* to push the measurement */ + if (Status == VL_ERROR_NONE) + stmvl53l0x_ps_read_measurement(data); + else + dbg("%s(%d) : Status = %d\n", + __func__, __LINE__, Status); + + dbg("Measured range:%d\n", + data->rangeData.RangeMilliMeter); + + if (data->enableDebug) + dbg("Measured range:%d\n", + data->rangeData.RangeMilliMeter); + + if (data->deviceMode == + VL_DEVICEMODE_SINGLE_RANGING) + Status = + papi_func_tbl->StartMeasurement( + vl53l0x_dev); + } + } +#ifdef DEBUG_TIME_LOG + stmvl53l0x_DebugTimeGet(&start_tv); +#endif + + } + + + vl53l0x_dev->interruptStatus = 0; + + mutex_unlock(&data->work_mutex); + +} + + +/* + * SysFS support + */ +static ssize_t stmvl53l0x_show_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enable_ps_sensor); +} + +static ssize_t stmvl53l0x_store_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + + unsigned int val; + + kstrtoint(buf, 10, &val); + if ((val != 0) && (val != 1)) { + err("store unvalid value=%ld\n", val); + return count; + } + mutex_lock(&data->work_mutex); + dbg("Enter, enable_ps_sensor flag:%d\n", + data->enable_ps_sensor); + dbg("enable ps senosr ( %ld)\n", val); + + if (val == 1) { + /* turn on tof sensor */ + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, NORMAL_MODE); + } else { + err("Already enabled. Skip !"); + } + } else { + /* turn off tof sensor */ + if (data->enable_ps_sensor == 1) { + data->enable_ps_sensor = 0; + /* to stop */ + stmvl53l0x_stop(data); + } + } + dbg("End\n"); + mutex_unlock(&data->work_mutex); + + return count; +} + +static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_enable_ps_sensor, + stmvl53l0x_store_enable_ps_sensor); + +static ssize_t stmvl53l0x_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enableDebug); +} + +/* for debug */ +static ssize_t stmvl53l0x_store_enable_debug(struct device *dev, + struct device_attribute *attr, const + char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int on; + + kstrtoint(buf, 10, &on); + if ((on != 0) && (on != 1)) { + err("set debug=%ld\n", on); + return count; + } + data->enableDebug = on; + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(enable_debug, 0660/*S_IWUSR | S_IRUGO*/, + stmvl53l0x_show_enable_debug, + stmvl53l0x_store_enable_debug); + +static ssize_t stmvl53l0x_show_set_delay_ms(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->delay_ms); +} + +/* for work handler scheduler time */ +static ssize_t stmvl53l0x_store_set_delay_ms(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int delay_ms; + + kstrtoint(buf, 10, &delay_ms); + if (delay_ms == 0) { + err("set delay_ms=%ld\n", delay_ms); + return count; + } + mutex_lock(&data->work_mutex); + data->delay_ms = delay_ms; + mutex_unlock(&data->work_mutex); + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_set_delay_ms, + stmvl53l0x_store_set_delay_ms); + +/* Timing Budget */ +static ssize_t stmvl53l0x_show_timing_budget(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n", data->timingBudget); +} + +static ssize_t stmvl53l0x_store_set_timing_budget(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int timingBudget; + + kstrtoint(buf, 10, &timingBudget); + if (timingBudget == 0) { + err("set timingBudget=%ld\n", timingBudget); + return count; + } + mutex_lock(&data->work_mutex); + data->timingBudget = timingBudget; + mutex_unlock(&data->work_mutex); + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_timing_budget, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_timing_budget, + stmvl53l0x_store_set_timing_budget); + + +/* Long Range */ +static ssize_t stmvl53l0x_show_long_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->useLongRange); +} + +static ssize_t stmvl53l0x_store_set_long_range(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int useLongRange; + + kstrtoint(buf, 10, &useLongRange); + if ((useLongRange != 0) && (useLongRange != 1)) { + err("set useLongRange=%ld\n", useLongRange); + return count; + } + + mutex_lock(&data->work_mutex); + data->useLongRange = useLongRange; + if (useLongRange) + data->timingBudget = 26000; + else + data->timingBudget = 200000; + + mutex_unlock(&data->work_mutex); + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_long_range, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_long_range, + stmvl53l0x_store_set_long_range); + +static ssize_t stmvl53l0x_show_meter(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + struct VL_RangingMeasurementData_t Measure; + + papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); + dbg("Measure = %d\n", Measure.RangeMilliMeter); + return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(show_meter, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_meter, + NULL); + +static ssize_t stmvl53l0x_show_xtalk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + struct VL_RangingMeasurementData_t Measure; + + dbg("Measure = %d\n", Measure.RangeMilliMeter); + return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); +} + +static ssize_t stmvl53l0x_set_xtalk(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + unsigned int targetDistance; + + kstrtoint(buf, 10, &targetDistance); + data->xtalkCalDistance = targetDistance; + stmvl53l0x_start(data, 3, XTALKCALIB_MODE); + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(xtalk_cal, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_xtalk, + stmvl53l0x_set_xtalk); + +static ssize_t stmvl53l0x_show_offset(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + struct VL_RangingMeasurementData_t Measure; + + papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); + dbg("Measure = %d\n", Measure.RangeMilliMeter); + return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); +} + +static ssize_t stmvl53l0x_set_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + unsigned int targetDistance; + + kstrtoint(buf, 10, &targetDistance); + data->offsetCalDistance = targetDistance; + stmvl53l0x_start(data, 3, OFFSETCALIB_MODE); + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(offset_cal, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_offset, + stmvl53l0x_set_offset); + +static struct attribute *stmvl53l0x_attributes[] = { + &dev_attr_enable_ps_sensor.attr, + &dev_attr_enable_debug.attr, + &dev_attr_set_delay_ms.attr , + &dev_attr_set_timing_budget.attr , + &dev_attr_set_long_range.attr , + &dev_attr_show_meter.attr , + &dev_attr_xtalk_cal.attr , + &dev_attr_offset_cal.attr , + NULL +}; + + +static const struct attribute_group stmvl53l0x_attr_group = { + .attrs = stmvl53l0x_attributes, +}; + +/* + * misc device file operation functions + */ +static int stmvl53l0x_ioctl_handler(struct file *file, + unsigned int cmd, unsigned long arg, + void __user *p) +{ + int rc = 0; + unsigned int xtalkint = 0; + unsigned int targetDistance = 0; + int8_t offsetint = 0; + struct vl_data *data = + container_of(file->private_data, + struct vl_data, miscdev); + struct stmvl53l0x_register reg; + struct stmvl53l0x_parameter parameter; + struct vl_data *vl53l0x_dev = data; + uint8_t deviceMode; + uint8_t page_num = 0; + + if (!data) + return -EINVAL; + + dbg("Enter enable_ps_sensor:%d\n", data->enable_ps_sensor); + switch (cmd) { + /* enable */ + case VL_IOCTL_INIT: + dbg("VL_IOCTL_INIT\n"); + /* turn on tof sensor only if it's not enabled by other + client */ + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, NORMAL_MODE); + } else + rc = -EINVAL; + break; + /* crosstalk calibration */ + case VL_IOCTL_XTALKCALB: + dbg("VL_IOCTL_XTALKCALB\n"); + data->xtalkCalDistance = 100; + if (copy_from_user(&targetDistance, (unsigned int *)p, + sizeof(unsigned int))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + data->xtalkCalDistance = targetDistance; + + /* turn on tof sensor only if it's not enabled by other + client */ + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, XTALKCALIB_MODE); + } else + rc = -EINVAL; + break; + /* set up Xtalk value */ + case VL_IOCTL_SETXTALK: + dbg("VL_IOCTL_SETXTALK\n"); + if (copy_from_user(&xtalkint, (unsigned int *)p, + sizeof(unsigned int))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + dbg("SETXTALK as 0x%x\n", xtalkint); +/* later + * SetXTalkCompensationRate(vl53l0x_dev, xtalkint); + */ + break; + /* offset calibration */ + case VL_IOCTL_OFFCALB: + dbg("VL_IOCTL_OFFCALB\n"); + data->offsetCalDistance = 50; + if (copy_from_user(&targetDistance, (unsigned int *)p, + sizeof(unsigned int))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + data->offsetCalDistance = targetDistance; + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, OFFSETCALIB_MODE); + } else + rc = -EINVAL; + break; + /* set up offset value */ + case VL_IOCTL_SETOFFSET: + dbg("VL_IOCTL_SETOFFSET\n"); + if (copy_from_user(&offsetint, (int8_t *)p, sizeof(int8_t))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + dbg("SETOFFSET as %d\n", offsetint); +/* later + SetOffsetCalibrationData(vl53l0x_dev, offsetint); +*/ + break; + /* disable */ + case VL_IOCTL_STOP: + dbg("VL_IOCTL_STOP\n"); + /* turn off tof sensor only if it's enabled by other client */ + if (data->enable_ps_sensor == 1) { + data->enable_ps_sensor = 0; + /* to stop */ + stmvl53l0x_stop(data); + } + break; + /* Get all range data */ + case VL_IOCTL_GETDATAS: + dbg("VL_IOCTL_GETDATAS\n"); + if (copy_to_user((struct VL_RangingMeasurementData_t *)p, + &(data->rangeData), + sizeof(struct VL_RangingMeasurementData_t))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + break; + /* Register tool */ + case VL_IOCTL_REGISTER: + dbg("VL_IOCTL_REGISTER\n"); + if (copy_from_user(®, (struct stmvl53l0x_register *)p, + sizeof(struct stmvl53l0x_register))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + reg.status = 0; + page_num = (uint8_t)((reg.reg_index & 0x0000ff00) >> 8); + dbg( +"VL_IOCTL_REGISTER, page number:%d\n", page_num); + if (page_num != 0) + reg.status = VL_WrByte(vl53l0x_dev, + 0xFF, page_num); + + switch (reg.reg_bytes) { + case(4): + if (reg.is_read) + reg.status = VL_RdDWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + ®.reg_data); + else + reg.status = VL_WrDWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + reg.reg_data); + break; + case(2): + if (reg.is_read) + reg.status = VL_RdWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint16_t *)®.reg_data); + else + reg.status = VL_WrWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint16_t)reg.reg_data); + break; + case(1): + if (reg.is_read) + reg.status = VL_RdByte(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint8_t *)®.reg_data); + else + reg.status = VL_WrByte(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint8_t)reg.reg_data); + break; + default: + reg.status = -1; + + } + if (page_num != 0) + reg.status = VL_WrByte(vl53l0x_dev, 0xFF, 0); + + + if (copy_to_user((struct stmvl53l0x_register *)p, ®, + sizeof(struct stmvl53l0x_register))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + break; + /* parameter access */ + case VL_IOCTL_PARAMETER: + dbg("VL_IOCTL_PARAMETER\n"); + if (copy_from_user(¶meter, (struct stmvl53l0x_parameter *)p, + sizeof(struct stmvl53l0x_parameter))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + parameter.status = 0; + if (data->enableDebug) + dbg("VL_IOCTL_PARAMETER Name = %d\n", + parameter.name); + switch (parameter.name) { + case (OFFSET_PAR): + if (parameter.is_read) + parameter.status = + papi_func_tbl->GetOffsetCalibrationDataMicroMeter( + vl53l0x_dev, ¶meter.value); + else + parameter.status = + papi_func_tbl->SetOffsetCalibrationDataMicroMeter( + vl53l0x_dev, parameter.value); + dbg("get parameter value as %d\n", + parameter.value); + break; + + case (REFERENCESPADS_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetReferenceSpads(vl53l0x_dev, + (uint32_t *)&(parameter.value), + (uint8_t *)&(parameter.value2)); + if (data->enableDebug) + dbg("Get RefSpad: Count:%u, Type:%u\n", + parameter.value, (uint8_t)parameter.value2); + } else { + if (data->enableDebug) + dbg("Set RefSpad: Count:%u, Type:%u\n", + parameter.value, (uint8_t)parameter.value2); + + parameter.status = + papi_func_tbl->SetReferenceSpads( + vl53l0x_dev, + (uint32_t)(parameter.value), + (uint8_t)(parameter.value2)); + } + break; + + case (REFCALIBRATION_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetRefCalibration(vl53l0x_dev, + (uint8_t *)&(parameter.value), + (uint8_t *)&(parameter.value2)); + if (data->enableDebug) + dbg("Get Ref: Vhv:%u, PhaseCal:%u\n", + (uint8_t)parameter.value, + (uint8_t)parameter.value2); + } else { + if (data->enableDebug) + dbg("Set Ref: Vhv:%u, PhaseCal:%u\n", + (uint8_t)parameter.value, + (uint8_t)parameter.value2); + parameter.status = + papi_func_tbl->SetRefCalibration( + vl53l0x_dev, (uint8_t)(parameter.value), + (uint8_t)(parameter.value2)); + } + break; + case (XTALKRATE_PAR): + if (parameter.is_read) + parameter.status = + papi_func_tbl->GetXTalkCompensationRateMegaCps( + vl53l0x_dev, (unsigned int *) + ¶meter.value); + else + parameter.status = + papi_func_tbl->SetXTalkCompensationRateMegaCps( + vl53l0x_dev, + (unsigned int) + parameter.value); + + break; + case (XTALKENABLE_PAR): + if (parameter.is_read) + parameter.status = + papi_func_tbl->GetXTalkCompensationEnable( + vl53l0x_dev, + (uint8_t *) ¶meter.value); + else + parameter.status = + papi_func_tbl->SetXTalkCompensationEnable( + vl53l0x_dev, + (uint8_t) parameter.value); + break; + case (GPIOFUNC_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetGpioConfig(vl53l0x_dev, 0, + &deviceMode, + &data->gpio_function, + &data->gpio_polarity); + parameter.value = data->gpio_function; + } else { + data->gpio_function = parameter.value; + parameter.status = + papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0, + data->gpio_function, + data->gpio_polarity); + } + break; + case (LOWTHRESH_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetInterruptThresholds( + vl53l0x_dev, 0, &(data->low_threshold), + &(data->high_threshold)); + parameter.value = data->low_threshold >> 16; + } else { + data->low_threshold = parameter.value << 16; + parameter.status = + papi_func_tbl->SetInterruptThresholds( + vl53l0x_dev, 0, data->low_threshold, + data->high_threshold); + } + break; + case (HIGHTHRESH_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetInterruptThresholds( + vl53l0x_dev, 0, &(data->low_threshold), + &(data->high_threshold)); + parameter.value = data->high_threshold >> 16; + } else { + data->high_threshold = parameter.value << 16; + parameter.status = + papi_func_tbl->SetInterruptThresholds( + vl53l0x_dev, 0, data->low_threshold, + data->high_threshold); + } + break; + case (DEVICEMODE_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetDeviceMode( + vl53l0x_dev, + (uint8_t *)& + (parameter.value)); + } else { + parameter.status = + papi_func_tbl->SetDeviceMode( + vl53l0x_dev, + (uint8_t)(parameter.value)); + data->deviceMode = + (uint8_t)(parameter.value); + } + break; + + + + case (INTERMEASUREMENT_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetInterMeasurementPeriodMilliSeconds( + vl53l0x_dev, (uint32_t *)&(parameter.value)); + } else { + parameter.status = + papi_func_tbl->SetInterMeasurementPeriodMilliSeconds( + vl53l0x_dev, (uint32_t)(parameter.value)); + data->interMeasurems = parameter.value; + } + break; + + } + + if (copy_to_user((struct stmvl53l0x_parameter *)p, ¶meter, + sizeof(struct stmvl53l0x_parameter))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int stmvl53l0x_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int stmvl53l0x_flush(struct file *file, fl_owner_t id) +{ + struct vl_data *data = container_of(file->private_data, + struct vl_data, miscdev); + (void) file; + (void) id; + + if (data) { + if (data->enable_ps_sensor == 1) { + /* turn off tof sensor if it's enabled */ + data->enable_ps_sensor = 0; + /* to stop */ + stmvl53l0x_stop(data); + } + } + return 0; +} + +static long stmvl53l0x_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + struct vl_data *data = + container_of(file->private_data, + struct vl_data, miscdev); + mutex_lock(&data->work_mutex); + ret = stmvl53l0x_ioctl_handler(file, cmd, arg, (void __user *)arg); + mutex_unlock(&data->work_mutex); + + return ret; +} + +/* + * Initialization function + */ +static int stmvl53l0x_init_client(struct vl_data *data) +{ + + int8_t Status = VL_ERROR_NONE; + struct VL_DeviceInfo_t DeviceInfo; + struct vl_data *vl53l0x_dev = data; + + uint32_t refSpadCount; + uint8_t isApertureSpads; + uint8_t VhvSettings; + uint8_t PhaseCal; + + dbg("Enter\n"); + + vl53l0x_dev->I2cDevAddr = 0x52; + vl53l0x_dev->comms_type = 1; + vl53l0x_dev->comms_speed_khz = 400; + + /* Setup API functions based on revision */ + stmvl53l0x_setupAPIFunctions(); + + if (Status == VL_ERROR_NONE && data->reset) { + dbg("Call of VL_DataInit\n"); + /* Data initialization */ + Status = papi_func_tbl->DataInit(vl53l0x_dev); + } + + if (Status == VL_ERROR_NONE) { + dbg("VL_GetDeviceInfo:\n"); + Status = papi_func_tbl->GetDeviceInfo(vl53l0x_dev, &DeviceInfo); + if (Status == VL_ERROR_NONE) { + dbg("Device Name : %s\n", DeviceInfo.Name); + dbg("Device Type : %s\n", DeviceInfo.Type); + dbg("Device ID : %s\n", DeviceInfo.ProductId); + dbg("Product type: %d\n", DeviceInfo.ProductType); + dbg("ProductRevisionMajor : %d\n", + DeviceInfo.ProductRevisionMajor); + dbg("ProductRevisionMinor : %d\n", + DeviceInfo.ProductRevisionMinor); + } + } + + if (Status == VL_ERROR_NONE) { + dbg("Call of VL_StaticInit\n"); + Status = papi_func_tbl->StaticInit(vl53l0x_dev); + /* Device Initialization */ + } + + if (Status == VL_ERROR_NONE && data->reset) { + if (papi_func_tbl->PerformRefCalibration != NULL) { + dbg("Call of VL_PerformRefCalibration\n"); + Status = papi_func_tbl->PerformRefCalibration( + vl53l0x_dev, &VhvSettings, &PhaseCal); + /* Ref calibration */ + } + } + + if (Status == VL_ERROR_NONE && data->reset) { + if (papi_func_tbl->PerformRefSpadManagement != NULL) { + dbg("Call of VL_PerformRefSpadManagement\n"); + Status = papi_func_tbl->PerformRefSpadManagement( + vl53l0x_dev, &refSpadCount, &isApertureSpads); + /* Ref Spad Management */ + } + data->reset = 0; + /* needed, even the function is NULL */ + } + + if (Status == VL_ERROR_NONE) { + + dbg("Call of VL_SetDeviceMode\n"); + Status = papi_func_tbl->SetDeviceMode(vl53l0x_dev, + VL_DEVICEMODE_SINGLE_RANGING); + /* Setup in single ranging mode */ + } + if (Status == VL_ERROR_NONE) + Status = papi_func_tbl->SetWrapAroundCheckEnable( + vl53l0x_dev, 1); + + dbg("End\n"); + + return 0; +} + +static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling, + enum init_mode_e mode) +{ + int rc = 0; + struct vl_data *vl53l0x_dev = data; + int8_t Status = VL_ERROR_NONE; + + dbg("Enter\n"); + + /* Power up */ + rc = pmodule_func_tbl->power_up(data->client_object, &data->reset); + if (rc) { + err("%d,error rc %d\n", __LINE__, rc); + return rc; + } + /* init */ + rc = stmvl53l0x_init_client(data); + if (rc) { + err("%d, error rc %d\n", __LINE__, rc); + pmodule_func_tbl->power_down(data->client_object); + return -EINVAL; + } + + /* check mode */ + if (mode != NORMAL_MODE) + papi_func_tbl->SetXTalkCompensationEnable(vl53l0x_dev, 1); + + if (mode == OFFSETCALIB_MODE) { + /*VL_SetOffsetCalibrationDataMicroMeter(vl53l0x_dev, 0);*/ + unsigned int OffsetMicroMeter; + + papi_func_tbl->PerformOffsetCalibration(vl53l0x_dev, + (data->offsetCalDistance<<16), + &OffsetMicroMeter); + dbg("Offset calibration:%u\n", OffsetMicroMeter); + return rc; + } else if (mode == XTALKCALIB_MODE) { + unsigned int XTalkCompensationRateMegaCps; + /*caltarget distance : 100mm and convert to + * fixed point 16 16 format + */ + papi_func_tbl->PerformXTalkCalibration(vl53l0x_dev, + (data->xtalkCalDistance<<16), + &XTalkCompensationRateMegaCps); + dbg("Xtalk calibration:%u\n", XTalkCompensationRateMegaCps); + return rc; + } + /* set up device parameters */ + data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW; + + /* Following two calls are made from IOCTL as well */ + papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0, + data->gpio_function, + VL_INTERRUPTPOLARITY_LOW); + + papi_func_tbl->SetInterruptThresholds(vl53l0x_dev, 0, + data->low_threshold, data->high_threshold); + + if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING) { + papi_func_tbl->SetInterMeasurementPeriodMilliSeconds( + vl53l0x_dev, data->interMeasurems); + } + + dbg("DeviceMode:0x%x, interMeasurems:%d==\n", data->deviceMode, + data->interMeasurems); + papi_func_tbl->SetDeviceMode(vl53l0x_dev, + data->deviceMode); + papi_func_tbl->ClearInterruptMask(vl53l0x_dev, + 0); + + if (vl53l0x_dev->useLongRange) { + dbg("Configure Long Ranging\n"); + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (unsigned int)(65536/10)); /* 0.1 * 65536 */ + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + (unsigned int)(60*65536)); + } else { + dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + dbg("Set Timing Budget = %u\n", + vl53l0x_dev->timingBudget); + Status = + papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds( + vl53l0x_dev, vl53l0x_dev->timingBudget); + } else { + dbg("SetLimitCheckValue failed err =%d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_PRE_RANGE, 18); + } else { + dbg("SetMeasurementTimingBudget failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_FINAL_RANGE, 14); + } else { + dbg("SetVcselPulsePeriod(PRE, 18) failed err = %d\n", + Status); + } + + if (Status != VL_ERROR_NONE) { + dbg("SetVcselPulsePeriod(FINAL, 14) failed err = %d\n", + Status); + } + } else { + dbg("Configure High Accuracy\n"); + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (unsigned int)(25 * 65536 / 100)); /* 0.25 * 65536 */ + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + (unsigned int)(18*65536)); + } else { + dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + dbg("Set Timing Budget = %u\n", + vl53l0x_dev->timingBudget); + Status = + papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds( + vl53l0x_dev, vl53l0x_dev->timingBudget); + } else { + dbg("SetLimitCheckValue failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_PRE_RANGE, 14); + } else { + dbg("SetMeasurementTimingBudget failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_FINAL_RANGE, 10); + } else { + dbg("SetVcselPulsePeriod failed err = %d\n", + Status); + } + + if (Status != VL_ERROR_NONE) { + dbg("SetVcselPulsePeriod failed err = %d\n", + Status); + } + + } + + /* start the ranging */ + papi_func_tbl->StartMeasurement(vl53l0x_dev); + data->enable_ps_sensor = 1; + + + dbg("End\n"); + + return rc; +} + +static int stmvl53l0x_stop(struct vl_data *data) +{ + int rc = 0; + struct vl_data *vl53l0x_dev = data; + + dbg("Enter\n"); + + /* stop - if continuous mode */ + if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_RANGING || + data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING) + papi_func_tbl->StopMeasurement(vl53l0x_dev); + + /* clean interrupt */ + papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0); + + /* cancel work handler */ + stmvl53l0x_cancel_handler(data); + /* power down */ + rc = pmodule_func_tbl->power_down(data->client_object); + if (rc) { + err("%d, error rc %d\n", __LINE__, rc); + return rc; + } + dbg("End\n"); + + return rc; +} + +/* + * I2C init/probing/exit functions + */ +static const struct file_operations stmvl53l0x_ranging_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = stmvl53l0x_ioctl, + .open = stmvl53l0x_open, + .flush = stmvl53l0x_flush, +}; + +int stmvl53l0x_setup(struct vl_data *data) +{ + int rc = 0; + + dbg("Enter\n"); + + /* init mutex */ + mutex_init(&data->update_lock); + mutex_init(&data->work_mutex); + + init_waitqueue_head(&data->poll_thread_wq); + + data->poll_thread = kthread_run(&stmvl53l0x_poll_thread, + (void *)data, "STM-VL53L0"); + if (data->poll_thread == NULL) { + dbg("%s(%d) - Failed to create Polling thread\n", + __func__, __LINE__); + goto exit_free_irq; + } + + /* init work handler */ + INIT_DELAYED_WORK(&data->dwork, stmvl53l0x_work_handler); + + /* Register to Input Device */ + data->input_dev_ps = input_allocate_device(); + if (!data->input_dev_ps) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + + goto exit_free_irq; + } + set_bit(EV_ABS, data->input_dev_ps->evbit); + /* range in cm*/ + input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 76, 0, 0); + /* tv_sec */ + input_set_abs_params(data->input_dev_ps, ABS_HAT0X, 0, 0xffffffff, + 0, 0); + /* tv_usec */ + input_set_abs_params(data->input_dev_ps, ABS_HAT0Y, 0, 0xffffffff, + 0, 0); + /* range in_mm */ + input_set_abs_params(data->input_dev_ps, ABS_HAT1X, 0, 765, 0, 0); + /* error code change maximum to 0xff for more flexibility */ + input_set_abs_params(data->input_dev_ps, ABS_HAT1Y, 0, 0xff, 0, 0); + /* rtnRate */ + input_set_abs_params(data->input_dev_ps, ABS_HAT2X, 0, 0xffffffff, + 0, 0); + /* rtn_amb_rate */ + input_set_abs_params(data->input_dev_ps, ABS_HAT2Y, 0, 0xffffffff, + 0, 0); + /* rtn_conv_time */ + input_set_abs_params(data->input_dev_ps, ABS_HAT3X, 0, 0xffffffff, + 0, 0); + /* dmax */ + input_set_abs_params(data->input_dev_ps, ABS_HAT3Y, 0, 0xffffffff, + 0, 0); + + input_set_abs_params(data->input_dev_ps, ABS_PRESSURE, 0, 0xffffffff, + 0, 0); + + input_set_abs_params(data->input_dev_ps, ABS_WHEEL , 0, 0xffffffff, + 0, 0); + + data->input_dev_ps->name = "STM VL53L0 proximity sensor"; + + rc = input_register_device(data->input_dev_ps); + if (rc) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + goto exit_free_dev_ps; + } + /* setup drv data */ + input_set_drvdata(data->input_dev_ps, data); + + /* Register sysfs hooks */ + data->range_kobj = kobject_create_and_add("range", kernel_kobj); + if (!data->range_kobj) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_group(&data->input_dev_ps->dev.kobj, + &stmvl53l0x_attr_group); + if (rc) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps_1; + } + /* init default device parameter value */ + data->enable_ps_sensor = 0; + data->reset = 1; + data->delay_ms = 30; /* delay time to 30ms */ + data->enableDebug = 0; + data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW; + data->gpio_function = VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY; + data->low_threshold = 60; + data->high_threshold = 200; + data->deviceMode = VL_DEVICEMODE_SINGLE_RANGING; + data->interMeasurems = 30; + data->timingBudget = 26000; + data->useLongRange = 1; + + dbg("support ver. %s enabled\n", DRIVER_VERSION); + dbg("End"); + + return 0; +exit_unregister_dev_ps_1: + kobject_put(data->range_kobj); +exit_unregister_dev_ps: + input_unregister_device(data->input_dev_ps); +exit_free_dev_ps: + input_free_device(data->input_dev_ps); +exit_free_irq: + kfree(data); + return rc; +} + +static int __init stmvl53l0x_init(void) +{ + int ret = -1; + + dbg("Enter\n"); + + /* assign function table */ + pmodule_func_tbl = &stmvl53l0x_module_func_tbl; + papi_func_tbl = &stmvl53l0x_api_func_tbl; + + /* client specific init function */ + ret = pmodule_func_tbl->init(); + + if (ret) + err("%d failed with %d\n", __LINE__, ret); + + dbg("End\n"); + + return ret; +} + +static void __exit stmvl53l0x_exit(void) +{ + dbg("Enter\n"); + + dbg("End\n"); +} + +MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(stmvl53l0x_init); +module_exit(stmvl53l0x_exit); diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 47a1a20f1b1693f905980bf33207db088bbe8da9..b46103878b6d0e9448d1a8391872a4247dcb979a 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1558,7 +1558,7 @@ static int elantech_set_properties(struct elantech_data *etd) case 5: etd->hw_version = 3; break; - case 6 ... 14: + case 6 ... 15: etd->hw_version = 4; break; default: diff --git a/drivers/input/sensors/smi130/Kconfig b/drivers/input/sensors/smi130/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3dd86c3201f031ef2f2bea4ce48dfefcabdb28b8 --- /dev/null +++ b/drivers/input/sensors/smi130/Kconfig @@ -0,0 +1,125 @@ +# +# Makefile for Bosch sensors driver. +# +config BOSCH_DRIVER_LOG_FUNC + tristate "Bosch Sensortec driver smart log function support" + depends on (I2C || SPI_MASTER) && SYSFS + help + If you say yes here, you get support for smart log function in Bosch Sensortec driver. + +config SENSORS_SMI_ACC2X2 + tristate "SMI130_ACC acceleration sensor support" + depends on I2C + help + If you say yes here, you get support for Bosch Sensortec's + acceleration sensors SMI_ACC255/SMI_ACC254/SMI_ACC355/SMI_ACC250E/SMI_ACC222E/SMI_ACC280. + +config SENSORS_SMI_ACC2X2_ENABLE_INT1 + tristate "SMI_ACC2X2 acceleration sensor interrupt INT1 support" + depends on SENSORS_SMI_ACC2X2 + help + If you say yes here, you get INT1 support for Bosch Sensortec + acceleration sensors SMI_ACC255/SMI_ACC250E/SMI_ACC222E/SMI_ACC280. + Select it will disable interrupt INT2 support + +config SENSORS_SMI_ACC2X2_ENABLE_INT2 + tristate "SMI_ACC2X2 acceleration sensor interrupt INT2 support" + depends on SENSORS_SMI_ACC2X2 && !SENSORS_SMI_ACC2X2_ENABLE_INT1 + help + If you say yes here, you get INT2 support for Bosch Sensortec + acceleration sensors SMI_ACC255/SMI_ACC250E/SMI_ACC222E/SMI_ACC280. + Can only open if you do NOT open interrupt INT1 support + +config SIG_MOTION + tristate "support significant motion sensor function" + depends on SENSORS_SMI_ACC2X2 && ( SENSORS_SMI_ACC2X2_ENABLE_INT1 || SENSORS_SMI_ACC2X2_ENABLE_INT2) + help + If you say yes here, if you want to support Bosch significant motion sensor function + +config DOUBLE_TAP + tristate "support double tap sensor function" + depends on SENSORS_SMI_ACC2X2 && ( SENSORS_SMI_ACC2X2_ENABLE_INT1 || SENSORS_SMI_ACC2X2_ENABLE_INT2) + help + If you say yes here, you get support Bosch double tap sensor function + +config SENSORS_SMI_GYRO + tristate "Bosch Gyroscope Sensor Driver" + depends on I2C + help + If you say yes here, you get support for Bosch Sensortec's + gyroscope sensor drivers of SMI130_GYRO/SMI055/BMI058 e.t.c. + +config SENSORS_SMI_GYRO_FIFO + tristate "Bosch Gyroscope FIFO Support" + depends on SENSORS_SMI_GYRO + help + If you say yes here, you get support for Gyroscope sensor FIFO operations. + Please check whether the chip supports fifo feature to open it. + +config SENSORS_BMI058 + tristate "BMI058 Sensor Support" + depends on (SENSORS_SMI_GYRO || SENSORS_SMI_ACC2X2) + help + If you say yes here, you get support for Bosch Sensortec's + sensor driver of BMI058. + +config SENSORS_YAS537 + tristate "YAS537 Magnetic Sensor Driver" + depends on I2C + help + If you say yes here, you get support for YAMAHA + sensor YAS537 Magnetic Sensor + +config SENSORS_BMM050 + tristate "BMM050 Magnetic Sensor Driver" + depends on I2C + help + If you say yes here, you get support for Bosch Sensortec's + sensor BMM050 Magnetic Sensor + +config SENSORS_AKM09911 + tristate "AKM09911 Mag Sensor Driver" + depends on I2C + help + If you say yes here, you get support AKM09911 Sensor support. + +config SENSORS_AKM09912 + tristate "AKM09912 Mag Sensor Driver" + depends on I2C + help + If you say yes here, you get support AKM09912 Sensor support. + +config SENSORS_SMI_ACC420 + tristate "SMI_ACC4XY Sensor Support" + depends on I2C || SPI_MASTER + help + If you say yes here, you get support for Bosch Sensortec's sensor driver of SMI_ACC420. +config SENSORS_SMI_ACC421 + tristate "SMI_ACC4XY Sensor Support" + depends on I2C || SPI_MASTER + help + If you say yes here, you get support for Bosch Sensortec's sensor driver of SMI_ACC421. +config SENSORS_SMI_ACC422 + tristate "SMI_ACC4XY Sensor Support" + depends on I2C || SPI_MASTER + help + If you say yes here, you get support for Bosch Sensortec's sensor driver of SMI_ACC422. +config SENSORS_SMI_ACC455 + tristate "SMI_ACC4XY Sensor Support" + depends on I2C || SPI_MASTER + help + If you say yes here, you get support for Bosch Sensortec's sensor driver of SMI_ACC455. + +config SMI_ACC4XY_MAG_INTERFACE_SUPPORT +tristate "SMI_ACC4XY Sensor mag interface support" +depends on SENSORS_SMI_ACC4XY + help + If you say yes here, you get support for Bosch Sensortec's + sensor driver of SMI_ACC4XY with mag sensor support. + +config ENABLE_SMI_ACC_GYRO_BUFFERING + bool "Enable accel & gyro boot time sensor sample buffering" + depends on IIO_ST_ASM330LHH + help + Say Y here if you want to buffer boot time sensor + samples for ASM330 accelerometer and gyroscope diff --git a/drivers/input/sensors/smi130/Makefile b/drivers/input/sensors/smi130/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ad1e5437d652d6ae9e700ed2a49771b53ab8c164 --- /dev/null +++ b/drivers/input/sensors/smi130/Makefile @@ -0,0 +1,47 @@ +# +# Makefile for Bosch sensor driver. +# + +obj-$(CONFIG_BOSCH_DRIVER_LOG_FUNC) += bs_log.o +obj-y += boschclass.o +ifeq ($(CONFIG_BOSCH_DRIVER_LOG_FUNC),y) + EXTRA_CFLAGS += -DBOSCH_DRIVER_LOG_FUNC +endif + +obj-y += smi130_acc.o + +ifeq ($(CONFIG_SENSORS_SMI_ACC2X2_ENABLE_INT1),y) + EXTRA_CFLAGS += -DSMI_ACC2X2_ENABLE_INT1 +endif + +ifeq ($(CONFIG_BOSCH_SMI_ACC2X2_ENABLE_INT2),y) + EXTRA_CFLAGS += -DSMI_ACC2X2_ENABLE_INT2 +endif + +obj-y += smi130_gyro_driver.o smi130_gyro.o +EXTRA_CFLAGS += -DSMI_GYRO_USE_BASIC_I2C_FUNC + +obj-y += smi130_driver.o smi130.o +ifeq ($(CONFIG_SMI130_MAG_INTERFACE_SUPPORT),y) + EXTRA_CFLAGS += -DSMI130_MAG_INTERFACE_SUPPORT +endif +ifeq ($(CONFIG_SENSORS_SMI130_ENABLE_INT1),y) + EXTRA_CFLAGS += -DSMI130_ENABLE_INT1 +endif + +ifeq ($(CONFIG_SENSORS_SMI130_ENABLE_INT2),y) + EXTRA_CFLAGS += -DSMI130_ENABLE_INT2 +endif + +obj-y += smi130_i2c.o + +EXTRA_CFLAGS += -DSMI_USE_BASIC_I2C_FUNC + +obj-$(CONFIG_SENSORS_SMI130_SPI) += smi130_spi.o + + + + + + + diff --git a/drivers/input/sensors/smi130/boschclass.c b/drivers/input/sensors/smi130/boschclass.c new file mode 100644 index 0000000000000000000000000000000000000000..8c28ab158da4767ed0308b35730a35695f703555 --- /dev/null +++ b/drivers/input/sensors/smi130/boschclass.c @@ -0,0 +1,341 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename boschclass.c + * @date 2015/11/17 13:44 + * @Modification Date 2018/08/28 18:20 + * @id "836294d" + * @version 1.5.9 + * + * @brief + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "boschclass.h" +#include "bs_log.h" + +static LIST_HEAD(bosch_dev_list); + +/* + * bosch_mutex protects access to both bosch_dev_list and input_handler_list. + * This also causes bosch_[un]register_device and bosch_[un]register_handler + * be mutually exclusive which simplifies locking in drivers implementing + * input handlers. + */ +static DEFINE_MUTEX(bosch_mutex); + + +static void bosch_dev_release(struct device *device) +{ + struct bosch_dev *dev = to_bosch_dev(device); + if (NULL != dev) + kfree(dev); + module_put(THIS_MODULE); +} + + +#ifdef CONFIG_PM +static int bosch_dev_suspend(struct device *dev) +{ + return 0; +} + +static int bosch_dev_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops bosch_dev_pm_ops = { + .suspend = bosch_dev_suspend, + .resume = bosch_dev_resume, + .poweroff = bosch_dev_suspend, + .restore = bosch_dev_resume, +}; +#endif /* CONFIG_PM */ + +static const struct attribute_group *bosch_dev_attr_groups[] = { + NULL +}; + +static struct device_type bosch_dev_type = { + .groups = bosch_dev_attr_groups, + .release = bosch_dev_release, +#ifdef CONFIG_PM + .pm = &bosch_dev_pm_ops, +#endif +}; + + + +static char *bosch_devnode(struct device *dev, mode_t *mode) +{ + return kasprintf(GFP_KERNEL, "%s", dev_name(dev)); +} + +struct class bosch_class = { + .name = "bosch", + .owner = THIS_MODULE, + .devnode = (void*)bosch_devnode, + .dev_release = bosch_dev_release, +}; +EXPORT_SYMBOL_GPL(bosch_class); + +/** + * bosch_allocate_device - allocate memory for new input device + * + * Returns prepared struct bosch_dev or NULL. + * + * NOTE: Use bosch_free_device() to free devices that have not been + * registered; bosch_unregister_device() should be used for already + * registered devices. + */ +struct bosch_dev *bosch_allocate_device(void) +{ + struct bosch_dev *dev; + + dev = kzalloc(sizeof(struct bosch_dev), GFP_KERNEL); + if (dev) { + dev->dev.type = &bosch_dev_type; + dev->dev.class = &bosch_class; + device_initialize(&dev->dev); + mutex_init(&dev->mutex); + INIT_LIST_HEAD(&dev->node); + __module_get(THIS_MODULE); + } + return dev; +} +EXPORT_SYMBOL(bosch_allocate_device); + + + +/** + * bosch_free_device - free memory occupied by bosch_dev structure + * @dev: input device to free + * + * This function should only be used if bosch_register_device() + * was not called yet or if it failed. Once device was registered + * use bosch_unregister_device() and memory will be freed once last + * reference to the device is dropped. + * + * Device should be allocated by bosch_allocate_device(). + * + * NOTE: If there are references to the input device then memory + * will not be freed until last reference is dropped. + */ +void bosch_free_device(struct bosch_dev *dev) +{ + if (dev) + bosch_put_device(dev); +} +EXPORT_SYMBOL(bosch_free_device); + +/** + * bosch_register_device - register device with input core + * @dev: device to be registered + * + * This function registers device with input core. The device must be + * allocated with bosch_allocate_device() and all it's capabilities + * set up before registering. + * If function fails the device must be freed with bosch_free_device(). + * Once device has been successfully registered it can be unregistered + * with bosch_unregister_device(); bosch_free_device() should not be + * called in this case. + */ +int bosch_register_device(struct bosch_dev *dev) +{ + const char *path; + int error; + + + /* + * If delay and period are pre-set by the driver, then autorepeating + * is handled by the driver itself and we don't do it in input.c. + */ + dev_set_name(&dev->dev, dev->name); + + error = device_add(&dev->dev); + if (error) + return error; + + path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); + PINFO("%s as %s\n", + dev->name ? dev->name : "Unspecified device", + path ? path : "N/A"); + kfree(path); + error = mutex_lock_interruptible(&bosch_mutex); + if (error) { + device_del(&dev->dev); + return error; + } + + list_add_tail(&dev->node, &bosch_dev_list); + + mutex_unlock(&bosch_mutex); + return 0; +} +EXPORT_SYMBOL(bosch_register_device); + +/** + * bosch_unregister_device - unregister previously registered device + * @dev: device to be unregistered + * + * This function unregisters an input device. Once device is unregistered + * the caller should not try to access it as it may get freed at any moment. + */ +void bosch_unregister_device(struct bosch_dev *dev) +{ + int ret = 0; + ret = mutex_lock_interruptible(&bosch_mutex); + if(ret){ + return; + } + + list_del_init(&dev->node); + mutex_unlock(&bosch_mutex); + device_unregister(&dev->dev); +} +EXPORT_SYMBOL(bosch_unregister_device); + +static int __init bosch_init(void) +{ + int err; + /*bosch class register*/ + err = class_register(&bosch_class); + if (err) { + pr_err("unable to register bosch_dev class\n"); + return err; + } + return err; +} + +static void __exit bosch_exit(void) +{ + /*bosch class*/ + class_unregister(&bosch_class); +} + +/*subsys_initcall(bosch_init);*/ + +MODULE_AUTHOR("contact@bosch-sensortec.com"); +MODULE_DESCRIPTION("BST CLASS CORE"); +MODULE_LICENSE("GPL V2"); + +module_init(bosch_init); +module_exit(bosch_exit); diff --git a/drivers/input/sensors/smi130/boschclass.h b/drivers/input/sensors/smi130/boschclass.h new file mode 100644 index 0000000000000000000000000000000000000000..a89cc5d94e64eb8ef2432de753b235b518fd014c --- /dev/null +++ b/drivers/input/sensors/smi130/boschclass.h @@ -0,0 +1,181 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename boschcalss.h + * @date 2015/11/17 13:44 + * @Modification Date 2018/08/28 18:20 + * @id "836294d" + * @version 1.5.9 + * + * @brief + */ + +#ifndef _BSTCLASS_H +#define _BSTCLASS_H + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#include +#include +#endif + +#include +#include +#include + +struct bosch_dev { + const char *name; + + int (*open)(struct bosch_dev *dev); + void (*close)(struct bosch_dev *dev); + struct mutex mutex; + struct device dev; + struct list_head node; +}; + +#define to_bosch_dev(d) container_of(d, struct bosch_dev, dev) + +struct bosch_dev *bosch_allocate_device(void); +void bosch_free_device(struct bosch_dev *dev); + +static inline struct bosch_dev *bosch_get_device(struct bosch_dev *dev) +{ + return dev ? to_bosch_dev(get_device(&dev->dev)) : NULL; +} + +static inline void bosch_put_device(struct bosch_dev *dev) +{ + if (dev) + put_device(&dev->dev); +} + +static inline void *bosch_get_drvdata(struct bosch_dev *dev) +{ + return dev_get_drvdata(&dev->dev); +} + +static inline void bosch_set_drvdata(struct bosch_dev *dev, void *data) +{ + dev_set_drvdata(&dev->dev, data); +} + +int __must_check bosch_register_device(struct bosch_dev *); +void bosch_unregister_device(struct bosch_dev *); + +void bosch_reset_device(struct bosch_dev *); + + +extern struct class bosch_class; + +#endif diff --git a/drivers/input/sensors/smi130/bs_log.c b/drivers/input/sensors/smi130/bs_log.c new file mode 100644 index 0000000000000000000000000000000000000000..05ddddd96683601bee5b6bdb2041a9e83599423a --- /dev/null +++ b/drivers/input/sensors/smi130/bs_log.c @@ -0,0 +1,153 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename bs_log.c + * @date "Wed Sep 24 15:27:12 2014 +0800" + * @Modification Date 2018/08/28 18:20 + * @id "e416c14" + * + * @brief + * The source file of BOSCH SENSOR LOG +*/ + + +#ifdef __KERNEL__ +#include +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef BOSCH_DRIVER_LOG_FUNC +#define BSLOG_VAR_DEF +#include "bs_log.h" + +void set_debug_log_level(uint8_t level) +{ + debug_log_level = level; +} + +uint8_t get_debug_log_level(void) +{ + return debug_log_level; +} + +EXPORT_SYMBOL(set_debug_log_level); +EXPORT_SYMBOL(get_debug_log_level); + +#endif/*BOSCH_DRIVER_LOG_FUNC*/ +/*@}*/ diff --git a/drivers/input/sensors/smi130/bs_log.h b/drivers/input/sensors/smi130/bs_log.h new file mode 100644 index 0000000000000000000000000000000000000000..86ef153c5281b488d5911f0e944c2d53e96e4cfe --- /dev/null +++ b/drivers/input/sensors/smi130/bs_log.h @@ -0,0 +1,274 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename bs_log.h + * @date "Sat Oct 11 16:12:16 2014 +0800" + * @Modification Date 2018/08/28 18:20 + * @id "762cc9e" + * + * @brief + * The head file of BOSCH SENSOR LOG +*/ + +#ifndef __BS_LOG_H +#define __BS_LOG_H + +#include + +/*! @ trace functions + @{*/ +/*! ERROR LOG LEVEL */ +#define LOG_LEVEL_E 3 +/*! NOTICE LOG LEVEL */ +#define LOG_LEVEL_N 5 +/*! INFORMATION LOG LEVEL */ +#define LOG_LEVEL_I 6 +/*! DEBUG LOG LEVEL */ +#define LOG_LEVEL_D 7 +/*! DEBUG_FWDL LOG LEVEL */ +#define LOG_LEVEL_DF 10 +/*! DEBUG_DATA LOG LEVEL */ +#define LOG_LEVEL_DA 15 +/*! ALL LOG LEVEL */ +#define LOG_LEVEL_A 20 + +#ifndef MODULE_TAG +/*! MODULE TAG DEFINATION */ +#define MODULE_TAG "" +#endif + +#ifndef LOG_LEVEL +/*! LOG LEVEL DEFINATION */ +#define LOG_LEVEL LOG_LEVEL_I +#endif + +#ifdef BOSCH_DRIVER_LOG_FUNC + #ifdef BSLOG_VAR_DEF + uint8_t debug_log_level = LOG_LEVEL; + #else + extern uint8_t debug_log_level; + #endif + + /*! print error message */ + #define PERR(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_E)\ + printk(KERN_INFO "\n" "[E]" KERN_ERR MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print notice message */ + #define PNOTICE(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_N)\ + printk(KERN_INFO "\n" "[N]" KERN_NOTICE MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print information message */ + #define PINFO(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_I)\ + printk(KERN_INFO "\n" "[I]" KERN_INFO MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print debug message */ + #define PDEBUG(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_D)\ + printk(KERN_INFO "\n" "[D]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print debug fw download message */ + #define PDEBUG_FWDL(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_DF)\ + printk(KERN_INFO "\n" "[DF]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print debug data log message */ + #define PDEBUG_DLOG(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_DA)\ + printk(KERN_INFO "\n" "[DA]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + void set_debug_log_level(uint8_t level); + uint8_t get_debug_log_level(void); + +#else + + #if (LOG_LEVEL >= LOG_LEVEL_E) + /*! print error message */ + #define PERR(fmt, args...) \ + printk(KERN_INFO "\n" "[E]" KERN_ERR MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PERR(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_N) + /*! print notice message */ + #define PNOTICE(fmt, args...) \ + printk(KERN_INFO "\n" "[N]" KERN_NOTICE MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PNOTICE(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_I) + /*! print information message */ + #define PINFO(fmt, args...) printk(KERN_INFO "\n" "[I]" KERN_INFO MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PINFO(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_D) + /*! print debug message */ + #define PDEBUG(fmt, args...) printk(KERN_INFO "\n" "[D]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PDEBUG(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_DF) + /*! print debug fw download message */ + #define PDEBUG_FWDL(fmt, args...) printk(KERN_INFO "\n" "[DF]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PDEBUG_FWDL(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_DA) + /*! print debug data log message */ + #define PDEBUG_DLOG(fmt, args...) printk(KERN_INFO "\n" "[DA]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PDEBUG_DLOG(fmt, args...) + #endif + + #define set_debug_log_level(level) {} + #define get_debug_log_level() (LOG_LEVEL) + +#endif + +#endif/*__BS_LOG_H*/ +/*@}*/ diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/sensors/smi130/modules.order similarity index 100% rename from drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i rename to drivers/input/sensors/smi130/modules.order diff --git a/drivers/input/sensors/smi130/readme.md b/drivers/input/sensors/smi130/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..48b2cc16b134b9015b279ea9656183088b66e347 --- /dev/null +++ b/drivers/input/sensors/smi130/readme.md @@ -0,0 +1,49 @@ +# SMI130 sensor API +## Introduction +This package contains the Robert Bosch GmbH's SMI130 sensor driver (sensor API) + +## Version +File | Version | Date +---------------------|---------|--------------- +smi130.h | 2.0.9 | 2018/08/28 +smi130.c | 2.0.9 | 2018/08/28 +smi130_spi.c | 1.3 | 2018/08/28 +smi130_i2c.c | 1.3 | 2018/08/28 +smi130_gyro_driver.c | 1.5.9 | 2018/08/28 +smi130_gyro.c | 1.5 | 2018/08/28 +smi130_gyro.h | 1.5 | 2018/08/28 +smi130_driver.h | 1.3 | 2018/08/28 +smi130_driver.c | 1.3 | 2018/08/28 +smi130_acc.c | 2.1.2 | 2018/08/28 +bs_log.h | | 2018/08/28 +bs_log.c | | 2018/08/28 +boschcalss.h | 1.5.9 | 2018/08/28 +boschclass.c | 1.5.9 | 2018/08/28 + + + +## File information +* smi130.h : The head file of SMI130API +* smi130.c : Sensor Driver for SMI130 sensor +* smi130_spi.c : This file implements moudle function, which add the driver to SPI core. +* smi130_i2c.c : This file implements moudle function, which add the driver to I2C core. +* smi130_driver.h : The head file of SMI130 device driver core code +* smi130_driver.c : This file implements the core code of SMI130 device driver +* bs_log.h : The head file of BOSCH SENSOR LOG +* bs_log.c : The source file of BOSCH SENSOR LOG +* boschcalss.h : +* boschclass.c : + + +## Supported sensor interface +* SPI 4-wire +* I2C + +## Copyright + +Copyright (C) 2016 - 2017 Bosch Sensortec GmbH +Modification Copyright (C) 2018 Robert Bosch Kft All Rights Reserved + +This software program is licensed subject to the GNU General +Public License (GPL).Version 2,June 1991, +available at http://www.fsf.org/copyleft/gpl.html \ No newline at end of file diff --git a/drivers/input/sensors/smi130/smi130.c b/drivers/input/sensors/smi130/smi130.c new file mode 100644 index 0000000000000000000000000000000000000000..1ddd3b56877a36b16a774ff3ea2f8d552afd1b5e --- /dev/null +++ b/drivers/input/sensors/smi130/smi130.c @@ -0,0 +1,18785 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. +* +* @filename smi130.c +* @Date: 2015/04/02 +* @Modification Date 2018/08/28 18:20 +* @id 836294d +* @Revision: 2.0.9 $ +* +* Usage: Sensor Driver for SMI130 sensor +*/ + + +#include "smi130.h" +#include + +/* user defined code to be added here ... */ +struct smi130_t *p_smi130; +/* used for reading the mag trim values for compensation*/ +struct trim_data_t mag_trim_mbl; +/* the following variable used for avoiding the selecting of auto mode +when it is running in the manual mode of BMM150 mag interface*/ +u8 V_bmm150_maual_auto_condition_u8_mbl = SMI130_INIT_VALUE; +/* used for reading the AKM compensating data */ +struct bosch_akm_sensitivity_data_t akm_asa_data_mbl; +/* Assign the fifo time */ +u32 V_fifo_time_U32_mbl = SMI130_INIT_VALUE; + +/* FIFO data read for 1024 bytes of data */ +u8 v_fifo_data_u8_mbl[FIFO_FRAME] = {SMI130_INIT_VALUE}; +/* YAMAHA-YAS532*/ +/* value of coeff*/ +static const int yas532_version_ac_coef[] = {YAS532_VERSION_AC_COEF_X, +YAS532_VERSION_AC_COEF_Y1, YAS532_VERSION_AC_COEF_Y2}; +/* used for reading the yas532 calibration data*/ +struct yas532_t yas532_data_mbl; +/* used for reading the yas537 calibration data*/ +struct yas537_t yas537_data_mbl; +/*! + * @brief + * This function is used for initialize + * bus read and bus write functions + * assign the chip id and device address + * chip id is read in the register 0x00 bit from 0 to 7 + * + * @param smi130 : structure pointer + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * While changing the parameter of the smi130_t + * consider the following point: + * Changing the reference value of the parameter + * will changes the local copy or local reference + * make sure your changes will not + * affect the reference value of the parameter + * (Better case don't change the reference value of the parameter) + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_init(struct smi130_t *smi130) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + u8 v_pmu_data_u8 = SMI130_INIT_VALUE; + /* assign smi130 ptr */ + p_smi130 = smi130; + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_CHIP_ID__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* read Chip Id */ + p_smi130->chip_id = v_data_u8; + /* To avoid gyro wakeup it is required to write 0x00 to 0x6C*/ + com_rslt += smi130_write_reg(SMI130_USER_PMU_TRIGGER_ADDR, + &v_pmu_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + return com_rslt; +} +/*! + * @brief + * This API write the data to + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_write_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write data from register*/ + com_rslt = + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130->dev_addr, + v_addr_u8, v_data_u8, v_len_u8); + } + return com_rslt; +} +/*! + * @brief + * This API reads the data from + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_read_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* Read data from register*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + v_addr_u8, v_data_u8, v_len_u8); + } + return com_rslt; +} +/*! + * @brief This API used to reads the fatal error + * from the Register 0x02 bit 0 + * This flag will be reset only by power-on-reset and soft reset + * + * + * @param v_fatal_err_u8 : The status of fatal error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fatal_err(u8 +*v_fatal_err_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* reading the fatal error status*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FATAL_ERR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fatal_err_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FATAL_ERR); + } + return com_rslt; +} +/*! + * @brief This API used to read the error code + * from register 0x02 bit 1 to 4 + * + * + * @param v_err_code_u8 : The status of error codes + * error_code | description + * ------------|--------------- + * 0x00 |no error + * 0x01 |ACC_CONF error (accel ODR and bandwidth not compatible) + * 0x02 |GYR_CONF error (Gyroscope ODR and bandwidth not compatible) + * 0x03 |Under sampling mode and interrupt uses pre filtered data + * 0x04 |reserved + * 0x05 |Selected trigger-readout offset in + * - |MAG_IF greater than selected ODR + * 0x06 |FIFO configuration error for header less mode + * 0x07 |Under sampling mode and pre filtered data as FIFO source + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_err_code(u8 +*v_err_code_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ERR_CODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_err_code_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_ERR_CODE); + } + return com_rslt; +} +/*! + * @brief This API Reads the i2c error code from the + * Register 0x02 bit 5. + * This error occurred in I2C master detected + * + * @param v_i2c_err_code_u8 : The status of i2c fail error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_fail_err(u8 +*v_i2c_err_code_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_I2C_FAIL_ERR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_err_code_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_I2C_FAIL_ERR); + } + return com_rslt; +} + /*! + * @brief This API Reads the dropped command error + * from the register 0x02 bit 6 + * + * + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_drop_cmd_err(u8 +*v_drop_cmd_err_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_DROP_CMD_ERR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_drop_cmd_err_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_DROP_CMD_ERR); + } + return com_rslt; +} +/*! + * @brief This API reads the magnetometer data ready + * interrupt not active. + * It reads from the error register 0x0x2 bit 7 + * + * + * + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_dada_rdy_err( +u8 *v_mag_data_rdy_err_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_MAG_DADA_RDY_ERR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_data_rdy_err_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_MAG_DADA_RDY_ERR); + } + return com_rslt; +} +/*! + * @brief This API reads the error status + * from the error register 0x02 bit 0 to 7 + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * @param v_fatal_er_u8r : The status of fatal error + * @param v_err_code_u8 : The status of error code + * @param v_i2c_fail_err_u8 : The status of I2C fail error + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_error_status(u8 *v_fatal_er_u8r, +u8 *v_err_code_u8, u8 *v_i2c_fail_err_u8, +u8 *v_drop_cmd_err_u8, u8 *v_mag_data_rdy_err_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the error codes*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_ERR_STAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* fatal error*/ + *v_fatal_er_u8r = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FATAL_ERR); + /* user error*/ + *v_err_code_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_ERR_CODE); + /* i2c fail error*/ + *v_i2c_fail_err_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_I2C_FAIL_ERR); + /* drop command error*/ + *v_drop_cmd_err_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_DROP_CMD_ERR); + /* mag data ready error*/ + *v_mag_data_rdy_err_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_MAG_DADA_RDY_ERR); + } + return com_rslt; +} +/*! + * @brief This API reads the magnetometer power mode from + * PMU status register 0x03 bit 0 and 1 + * + * @param v_mag_power_mode_stat_u8 : The value of mag power mode + * mag_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x02 + * + * + * @note The power mode of mag set by the 0x7E command register + * @note using the function "smi130_set_command_register()" + * value | mode + * ---------|---------------- + * 0x18 | MAG_MODE_SUSPEND + * 0x19 | MAG_MODE_NORMAL + * 0x1A | MAG_MODE_LOWPOWER + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_power_mode_stat(u8 +*v_mag_power_mode_stat_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_POWER_MODE_STAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_power_mode_stat_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_MAG_POWER_MODE_STAT); + } + return com_rslt; +} +/*! + * @brief This API reads the gyroscope power mode from + * PMU status register 0x03 bit 2 and 3 + * + * @param v_gyro_power_mode_stat_u8 : The value of gyro power mode + * gyro_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * FAST POWER UP | 0x03 + * + * @note The power mode of gyro set by the 0x7E command register + * @note using the function "smi130_set_command_register()" + * value | mode + * ---------|---------------- + * 0x14 | GYRO_MODE_SUSPEND + * 0x15 | GYRO_MODE_NORMAL + * 0x17 | GYRO_MODE_FASTSTARTUP + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_power_mode_stat(u8 +*v_gyro_power_mode_stat_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_GYRO_POWER_MODE_STAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_power_mode_stat_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_POWER_MODE_STAT); + } + return com_rslt; +} +/*! + * @brief This API reads the accelerometer power mode from + * PMU status register 0x03 bit 4 and 5 + * + * + * @param v_accel_power_mode_stat_u8 : The value of accel power mode + * accel_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x02 + * + * @note The power mode of accel set by the 0x7E command register + * @note using the function "smi130_set_command_register()" + * value | mode + * ---------|---------------- + * 0x11 | ACCEL_MODE_NORMAL + * 0x12 | ACCEL_LOWPOWER + * 0x10 | ACCEL_SUSPEND + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_power_mode_stat(u8 +*v_accel_power_mode_stat_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_POWER_MODE_STAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_power_mode_stat_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_POWER_MODE_STAT); + } + return com_rslt; +} +/*! + * @brief This API switch mag interface to normal mode + * and confirm whether the mode switching done successfully or not +* + * @return results of bus communication function and current MAG_PMU result + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_interface_normal(void) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + /* aim to check the result of switching mag normal */ + u8 v_try_times_u8 = SMI130_MAG_NOAMRL_SWITCH_TIMES; + u8 v_mag_pum_status_u8 = SMI130_INIT_VALUE; + + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt = smi130_set_command_register(MAG_MODE_NORMAL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + while (v_try_times_u8) { + com_rslt = smi130_get_mag_power_mode_stat(&v_mag_pum_status_u8); + if (v_mag_pum_status_u8 == MAG_INTERFACE_PMU_ENABLE) + break; + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + v_try_times_u8--; + } + if (v_mag_pum_status_u8 == MAG_INTERFACE_PMU_ENABLE) + com_rslt += SUCCESS; + else + com_rslt += E_SMI130_COMM_RES; + + return com_rslt; +} +/*! + * @brief This API reads magnetometer data X values + * from the register 0x04 and 0x05 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_x_s16 : The value of mag x + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_x(s16 *v_mag_x_s16, +u8 v_sensor_select_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the mag X lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[SMI130_MAG_X_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_DATA_MAG_X_LSB__REG, + v_data_u8, SMI130_MAG_X_DATA_LENGTH); + /* X axis*/ + v_data_u8[SMI130_MAG_X_LSB_BYTE] = + SMI130_GET_BITSLICE(v_data_u8[SMI130_MAG_X_LSB_BYTE], + SMI130_USER_DATA_MAG_X_LSB); + *v_mag_x_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_MAG_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[SMI130_MAG_X_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_0_MAG_X_LSB__REG, + v_data_u8, SMI130_MAG_X_DATA_LENGTH); + *v_mag_x_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_MAG_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_MAG_X_LSB_BYTE])); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data Y values + * from the register 0x06 and 0x07 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_y_s16 : The value of mag y + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_y(s16 *v_mag_y_s16, +u8 v_sensor_select_u8) +{ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_OUT_OF_RANGE; + /* Array contains the mag Y lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[SMI130_MAG_Y_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_DATA_MAG_Y_LSB__REG, + v_data_u8, SMI130_MAG_Y_DATA_LENGTH); + /*Y-axis lsb value shifting*/ + v_data_u8[SMI130_MAG_Y_LSB_BYTE] = + SMI130_GET_BITSLICE(v_data_u8[SMI130_MAG_Y_LSB_BYTE], + SMI130_USER_DATA_MAG_Y_LSB); + *v_mag_y_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_MAG_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[SMI130_MAG_Y_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_DATA_2_MAG_Y_LSB__REG, + v_data_u8, SMI130_MAG_Y_DATA_LENGTH); + *v_mag_y_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_MAG_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_MAG_Y_LSB_BYTE])); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data Z values + * from the register 0x08 and 0x09 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_z_s16 : The value of mag z + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_z(s16 *v_mag_z_s16, +u8 v_sensor_select_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the mag Z lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[SMI130_MAG_Z_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_DATA_MAG_Z_LSB__REG, + v_data_u8, SMI130_MAG_Z_DATA_LENGTH); + /*Z-axis lsb value shifting*/ + v_data_u8[SMI130_MAG_Z_LSB_BYTE] = + SMI130_GET_BITSLICE(v_data_u8[SMI130_MAG_Z_LSB_BYTE], + SMI130_USER_DATA_MAG_Z_LSB); + *v_mag_z_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_MAG_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_07_BITS) | + (v_data_u8[SMI130_MAG_Z_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_DATA_4_MAG_Z_LSB__REG, + v_data_u8, SMI130_MAG_Z_DATA_LENGTH); + *v_mag_z_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_MAG_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | ( + v_data_u8[SMI130_MAG_Z_LSB_BYTE])); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data RHALL values + * from the register 0x0A and 0x0B + * + * + * @param v_mag_r_s16 : The value of BMM150 r data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_r(s16 *v_mag_r_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the mag R lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[SMI130_MAG_R_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_6_RHALL_LSB__REG, + v_data_u8, SMI130_MAG_R_DATA_LENGTH); + /*R-axis lsb value shifting*/ + v_data_u8[SMI130_MAG_R_LSB_BYTE] = + SMI130_GET_BITSLICE(v_data_u8[SMI130_MAG_R_LSB_BYTE], + SMI130_USER_DATA_MAG_R_LSB); + *v_mag_r_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_MAG_R_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS) | + (v_data_u8[SMI130_MAG_R_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data X,Y,Z values + * from the register 0x04 to 0x09 + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag xyz data + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_xyz( +struct smi130_mag_t *mag, u8 v_sensor_select_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the mag XYZ lSB and MSB data + v_data_u8[0] - X-LSB + v_data_u8[1] - X-MSB + v_data_u8[0] - Y-LSB + v_data_u8[1] - Y-MSB + v_data_u8[0] - Z-LSB + v_data_u8[1] - Z-MSB + */ + u8 v_data_u8[SMI130_MAG_XYZ_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_DATA_MAG_X_LSB__REG, + v_data_u8, SMI130_MAG_XYZ_DATA_LENGTH); + /*X-axis lsb value shifting*/ + v_data_u8[SMI130_DATA_FRAME_MAG_X_LSB_BYTE] = + SMI130_GET_BITSLICE( + v_data_u8[SMI130_DATA_FRAME_MAG_X_LSB_BYTE], + SMI130_USER_DATA_MAG_X_LSB); + /* Data X */ + mag->x = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[SMI130_DATA_FRAME_MAG_X_LSB_BYTE])); + /* Data Y */ + /*Y-axis lsb value shifting*/ + v_data_u8[SMI130_DATA_FRAME_MAG_Y_LSB_BYTE] = + SMI130_GET_BITSLICE( + v_data_u8[SMI130_DATA_FRAME_MAG_Y_LSB_BYTE], + SMI130_USER_DATA_MAG_Y_LSB); + mag->y = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[SMI130_DATA_FRAME_MAG_Y_LSB_BYTE])); + + /* Data Z */ + /*Z-axis lsb value shifting*/ + v_data_u8[SMI130_DATA_FRAME_MAG_Z_LSB_BYTE] + = SMI130_GET_BITSLICE( + v_data_u8[SMI130_DATA_FRAME_MAG_Z_LSB_BYTE], + SMI130_USER_DATA_MAG_Z_LSB); + mag->z = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_07_BITS) | + (v_data_u8[SMI130_DATA_FRAME_MAG_Z_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_0_MAG_X_LSB__REG, + v_data_u8, SMI130_MAG_XYZ_DATA_LENGTH); + /* Data X */ + mag->x = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_DATA_FRAME_MAG_X_LSB_BYTE])); + /* Data Y */ + mag->y = ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_DATA_FRAME_MAG_Y_LSB_BYTE])); + /* Data Z */ + mag->z = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_DATA_FRAME_MAG_Z_LSB_BYTE])); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*!* + * @brief This API reads magnetometer data X,Y,Z,r + * values from the register 0x04 to 0x0B + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag-BMM150 xyzr data + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_xyzr( +struct smi130_mag_xyzr_t *mag) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8[SMI130_MAG_XYZR_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_MAG_X_LSB__REG, + v_data_u8, SMI130_MAG_XYZR_DATA_LENGTH); + + /* Data X */ + /*X-axis lsb value shifting*/ + v_data_u8[SMI130_DATA_FRAME_MAG_X_LSB_BYTE] + = SMI130_GET_BITSLICE( + v_data_u8[SMI130_DATA_FRAME_MAG_X_LSB_BYTE], + SMI130_USER_DATA_MAG_X_LSB); + mag->x = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_05_BITS) + | (v_data_u8[SMI130_DATA_FRAME_MAG_X_LSB_BYTE])); + /* Data Y */ + /*Y-axis lsb value shifting*/ + v_data_u8[SMI130_DATA_FRAME_MAG_Y_LSB_BYTE] + = SMI130_GET_BITSLICE( + v_data_u8[SMI130_DATA_FRAME_MAG_Y_LSB_BYTE], + SMI130_USER_DATA_MAG_Y_LSB); + mag->y = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_05_BITS) + | (v_data_u8[ + SMI130_DATA_FRAME_MAG_Y_LSB_BYTE])); + + /* Data Z */ + /*Z-axis lsb value shifting*/ + v_data_u8[SMI130_DATA_FRAME_MAG_Z_LSB_BYTE] + = SMI130_GET_BITSLICE( + v_data_u8[SMI130_DATA_FRAME_MAG_Z_LSB_BYTE], + SMI130_USER_DATA_MAG_Z_LSB); + mag->z = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_07_BITS) + | (v_data_u8[SMI130_DATA_FRAME_MAG_Z_LSB_BYTE])); + + /* RHall */ + /*R-axis lsb value shifting*/ + v_data_u8[SMI130_DATA_FRAME_MAG_R_LSB_BYTE] + = SMI130_GET_BITSLICE( + v_data_u8[SMI130_DATA_FRAME_MAG_R_LSB_BYTE], + SMI130_USER_DATA_MAG_R_LSB); + mag->r = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_MAG_R_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS) + | (v_data_u8[SMI130_DATA_FRAME_MAG_R_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data X values + * form the register 0x0C and 0x0D + * + * + * + * + * @param v_gyro_x_s16 : The value of gyro x data + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_x(s16 *v_gyro_x_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the gyro X lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[MSB_ONE] - MSB*/ + u8 v_data_u8[SMI130_GYRO_X_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_8_GYRO_X_LSB__REG, + v_data_u8, SMI130_GYRO_DATA_LENGTH); + + *v_gyro_x_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_GYRO_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_GYRO_X_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data Y values + * form the register 0x0E and 0x0F + * + * + * + * + * @param v_gyro_y_s16 : The value of gyro y data + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error result of communication routines + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_y(s16 *v_gyro_y_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the gyro Y lSB and MSB data + v_data_u8[LSB_ZERO] - LSB + v_data_u8[MSB_ONE] - MSB*/ + u8 v_data_u8[SMI130_GYRO_Y_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro y data*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_10_GYRO_Y_LSB__REG, + v_data_u8, SMI130_GYRO_DATA_LENGTH); + + *v_gyro_y_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_GYRO_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_GYRO_Y_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data Z values + * form the register 0x10 and 0x11 + * + * + * + * + * @param v_gyro_z_s16 : The value of gyro z data + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_z(s16 *v_gyro_z_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the gyro Z lSB and MSB data + v_data_u8[LSB_ZERO] - LSB + v_data_u8[MSB_ONE] - MSB*/ + u8 v_data_u8[SMI130_GYRO_Z_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro z data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_12_GYRO_Z_LSB__REG, + v_data_u8, SMI130_GYRO_DATA_LENGTH); + + *v_gyro_z_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_GYRO_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_GYRO_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data X,Y,Z values + * from the register 0x0C to 0x11 + * + * + * + * + * @param gyro : The value of gyro xyz + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_xyz(struct smi130_gyro_t *gyro) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the mag XYZ lSB and MSB data + v_data_u8[0] - X-LSB + v_data_u8[1] - X-MSB + v_data_u8[0] - Y-LSB + v_data_u8[1] - Y-MSB + v_data_u8[0] - Z-LSB + v_data_u8[1] - Z-MSB + */ + u8 v_data_u8[SMI130_GYRO_XYZ_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the gyro xyz data*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_8_GYRO_X_LSB__REG, + v_data_u8, SMI130_GYRO_XYZ_DATA_LENGTH); + + /* Data X */ + gyro->x = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_GYRO_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_DATA_FRAME_GYRO_X_LSB_BYTE])); + /* Data Y */ + gyro->y = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_GYRO_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_DATA_FRAME_GYRO_Y_LSB_BYTE])); + + /* Data Z */ + gyro->z = (s16) + ((((s32)((s8)v_data_u8[ + SMI130_DATA_FRAME_GYRO_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_DATA_FRAME_GYRO_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data X values + * form the register 0x12 and 0x13 + * + * + * + * + * @param v_accel_x_s16 : The value of accel x + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_x(s16 *v_accel_x_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the accel X lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[SMI130_ACCEL_X_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_14_ACCEL_X_LSB__REG, + v_data_u8, SMI130_ACCEL_DATA_LENGTH); + + *v_accel_x_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_ACCEL_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_ACCEL_X_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data Y values + * form the register 0x14 and 0x15 + * + * + * + * + * @param v_accel_y_s16 : The value of accel y + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_y(s16 *v_accel_y_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the accel Y lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[SMI130_ACCEL_Y_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_16_ACCEL_Y_LSB__REG, + v_data_u8, SMI130_ACCEL_DATA_LENGTH); + + *v_accel_y_s16 = (s16) + ((((s32)((s8)v_data_u8[SMI130_ACCEL_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[SMI130_ACCEL_Y_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data Z values + * form the register 0x16 and 0x17 + * + * + * + * + * @param v_accel_z_s16 : The value of accel z + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_z(s16 *v_accel_z_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the accel Z lSB and MSB data + a_data_u8r[LSB_ZERO] - LSB + a_data_u8r[MSB_ONE] - MSB*/ + u8 a_data_u8r[SMI130_ACCEL_Z_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_18_ACCEL_Z_LSB__REG, + a_data_u8r, SMI130_ACCEL_DATA_LENGTH); + + *v_accel_z_s16 = (s16) + ((((s32)((s8)a_data_u8r[SMI130_ACCEL_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[SMI130_ACCEL_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data X,Y,Z values + * from the register 0x12 to 0x17 + * + * + * + * + * @param accel :The value of accel xyz + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_xyz( +struct smi130_accel_t *accel) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the accel XYZ lSB and MSB data + a_data_u8r[0] - X-LSB + a_data_u8r[1] - X-MSB + a_data_u8r[0] - Y-LSB + a_data_u8r[1] - Y-MSB + a_data_u8r[0] - Z-LSB + a_data_u8r[1] - Z-MSB + */ + u8 a_data_u8r[SMI130_ACCEL_XYZ_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_14_ACCEL_X_LSB__REG, + a_data_u8r, SMI130_ACCEL_XYZ_DATA_LENGTH); + + /* Data X */ + accel->x = (s16) + ((((s32)((s8)a_data_u8r[ + SMI130_DATA_FRAME_ACCEL_X_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[SMI130_DATA_FRAME_ACCEL_X_LSB_BYTE])); + /* Data Y */ + accel->y = (s16) + ((((s32)((s8)a_data_u8r[ + SMI130_DATA_FRAME_ACCEL_Y_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[SMI130_DATA_FRAME_ACCEL_Y_LSB_BYTE])); + + /* Data Z */ + accel->z = (s16) + ((((s32)((s8)a_data_u8r[ + SMI130_DATA_FRAME_ACCEL_Z_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[SMI130_DATA_FRAME_ACCEL_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads sensor_time from the register + * 0x18 to 0x1A + * + * + * @param v_sensor_time_u32 : The value of sensor time + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_sensor_time(u32 *v_sensor_time_u32) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the sensor time it is 32 bit data + a_data_u8r[0] - sensor time + a_data_u8r[1] - sensor time + a_data_u8r[0] - sensor time + */ + u8 a_data_u8r[SMI130_SENSOR_TIME_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_SENSORTIME_0_SENSOR_TIME_LSB__REG, + a_data_u8r, SMI130_SENSOR_TIME_LENGTH); + + *v_sensor_time_u32 = (u32) + ((((u32)a_data_u8r[SMI130_SENSOR_TIME_MSB_BYTE]) + << SMI130_SHIFT_BIT_POSITION_BY_16_BITS) + |(((u32)a_data_u8r[SMI130_SENSOR_TIME_XLSB_BYTE]) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[SMI130_SENSOR_TIME_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads the Gyroscope self test + * status from the register 0x1B bit 1 + * + * + * @param v_gyro_selftest_u8 : The value of gyro self test status + * value | status + * ---------|---------------- + * 0 | Gyroscope self test is running or failed + * 1 | Gyroscope self test completed successfully + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_selftest(u8 +*v_gyro_selftest_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STAT_GYRO_SELFTEST_OK__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_selftest_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STAT_GYRO_SELFTEST_OK); + } + return com_rslt; +} +/*! + * @brief This API reads the status of + * mag manual interface operation form the register 0x1B bit 2 + * + * + * + * @param v_mag_manual_stat_u8 : The value of mag manual operation status + * value | status + * ---------|---------------- + * 0 | Indicates no manual magnetometer + * - | interface operation is ongoing + * 1 | Indicates manual magnetometer + * - | interface operation is ongoing + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_manual_operation_stat(u8 +*v_mag_manual_stat_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read manual operation*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STAT_MAG_MANUAL_OPERATION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_manual_stat_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STAT_MAG_MANUAL_OPERATION); + } + return com_rslt; +} +/*! + * @brief This API reads the fast offset compensation + * status form the register 0x1B bit 3 + * + * + * @param v_foc_rdy_u8 : The status of fast compensation + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_rdy(u8 +*v_foc_rdy_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the FOC status*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STAT_FOC_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_rdy_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STAT_FOC_RDY); + } + return com_rslt; +} +/*! + * @brief This API Reads the nvm_rdy status from the + * resister 0x1B bit 4 + * + * + * @param v_nvm_rdy_u8 : The value of NVM ready status + * value | status + * ---------|---------------- + * 0 | NVM write operation in progress + * 1 | NVM is ready to accept a new write trigger + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_nvm_rdy(u8 +*v_nvm_rdy_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the nvm ready status*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STAT_NVM_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_nvm_rdy_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STAT_NVM_RDY); + } + return com_rslt; +} +/*! + * @brief This API reads the status of mag data ready + * from the register 0x1B bit 5 + * The status get reset when one mag data register is read out + * + * @param v_data_rdy_u8 : The value of mag data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_data_rdy_mag(u8 +*v_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STAT_DATA_RDY_MAG__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STAT_DATA_RDY_MAG); + } + return com_rslt; +} +/*! + * @brief This API reads the status of gyro data ready form the + * register 0x1B bit 6 + * The status get reset when gyro data register read out + * + * + * @param v_data_rdy_u8 : The value of gyro data ready + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_data_rdy(u8 +*v_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STAT_DATA_RDY_GYRO__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STAT_DATA_RDY_GYRO); + } + return com_rslt; +} +/*! + * @brief This API reads the status of accel data ready form the + * register 0x1B bit 7 + * The status get reset when accel data register read out + * + * + * @param v_data_rdy_u8 : The value of accel data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_data_rdy(u8 +*v_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /*reads the status of accel data ready*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STAT_DATA_RDY_ACCEL__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STAT_DATA_RDY_ACCEL); + } + return com_rslt; +} +/*! + * @brief This API reads the step detector interrupt status + * from the register 0x1C bit 0 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_step_intr_u8 : The status of step detector interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_step_intr(u8 +*v_step_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_STEP_INTR__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_step_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_STEP_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the + * significant motion interrupt status + * from the register 0x1C bit 1 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_significant_intr_u8 : The status of step + * motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_significant_intr(u8 +*v_significant_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_significant_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR); + } + return com_rslt; +} + /*! + * @brief This API reads the any motion interrupt status + * from the register 0x1C bit 2 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * @param v_any_motion_intr_u8 : The status of any-motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_any_motion_intr(u8 +*v_any_motion_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_ANY_MOTION__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_ANY_MOTION); + } + return com_rslt; +} +/*! + * @brief This API reads the power mode trigger interrupt status + * from the register 0x1C bit 3 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_pmu_trigger_intr_u8 : The status of power mode trigger interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_pmu_trigger_intr(u8 +*v_pmu_trigger_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_PMU_TRIGGER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_pmu_trigger_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_PMU_TRIGGER); + } + return com_rslt; +} +/*! + * @brief This API reads the double tab status + * from the register 0x1C bit 4 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_double_tap_intr_u8 :The status of double tab interrupt + * + * @note Double tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note smi130_set_intr_double_tap() + * @note AXIS MAPPING + * @note smi130_get_stat2_tap_first_x() + * @note smi130_get_stat2_tap_first_y() + * @note smi130_get_stat2_tap_first_z() + * @note DURATION + * @note smi130_set_intr_tap_durn() + * @note THRESHOLD + * @note smi130_set_intr_tap_thres() + * @note TAP QUIET + * @note smi130_set_intr_tap_quiet() + * @note TAP SHOCK + * @note smi130_set_intr_tap_shock() + * @note TAP SOURCE + * @note smi130_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_double_tap_intr(u8 +*v_double_tap_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_DOUBLE_TAP_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_double_tap_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_DOUBLE_TAP_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the single tab status + * from the register 0x1C bit 5 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_single_tap_intr_u8 :The status of single tap interrupt + * + * @note Single tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note smi130_set_intr_single_tap() + * @note AXIS MAPPING + * @note smi130_get_stat2_tap_first_x() + * @note smi130_get_stat2_tap_first_y() + * @note smi130_get_stat2_tap_first_z() + * @note DURATION + * @note smi130_set_intr_tap_durn() + * @note THRESHOLD + * @note smi130_set_intr_tap_thres() + * @note TAP QUIET + * @note smi130_set_intr_tap_quiet() + * @note TAP SHOCK + * @note smi130_set_intr_tap_shock() + * @note TAP SOURCE + * @note smi130_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_single_tap_intr(u8 +*v_single_tap_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_SINGLE_TAP_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_single_tap_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_SINGLE_TAP_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the orient_mbl status + * from the register 0x1C bit 6 + * flag is associated with a specific interrupt function. + * It is set when the orient_mbl interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_orient_mbl_intr_u8 : The status of orient_mbl interrupt + * + * @note For orient_mbl interrupt configuration use the following functions + * @note STATUS + * @note smi130_get_stat0_orient_mbl_intr() + * @note AXIS MAPPING + * @note smi130_get_stat3_orient_mbl_xy() + * @note smi130_get_stat3_orient_mbl_z() + * @note smi130_set_intr_orient_mbl_axes_enable() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_orient_mbl() + * @note INTERRUPT OUTPUT + * @note smi130_set_intr_orient_mbl_ud_enable() + * @note THETA + * @note smi130_set_intr_orient_mbl_theta() + * @note HYSTERESIS + * @note smi130_set_intr_orient_mbl_hyst() + * @note BLOCKING + * @note smi130_set_intr_orient_mbl_blocking() + * @note MODE + * @note smi130_set_intr_orient_mbl_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_orient_mbl_intr(u8 +*v_orient_mbl_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_ORIENT__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_ORIENT); + } + return com_rslt; +} +/*! + * @brief This API reads the flat interrupt status + * from the register 0x1C bit 7 + * flag is associated with a specific interrupt function. + * It is set when the flat interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_flat_intr_u8 : The status of flat interrupt + * + * @note For flat configuration use the following functions + * @note STATS + * @note smi130_get_stat0_flat_intr() + * @note smi130_get_stat3_flat() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_flat() + * @note THETA + * @note smi130_set_intr_flat_theta() + * @note HOLD TIME + * @note smi130_set_intr_flat_hold() + * @note HYSTERESIS + * @note smi130_set_intr_flat_hyst() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_flat_intr(u8 +*v_flat_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_0_FLAT__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_0_FLAT); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g interrupt status + * from the register 0x1D bit 2 + * flag is associated with a specific interrupt function. + * It is set when the high g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_high_g_intr_u8 : The status of high_g interrupt + * + * @note High_g interrupt configured by following functions + * @note STATUS + * @note smi130_get_stat1_high_g_intr() + * @note AXIS MAPPING + * @note smi130_get_stat3_high_g_first_x() + * @note smi130_get_stat3_high_g_first_y() + * @note smi130_get_stat3_high_g_first_z() + * @note SIGN MAPPING + * @note smi130_get_stat3_high_g_first_sign() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_high_g() + * @note HYSTERESIS + * @note smi130_set_intr_high_g_hyst() + * @note DURATION + * @note smi130_set_intr_high_g_durn() + * @note THRESHOLD + * @note smi130_set_intr_high_g_thres() + * @note SOURCE + * @note smi130_set_intr_low_high_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_high_g_intr(u8 +*v_high_g_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_1_HIGH_G_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_1_HIGH_G_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the low g interrupt status + * from the register 0x1D bit 3 + * flag is associated with a specific interrupt function. + * It is set when the low g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_low_g_intr_u8 : The status of low_g interrupt + * + * @note Low_g interrupt configured by following functions + * @note STATUS + * @note smi130_get_stat1_low_g_intr() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_low_g() + * @note SOURCE + * @note smi130_set_intr_low_high_source() + * @note DURATION + * @note smi130_set_intr_low_g_durn() + * @note THRESHOLD + * @note smi130_set_intr_low_g_thres() + * @note HYSTERESIS + * @note smi130_set_intr_low_g_hyst() + * @note MODE + * @note smi130_set_intr_low_g_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_low_g_intr(u8 +*v_low_g_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_1_LOW_G_INTR__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_1_LOW_G_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data ready interrupt status + * from the register 0x1D bit 4 + * flag is associated with a specific interrupt function. + * It is set when the data ready interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_data_rdy_intr_u8 : The status of data ready interrupt + * + * @note Data ready interrupt configured by following functions + * @note STATUS + * @note smi130_get_stat1_data_rdy_intr() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_data_rdy() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_data_rdy_intr(u8 +*v_data_rdy_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_1_DATA_RDY_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_1_DATA_RDY_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data ready FIFO full interrupt status + * from the register 0x1D bit 5 + * flag is associated with a specific interrupt function. + * It is set when the FIFO full interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will + * be permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_full_intr_u8 : The status of fifo full interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note smi130_set_intr_fifo_full() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_fifo_full_intr(u8 +*v_fifo_full_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_1_FIFO_FULL_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_full_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_1_FIFO_FULL_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data + * ready FIFO watermark interrupt status + * from the register 0x1D bit 6 + * flag is associated with a specific interrupt function. + * It is set when the FIFO watermark interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_wm_intr_u8 : The status of fifo water mark interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note smi130_set_intr_fifo_wm() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_fifo_wm_intr(u8 +*v_fifo_wm_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_1_FIFO_WM_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_wm_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_1_FIFO_WM_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data ready no motion interrupt status + * from the register 0x1D bit 7 + * flag is associated with a specific interrupt function. + * It is set when the no motion interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_nomotion_intr_u8 : The status of no motion interrupt + * + * @note No motion interrupt can be configured by following function + * @note STATUS + * @note smi130_get_stat1_nomotion_intr() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_nomotion() + * @note DURATION + * @note smi130_set_intr_slow_no_motion_durn() + * @note THRESHOLD + * @note smi130_set_intr_slow_no_motion_thres() + * @note SLOW/NO MOTION SELECT + * @note smi130_set_intr_slow_no_motion_select() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_nomotion_intr(u8 +*v_nomotion_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the no motion interrupt*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_1_NOMOTION_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_nomotion_intr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_1_NOMOTION_INTR); + } + return com_rslt; +} +/*! + *@brief This API reads the status of any motion first x + * from the register 0x1E bit 0 + * + * + *@param v_anymotion_first_x_u8 : The status of any motion first x interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_first_x(u8 +*v_anymotion_first_x_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the any motion first x interrupt*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_anymotion_first_x_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X); + } + return com_rslt; +} +/*! + * @brief This API reads the status of any motion first y interrupt + * from the register 0x1E bit 1 + * + * + * + *@param v_any_motion_first_y_u8 : The status of any motion first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_first_y(u8 +*v_any_motion_first_y_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the any motion first y interrupt*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_first_y_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y); + } + return com_rslt; +} +/*! + * @brief This API reads the status of any motion first z interrupt + * from the register 0x1E bit 2 + * + * + * + * + *@param v_any_motion_first_z_u8 : The status of any motion first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_first_z(u8 +*v_any_motion_first_z_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the any motion first z interrupt*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_first_z_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the any motion sign status from the + * register 0x1E bit 3 + * + * + * + * + * @param v_anymotion_sign_u8 : The status of any motion sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_sign(u8 +*v_anymotion_sign_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read any motion sign interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_anymotion_sign_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN); + } + return com_rslt; +} +/*! + * @brief This API reads the any motion tap first x status from the + * register 0x1E bit 4 + * + * + * + * + * @param v_tap_first_x_u8 :The status of any motion tap first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_first_x(u8 +*v_tap_first_x_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap first x interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_TAP_FIRST_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_first_x_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_TAP_FIRST_X); + } + return com_rslt; +} +/*! + * @brief This API reads the tap first y interrupt status from the + * register 0x1E bit 5 + * + * + * + * + * @param v_tap_first_y_u8 :The status of tap first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_first_y(u8 +*v_tap_first_y_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap first y interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_TAP_FIRST_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_first_y_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_TAP_FIRST_Y); + } + return com_rslt; +} +/*! + * @brief This API reads the tap first z interrupt status from the + * register 0x1E bit 6 + * + * + * + * + * @param v_tap_first_z_u8 :The status of tap first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_first_z(u8 +*v_tap_first_z_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap first z interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_TAP_FIRST_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_first_z_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_TAP_FIRST_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the tap sign status from the + * register 0x1E bit 7 + * + * + * + * + * @param v_tap_sign_u8 : The status of tap sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_sign(u8 +*v_tap_sign_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap_sign interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_2_TAP_SIGN__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_sign_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_2_TAP_SIGN); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g first x status from the + * register 0x1F bit 0 + * + * + * + * + * @param v_high_g_first_x_u8 :The status of high_g first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_first_x(u8 +*v_high_g_first_x_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read highg_x interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_first_x_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_X); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g first y status from the + * register 0x1F bit 1 + * + * + * + * + * @param v_high_g_first_y_u8 : The status of high_g first y + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_first_y(u8 +*v_high_g_first_y_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read highg_y interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_first_y_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Y); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g first z status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_first_z_u8 : The status of high_g first z + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_first_z(u8 +*v_high_g_first_z_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read highg_z interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_first_z_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the high sign status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_sign_u8 :The status of high sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_sign(u8 +*v_high_g_sign_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read highg_sign interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_3_HIGH_G_SIGN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_sign_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_3_HIGH_G_SIGN); + } + return com_rslt; +} +/*! + * @brief This API reads the status of orient_mbl_xy plane + * from the register 0x1F bit 4 and 5 + * + * + * @param v_orient_mbl_xy_u8 :The status of orient_mbl_xy plane + * value | status + * -----------|------------- + * 0x00 | portrait upright + * 0x01 | portrait upside down + * 0x02 | landscape left + * 0x03 | landscape right + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_orient_mbl_xy(u8 +*v_orient_mbl_xy_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read orient_mbl plane xy interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_3_ORIENT_XY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_xy_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_3_ORIENT_XY); + } + return com_rslt; +} +/*! + * @brief This API reads the status of orient_mbl z plane + * from the register 0x1F bit 6 + * + * + * @param v_orient_mbl_z_u8 :The status of orient_mbl z + * value | status + * -----------|------------- + * 0x00 | upward looking + * 0x01 | downward looking + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_orient_mbl_z(u8 +*v_orient_mbl_z_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read orient_mbl z plane interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_3_ORIENT_Z__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_z_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_3_ORIENT_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the flat status from the register + * 0x1F bit 7 + * + * + * @param v_flat_u8 : The status of flat interrupt + * value | status + * -----------|------------- + * 0x00 | non flat + * 0x01 | flat position + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_flat(u8 +*v_flat_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read flat interrupt status */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_INTR_STAT_3_FLAT__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_STAT_3_FLAT); + } + return com_rslt; +} +/*! + * @brief This API reads the temperature of the sensor + * from the register 0x21 bit 0 to 7 + * + * + * + * @param v_temp_s16 : The value of temperature + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_temp(s16 +*v_temp_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the temperature lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[SMI130_TEMP_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read temperature data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_TEMP_LSB_VALUE__REG, v_data_u8, + SMI130_TEMP_DATA_LENGTH); + *v_temp_s16 = + (s16)(((s32)((s8) (v_data_u8[SMI130_TEMP_MSB_BYTE]) << + SMI130_SHIFT_BIT_POSITION_BY_08_BITS)) + | v_data_u8[SMI130_TEMP_LSB_BYTE]); + } + return com_rslt; +} +/*! + * @brief This API reads the of the sensor + * form the register 0x23 and 0x24 bit 0 to 7 and 0 to 2 + * @brief this byte counter is updated each time a complete frame + * was read or writtern + * + * + * @param v_fifo_length_u32 : The value of fifo byte counter + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_fifo_length(u32 *v_fifo_length_u32) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array contains the fifo length data + v_data_u8[0] - fifo length + v_data_u8[1] - fifo length*/ + u8 a_data_u8r[SMI130_FIFO_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read fifo length*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_BYTE_COUNTER_LSB__REG, a_data_u8r, + SMI130_FIFO_DATA_LENGTH); + + a_data_u8r[SMI130_FIFO_LENGTH_MSB_BYTE] = + SMI130_GET_BITSLICE( + a_data_u8r[SMI130_FIFO_LENGTH_MSB_BYTE], + SMI130_USER_FIFO_BYTE_COUNTER_MSB); + + *v_fifo_length_u32 = + (u32)(((u32)((u8) ( + a_data_u8r[SMI130_FIFO_LENGTH_MSB_BYTE]) << + SMI130_SHIFT_BIT_POSITION_BY_08_BITS)) + | a_data_u8r[SMI130_FIFO_LENGTH_LSB_BYTE]); + } + return com_rslt; +} +/*! + * @brief This API reads the fifo data of the sensor + * from the register 0x24 + * @brief Data format depends on the setting of register FIFO_CONFIG + * + * + * + * @param v_fifodata_u8 : Pointer holding the fifo data + * @param fifo_length_u16 : The value of fifo length maximum + * 1024 + * + * @note For reading FIFO data use the following functions + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_fifo_data( +u8 *v_fifodata_u8, u16 v_fifo_length_u16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read fifo data*/ + com_rslt = + p_smi130->SMI130_BURST_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_DATA__REG, + v_fifodata_u8, v_fifo_length_u16); + + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | SMI130_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | SMI130_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | SMI130_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | SMI130_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | SMI130_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | SMI130_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | SMI130_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | SMI130_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | SMI130_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | SMI130_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | SMI130_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | SMI130_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_output_data_rate( +u8 *v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel output data rate*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_output_data_rate_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | SMI130_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | SMI130_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | SMI130_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | SMI130_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | SMI130_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | SMI130_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | SMI130_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | SMI130_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | SMI130_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | SMI130_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | SMI130_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | SMI130_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_output_data_rate( +u8 v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* accel output data rate selection */ + if ((v_output_data_rate_u8 != SMI130_INIT_VALUE) && + (v_output_data_rate_u8 <= SMI130_MAX_ACCEL_OUTPUT_DATA_RATE)) { + /* write accel output data rate */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE, + v_output_data_rate_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "SMI130_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_bw(u8 *v_bw_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel bandwidth */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_ACCEL_BW__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_bw_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_CONFIG_ACCEL_BW); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "SMI130_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_bw(u8 v_bw_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* select accel bandwidth*/ + if (v_bw_u8 <= SMI130_MAX_ACCEL_BW) { + /* write accel bandwidth*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_ACCEL_BW__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_CONFIG_ACCEL_BW, + v_bw_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_ACCEL_BW__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_under_sampling_parameter( +u8 *v_accel_under_sampling_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel under sampling parameter */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_under_sampling_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING); + } + return com_rslt; +} +/*! + * @brief This API is used to set the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_under_sampling_parameter( +u8 v_accel_under_sampling_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_accel_under_sampling_u8 <= SMI130_MAX_UNDER_SAMPLING) { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + /* write the accel under sampling parameter */ + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING, + v_accel_under_sampling_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} +return com_rslt; +} +/*! + * @brief This API is used to get the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | SMI130_ACCEL_RANGE_2G + * 0x05 | SMI130_ACCEL_RANGE_4G + * 0x08 | SMI130_ACCEL_RANGE_8G + * 0x0C | SMI130_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_range( +u8 *v_range_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel range*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_RANGE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_range_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_RANGE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | SMI130_ACCEL_RANGE_2G + * 0x05 | SMI130_ACCEL_RANGE_4G + * 0x08 | SMI130_ACCEL_RANGE_8G + * 0x0C | SMI130_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_range(u8 v_range_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if ((v_range_u8 == SMI130_ACCEL_RANGE0) || + (v_range_u8 == SMI130_ACCEL_RANGE1) || + (v_range_u8 == SMI130_ACCEL_RANGE3) || + (v_range_u8 == SMI130_ACCEL_RANGE4)) { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_ACCEL_RANGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE( + v_data_u8, SMI130_USER_ACCEL_RANGE, + v_range_u8); + /* write the accel range*/ + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_RANGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | SMI130_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | SMI130_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | SMI130_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | SMI130_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | SMI130_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | SMI130_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | SMI130_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | SMI130_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_output_data_rate( +u8 *v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the gyro output data rate*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_output_data_rate_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | SMI130_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | SMI130_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | SMI130_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | SMI130_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | SMI130_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | SMI130_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | SMI130_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | SMI130_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_output_data_rate( +u8 v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* select the gyro output data rate*/ + if ((v_output_data_rate_u8 < SMI130_OUTPUT_DATA_RATE6) && + (v_output_data_rate_u8 != SMI130_INIT_VALUE) + && (v_output_data_rate_u8 != SMI130_OUTPUT_DATA_RATE1) + && (v_output_data_rate_u8 != SMI130_OUTPUT_DATA_RATE2) + && (v_output_data_rate_u8 != SMI130_OUTPUT_DATA_RATE3) + && (v_output_data_rate_u8 != SMI130_OUTPUT_DATA_RATE4) + && (v_output_data_rate_u8 != SMI130_OUTPUT_DATA_RATE5) + && (v_output_data_rate_u8 != SMI130_OUTPUT_DATA_RATE6) + && (v_output_data_rate_u8 != SMI130_OUTPUT_DATA_RATE7)) { + /* write the gyro output data rate */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE, + v_output_data_rate_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | SMI130_GYRO_OSR4_MODE + * 0x01 | SMI130_GYRO_OSR2_MODE + * 0x02 | SMI130_GYRO_NORMAL_MODE + * 0x03 | SMI130_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_bw(u8 *v_bw_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro bandwidth*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_GYRO_CONFIG_BW__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_bw_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_CONFIG_BW); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | SMI130_GYRO_OSR4_MODE + * 0x01 | SMI130_GYRO_OSR2_MODE + * 0x02 | SMI130_GYRO_NORMAL_MODE + * 0x03 | SMI130_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_bw(u8 v_bw_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_bw_u8 <= SMI130_MAX_GYRO_BW) { + /* write the gyro bandwidth*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_GYRO_CONFIG_BW__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_CONFIG_BW, v_bw_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_CONFIG_BW__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | SMI130_GYRO_RANGE_2000_DEG_SEC + * 0x01 | SMI130_GYRO_RANGE_1000_DEG_SEC + * 0x02 | SMI130_GYRO_RANGE_500_DEG_SEC + * 0x03 | SMI130_GYRO_RANGE_250_DEG_SEC + * 0x04 | SMI130_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_range(u8 *v_range_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the gyro range */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_GYRO_RANGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_range_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_RANGE); + } + return com_rslt; +} +/*! + * @brief This API set the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | SMI130_GYRO_RANGE_2000_DEG_SEC + * 0x01 | SMI130_GYRO_RANGE_1000_DEG_SEC + * 0x02 | SMI130_GYRO_RANGE_500_DEG_SEC + * 0x03 | SMI130_GYRO_RANGE_250_DEG_SEC + * 0x04 | SMI130_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_range(u8 v_range_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_range_u8 <= SMI130_MAX_GYRO_RANGE) { + /* write the gyro range value */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_GYRO_RANGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_RANGE, + v_range_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_GYRO_RANGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |SMI130_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |SMI130_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |SMI130_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |SMI130_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |SMI130_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |SMI130_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |SMI130_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |SMI130_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |SMI130_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |SMI130_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |SMI130_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |SMI130_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_output_data_rate( +u8 *v_output_data_rat_u8e) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the mag data output rate*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_output_data_rat_u8e = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |SMI130_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |SMI130_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |SMI130_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |SMI130_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |SMI130_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |SMI130_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |SMI130_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |SMI130_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |SMI130_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |SMI130_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |SMI130_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |SMI130_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_output_data_rate( +u8 v_output_data_rat_u8e) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* select the mag data output rate*/ + if ((v_output_data_rat_u8e + <= SMI130_MAX_ACCEL_OUTPUT_DATA_RATE) + && (v_output_data_rat_u8e + != SMI130_OUTPUT_DATA_RATE0) + && (v_output_data_rat_u8e + != SMI130_OUTPUT_DATA_RATE6) + && (v_output_data_rat_u8e + != SMI130_OUTPUT_DATA_RATE7)) { + /* write the mag data output rate*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE, + v_output_data_rat_u8e); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API is used to read Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_down_gyro( +u8 *v_fifo_down_gyro_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the gyro fifo down*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_DOWN_GYRO__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_down_gyro_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_DOWN_GYRO); + } + return com_rslt; +} + /*! + * @brief This API is used to set Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_down_gyro( +u8 v_fifo_down_gyro_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the gyro fifo down*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_DOWN_GYRO__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE( + v_data_u8, + SMI130_USER_FIFO_DOWN_GYRO, + v_fifo_down_gyro_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_DOWN_GYRO__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_fifo_filter_data( +u8 *v_gyro_fifo_filter_data_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the gyro fifo filter data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_FILTER_GYRO__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_fifo_filter_data_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_FILTER_GYRO); + } + return com_rslt; +} +/*! + * @brief This API is used to set gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_fifo_filter_data( +u8 v_gyro_fifo_filter_data_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_gyro_fifo_filter_data_u8 + <= SMI130_MAX_VALUE_FIFO_FILTER) { + /* write the gyro fifo filter data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_FILTER_GYRO__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE( + v_data_u8, + SMI130_USER_FIFO_FILTER_GYRO, + v_gyro_fifo_filter_data_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_FILTER_GYRO__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_down_accel( +u8 *v_fifo_down_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel fifo down data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_DOWN_ACCEL__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_down_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_DOWN_ACCEL); + } + return com_rslt; +} + /*! + * @brief This API is used to set Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_down_accel( +u8 v_fifo_down_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the accel fifo down data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_DOWN_ACCEL__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_DOWN_ACCEL, v_fifo_down_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_DOWN_ACCEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_fifo_filter_data( +u8 *v_accel_fifo_filter_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel fifo filter data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_FILTER_ACCEL__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_fifo_filter_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_FILTER_ACCEL); + } + return com_rslt; +} +/*! + * @brief This API is used to set accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_fifo_filter_data( +u8 v_accel_fifo_filter_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_accel_fifo_filter_u8 <= SMI130_MAX_VALUE_FIFO_FILTER) { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_FILTER_ACCEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + /* write accel fifo filter data */ + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_FILTER_ACCEL, + v_accel_fifo_filter_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_FILTER_ACCEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_wm( +u8 *v_fifo_wm_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the fifo water mark level*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_WM__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_wm_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_WM); + } + return com_rslt; +} +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_wm( +u8 v_fifo_wm_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the fifo water mark level*/ + com_rslt = + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_WM__REG, + &v_fifo_wm_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API reads fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_time_enable( +u8 *v_fifo_time_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the fifo sensor time*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_TIME_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_time_enable_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_TIME_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_time_enable( +u8 v_fifo_time_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_fifo_time_enable_u8 <= SMI130_MAX_VALUE_FIFO_TIME) { + /* write the fifo sensor time*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_TIME_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_TIME_ENABLE, + v_fifo_time_enable_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_TIME_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_tag_intr2_enable( +u8 *v_fifo_tag_intr2_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the fifo tag interrupt2*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_TAG_INTR2_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_tag_intr2_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_TAG_INTR2_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_tag_intr2_enable( +u8 v_fifo_tag_intr2_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_fifo_tag_intr2_u8 <= SMI130_MAX_VALUE_FIFO_INTR) { + /* write the fifo tag interrupt2*/ + com_rslt = smi130_set_input_enable(1, + v_fifo_tag_intr2_u8); + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_TAG_INTR2_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_TAG_INTR2_ENABLE, + v_fifo_tag_intr2_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_TAG_INTR2_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API get FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_tag_intr1_enable( +u8 *v_fifo_tag_intr1_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read fifo tag interrupt*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_TAG_INTR1_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_tag_intr1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_TAG_INTR1_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_tag_intr1_enable( +u8 v_fifo_tag_intr1_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_fifo_tag_intr1_u8 <= SMI130_MAX_VALUE_FIFO_INTR) { + /* write the fifo tag interrupt*/ + com_rslt = smi130_set_input_enable(SMI130_INIT_VALUE, + v_fifo_tag_intr1_u8); + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_TAG_INTR1_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_TAG_INTR1_ENABLE, + v_fifo_tag_intr1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_TAG_INTR1_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_header_enable( +u8 *v_fifo_header_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read fifo header */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_HEADER_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_header_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_HEADER_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_header_enable( +u8 v_fifo_header_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_fifo_header_u8 <= SMI130_MAX_VALUE_FIFO_HEADER) { + /* write the fifo header */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_HEADER_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_HEADER_ENABLE, + v_fifo_header_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_HEADER_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_mag_enable( +u8 *v_fifo_mag_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the fifo mag enable*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_MAG_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_mag_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_MAG_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_mag_enable( +u8 v_fifo_mag_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_fifo_mag_u8 <= SMI130_MAX_VALUE_FIFO_MAG) { + /* write the fifo mag enable*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_FIFO_MAG_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_MAG_ENABLE, + v_fifo_mag_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_FIFO_MAG_ENABLE__REG, + &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_accel_enable( +u8 *v_fifo_accel_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel fifo enable*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_ACCEL_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_accel_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_ACCEL_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_accel_enable( +u8 v_fifo_accel_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_fifo_accel_u8 <= SMI130_MAX_VALUE_FIFO_ACCEL) { + /* write the fifo mag enables*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_ACCEL_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_ACCEL_ENABLE, v_fifo_accel_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_ACCEL_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_gyro_enable( +u8 *v_fifo_gyro_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read fifo gyro enable */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_GYRO_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_gyro_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_GYRO_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_gyro_enable( +u8 v_fifo_gyro_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_fifo_gyro_u8 <= SMI130_MAX_VALUE_FIFO_GYRO) { + /* write fifo gyro enable*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_FIFO_GYRO_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FIFO_GYRO_ENABLE, v_fifo_gyro_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FIFO_GYRO_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_device_addr( +u8 *v_i2c_device_addr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the mag I2C device address*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_I2C_DEVICE_ADDR__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_device_addr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_I2C_DEVICE_ADDR); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_i2c_device_addr( +u8 v_i2c_device_addr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the mag I2C device address*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_I2C_DEVICE_ADDR__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_I2C_DEVICE_ADDR, + v_i2c_device_addr_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_I2C_DEVICE_ADDR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_burst( +u8 *v_mag_burst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read mag burst mode length*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_BURST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_burst_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_MAG_BURST); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_burst( +u8 v_mag_burst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write mag burst mode length*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_BURST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_MAG_BURST, v_mag_burst_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_MAG_BURST__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_offset( +u8 *v_mag_offset_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_OFFSET__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_offset_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_MAG_OFFSET); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_offset( +u8 v_mag_offset_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_OFFSET__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_MAG_OFFSET, v_mag_offset_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_OFFSET__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } +return com_rslt; +} +/*! + * @brief This API is used to read + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_manual_enable( +u8 *v_mag_manual_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read mag manual */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_MANUAL_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_manual_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_MAG_MANUAL_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_manual_enable( +u8 v_mag_manual_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the mag manual*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_MANUAL_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + if (com_rslt == SUCCESS) { + /* set the bit of mag manual enable*/ + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_MAG_MANUAL_ENABLE, v_mag_manual_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130->dev_addr, + SMI130_USER_MAG_MANUAL_ENABLE__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + if (com_rslt == SUCCESS) + p_smi130->mag_manual_enable = v_mag_manual_u8; + else + p_smi130->mag_manual_enable = E_SMI130_COMM_RES; + } +return com_rslt; +} +/*! + * @brief This API is used to read data + * magnetometer address to read from the register 0x4D bit 0 to 7 + * @brief It used to provide mag read address of auxiliary mag + * + * + * + * + * @param v_mag_read_addr_u8 : The value of address need to be read + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_read_addr( +u8 *v_mag_read_addr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the written address*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_READ_ADDR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_read_addr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_READ_ADDR); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4D bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_read_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_read_addr( +u8 v_mag_read_addr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the mag read address*/ + com_rslt = + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130->dev_addr, + SMI130_USER_READ_ADDR__REG, &v_mag_read_addr_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_write_addr( +u8 *v_mag_write_addr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the address of last written */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_WRITE_ADDR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_write_addr_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_WRITE_ADDR); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_write_addr( +u8 v_mag_write_addr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the data of mag address to write data */ + com_rslt = + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130->dev_addr, + SMI130_USER_WRITE_ADDR__REG, &v_mag_write_addr_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_write_data( +u8 *v_mag_write_data_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_WRITE_DATA__REG, &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_write_data_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_WRITE_DATA); + } + return com_rslt; +} +/*! + * @brief This API is used to set magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_write_data( +u8 v_mag_write_data_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130->dev_addr, + SMI130_USER_WRITE_DATA__REG, &v_mag_write_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_ANY_MOTION_X_ENABLE + * 1 | SMI130_ANY_MOTION_Y_ENABLE + * 2 | SMI130_ANY_MOTION_Z_ENABLE + * 3 | SMI130_DOUBLE_TAP_ENABLE + * 4 | SMI130_SINGLE_TAP_ENABLE + * 5 | SMI130_ORIENT_ENABLE + * 6 | SMI130_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_enable_0( +u8 v_enable_u8, u8 *v_intr_enable_zero_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* select interrupt to read*/ + switch (v_enable_u8) { + case SMI130_ANY_MOTION_X_ENABLE: + /* read the any motion interrupt x data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE); + break; + case SMI130_ANY_MOTION_Y_ENABLE: + /* read the any motion interrupt y data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE); + break; + case SMI130_ANY_MOTION_Z_ENABLE: + /* read the any motion interrupt z data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE); + break; + case SMI130_DOUBLE_TAP_ENABLE: + /* read the double tap interrupt data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE); + break; + case SMI130_SINGLE_TAP_ENABLE: + /* read the single tap interrupt data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE); + break; + case SMI130_ORIENT_ENABLE: + /* read the orient_mbl interrupt data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE); + break; + case SMI130_FLAT_ENABLE: + /* read the flat interrupt data */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to set + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_ANY_MOTION_X_ENABLE + * 1 | SMI130_ANY_MOTION_Y_ENABLE + * 2 | SMI130_ANY_MOTION_Z_ENABLE + * 3 | SMI130_DOUBLE_TAP_ENABLE + * 4 | SMI130_SINGLE_TAP_ENABLE + * 5 | SMI130_ORIENT_ENABLE + * 6 | SMI130_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_enable_0( +u8 v_enable_u8, u8 v_intr_enable_zero_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_enable_u8) { + case SMI130_ANY_MOTION_X_ENABLE: + /* write any motion x*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_ANY_MOTION_Y_ENABLE: + /* write any motion y*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_ANY_MOTION_Z_ENABLE: + /* write any motion z*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_DOUBLE_TAP_ENABLE: + /* write double tap*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_SINGLE_TAP_ENABLE: + /* write single tap */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_ORIENT_ENABLE: + /* write orient_mbl interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_FLAT_ENABLE: + /* write flat interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief This API is used to read + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_HIGH_G_X_ENABLE + * 1 | SMI130_HIGH_G_Y_ENABLE + * 2 | SMI130_HIGH_G_Z_ENABLE + * 3 | SMI130_LOW_G_ENABLE + * 4 | SMI130_DATA_RDY_ENABLE + * 5 | SMI130_FIFO_FULL_ENABLE + * 6 | SMI130_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_enable_1( +u8 v_enable_u8, u8 *v_intr_enable_1_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_enable_u8) { + case SMI130_HIGH_G_X_ENABLE: + /* read high_g_x interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE); + break; + case SMI130_HIGH_G_Y_ENABLE: + /* read high_g_y interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE); + break; + case SMI130_HIGH_G_Z_ENABLE: + /* read high_g_z interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE); + break; + case SMI130_LOW_G_ENABLE: + /* read low_g interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE); + break; + case SMI130_DATA_RDY_ENABLE: + /* read data ready interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE); + break; + case SMI130_FIFO_FULL_ENABLE: + /* read fifo full interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE); + break; + case SMI130_FIFO_WM_ENABLE: + /* read fifo water mark interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to set + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_HIGH_G_X_ENABLE + * 1 | SMI130_HIGH_G_Y_ENABLE + * 2 | SMI130_HIGH_G_Z_ENABLE + * 3 | SMI130_LOW_G_ENABLE + * 4 | SMI130_DATA_RDY_ENABLE + * 5 | SMI130_FIFO_FULL_ENABLE + * 6 | SMI130_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_enable_1( +u8 v_enable_u8, u8 v_intr_enable_1_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_enable_u8) { + case SMI130_HIGH_G_X_ENABLE: + /* write high_g_x interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_HIGH_G_Y_ENABLE: + /* write high_g_y interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_HIGH_G_Z_ENABLE: + /* write high_g_z interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_LOW_G_ENABLE: + /* write low_g interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_DATA_RDY_ENABLE: + /* write data ready interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_FIFO_FULL_ENABLE: + /* write fifo full interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_FIFO_WM_ENABLE: + /* write fifo water mark interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_NOMOTION_X_ENABLE + * 1 | SMI130_NOMOTION_Y_ENABLE + * 2 | SMI130_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_enable_2( +u8 v_enable_u8, u8 *v_intr_enable_2_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_enable_u8) { + case SMI130_NOMOTION_X_ENABLE: + /* read no motion x */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_2_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE); + break; + case SMI130_NOMOTION_Y_ENABLE: + /* read no motion y */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_2_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE); + break; + case SMI130_NOMOTION_Z_ENABLE: + /* read no motion z */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_2_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to set + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_NOMOTION_X_ENABLE + * 1 | SMI130_NOMOTION_Y_ENABLE + * 2 | SMI130_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_enable_2( +u8 v_enable_u8, u8 v_intr_enable_2_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_enable_u8) { + case SMI130_NOMOTION_X_ENABLE: + /* write no motion x */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE, + v_intr_enable_2_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_NOMOTION_Y_ENABLE: + /* write no motion y */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE, + v_intr_enable_2_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_NOMOTION_Z_ENABLE: + /* write no motion z */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE, + v_intr_enable_2_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief This API is used to read + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_step_detector_enable( +u8 *v_step_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the step detector interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_step_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API is used to set + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_detector_enable( +u8 v_step_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE, + v_step_intr_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | SMI130_INTR1_EDGE_CTRL + * 1 | SMI130_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_EDGE + * 0x00 | SMI130_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_edge_ctrl( +u8 v_channel_u8, u8 *v_intr_edge_ctrl_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_EDGE_CTRL: + /* read the edge trigger interrupt1*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_EDGE_CTRL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_edge_ctrl_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_EDGE_CTRL); + break; + case SMI130_INTR2_EDGE_CTRL: + /* read the edge trigger interrupt2*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_EDGE_CTRL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_edge_ctrl_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_EDGE_CTRL); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | SMI130_INTR1_EDGE_CTRL + * 1 | SMI130_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_EDGE + * 0x00 | SMI130_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_edge_ctrl( +u8 v_channel_u8, u8 v_intr_edge_ctrl_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_EDGE_CTRL: + /* write the edge trigger interrupt1*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_EDGE_CTRL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_EDGE_CTRL, + v_intr_edge_ctrl_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_EDGE_CTRL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_EDGE_CTRL: + /* write the edge trigger interrupt2*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_EDGE_CTRL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_EDGE_CTRL, + v_intr_edge_ctrl_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_EDGE_CTRL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used for get the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_LEVEL + * 1 | SMI130_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_LEVEL_HIGH + * 0x00 | SMI130_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_level( +u8 v_channel_u8, u8 *v_intr_level_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_LEVEL: + /* read the interrupt1 level*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_LEVEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_level_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_LEVEL); + break; + case SMI130_INTR2_LEVEL: + /* read the interrupt2 level*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_LEVEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_level_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_LEVEL); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used for set the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_LEVEL + * 1 | SMI130_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_LEVEL_HIGH + * 0x00 | SMI130_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_level( +u8 v_channel_u8, u8 v_intr_level_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_LEVEL: + /* write the interrupt1 level*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_LEVEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_LEVEL, v_intr_level_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_LEVEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_LEVEL: + /* write the interrupt2 level*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_LEVEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_LEVEL, v_intr_level_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_LEVEL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used to get configured output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_OPEN_DRAIN + * 0x00 | SMI130_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_output_type( +u8 v_channel_u8, u8 *v_intr_output_type_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_OUTPUT_TYPE: + /* read the output type of interrupt1*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_OUTPUT_TYPE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_output_type_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_OUTPUT_TYPE); + break; + case SMI130_INTR2_OUTPUT_TYPE: + /* read the output type of interrupt2*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_OUTPUT_TYPE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_output_type_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_OUTPUT_TYPE); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used to set output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_OPEN_DRAIN + * 0x00 | SMI130_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_output_type( +u8 v_channel_u8, u8 v_intr_output_type_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_OUTPUT_TYPE: + /* write the output type of interrupt1*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_OUTPUT_TYPE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_OUTPUT_TYPE, + v_intr_output_type_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_OUTPUT_TYPE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_OUTPUT_TYPE: + /* write the output type of interrupt2*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_OUTPUT_TYPE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_OUTPUT_TYPE, + v_intr_output_type_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_OUTPUT_TYPE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief API used to get the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_output_enable( +u8 v_channel_u8, u8 *v_output_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_OUTPUT_ENABLE: + /* read the output enable of interrupt1*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_OUTPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_output_enable_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_OUTPUT_ENABLE); + break; + case SMI130_INTR2_OUTPUT_ENABLE: + /* read the output enable of interrupt2*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_OUTPUT_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_output_enable_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_OUTPUT_EN); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief API used to set the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_output_enable( +u8 v_channel_u8, u8 v_output_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_OUTPUT_ENABLE: + /* write the output enable of interrupt1*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_OUTPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_OUTPUT_ENABLE, + v_output_enable_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_OUTPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_OUTPUT_ENABLE: + /* write the output enable of interrupt2*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_OUTPUT_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_OUTPUT_EN, + v_output_enable_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_OUTPUT_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! +* @brief This API is used to get the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orient_mblation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* SMI130_LATCH_DUR_NONE | 0x00 +* SMI130_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* SMI130_LATCH_DUR_625_MICRO_SEC | 0x02 +* SMI130_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* SMI130_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* SMI130_LATCH_DUR_5_MILLI_SEC | 0x05 +* SMI130_LATCH_DUR_10_MILLI_SEC | 0x06 +* SMI130_LATCH_DUR_20_MILLI_SEC | 0x07 +* SMI130_LATCH_DUR_40_MILLI_SEC | 0x08 +* SMI130_LATCH_DUR_80_MILLI_SEC | 0x09 +* SMI130_LATCH_DUR_160_MILLI_SEC | 0x0A +* SMI130_LATCH_DUR_320_MILLI_SEC | 0x0B +* SMI130_LATCH_DUR_640_MILLI_SEC | 0x0C +* SMI130_LATCH_DUR_1_28_SEC | 0x0D +* SMI130_LATCH_DUR_2_56_SEC | 0x0E +* SMI130_LATCHED | 0x0F +* +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_latch_intr( +u8 *v_latch_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the latch duration value */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_LATCH__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_latch_intr_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LATCH); + } + return com_rslt; +} +/*! +* @brief This API is used to set the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orient_mblation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* SMI130_LATCH_DUR_NONE | 0x00 +* SMI130_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* SMI130_LATCH_DUR_625_MICRO_SEC | 0x02 +* SMI130_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* SMI130_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* SMI130_LATCH_DUR_5_MILLI_SEC | 0x05 +* SMI130_LATCH_DUR_10_MILLI_SEC | 0x06 +* SMI130_LATCH_DUR_20_MILLI_SEC | 0x07 +* SMI130_LATCH_DUR_40_MILLI_SEC | 0x08 +* SMI130_LATCH_DUR_80_MILLI_SEC | 0x09 +* SMI130_LATCH_DUR_160_MILLI_SEC | 0x0A +* SMI130_LATCH_DUR_320_MILLI_SEC | 0x0B +* SMI130_LATCH_DUR_640_MILLI_SEC | 0x0C +* SMI130_LATCH_DUR_1_28_SEC | 0x0D +* SMI130_LATCH_DUR_2_56_SEC | 0x0E +* SMI130_LATCHED | 0x0F +* +* +* + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error +* +* +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_latch_intr(u8 v_latch_intr_u8) +{ + u8 v_data_u8 = SMI130_INIT_VALUE; + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_latch_intr_u8 <= SMI130_MAX_LATCH_INTR) { + /* write the latch duration value */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_LATCH__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LATCH, v_latch_intr_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_LATCH__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief API used to get input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | SMI130_INTR1_INPUT_ENABLE + * 1 | SMI130_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_input_enable( +u8 v_channel_u8, u8 *v_input_en_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read input enable of interrup1 and interrupt2*/ + case SMI130_INTR1_INPUT_ENABLE: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_INPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_input_en_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_INPUT_ENABLE); + break; + case SMI130_INTR2_INPUT_ENABLE: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_INPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_input_en_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_INPUT_ENABLE); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used to set input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | SMI130_INTR1_INPUT_ENABLE + * 1 | SMI130_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_input_enable( +u8 v_channel_u8, u8 v_input_en_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write input enable of interrup1 and interrupt2*/ + case SMI130_INTR1_INPUT_ENABLE: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_INPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR1_INPUT_ENABLE, v_input_en_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR1_INPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_INPUT_ENABLE: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_INPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR2_INPUT_ENABLE, v_input_en_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR2_INPUT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief reads the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_LOW_G + * 1 | SMI130_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g( +u8 v_channel_u8, u8 *v_intr_low_g_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the low_g interrupt */ + case SMI130_INTR1_MAP_LOW_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_low_g_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_LOW_G); + break; + case SMI130_INTR2_MAP_LOW_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_low_g_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_LOW_G); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief set the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_LOW_G + * 1 | SMI130_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g( +u8 v_channel_u8, u8 v_intr_low_g_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +u8 v_step_cnt_stat_u8 = SMI130_INIT_VALUE; +u8 v_step_det_stat_u8 = SMI130_INIT_VALUE; + +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* check the step detector interrupt enable status*/ + com_rslt = smi130_get_step_detector_enable(&v_step_det_stat_u8); + /* disable the step detector interrupt */ + if (v_step_det_stat_u8 != SMI130_INIT_VALUE) + com_rslt += smi130_set_step_detector_enable(SMI130_INIT_VALUE); + /* check the step counter interrupt enable status*/ + com_rslt += smi130_get_step_counter_enable(&v_step_cnt_stat_u8); + /* disable the step counter interrupt */ + if (v_step_cnt_stat_u8 != SMI130_INIT_VALUE) + com_rslt += smi130_set_step_counter_enable( + SMI130_INIT_VALUE); + switch (v_channel_u8) { + /* write the low_g interrupt*/ + case SMI130_INTR1_MAP_LOW_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_LOW_G, v_intr_low_g_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_LOW_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_LOW_G, v_intr_low_g_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_HIGH_G + * 1 | SMI130_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g( +u8 v_channel_u8, u8 *v_intr_high_g_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the high_g interrupt*/ + switch (v_channel_u8) { + case SMI130_INTR1_MAP_HIGH_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_HIGH_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_high_g_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_HIGH_G); + break; + case SMI130_INTR2_MAP_HIGH_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_HIGH_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_high_g_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_HIGH_G); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_HIGH_G + * 1 | SMI130_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g( +u8 v_channel_u8, u8 v_intr_high_g_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the high_g interrupt*/ + case SMI130_INTR1_MAP_HIGH_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_HIGH_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_HIGH_G, v_intr_high_g_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_HIGH_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_HIGH_G: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_HIGH_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_HIGH_G, v_intr_high_g_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_HIGH_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ANY_MOTION + * 1 | SMI130_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_any_motion( +u8 v_channel_u8, u8 *v_intr_any_motion_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the any motion interrupt */ + case SMI130_INTR1_MAP_ANY_MOTION: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_any_motion_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION); + break; + case SMI130_INTR2_MAP_ANY_MOTION: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_any_motion_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ANY_MOTION + * 1 | SMI130_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_any_motion( +u8 v_channel_u8, u8 v_intr_any_motion_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +u8 sig_mot_stat = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the status of significant motion interrupt */ + com_rslt = smi130_get_intr_significant_motion_select(&sig_mot_stat); + /* disable the significant motion interrupt */ + if (sig_mot_stat != SMI130_INIT_VALUE) + com_rslt += smi130_set_intr_significant_motion_select( + SMI130_INIT_VALUE); + switch (v_channel_u8) { + /* write the any motion interrupt */ + case SMI130_INTR1_MAP_ANY_MOTION: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION, + v_intr_any_motion_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_ANY_MOTION: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION, + v_intr_any_motion_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_NOMO + * 1 | SMI130_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_nomotion( +u8 v_channel_u8, u8 *v_intr_nomotion_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the no motion interrupt*/ + case SMI130_INTR1_MAP_NOMO: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_NOMOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_nomotion_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_NOMOTION); + break; + case SMI130_INTR2_MAP_NOMO: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_NOMOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_nomotion_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_NOMOTION); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_NOMO + * 1 | SMI130_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_nomotion( +u8 v_channel_u8, u8 v_intr_nomotion_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the no motion interrupt*/ + case SMI130_INTR1_MAP_NOMO: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_NOMOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_NOMOTION, + v_intr_nomotion_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_NOMOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_NOMO: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_NOMOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_NOMOTION, + v_intr_nomotion_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_NOMOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DOUBLE_TAP + * 1 | SMI130_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_double_tap( +u8 v_channel_u8, u8 *v_intr_double_tap_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + case SMI130_INTR1_MAP_DOUBLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_double_tap_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP); + break; + case SMI130_INTR2_MAP_DOUBLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_double_tap_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DOUBLE_TAP + * 1 | SMI130_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_double_tap( +u8 v_channel_u8, u8 v_intr_double_tap_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* set the double tap interrupt */ + case SMI130_INTR1_MAP_DOUBLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP, + v_intr_double_tap_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_DOUBLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP, + v_intr_double_tap_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_SINGLE_TAP + * 1 | SMI130_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_single_tap( +u8 v_channel_u8, u8 *v_intr_single_tap_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* reads the single tap interrupt*/ + case SMI130_INTR1_MAP_SINGLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_single_tap_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP); + break; + case SMI130_INTR2_MAP_SINGLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_single_tap_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_SINGLE_TAP + * 1 | SMI130_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_single_tap( +u8 v_channel_u8, u8 v_intr_single_tap_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the single tap interrupt */ + case SMI130_INTR1_MAP_SINGLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP, + v_intr_single_tap_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_SINGLE_TAP: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP, + v_intr_single_tap_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient_mbl interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ORIENT + * 1 | SMI130_INTR2_MAP_ORIENT + * + * @param v_intr_orient_mbl_u8 : The value of orient_mbl enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl( +u8 v_channel_u8, u8 *v_intr_orient_mbl_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the orient_mblation interrupt*/ + case SMI130_INTR1_MAP_ORIENT: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_ORIENT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_orient_mbl_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_ORIENT); + break; + case SMI130_INTR2_MAP_ORIENT: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_ORIENT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_orient_mbl_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_ORIENT); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient_mbl interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ORIENT + * 1 | SMI130_INTR2_MAP_ORIENT + * + * @param v_intr_orient_mbl_u8 : The value of orient_mbl enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl( +u8 v_channel_u8, u8 v_intr_orient_mbl_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the orient_mblation interrupt*/ + case SMI130_INTR1_MAP_ORIENT: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_ORIENT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_ORIENT, v_intr_orient_mbl_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_ORIENT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_ORIENT: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_ORIENT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_ORIENT, v_intr_orient_mbl_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_ORIENT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief Reads the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FLAT + * 1 | SMI130_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat( +u8 v_channel_u8, u8 *v_intr_flat_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the flat interrupt*/ + case SMI130_INTR1_MAP_FLAT: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_FLAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_flat_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_FLAT); + break; + case SMI130_INTR2_MAP_FLAT: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_FLAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_flat_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_FLAT); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief Write the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FLAT + * 1 | SMI130_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat( +u8 v_channel_u8, u8 v_intr_flat_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the flat interrupt */ + case SMI130_INTR1_MAP_FLAT: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_0_INTR1_FLAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_0_INTR1_FLAT, + v_intr_flat_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_MAP_0_INTR1_FLAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_FLAT: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_2_INTR2_FLAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_2_INTR2_FLAT, + v_intr_flat_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_MAP_2_INTR2_FLAT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Reads PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_PMUTRIG + * 1 | SMI130_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_pmu_trig( +u8 v_channel_u8, u8 *v_intr_pmu_trig_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the pmu trigger interrupt*/ + case SMI130_INTR1_MAP_PMUTRIG: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_pmu_trig_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG); + break; + case SMI130_INTR2_MAP_PMUTRIG: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_pmu_trig_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_PMUTRIG + * 1 | SMI130_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | trigger enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_pmu_trig( +u8 v_channel_u8, u8 v_intr_pmu_trig_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the pmu trigger interrupt */ + case SMI130_INTR1_MAP_PMUTRIG: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG, + v_intr_pmu_trig_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_PMUTRIG: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG, + v_intr_pmu_trig_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_FULL + * 1 | SMI130_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_fifo_full( +u8 v_channel_u8, u8 *v_intr_fifo_full_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the fifo full interrupt */ + case SMI130_INTR1_MAP_FIFO_FULL: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_full_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL); + break; + case SMI130_INTR2_MAP_FIFO_FULL: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_full_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_FULL + * 1 | SMI130_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_fifo_full( +u8 v_channel_u8, u8 v_intr_fifo_full_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the fifo full interrupt */ + case SMI130_INTR1_MAP_FIFO_FULL: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL, + v_intr_fifo_full_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_FIFO_FULL: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL, + v_intr_fifo_full_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Reads FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_WM + * 1 | SMI130_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_fifo_wm( +u8 v_channel_u8, u8 *v_intr_fifo_wm_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the fifo water mark interrupt */ + case SMI130_INTR1_MAP_FIFO_WM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_wm_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM); + break; + case SMI130_INTR2_MAP_FIFO_WM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_wm_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_WM + * 1 | SMI130_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_fifo_wm( +u8 v_channel_u8, u8 v_intr_fifo_wm_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the fifo water mark interrupt */ + case SMI130_INTR1_MAP_FIFO_WM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM, + v_intr_fifo_wm_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_FIFO_WM: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM, + v_intr_fifo_wm_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, + SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Reads Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DATA_RDY + * 1 | SMI130_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_data_rdy( +u8 v_channel_u8, u8 *v_intr_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /*Read Data Ready interrupt*/ + case SMI130_INTR1_MAP_DATA_RDY: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_data_rdy_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY); + break; + case SMI130_INTR2_MAP_DATA_RDY: + com_rslt = p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_data_rdy_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DATA_RDY + * 1 | SMI130_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_data_rdy( +u8 v_channel_u8, u8 v_intr_data_rdy_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + switch (v_channel_u8) { + /*Write Data Ready interrupt*/ + case SMI130_INTR1_MAP_DATA_RDY: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY, + v_intr_data_rdy_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case SMI130_INTR2_MAP_DATA_RDY: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY, + v_intr_data_rdy_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC(p_smi130-> + dev_addr, SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief This API reads data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_source(u8 *v_tap_source_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the tap source interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_source_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE); + } + return com_rslt; +} + /*! + * @brief This API write data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_source( +u8 v_tap_source_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_tap_source_u8 <= SMI130_MAX_VALUE_SOURCE_INTR) { + /* write the tap source interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE, + v_tap_source_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API Reads Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_high_source( +u8 *v_low_high_source_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the high_low_g source interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_low_high_source_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE); + } + return com_rslt; +} +/*! + * @brief This API write Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_high_source( +u8 v_low_high_source_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_low_high_source_u8 <= SMI130_MAX_VALUE_SOURCE_INTR) { + /* write the high_low_g source interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE, + v_low_high_source_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API reads Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_motion_source( +u8 *v_motion_source_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the any/no motion interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_motion_source_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE); + } + return com_rslt; +} + /*! + * @brief This API write Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_motion_source( +u8 v_motion_source_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_motion_source_u8 <= SMI130_MAX_VALUE_SOURCE_INTR) { + /* write the any/no motion interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE, + v_motion_source_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API is used to read the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_durn( +u8 *v_low_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the low_g interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_durn_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_0_INTR_LOW_DURN); + } + return com_rslt; +} + /*! + * @brief This API is used to write the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_durn(u8 v_low_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the low_g interrupt */ + com_rslt = p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__REG, + &v_low_g_durn_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_thres( +u8 *v_low_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read low_g threshold */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_thres_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_1_INTR_LOW_THRES); + } + return com_rslt; +} +/*! + * @brief This API is used to write Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_thres( +u8 v_low_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write low_g threshold */ + com_rslt = p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__REG, + &v_low_g_thres_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} + /*! + * @brief This API Reads Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_hyst( +u8 *v_low_hyst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read low_g hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_low_hyst_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST); + } + return com_rslt; +} + /*! + * @brief This API write Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_hyst( +u8 v_low_hyst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write low_g hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST, + v_low_hyst_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API reads Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_mode(u8 *v_low_g_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /*read Low-g interrupt mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_mode_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE); + } + return com_rslt; +} +/*! + * @brief This API write Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_mode( +u8 v_low_g_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_low_g_mode_u8 <= SMI130_MAX_VALUE_LOW_G_MODE) { + /*write Low-g interrupt mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE, + v_low_g_mode_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g_hyst( +u8 *v_high_g_hyst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read high_g hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_hyst_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST); + } + return com_rslt; +} +/*! + * @brief This API write High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g_hyst( +u8 v_high_g_hyst_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write high_g hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST, + v_high_g_hyst_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } +return com_rslt; +} +/*! + * @brief This API is used to read Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g_durn( +u8 *v_high_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read high_g duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_durn_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN); + } + return com_rslt; +} +/*! + * @brief This API is used to write Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g_durn( +u8 v_high_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write high_g duration*/ + com_rslt = p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__REG, + &v_high_g_durn_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g_thres( +u8 *v_high_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_thres_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES); + } + return com_rslt; +} +/*! + * @brief This API is used to write Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g_thres( +u8 v_high_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + com_rslt = p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__REG, + &v_high_g_thres_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API reads any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_any_motion_durn( +u8 *v_any_motion_durn_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read any motion duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_durn_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN); + } + return com_rslt; +} +/*! + * @brief This API write any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_any_motion_durn( +u8 v_any_motion_durn_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write any motion duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN, + v_any_motion_durn_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_slow_no_motion_durn( +u8 *v_slow_no_motion_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read slow no motion duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_slow_no_motion_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN); + } +return com_rslt; +} + /*! + * @brief This API write Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_slow_no_motion_durn( +u8 v_slow_no_motion_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write slow no motion duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN, + v_slow_no_motion_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } +} +return com_rslt; +} +/*! + * @brief This API is used to read threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_any_motion_thres( +u8 *v_any_motion_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read any motion threshold*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_thres_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES); + } + return com_rslt; +} +/*! + * @brief This API is used to write threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_any_motion_thres( +u8 v_any_motion_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write any motion threshold*/ + com_rslt = p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__REG, + &v_any_motion_thres_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} + /*! + * @brief This API is used to read threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_slow_no_motion_thres( +u8 *v_slow_no_motion_thres_u8) +{ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read slow no motion threshold*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_slow_no_motion_thres_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES); + } +return com_rslt; +} + /*! + * @brief This API is used to write threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_slow_no_motion_thres( +u8 v_slow_no_motion_thres_u8) +{ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write slow no motion threshold*/ + com_rslt = p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__REG, + &v_slow_no_motion_thres_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } +return com_rslt; +} + /*! + * @brief This API is used to read + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_slow_no_motion_select( +u8 *v_intr_slow_no_motion_select_u8) +{ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read slow no motion select*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_slow_no_motion_select_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT); + } +return com_rslt; +} + /*! + * @brief This API is used to write + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_slow_no_motion_select( +u8 v_intr_slow_no_motion_select_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; +} else { +if (v_intr_slow_no_motion_select_u8 <= SMI130_MAX_VALUE_NO_MOTION) { + /* write slow no motion select*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT, + v_intr_slow_no_motion_select_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } +} else { +com_rslt = E_SMI130_OUT_OF_RANGE; +} +} +return com_rslt; +} + /*! + * @brief This API is used to select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_significant_motion_select( +u8 *v_intr_significant_motion_select_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the significant or any motion interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_significant_motion_select_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT); + } + return com_rslt; +} + /*! + * @brief This API is used to write, select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_significant_motion_select( +u8 v_intr_significant_motion_select_u8) +{ +/* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_intr_significant_motion_select_u8 <= + SMI130_MAX_VALUE_SIGNIFICANT_MOTION) { + /* write the significant or any motion interrupt*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT, + v_intr_significant_motion_select_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API is used to read + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_significant_motion_skip( +u8 *v_int_sig_mot_skip_u8) +{ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read significant skip time*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_int_sig_mot_skip_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP); + } + return com_rslt; +} + /*! + * @brief This API is used to write + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_significant_motion_skip( +u8 v_int_sig_mot_skip_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_int_sig_mot_skip_u8 <= SMI130_MAX_UNDER_SIG_MOTION) { + /* write significant skip time*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP, + v_int_sig_mot_skip_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API is used to read + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_significant_motion_proof( +u8 *v_significant_motion_proof_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read significant proof time */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_significant_motion_proof_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF); + } + return com_rslt; +} + /*! + * @brief This API is used to write + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_significant_motion_proof( +u8 v_significant_motion_proof_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_significant_motion_proof_u8 + <= SMI130_MAX_UNDER_SIG_MOTION) { + /* write significant proof time */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF, + v_significant_motion_proof_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_DURN_50MS + * 0x01 | SMI130_TAP_DURN_100MS + * 0x03 | SMI130_TAP_DURN_150MS + * 0x04 | SMI130_TAP_DURN_200MS + * 0x05 | SMI130_TAP_DURN_250MS + * 0x06 | SMI130_TAP_DURN_375MS + * 0x07 | SMI130_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_durn( +u8 *v_tap_durn_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_durn_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_INTR_TAP_0_INTR_TAP_DURN); + } + return com_rslt; +} +/*! + * @brief This API is used to write the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_DURN_50MS + * 0x01 | SMI130_TAP_DURN_100MS + * 0x03 | SMI130_TAP_DURN_150MS + * 0x04 | SMI130_TAP_DURN_200MS + * 0x05 | SMI130_TAP_DURN_250MS + * 0x06 | SMI130_TAP_DURN_375MS + * 0x07 | SMI130_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_durn( +u8 v_tap_durn_u8) +{ + u8 v_data_u8 = SMI130_INIT_VALUE; + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_tap_durn_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_tap_durn_u8 <= SMI130_MAX_TAP_TURN) { + switch (v_tap_durn_u8) { + case SMI130_TAP_DURN_50MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_50MS; + break; + case SMI130_TAP_DURN_100MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_100MS; + break; + case SMI130_TAP_DURN_150MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_150MS; + break; + case SMI130_TAP_DURN_200MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_200MS; + break; + case SMI130_TAP_DURN_250MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_250MS; + break; + case SMI130_TAP_DURN_375MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_375MS; + break; + case SMI130_TAP_DURN_500MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_500MS; + break; + case SMI130_TAP_DURN_700MS: + v_data_tap_durn_u8 = SMI130_TAP_DURN_700MS; + break; + default: + break; + } + /* write tap duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_TAP_0_INTR_TAP_DURN, + v_data_tap_durn_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_DURN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_SHOCK_50MS + * 0x01 | SMI130_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_shock( +u8 *v_tap_shock_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap shock duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_shock_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK); + } + return com_rslt; +} + /*! + * @brief This API write the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_SHOCK_50MS + * 0x01 | SMI130_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_shock(u8 v_tap_shock_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_tap_shock_u8 <= SMI130_MAX_VALUE_TAP_SHOCK) { + /* write tap shock duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK, + v_tap_shock_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_QUIET_30MS + * 0x01 | SMI130_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_quiet( +u8 *v_tap_quiet_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap quiet duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_quiet_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET); + } + return com_rslt; +} +/*! + * @brief This API write + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_QUIET_30MS + * 0x01 | SMI130_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_quiet(u8 v_tap_quiet_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_tap_quiet_u8 <= SMI130_MAX_VALUE_TAP_QUIET) { + /* write tap quiet duration*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET, + v_tap_quiet_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_thres( +u8 *v_tap_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read tap threshold*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_TAP_1_INTR_TAP_THRES__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_thres_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_TAP_1_INTR_TAP_THRES); + } + return com_rslt; +} + /*! + * @brief This API write Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_thres( +u8 v_tap_thres_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write tap threshold*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_1_INTR_TAP_THRES__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_TAP_1_INTR_TAP_THRES, + v_tap_thres_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_TAP_1_INTR_TAP_THRES__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read the threshold for orient_mblation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mbl_mode_u8 : The value of threshold for orient_mblation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_mode( +u8 *v_orient_mbl_mode_u8) +{ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read orient_mblation threshold*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_mode_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE); + } + return com_rslt; +} + /*! + * @brief This API write the threshold for orient_mblation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mbl_mode_u8 : The value of threshold for orient_mblation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_mode( +u8 v_orient_mbl_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_orient_mbl_mode_u8 <= SMI130_MAX_ORIENT_MODE) { + /* write orient_mblation threshold*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE, + v_orient_mbl_mode_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read the orient_mbl blocking mode + * that is used for the generation of the orient_mblation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_mbl_blocking_u8 : The value of orient_mbl blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient_mbl is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_blocking( +u8 *v_orient_mbl_blocking_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read orient_mbl blocking mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_blocking_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING); + } + return com_rslt; +} +/*! + * @brief This API write the orient_mbl blocking mode + * that is used for the generation of the orient_mblation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_mbl_blocking_u8 : The value of orient_mbl blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient_mbl is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_blocking( +u8 v_orient_mbl_blocking_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_orient_mbl_blocking_u8 <= SMI130_MAX_ORIENT_BLOCKING) { + /* write orient_mbl blocking mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING, + v_orient_mbl_blocking_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} +return com_rslt; +} +/*! + * @brief This API read Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_mbl_hyst_u8 : The value of orient_mbl hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_hyst( +u8 *v_orient_mbl_hyst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read orient_mbl hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_hyst_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST); + } + return com_rslt; +} +/*! + * @brief This API write Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_mbl_hyst_u8 : The value of orient_mbl hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_hyst( +u8 v_orient_mbl_hyst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write orient_mbl hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST, + v_orient_mbl_hyst_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_mbl_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_theta( +u8 *v_orient_mbl_theta_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read Orient blocking angle*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_theta_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA); + } + return com_rslt; +} + /*! + * @brief This API write Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_mbl_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_theta( +u8 v_orient_mbl_theta_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_orient_mbl_theta_u8 <= SMI130_MAX_ORIENT_THETA) { + /* write Orient blocking angle*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA, + v_orient_mbl_theta_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} +return com_rslt; +} +/*! + * @brief This API read orient_mbl change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_mbl_ud_u8 : The value of orient_mbl change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orient_mblation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_ud_enable( +u8 *v_orient_mbl_ud_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read orient_mbl up/down enable*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_ud_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write orient_mbl change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_mbl_ud_u8 : The value of orient_mbl change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orient_mblation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_ud_enable( +u8 v_orient_mbl_ud_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_orient_mbl_ud_u8 <= SMI130_MAX_VALUE_ORIENT_UD) { + /* write orient_mbl up/down enable */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE, + v_orient_mbl_ud_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API read orient_mblation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_mbl_axes_u8 : The value of orient_mbl axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_mbl_ax_noex + * 0x01 | x = y, y = z, z = x|orient_mbl_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_axes_enable( +u8 *v_orient_mbl_axes_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read orient_mblation axes changes */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mbl_axes_u8 = SMI130_GET_BITSLICE + (v_data_u8, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX); + } + return com_rslt; +} + /*! + * @brief This API write orient_mblation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_mbl_axes_u8 : The value of orient_mbl axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_mbl_ax_noex + * 0x01 | x = y, y = z, z = x|orient_mbl_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_axes_enable( +u8 v_orient_mbl_axes_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_orient_mbl_axes_u8 <= SMI130_MAX_VALUE_ORIENT_AXES) { + /*write orient_mblation axes changes */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX, + v_orient_mbl_axes_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API read Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat_theta( +u8 *v_flat_theta_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read Flat angle*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_theta_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA); + } + return com_rslt; +} + /*! + * @brief This API write Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat_theta( +u8 v_flat_theta_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_flat_theta_u8 <= SMI130_MAX_FLAT_THETA) { + /* write Flat angle */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA, + v_flat_theta_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat_hold( +u8 *v_flat_hold_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read flat hold time*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_hold_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD); + } + return com_rslt; +} +/*! + * @brief This API write Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat_hold( +u8 v_flat_hold_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_flat_hold_u8 <= SMI130_MAX_FLAT_HOLD) { + /* write flat hold time*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD, + v_flat_hold_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat_hyst( +u8 *v_flat_hyst_u8) +{ + /* variable used to return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the flat hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_hyst_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST); + } + return com_rslt; +} +/*! + * @brief This API write flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat_hyst( +u8 v_flat_hyst_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_flat_hyst_u8 <= SMI130_MAX_FLAT_HYST) { + /* read the flat hysteresis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST, + v_flat_hyst_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_accel_z(u8 *v_foc_accel_z_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel offset compensation for z axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_accel_z_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_Z); + } + return com_rslt; +} + /*! + * @brief This API write accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_accel_z( +u8 v_foc_accel_z_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write the accel offset compensation for z axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_Z, + v_foc_accel_z_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API read accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_accel_y(u8 *v_foc_accel_y_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel offset compensation for y axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_accel_y_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_Y); + } + return com_rslt; +} +/*! + * @brief This API write accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x02 | -1g + * 0x03 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_accel_y(u8 v_foc_accel_y_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_foc_accel_y_u8 <= SMI130_MAX_ACCEL_FOC) { + /* write the accel offset compensation for y axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_Y, + v_foc_accel_y_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x02 | -1g + * 0x03 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_accel_x(u8 *v_foc_accel_x_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the accel offset compensation for x axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_accel_x_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_X); + } + return com_rslt; +} +/*! + * @brief This API write accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_accel_x(u8 v_foc_accel_x_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_foc_accel_x_u8 <= SMI130_MAX_ACCEL_FOC) { + /* write the accel offset compensation for x axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_X, + v_foc_accel_x_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API writes accel fast offset compensation + * from the register 0x69 bit 0 to 5 + * @brief This API writes each axis individually + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_u8: The value of accel offset compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_axis_u8: The value of accel offset axis selection + * value | axis + * ----------|------------------- + * 0 | FOC_X_AXIS + * 1 | FOC_Y_AXIS + * 2 | FOC_Z_AXIS + * + * @param v_accel_offset_s8: The accel offset value + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_foc_trigger(u8 v_axis_u8, +u8 v_foc_accel_u8, s8 *v_accel_offset_s8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +s8 v_status_s8 = SUCCESS; +u8 v_timeout_u8 = SMI130_INIT_VALUE; +s8 v_foc_accel_offset_x_s8 = SMI130_INIT_VALUE; +s8 v_foc_accel_offset_y_s8 = SMI130_INIT_VALUE; +s8 v_foc_accel_offset_z_s8 = SMI130_INIT_VALUE; +u8 focstatus = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; +} else { + v_status_s8 = smi130_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + switch (v_axis_u8) { + case FOC_X_AXIS: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_X, + v_foc_accel_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the + FOC need to write + 0x03 in the register 0x7e*/ + com_rslt += + smi130_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += + smi130_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH + && v_timeout_u8 < + SMI130_MAXIMUM_TIMEOUT)) { + p_smi130->delay_msec( + SMI130_DELAY_SETTLING_TIME); + com_rslt = smi130_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == SMI130_FOC_STAT_HIGH)) { + com_rslt += + smi130_get_accel_offset_compensation_xaxis( + &v_foc_accel_offset_x_s8); + *v_accel_offset_s8 = + v_foc_accel_offset_x_s8; + } + break; + case FOC_Y_AXIS: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_Y, + v_foc_accel_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC + need to write 0x03 + in the register 0x7e*/ + com_rslt += + smi130_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += + smi130_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH + && v_timeout_u8 < + SMI130_MAXIMUM_TIMEOUT)) { + p_smi130->delay_msec( + SMI130_DELAY_SETTLING_TIME); + com_rslt = smi130_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == SMI130_FOC_STAT_HIGH)) { + com_rslt += + smi130_get_accel_offset_compensation_yaxis( + &v_foc_accel_offset_y_s8); + *v_accel_offset_s8 = + v_foc_accel_offset_y_s8; + } + break; + case FOC_Z_AXIS: + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FOC_ACCEL_Z, + v_foc_accel_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC need to write + 0x03 in the register 0x7e*/ + com_rslt += + smi130_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += + smi130_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH + && v_timeout_u8 < + SMI130_MAXIMUM_TIMEOUT)) { + p_smi130->delay_msec( + SMI130_DELAY_SETTLING_TIME); + com_rslt = smi130_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == SMI130_FOC_STAT_HIGH)) { + com_rslt += + smi130_get_accel_offset_compensation_zaxis( + &v_foc_accel_offset_z_s8); + *v_accel_offset_s8 = + v_foc_accel_offset_z_s8; + } + break; + default: + break; + } + } else { + com_rslt = ERROR; + } +} +return com_rslt; +} +/*! + * @brief This API write fast accel offset compensation + * it writes all axis together.To the register 0x69 bit 0 to 5 + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_x_u8: The value of accel offset x compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_y_u8: The value of accel offset y compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_z_u8: The value of accel offset z compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_accel_off_x_s8: The value of accel offset x axis + * @param v_accel_off_y_s8: The value of accel offset y axis + * @param v_accel_off_z_s8: The value of accel offset z axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_accel_foc_trigger_xyz(u8 v_foc_accel_x_u8, +u8 v_foc_accel_y_u8, u8 v_foc_accel_z_u8, s8 *v_accel_off_x_s8, +s8 *v_accel_off_y_s8, s8 *v_accel_off_z_s8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 focx = SMI130_INIT_VALUE; +u8 focy = SMI130_INIT_VALUE; +u8 focz = SMI130_INIT_VALUE; +s8 v_foc_accel_offset_x_s8 = SMI130_INIT_VALUE; +s8 v_foc_accel_offset_y_s8 = SMI130_INIT_VALUE; +s8 v_foc_accel_offset_z_s8 = SMI130_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +u8 v_timeout_u8 = SMI130_INIT_VALUE; +u8 focstatus = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + v_status_s8 = smi130_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* foc x axis*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_X__REG, + &focx, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + focx = SMI130_SET_BITSLICE(focx, + SMI130_USER_FOC_ACCEL_X, + v_foc_accel_x_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_X__REG, + &focx, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + /* foc y axis*/ + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Y__REG, + &focy, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + focy = SMI130_SET_BITSLICE(focy, + SMI130_USER_FOC_ACCEL_Y, + v_foc_accel_y_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Y__REG, + &focy, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + /* foc z axis*/ + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Z__REG, + &focz, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + focz = SMI130_SET_BITSLICE(focz, + SMI130_USER_FOC_ACCEL_Z, + v_foc_accel_z_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_ACCEL_Z__REG, + &focz, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC need to + write 0x03 in the register 0x7e*/ + com_rslt += smi130_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += smi130_get_foc_rdy( + &focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH + && v_timeout_u8 < + SMI130_MAXIMUM_TIMEOUT)) { + p_smi130->delay_msec( + SMI130_DELAY_SETTLING_TIME); + com_rslt = smi130_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == SMI130_GEN_READ_WRITE_DATA_LENGTH)) { + com_rslt += + smi130_get_accel_offset_compensation_xaxis( + &v_foc_accel_offset_x_s8); + *v_accel_off_x_s8 = + v_foc_accel_offset_x_s8; + com_rslt += + smi130_get_accel_offset_compensation_yaxis( + &v_foc_accel_offset_y_s8); + *v_accel_off_y_s8 = + v_foc_accel_offset_y_s8; + com_rslt += + smi130_get_accel_offset_compensation_zaxis( + &v_foc_accel_offset_z_s8); + *v_accel_off_z_s8 = + v_foc_accel_offset_z_s8; + } + } else { + com_rslt = ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_gyro_enable( +u8 *v_foc_gyro_u8) +{ + /* used for return the status of bus communication */ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the gyro fast offset enable*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_FOC_GYRO_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_gyro_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_FOC_GYRO_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * @param v_gyro_off_x_s16 : The value of gyro fast offset x axis data + * @param v_gyro_off_y_s16 : The value of gyro fast offset y axis data + * @param v_gyro_off_z_s16 : The value of gyro fast offset z axis data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_gyro_enable( +u8 v_foc_gyro_u8, s16 *v_gyro_off_x_s16, +s16 *v_gyro_off_y_s16, s16 *v_gyro_off_z_s16) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +u8 v_timeout_u8 = SMI130_INIT_VALUE; +s16 offsetx = SMI130_INIT_VALUE; +s16 offsety = SMI130_INIT_VALUE; +s16 offsetz = SMI130_INIT_VALUE; +u8 focstatus = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + v_status_s8 = smi130_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_FOC_GYRO_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_FOC_GYRO_ENABLE, + v_foc_gyro_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_FOC_GYRO_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC need to write 0x03 + in the register 0x7e*/ + com_rslt += smi130_set_command_register + (START_FOC_ACCEL_GYRO); + + com_rslt += smi130_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != SMI130_FOC_STAT_HIGH + && v_timeout_u8 < + SMI130_MAXIMUM_TIMEOUT)) { + p_smi130->delay_msec( + SMI130_DELAY_SETTLING_TIME); + com_rslt = smi130_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == SMI130_FOC_STAT_HIGH)) { + com_rslt += + smi130_get_gyro_offset_compensation_xaxis + (&offsetx); + *v_gyro_off_x_s16 = offsetx; + + com_rslt += + smi130_get_gyro_offset_compensation_yaxis + (&offsety); + *v_gyro_off_y_s16 = offsety; + + com_rslt += + smi130_get_gyro_offset_compensation_zaxis( + &offsetz); + *v_gyro_off_z_s16 = offsetz; + } + } else { + com_rslt = ERROR; + } + } +return com_rslt; +} + /*! + * @brief This API read NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_nvm_prog_enable( +u8 *v_nvm_prog_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read NVM program*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_CONFIG_NVM_PROG_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_nvm_prog_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_CONFIG_NVM_PROG_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API write NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_nvm_prog_enable( +u8 v_nvm_prog_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_nvm_prog_u8 <= SMI130_MAX_VALUE_NVM_PROG) { + /* write the NVM program*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_CONFIG_NVM_PROG_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_CONFIG_NVM_PROG_ENABLE, + v_nvm_prog_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_CONFIG_NVM_PROG_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_spi3( +u8 *v_spi3_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read SPI mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_SPI3__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_spi3_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_SPI3); + } + return com_rslt; +} +/*! + * @brief This API write to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_spi3( +u8 v_spi3_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_spi3_u8 <= SMI130_MAX_VALUE_SPI3) { + /* write SPI mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_SPI3__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_SPI3, + v_spi3_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_SPI3__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_wdt_select( +u8 *v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read I2C watch dog timer */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_I2C_WDT_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_wdt_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_I2C_WDT_SELECT); + } + return com_rslt; +} +/*! + * @brief This API write I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_i2c_wdt_select( +u8 v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_i2c_wdt_u8 <= SMI130_MAX_VALUE_I2C_WDT) { + /* write I2C watch dog timer */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_I2C_WDT_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_I2C_WDT_SELECT, + v_i2c_wdt_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_I2C_WDT_SELECT__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_wdt_enable( +u8 *v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read i2c watch dog eneble */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_wdt_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_i2c_wdt_enable( +u8 v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_i2c_wdt_u8 <= SMI130_MAX_VALUE_I2C_WDT) { + /* write i2c watch dog eneble */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE, + v_i2c_wdt_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_if_mode( +u8 *v_if_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read if mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_IF_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_if_mode_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_IF_MODE); + } + return com_rslt; +} +/*! + * @brief This API write I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_if_mode( +u8 v_if_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_if_mode_u8 <= SMI130_MAX_IF_MODE) { + /* write if mode*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_IF_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_IF_CONFIG_IF_MODE, + v_if_mode_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_IF_CONFIG_IF_MODE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_sleep_trigger( +u8 *v_gyro_sleep_trigger_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro sleep trigger */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SLEEP_TRIGGER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_sleep_trigger_u8 = + SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_SLEEP_TRIGGER); + } + return com_rslt; +} +/*! + * @brief This API write gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_sleep_trigger( +u8 v_gyro_sleep_trigger_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_gyro_sleep_trigger_u8 <= SMI130_MAX_GYRO_SLEEP_TIGGER) { + /* write gyro sleep trigger */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SLEEP_TRIGGER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_SLEEP_TRIGGER, + v_gyro_sleep_trigger_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SLEEP_TRIGGER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_wakeup_trigger( +u8 *v_gyro_wakeup_trigger_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro wakeup trigger */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_WAKEUP_TRIGGER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_wakeup_trigger_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_GYRO_WAKEUP_TRIGGER); + } + return com_rslt; +} +/*! + * @brief This API write gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_wakeup_trigger( +u8 v_gyro_wakeup_trigger_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_gyro_wakeup_trigger_u8 + <= SMI130_MAX_GYRO_WAKEUP_TRIGGER) { + /* write gyro wakeup trigger */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_WAKEUP_TRIGGER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_WAKEUP_TRIGGER, + v_gyro_wakeup_trigger_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_WAKEUP_TRIGGER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_sleep_state( +u8 *v_gyro_sleep_state_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro sleep state*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SLEEP_STATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_sleep_state_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_GYRO_SLEEP_STATE); + } + return com_rslt; +} +/*! + * @brief This API write Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_sleep_state( +u8 v_gyro_sleep_state_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_gyro_sleep_state_u8 <= SMI130_MAX_VALUE_SLEEP_STATE) { + /* write gyro sleep state*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SLEEP_STATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_SLEEP_STATE, + v_gyro_sleep_state_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SLEEP_STATE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_wakeup_intr( +u8 *v_gyro_wakeup_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro wakeup interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_WAKEUP_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_wakeup_intr_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_GYRO_WAKEUP_INTR); + } + return com_rslt; +} +/*! + * @brief This API write gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_wakeup_intr( +u8 v_gyro_wakeup_intr_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_gyro_wakeup_intr_u8 <= SMI130_MAX_VALUE_WAKEUP_INTR) { + /* write gyro wakeup interrupt */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_WAKEUP_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_WAKEUP_INTR, + v_gyro_wakeup_intr_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_WAKEUP_INTR__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_selftest_axis( +u8 *v_accel_selftest_axis_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read accel self test axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_SELFTEST_AXIS__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_selftest_axis_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_ACCEL_SELFTEST_AXIS); + } + return com_rslt; +} +/*! + * @brief This API write accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_selftest_axis( +u8 v_accel_selftest_axis_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_accel_selftest_axis_u8 + <= SMI130_MAX_ACCEL_SELFTEST_AXIS) { + /* write accel self test axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_SELFTEST_AXIS__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_SELFTEST_AXIS, + v_accel_selftest_axis_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_SELFTEST_AXIS__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_selftest_sign( +u8 *v_accel_selftest_sign_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read accel self test axis sign*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_SELFTEST_SIGN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_selftest_sign_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_ACCEL_SELFTEST_SIGN); + } + return com_rslt; +} +/*! + * @brief This API write accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_selftest_sign( +u8 v_accel_selftest_sign_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_accel_selftest_sign_u8 <= + SMI130_MAX_VALUE_SELFTEST_SIGN) { + /* write accel self test axis sign*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_SELFTEST_SIGN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_ACCEL_SELFTEST_SIGN, + v_accel_selftest_sign_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_ACCEL_SELFTEST_SIGN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_selftest_amp( +u8 *v_accel_selftest_amp_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read self test amplitude*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_SELFTEST_AMP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_selftest_amp_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_SELFTEST_AMP); + } + return com_rslt; +} +/*! + * @brief This API write accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_selftest_amp( +u8 v_accel_selftest_amp_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_accel_selftest_amp_u8 <= + SMI130_MAX_VALUE_SELFTEST_AMP) { + /* write self test amplitude*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_SELFTEST_AMP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_SELFTEST_AMP, + v_accel_selftest_amp_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_SELFTEST_AMP__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_selftest_start( +u8 *v_gyro_selftest_start_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro self test start */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SELFTEST_START__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_selftest_start_u8 = SMI130_GET_BITSLICE( + v_data_u8, + SMI130_USER_GYRO_SELFTEST_START); + } + return com_rslt; +} +/*! + * @brief This API write gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_selftest_start( +u8 v_gyro_selftest_start_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_gyro_selftest_start_u8 <= + SMI130_MAX_VALUE_SELFTEST_START) { + /* write gyro self test start */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SELFTEST_START__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_GYRO_SELFTEST_START, + v_gyro_selftest_start_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_GYRO_SELFTEST_START__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_spi_enable(u8 *v_spi_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read interface section*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_SPI_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_spi_enable_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_NV_CONFIG_SPI_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API write primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_spi_enable(u8 v_spi_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write interface section*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_SPI_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_NV_CONFIG_SPI_ENABLE, + v_spi_enable_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_SPI_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_spare0_trim(u8 *v_spare0_trim_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read spare zero*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_SPARE0__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_spare0_trim_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_NV_CONFIG_SPARE0); + } + return com_rslt; +} + /*! + * @brief This API write the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_spare0_trim(u8 v_spare0_trim_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write spare zero*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_SPARE0__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_NV_CONFIG_SPARE0, + v_spare0_trim_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_SPARE0__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_nvm_counter(u8 *v_nvm_counter_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read NVM counter*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_NVM_COUNTER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_nvm_counter_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_NV_CONFIG_NVM_COUNTER); + } + return com_rslt; +} + /*! + * @brief This API write the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_nvm_counter( +u8 v_nvm_counter_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write NVM counter*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_NVM_COUNTER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_NV_CONFIG_NVM_COUNTER, + v_nvm_counter_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_NV_CONFIG_NVM_COUNTER__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API read accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_compensation_xaxis( +s8 *v_accel_off_x_s8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read accel manual offset compensation of x axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_0_ACCEL_OFF_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_x_s8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_0_ACCEL_OFF_X); + } + return com_rslt; +} +/*! + * @brief This API write accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_compensation_xaxis( +s8 v_accel_off_x_s8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* enable accel offset */ + v_status_s8 = smi130_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* write accel manual offset compensation of x axis*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_0_ACCEL_OFF_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE( + v_data_u8, + SMI130_USER_OFFSET_0_ACCEL_OFF_X, + v_accel_off_x_s8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_0_ACCEL_OFF_X__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = ERROR; + } + } + return com_rslt; +} +/*! + * @brief This API read accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_compensation_yaxis( +s8 *v_accel_off_y_s8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read accel manual offset compensation of y axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_1_ACCEL_OFF_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_y_s8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_1_ACCEL_OFF_Y); + } + return com_rslt; +} +/*! + * @brief This API write accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_compensation_yaxis( +s8 v_accel_off_y_s8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* enable accel offset */ + v_status_s8 = smi130_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* write accel manual offset compensation of y axis*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_1_ACCEL_OFF_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE( + v_data_u8, + SMI130_USER_OFFSET_1_ACCEL_OFF_Y, + v_accel_off_y_s8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_1_ACCEL_OFF_Y__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = ERROR; + } + } + return com_rslt; +} +/*! + * @brief This API read accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_compensation_zaxis( +s8 *v_accel_off_z_s8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read accel manual offset compensation of z axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_2_ACCEL_OFF_Z__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_z_s8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_2_ACCEL_OFF_Z); + } + return com_rslt; +} +/*! + * @brief This API write accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_compensation_zaxis( +s8 v_accel_off_z_s8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + u8 v_status_s8 = SUCCESS; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* enable accel offset */ + v_status_s8 = smi130_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* write accel manual offset + compensation of z axis*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_2_ACCEL_OFF_Z__REG, + &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_2_ACCEL_OFF_Z, + v_accel_off_z_s8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_2_ACCEL_OFF_Z__REG, + &v_data_u8, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = ERROR; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_compensation_xaxis( +s16 *v_gyro_off_x_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data1_u8r = SMI130_INIT_VALUE; + u8 v_data2_u8r = SMI130_INIT_VALUE; + s16 v_data3_u8r, v_data4_u8r = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro offset x*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_3_GYRO_OFF_X__REG, + &v_data1_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = SMI130_GET_BITSLICE(v_data1_u8r, + SMI130_USER_OFFSET_3_GYRO_OFF_X); + com_rslt += p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_X__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = SMI130_GET_BITSLICE(v_data2_u8r, + SMI130_USER_OFFSET_6_GYRO_OFF_X); + v_data3_u8r = v_data2_u8r + << SMI130_SHIFT_BIT_POSITION_BY_14_BITS; + v_data4_u8r = v_data1_u8r + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS; + v_data3_u8r = v_data3_u8r | v_data4_u8r; + *v_gyro_off_x_s16 = v_data3_u8r + >> SMI130_SHIFT_BIT_POSITION_BY_06_BITS; + } + return com_rslt; +} +/*! + * @brief This API write gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_compensation_xaxis( +s16 v_gyro_off_x_s16) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data1_u8r, v_data2_u8r = SMI130_INIT_VALUE; +u16 v_data3_u8r = SMI130_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write gyro offset x*/ + v_status_s8 = smi130_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_3_GYRO_OFF_X__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data1_u8r = + ((s8) (v_gyro_off_x_s16 & + SMI130_GYRO_MANUAL_OFFSET_0_7)); + v_data2_u8r = SMI130_SET_BITSLICE( + v_data2_u8r, + SMI130_USER_OFFSET_3_GYRO_OFF_X, + v_data1_u8r); + /* write 0x74 bit 0 to 7*/ + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_3_GYRO_OFF_X__REG, + &v_data2_u8r, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + com_rslt += p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_X__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u8r = + (u16) (v_gyro_off_x_s16 & + SMI130_GYRO_MANUAL_OFFSET_8_9); + v_data1_u8r = (u8)(v_data3_u8r + >> SMI130_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = SMI130_SET_BITSLICE( + v_data2_u8r, + SMI130_USER_OFFSET_6_GYRO_OFF_X, + v_data1_u8r); + /* write 0x77 bit 0 and 1*/ + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_X__REG, + &v_data2_u8r, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + return ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_compensation_yaxis( +s16 *v_gyro_off_y_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data1_u8r = SMI130_INIT_VALUE; + u8 v_data2_u8r = SMI130_INIT_VALUE; + s16 v_data3_u8r, v_data4_u8r = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro offset y*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_4_GYRO_OFF_Y__REG, + &v_data1_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = SMI130_GET_BITSLICE(v_data1_u8r, + SMI130_USER_OFFSET_4_GYRO_OFF_Y); + com_rslt += p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_Y__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = SMI130_GET_BITSLICE(v_data2_u8r, + SMI130_USER_OFFSET_6_GYRO_OFF_Y); + v_data3_u8r = v_data2_u8r + << SMI130_SHIFT_BIT_POSITION_BY_14_BITS; + v_data4_u8r = v_data1_u8r + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS; + v_data3_u8r = v_data3_u8r | v_data4_u8r; + *v_gyro_off_y_s16 = v_data3_u8r + >> SMI130_SHIFT_BIT_POSITION_BY_06_BITS; + } + return com_rslt; +} +/*! + * @brief This API write gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_compensation_yaxis( +s16 v_gyro_off_y_s16) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data1_u8r, v_data2_u8r = SMI130_INIT_VALUE; +u16 v_data3_u8r = SMI130_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* enable gyro offset bit */ + v_status_s8 = smi130_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + /* write gyro offset y*/ + if (v_status_s8 == SUCCESS) { + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_4_GYRO_OFF_Y__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data1_u8r = + ((s8) (v_gyro_off_y_s16 & + SMI130_GYRO_MANUAL_OFFSET_0_7)); + v_data2_u8r = SMI130_SET_BITSLICE( + v_data2_u8r, + SMI130_USER_OFFSET_4_GYRO_OFF_Y, + v_data1_u8r); + /* write 0x75 bit 0 to 7*/ + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_4_GYRO_OFF_Y__REG, + &v_data2_u8r, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + com_rslt += p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_Y__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u8r = + (u16) (v_gyro_off_y_s16 & + SMI130_GYRO_MANUAL_OFFSET_8_9); + v_data1_u8r = (u8)(v_data3_u8r + >> SMI130_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = SMI130_SET_BITSLICE( + v_data2_u8r, + SMI130_USER_OFFSET_6_GYRO_OFF_Y, + v_data1_u8r); + /* write 0x77 bit 2 and 3*/ + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_Y__REG, + &v_data2_u8r, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + return ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_compensation_zaxis( +s16 *v_gyro_off_z_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data1_u8r = SMI130_INIT_VALUE; + u8 v_data2_u8r = SMI130_INIT_VALUE; + s16 v_data3_u8r, v_data4_u8r = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro manual offset z axis*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_5_GYRO_OFF_Z__REG, + &v_data1_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = SMI130_GET_BITSLICE + (v_data1_u8r, + SMI130_USER_OFFSET_5_GYRO_OFF_Z); + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_Z__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = SMI130_GET_BITSLICE( + v_data2_u8r, + SMI130_USER_OFFSET_6_GYRO_OFF_Z); + v_data3_u8r = v_data2_u8r + << SMI130_SHIFT_BIT_POSITION_BY_14_BITS; + v_data4_u8r = v_data1_u8r + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS; + v_data3_u8r = v_data3_u8r | v_data4_u8r; + *v_gyro_off_z_s16 = v_data3_u8r + >> SMI130_SHIFT_BIT_POSITION_BY_06_BITS; + } + return com_rslt; +} +/*! + * @brief This API write gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_compensation_zaxis( +s16 v_gyro_off_z_s16) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data1_u8r, v_data2_u8r = SMI130_INIT_VALUE; +u16 v_data3_u8r = SMI130_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* enable gyro offset*/ + v_status_s8 = smi130_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + /* write gyro manual offset z axis*/ + if (v_status_s8 == SUCCESS) { + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_5_GYRO_OFF_Z__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data1_u8r = + ((u8) (v_gyro_off_z_s16 & + SMI130_GYRO_MANUAL_OFFSET_0_7)); + v_data2_u8r = SMI130_SET_BITSLICE( + v_data2_u8r, + SMI130_USER_OFFSET_5_GYRO_OFF_Z, + v_data1_u8r); + /* write 0x76 bit 0 to 7*/ + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_5_GYRO_OFF_Z__REG, + &v_data2_u8r, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + com_rslt += p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_Z__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u8r = + (u16) (v_gyro_off_z_s16 & + SMI130_GYRO_MANUAL_OFFSET_8_9); + v_data1_u8r = (u8)(v_data3_u8r + >> SMI130_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = SMI130_SET_BITSLICE( + v_data2_u8r, + SMI130_USER_OFFSET_6_GYRO_OFF_Z, + v_data1_u8r); + /* write 0x77 bit 4 and 5*/ + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_Z__REG, + &v_data2_u8r, + SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + return ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_enable( +u8 *v_accel_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read accel offset enable */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_enable_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_enable( +u8 v_accel_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write accel offset enable */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE, + v_accel_off_enable_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_enable( +u8 *v_gyro_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read gyro offset*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_off_enable_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_6_GYRO_OFF_EN); + } + return com_rslt; +} +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_enable( +u8 v_gyro_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write gyro offset*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_OFFSET_6_GYRO_OFF_EN, + v_gyro_off_enable_u8); + com_rslt += p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_USER_OFFSET_6_GYRO_OFF_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API reads step counter value + * form the register 0x78 and 0x79 + * + * + * + * + * @param v_step_cnt_s16 : The value of step counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_step_count(u16 *v_step_cnt_s16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* array having the step counter LSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 a_data_u8r[SMI130_STEP_COUNT_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read step counter */ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STEP_COUNT_LSB__REG, + a_data_u8r, SMI130_STEP_COUNTER_LENGTH); + + *v_step_cnt_s16 = (s16) + ((((s32)((s8)a_data_u8r[SMI130_STEP_COUNT_MSB_BYTE])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[SMI130_STEP_COUNT_LSB_BYTE])); + } + return com_rslt; +} + /*! + * @brief This API Reads + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : The value of step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_step_config( +u16 *v_step_config_u16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data1_u8r = SMI130_INIT_VALUE; + u8 v_data2_u8r = SMI130_INIT_VALUE; + u16 v_data3_u8r = SMI130_INIT_VALUE; + /* Read the 0 to 7 bit*/ + com_rslt = + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ZERO__REG, + &v_data1_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* Read the 8 to 10 bit*/ + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ONE_CNF1__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = SMI130_GET_BITSLICE(v_data2_u8r, + SMI130_USER_STEP_CONFIG_ONE_CNF1); + v_data3_u8r = ((u16)((((u32) + ((u8)v_data2_u8r)) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (v_data1_u8r))); + /* Read the 11 to 14 bit*/ + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ONE_CNF2__REG, + &v_data1_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = SMI130_GET_BITSLICE(v_data1_u8r, + SMI130_USER_STEP_CONFIG_ONE_CNF2); + *v_step_config_u16 = ((u16)((((u32) + ((u8)v_data1_u8r)) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (v_data3_u8r))); + + return com_rslt; +} + /*! + * @brief This API write + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : + * the value of Enable step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_config( +u16 v_step_config_u16) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data1_u8r = SMI130_INIT_VALUE; + u8 v_data2_u8r = SMI130_INIT_VALUE; + u16 v_data3_u16 = SMI130_INIT_VALUE; + + /* write the 0 to 7 bit*/ + v_data1_u8r = (u8)(v_step_config_u16 & + SMI130_STEP_CONFIG_0_7); + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ZERO__REG, + &v_data1_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* write the 8 to 10 bit*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ONE_CNF1__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u16 = (u16) (v_step_config_u16 & + SMI130_STEP_CONFIG_8_10); + v_data1_u8r = (u8)(v_data3_u16 + >> SMI130_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = SMI130_SET_BITSLICE(v_data2_u8r, + SMI130_USER_STEP_CONFIG_ONE_CNF1, v_data1_u8r); + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ONE_CNF1__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + /* write the 11 to 14 bit*/ + com_rslt += p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ONE_CNF2__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u16 = (u16) (v_step_config_u16 & + SMI130_STEP_CONFIG_11_14); + v_data1_u8r = (u8)(v_data3_u16 + >> SMI130_SHIFT_BIT_POSITION_BY_12_BITS); + v_data2_u8r = SMI130_SET_BITSLICE(v_data2_u8r, + SMI130_USER_STEP_CONFIG_ONE_CNF2, v_data1_u8r); + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_ONE_CNF2__REG, + &v_data2_u8r, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + + return com_rslt; +} + /*! + * @brief This API read enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_step_counter_enable( +u8 *v_step_counter_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the step counter */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_step_counter_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API write enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_counter_enable(u8 v_step_counter_u8) +{ +/* variable used for return the status of communication result*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_data_u8 = SMI130_INIT_VALUE; +/* check the p_smi130 structure as NULL*/ +if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; +} else { + if (v_step_counter_u8 <= SMI130_MAX_GYRO_STEP_COUNTER) { + /* write the step counter */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE, + v_step_counter_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } +} + return com_rslt; +} + /*! + * @brief This API set Step counter modes + * + * + * @param v_step_mode_u8 : The value of step counter mode + * value | mode + * ----------|----------- + * 0 | SMI130_STEP_NORMAL_MODE + * 1 | SMI130_STEP_SENSITIVE_MODE + * 2 | SMI130_STEP_ROBUST_MODE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_mode(u8 v_step_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + + switch (v_step_mode_u8) { + case SMI130_STEP_NORMAL_MODE: + com_rslt = smi130_set_step_config( + STEP_CONFIG_NORMAL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_STEP_SENSITIVE_MODE: + com_rslt = smi130_set_step_config( + STEP_CONFIG_SENSITIVE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_STEP_ROBUST_MODE: + com_rslt = smi130_set_step_config( + STEP_CONFIG_ROBUST); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + + return com_rslt; +} +/*! + * @brief This API used to trigger the signification motion + * interrupt + * + * + * @param v_significant_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | SMI130_MAP_INTR1 + * 1 | SMI130_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_map_significant_motion_intr( +u8 v_significant_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_sig_motion_u8 = SMI130_INIT_VALUE; + u8 v_data_u8 = SMI130_INIT_VALUE; + u8 v_any_motion_intr1_stat_u8 = SMI130_ENABLE_ANY_MOTION_INTR1; + u8 v_any_motion_intr2_stat_u8 = SMI130_ENABLE_ANY_MOTION_INTR2; + u8 v_any_motion_axis_stat_u8 = SMI130_ENABLE_ANY_MOTION_AXIS; + /* enable the significant motion interrupt */ + com_rslt = smi130_get_intr_significant_motion_select(&v_sig_motion_u8); + if (v_sig_motion_u8 != SMI130_SIG_MOTION_STAT_HIGH) + com_rslt += smi130_set_intr_significant_motion_select( + SMI130_SIG_MOTION_INTR_ENABLE); + switch (v_significant_u8) { + case SMI130_MAP_INTR1: + /* interrupt */ + com_rslt += smi130_read_reg( + SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_intr1_stat_u8; + /* map the signification interrupt to any-motion interrupt1*/ + com_rslt += smi130_write_reg( + SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* axis*/ + com_rslt = smi130_read_reg(SMI130_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_axis_stat_u8; + com_rslt += smi130_write_reg( + SMI130_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + + case SMI130_MAP_INTR2: + /* map the signification interrupt to any-motion interrupt2*/ + com_rslt += smi130_read_reg( + SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_intr2_stat_u8; + com_rslt += smi130_write_reg( + SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* axis*/ + com_rslt = smi130_read_reg(SMI130_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_axis_stat_u8; + com_rslt += smi130_write_reg( + SMI130_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + + } + return com_rslt; +} +/*! + * @brief This API used to trigger the step detector + * interrupt + * + * + * @param v_step_detector_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | SMI130_MAP_INTR1 + * 1 | SMI130_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_map_step_detector_intr( +u8 v_step_detector_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_step_det_u8 = SMI130_INIT_VALUE; + u8 v_data_u8 = SMI130_INIT_VALUE; + u8 v_low_g_intr_u81_stat_u8 = SMI130_LOW_G_INTR_STAT; + u8 v_low_g_intr_u82_stat_u8 = SMI130_LOW_G_INTR_STAT; + u8 v_low_g_enable_u8 = SMI130_ENABLE_LOW_G; + /* read the v_status_s8 of step detector interrupt*/ + com_rslt = smi130_get_step_detector_enable(&v_step_det_u8); + if (v_step_det_u8 != SMI130_STEP_DET_STAT_HIGH) + com_rslt += smi130_set_step_detector_enable( + SMI130_STEP_DETECT_INTR_ENABLE); + switch (v_step_detector_u8) { + case SMI130_MAP_INTR1: + com_rslt += smi130_read_reg( + SMI130_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_intr_u81_stat_u8; + /* map the step detector interrupt + to Low-g interrupt 1*/ + com_rslt += smi130_write_reg( + SMI130_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Enable the Low-g interrupt*/ + com_rslt = smi130_read_reg( + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_enable_u8; + com_rslt += smi130_write_reg( + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_MAP_INTR2: + /* map the step detector interrupt + to Low-g interrupt 1*/ + com_rslt += smi130_read_reg( + SMI130_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_intr_u82_stat_u8; + + com_rslt += smi130_write_reg( + SMI130_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Enable the Low-g interrupt*/ + com_rslt = smi130_read_reg( + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_enable_u8; + com_rslt += smi130_write_reg( + SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + return com_rslt; +} + /*! + * @brief This API used to clear the step counter interrupt + * interrupt + * + * + * @param : None + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_clear_step_counter(void) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* clear the step counter*/ + com_rslt = smi130_set_command_register(RESET_STEP_COUNTER); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + + return com_rslt; + +} + /*! + * @brief This API writes value to the register 0x7E bit 0 to 7 + * + * + * @param v_command_reg_u8 : The value to write command register + * value | Description + * ---------|-------------------------------------------------------- + * 0x00 | Reserved + * 0x03 | Starts fast offset calibration for the accel and gyro + * 0x10 | Sets the PMU mode for the Accelerometer to suspend + * 0x11 | Sets the PMU mode for the Accelerometer to normal + * 0x12 | Sets the PMU mode for the Accelerometer Lowpower + * 0x14 | Sets the PMU mode for the Gyroscope to suspend + * 0x15 | Sets the PMU mode for the Gyroscope to normal + * 0x16 | Reserved + * 0x17 | Sets the PMU mode for the Gyroscope to fast start-up + * 0x18 | Sets the PMU mode for the Magnetometer to suspend + * 0x19 | Sets the PMU mode for the Magnetometer to normal + * 0x1A | Sets the PMU mode for the Magnetometer to Lowpower + * 0xB0 | Clears all data in the FIFO + * 0xB1 | Resets the interrupt engine + * 0xB2 | step_cnt_clr Clears the step counter + * 0xB6 | Triggers a reset + * 0x37 | See extmode_en_last + * 0x9A | See extmode_en_last + * 0xC0 | Enable the extended mode + * 0xC4 | Erase NVM cell + * 0xC8 | Load NVM cell + * 0xF0 | Reset acceleration data path + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_command_register(u8 v_command_reg_u8) +{ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write command register */ + com_rslt = p_smi130->SMI130_BUS_WRITE_FUNC( + p_smi130->dev_addr, + SMI130_CMD_COMMANDS__REG, + &v_command_reg_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} + /*! + * @brief This API read target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_target_page(u8 *v_target_page_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the page*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_CMD_TARGET_PAGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_target_page_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_CMD_TARGET_PAGE); + } + return com_rslt; +} + /*! + * @brief This API write target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_target_page(u8 v_target_page_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_target_page_u8 <= SMI130_MAX_TARGET_PAGE) { + /* write the page*/ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_CMD_TARGET_PAGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_CMD_TARGET_PAGE, + v_target_page_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_CMD_TARGET_PAGE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_paging_enable(u8 *v_page_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the page enable */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_CMD_PAGING_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_page_enable_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_CMD_PAGING_EN); + } + return com_rslt; +} + /*! + * @brief This API write page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_paging_enable( +u8 v_page_enable_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + if (v_page_enable_u8 <= SMI130_MAX_VALUE_PAGE) { + /* write the page enable */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_CMD_PAGING_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_CMD_PAGING_EN, + v_page_enable_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_CMD_PAGING_EN__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_SMI130_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_pullup_configuration( +u8 *v_control_pullup_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read pull up value */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC( + p_smi130->dev_addr, + SMI130_COM_C_TRIM_FIVE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + *v_control_pullup_u8 = SMI130_GET_BITSLICE(v_data_u8, + SMI130_COM_C_TRIM_FIVE); + } + return com_rslt; + +} + /*! + * @brief This API write + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_pullup_configuration( +u8 v_control_pullup_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* write pull up value */ + com_rslt = p_smi130->SMI130_BUS_READ_FUNC + (p_smi130->dev_addr, + SMI130_COM_C_TRIM_FIVE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + SMI130_SET_BITSLICE(v_data_u8, + SMI130_COM_C_TRIM_FIVE, + v_control_pullup_u8); + com_rslt += + p_smi130->SMI130_BUS_WRITE_FUNC + (p_smi130->dev_addr, + SMI130_COM_C_TRIM_FIVE__REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + +/*! + * @brief This function used for read the compensated value of mag + * Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_compensate_xyz( +struct smi130_mag_xyz_s32_t *mag_comp_xyz) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + struct smi130_mag_xyzr_t mag_xyzr; + com_rslt = smi130_read_mag_xyzr(&mag_xyzr); + if (com_rslt) + return com_rslt; + /* Compensation for X axis */ + mag_comp_xyz->x = smi130_bmm150_mag_compensate_X( + mag_xyzr.x, mag_xyzr.r); + + /* Compensation for Y axis */ + mag_comp_xyz->y = smi130_bmm150_mag_compensate_Y( + mag_xyzr.y, mag_xyzr.r); + + /* Compensation for Z axis */ + mag_comp_xyz->z = smi130_bmm150_mag_compensate_Z( + mag_xyzr.z, mag_xyzr.r); + + return com_rslt; +} + +/*! + * @brief This function used for read the compensated value of mag + * Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_compensate_xyz_raw( +struct smi130_mag_xyz_s32_t *mag_comp_xyz, struct smi130_mag_xyzr_t mag_xyzr) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + + /* Compensation for X axis */ + mag_comp_xyz->x = smi130_bmm150_mag_compensate_X( + mag_xyzr.x, mag_xyzr.r); + + /* Compensation for Y axis */ + mag_comp_xyz->y = smi130_bmm150_mag_compensate_Y( + mag_xyzr.y, mag_xyzr.r); + + /* Compensation for Z axis */ + mag_comp_xyz->z = smi130_bmm150_mag_compensate_Z( + mag_xyzr.z, mag_xyzr.r); + + return com_rslt; +} +/*! + * @brief This API used to get the compensated BMM150-X data + * the out put of X as s32 + * Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_x_s16 : The value of mag raw X data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated X data value output as s32 + * + */ +s32 smi130_bmm150_mag_compensate_X(s16 v_mag_data_x_s16, u16 v_data_r_u16) +{ +s32 inter_retval = SMI130_INIT_VALUE; +/* no overflow */ +if (v_mag_data_x_s16 != SMI130_MAG_FLIP_OVERFLOW_ADCVAL) { + if ((v_data_r_u16 != 0) + && (mag_trim_mbl.dig_xyz1 != 0)) { + inter_retval = ((s32)(((u16) + ((((s32)mag_trim_mbl.dig_xyz1) + << SMI130_SHIFT_BIT_POSITION_BY_14_BITS)/ + (v_data_r_u16 != 0 ? + v_data_r_u16 : mag_trim_mbl.dig_xyz1))) - + ((u16)0x4000))); + } else { + inter_retval = SMI130_MAG_OVERFLOW_OUTPUT; + return inter_retval; + } + inter_retval = ((s32)((((s32)v_mag_data_x_s16) * + ((((((((s32)mag_trim_mbl.dig_xy2) * + ((((s32)inter_retval) * + ((s32)inter_retval)) + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS)) + + (((s32)inter_retval) * + ((s32)(((s16)mag_trim_mbl.dig_xy1) + << SMI130_SHIFT_BIT_POSITION_BY_07_BITS)))) + >> SMI130_SHIFT_BIT_POSITION_BY_09_BITS) + + ((s32)0x100000)) * + ((s32)(((s16)mag_trim_mbl.dig_x2) + + ((s16)0xA0)))) + >> SMI130_SHIFT_BIT_POSITION_BY_12_BITS)) + >> SMI130_SHIFT_BIT_POSITION_BY_13_BITS)) + + (((s16)mag_trim_mbl.dig_x1) + << SMI130_SHIFT_BIT_POSITION_BY_03_BITS); + /* check the overflow output */ + if (inter_retval == (s32)SMI130_MAG_OVERFLOW_OUTPUT) + inter_retval = SMI130_MAG_OVERFLOW_OUTPUT_S32; +} else { + /* overflow */ + inter_retval = SMI130_MAG_OVERFLOW_OUTPUT; +} +return inter_retval; +} +/*! + * @brief This API used to get the compensated BMM150-Y data + * the out put of Y as s32 + * Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_y_s16 : The value of mag raw Y data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Y data value output as s32 + */ +s32 smi130_bmm150_mag_compensate_Y(s16 v_mag_data_y_s16, u16 v_data_r_u16) +{ +s32 inter_retval = SMI130_INIT_VALUE; +/* no overflow */ +if (v_mag_data_y_s16 != SMI130_MAG_FLIP_OVERFLOW_ADCVAL) { + if ((v_data_r_u16 != 0) + && (mag_trim_mbl.dig_xyz1 != 0)) { + inter_retval = ((s32)(((u16)((( + (s32)mag_trim_mbl.dig_xyz1) + << SMI130_SHIFT_BIT_POSITION_BY_14_BITS) / + (v_data_r_u16 != 0 ? + v_data_r_u16 : mag_trim_mbl.dig_xyz1))) - + ((u16)0x4000))); + } else { + inter_retval = SMI130_MAG_OVERFLOW_OUTPUT; + return inter_retval; + } + inter_retval = ((s32)((((s32)v_mag_data_y_s16) * ((((((((s32) + mag_trim_mbl.dig_xy2) * ((((s32) inter_retval) * + ((s32)inter_retval)) >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS)) + + (((s32)inter_retval) * + ((s32)(((s16)mag_trim_mbl.dig_xy1) + << SMI130_SHIFT_BIT_POSITION_BY_07_BITS)))) + >> SMI130_SHIFT_BIT_POSITION_BY_09_BITS) + + ((s32)0x100000)) + * ((s32)(((s16)mag_trim_mbl.dig_y2) + + ((s16)0xA0)))) + >> SMI130_SHIFT_BIT_POSITION_BY_12_BITS)) + >> SMI130_SHIFT_BIT_POSITION_BY_13_BITS)) + + (((s16)mag_trim_mbl.dig_y1) + << SMI130_SHIFT_BIT_POSITION_BY_03_BITS); + /* check the overflow output */ + if (inter_retval == (s32)SMI130_MAG_OVERFLOW_OUTPUT) + inter_retval = SMI130_MAG_OVERFLOW_OUTPUT_S32; +} else { + /* overflow */ + inter_retval = SMI130_MAG_OVERFLOW_OUTPUT; +} +return inter_retval; +} +/*! + * @brief This API used to get the compensated BMM150-Z data + * the out put of Z as s32 + * Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_z_s16 : The value of mag raw Z data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Z data value output as s32 + */ +s32 smi130_bmm150_mag_compensate_Z(s16 v_mag_data_z_s16, u16 v_data_r_u16) +{ + s32 retval = SMI130_INIT_VALUE; + + if (v_mag_data_z_s16 != SMI130_MAG_HALL_OVERFLOW_ADCVAL) { + if ((v_data_r_u16 != 0) + && (mag_trim_mbl.dig_z2 != 0) + /* && (mag_trim_mbl.dig_z3 != 0)*/ + && (mag_trim_mbl.dig_z1 != 0) + && (mag_trim_mbl.dig_xyz1 != 0)) { + retval = (((((s32)(v_mag_data_z_s16 - mag_trim_mbl.dig_z4)) + << SMI130_SHIFT_BIT_POSITION_BY_15_BITS) - + ((((s32)mag_trim_mbl.dig_z3) * + ((s32)(((s16)v_data_r_u16) - + ((s16)mag_trim_mbl.dig_xyz1)))) + >> SMI130_SHIFT_BIT_POSITION_BY_02_BITS))/ + (mag_trim_mbl.dig_z2 + + ((s16)(((((s32)mag_trim_mbl.dig_z1) * + ((((s16)v_data_r_u16) + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT))) + + (1 << SMI130_SHIFT_BIT_POSITION_BY_15_BITS)) + >> SMI130_SHIFT_BIT_POSITION_BY_16_BITS)))); + } + } else { + retval = SMI130_MAG_OVERFLOW_OUTPUT; + } + return retval; +} + /*! + * @brief This function used for initialize the bmm150 sensor + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_interface_init(void) +{ + /* This variable used for provide the communication + results*/ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + u8 v_pull_value_u8 = SMI130_INIT_VALUE; + u8 v_data_u8 = SMI130_INIT_VALUE; + /* accel operation mode to normal*/ + com_rslt = smi130_set_command_register(ACCEL_MODE_NORMAL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* write the mag power mode as NORMAL*/ + com_rslt += smi130_set_mag_interface_normal(); + + /* register 0x7E write the 0x37, 0x9A and 0x30*/ + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_ONE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_TWO); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_THREE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /*switch the page1*/ + com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_target_page(&v_data_u8); + com_rslt += smi130_set_paging_enable(SMI130_WRITE_ENABLE_PAGE1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_paging_enable(&v_data_u8); + /* enable the pullup configuration from + the register 0x05 bit 4 and 5 as 10*/ + smi130_get_pullup_configuration(&v_pull_value_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + v_pull_value_u8 = v_pull_value_u8 | SMI130_PULL_UP_DATA; + com_rslt += smi130_set_pullup_configuration(v_pull_value_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /*switch the page0*/ + com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE0); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_target_page(&v_data_u8); + /* Write the BMM150 i2c address*/ + com_rslt += smi130_set_i2c_device_addr(SMI130_AUX_BMM150_I2C_ADDRESS); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* enable the mag interface to manual mode*/ + com_rslt += smi130_set_mag_manual_enable(SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_mag_manual_enable(&v_data_u8); + /*Enable the MAG interface */ + com_rslt += smi130_set_if_mode(SMI130_ENABLE_MAG_IF_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_if_mode(&v_data_u8); + /* Mag normal mode*/ + com_rslt += smi130_bmm150_mag_wakeup(); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Read the BMM150 device id is 0x32*/ + /*com_rslt += smi130_set_mag_read_addr(SMI130_BMM150_CHIP_ID);*/ + /*p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY);*/ + /*com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH);*/ + /**v_chip_id_u8 = v_data_u8;*/ + /*p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY);*/ + /* write the power mode register*/ + com_rslt += smi130_set_mag_write_data(SMI130_BMM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /*write 0x4C register to write set power mode to normal*/ + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_MODE_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* read the mag trim values*/ + com_rslt += smi130_read_bmm150_mag_trim_mbl(); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + /* To avoid the auto mode enable when manual mode operation running*/ + V_bmm150_maual_auto_condition_u8_mbl = SMI130_MANUAL_ENABLE; + /* write the XY and Z repetitions*/ + com_rslt += smi130_set_bmm150_mag_presetmode( + SMI130_MAG_PRESETMODE_REGULAR); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + /* To avoid the auto mode enable when manual mode operation running*/ + V_bmm150_maual_auto_condition_u8_mbl = SMI130_MANUAL_DISABLE; + /* Set the power mode of mag as force mode*/ + /* The data have to write for the register + It write the value in the register 0x4F */ + com_rslt += smi130_set_mag_write_data(SMI130_BMM150_FORCE_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + /* write into power mode register*/ + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_MODE_REG); + /* write the mag v_data_bw_u8 as 25Hz*/ + com_rslt += smi130_set_mag_output_data_rate( + SMI130_MAG_OUTPUT_DATA_RATE_25HZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + /* When mag interface is auto mode - The mag read address + starts the register 0x42*/ + com_rslt += smi130_set_mag_read_addr( + SMI130_BMM150_DATA_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* enable mag interface to auto mode*/ + com_rslt += smi130_set_mag_manual_enable(SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_mag_manual_enable(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + return com_rslt; +} + /*! + * @brief This function used for set the mag power control + * bit enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_wakeup(void) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + u8 v_try_times_u8 = SMI130_BMM150_MAX_RETRY_WAKEUP; + u8 v_power_control_bit_u8 = SMI130_INIT_VALUE; + u8 i = SMI130_INIT_VALUE; + + for (i = SMI130_INIT_VALUE; i < v_try_times_u8; i++) { + com_rslt = smi130_set_mag_write_data(SMI130_BMM150_POWER_ON); + p_smi130->delay_msec(SMI130_BMM150_WAKEUP_DELAY1); + /*write 0x4B register to enable power control bit*/ + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_CONTROL_REG); + p_smi130->delay_msec(SMI130_BMM150_WAKEUP_DELAY2); + com_rslt += smi130_set_mag_read_addr( + SMI130_BMM150_POWE_CONTROL_REG); + /* 0x04 is secondary read mag x lsb register */ + p_smi130->delay_msec(SMI130_BMM150_WAKEUP_DELAY3); + com_rslt += smi130_read_reg(SMI130_USER_DATA_0_ADDR, + &v_power_control_bit_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + v_power_control_bit_u8 = SMI130_BMM150_SET_POWER_CONTROL + & v_power_control_bit_u8; + if (v_power_control_bit_u8 == SMI130_BMM150_POWER_ON) + break; + } + com_rslt = (i >= v_try_times_u8) ? + SMI130_BMM150_POWER_ON_FAIL : SMI130_BMM150_POWER_ON_SUCCESS; + return com_rslt; +} + /*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | SMI130_MAG_FORCE_MODE + * 1 | SMI130_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_bmm150_mag_and_secondary_if_power_mode( +u8 v_mag_sec_if_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + /* set the accel power mode to NORMAL*/ + com_rslt = smi130_set_command_register(ACCEL_MODE_NORMAL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + /* set mag interface manual mode*/ + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) { + com_rslt += smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + + switch (v_mag_sec_if_pow_mode_u8) { + case SMI130_MAG_FORCE_MODE: + /* set the secondary mag power mode as NORMAL*/ + com_rslt += smi130_set_mag_interface_normal(); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + /* set the mag power mode as FORCE mode*/ + com_rslt += smi130_bmm150_mag_set_power_mode(FORCE_MODE); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_MAG_SUSPEND_MODE: + /* set the mag power mode as SUSPEND mode*/ + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + com_rslt += smi130_bmm150_mag_set_power_mode(SUSPEND_MODE); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* set the secondary mag power mode as SUSPEND*/ + com_rslt += smi130_set_command_register(MAG_MODE_SUSPEND); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) { + /* set mag interface auto mode*/ + com_rslt += smi130_set_mag_manual_enable( + SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + return com_rslt; +} +/*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @param v_mag_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | FORCE_MODE + * 1 | SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_set_power_mode( +u8 v_mag_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + u8 manual_enable_status = 0; + /* set mag interface manual mode*/ + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) { + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_get_mag_manual_enable(&manual_enable_status); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + printk(KERN_INFO "1com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_smi130->mag_manual_enable, manual_enable_status); + } + printk(KERN_INFO "2com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_smi130->mag_manual_enable, manual_enable_status); + + switch (v_mag_pow_mode_u8) { + case FORCE_MODE: + /* Set the power control bit enabled */ + com_rslt = smi130_bmm150_mag_wakeup(); + /* write the mag power mode as FORCE mode*/ + com_rslt += smi130_set_mag_write_data( + SMI130_BMM150_FORCE_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* To avoid the auto mode enable when manual + mode operation running*/ + V_bmm150_maual_auto_condition_u8_mbl = SMI130_MANUAL_ENABLE; + /* set the preset mode */ + com_rslt += smi130_set_bmm150_mag_presetmode( + SMI130_MAG_PRESETMODE_REGULAR); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* To avoid the auto mode enable when manual + mode operation running*/ + V_bmm150_maual_auto_condition_u8_mbl = SMI130_MANUAL_DISABLE; + /* set the mag read address to data registers*/ + com_rslt += smi130_set_mag_read_addr( + SMI130_BMM150_DATA_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SUSPEND_MODE: + printk(KERN_INFO "3com_rslt:%d, manual:%d, read_manual:%d\n", + com_rslt, p_smi130->mag_manual_enable, manual_enable_status); + /* Set the power mode of mag as suspend mode*/ + com_rslt += smi130_set_mag_write_data( + SMI130_BMM150_POWER_OFF); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_CONTROL_REG); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + printk(KERN_INFO "4com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_smi130->mag_manual_enable, manual_enable_status); + /* set mag interface auto mode*/ + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) { + com_rslt += smi130_set_mag_manual_enable( + SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_get_mag_manual_enable(&manual_enable_status); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "5com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_smi130->mag_manual_enable, manual_enable_status); + return com_rslt; +} +/*! + * @brief This API used to set the pre-set modes of bmm150 + * The pre-set mode setting is depend on data rate and xy and z repetitions + * + * @note + * Before set the mag preset mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_mode_u8: The value of pre-set mode selection value + * value | pre_set mode + * ----------|------------ + * 1 | SMI130_MAG_PRESETMODE_LOWPOWER + * 2 | SMI130_MAG_PRESETMODE_REGULAR + * 3 | SMI130_MAG_PRESETMODE_HIGHACCURACY + * 4 | SMI130_MAG_PRESETMODE_ENHANCED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_bmm150_mag_presetmode(u8 v_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + switch (v_mode_u8) { + case SMI130_MAG_PRESETMODE_LOWPOWER: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = smi130_set_mag_write_data( + SMI130_MAG_LOWPOWER_REPXY); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_XY_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_LOWPOWER_REPZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_Z_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 10 to the register 0x4C*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_LOWPOWER_DR); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_MODE_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_MAG_PRESETMODE_REGULAR: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = smi130_set_mag_write_data( + SMI130_MAG_REGULAR_REPXY); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_XY_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_REGULAR_REPZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_Z_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 10 to the register 0x4C*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_REGULAR_DR); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_MODE_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_MAG_PRESETMODE_HIGHACCURACY: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = smi130_set_mag_write_data( + SMI130_MAG_HIGHACCURACY_REPXY); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_XY_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_HIGHACCURACY_REPZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_Z_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 20 to the register 0x4C*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_HIGHACCURACY_DR); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_MODE_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_MAG_PRESETMODE_ENHANCED: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = smi130_set_mag_write_data( + SMI130_MAG_ENHANCED_REPXY); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_XY_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_ENHANCED_REPZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_Z_REP); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 10 to the register 0x4C*/ + com_rslt += smi130_set_mag_write_data( + SMI130_MAG_ENHANCED_DR); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + SMI130_BMM150_POWE_MODE_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + + return com_rslt; +} + /*! + * @brief This function used for read the trim values of magnetometer + * + * @note + * Before reading the mag trimming values + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_bmm150_mag_trim_mbl(void) +{ + /* This variable used for provide the communication + results*/ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array holding the bmm150 trim data + */ + u8 v_data_u8[SMI130_MAG_TRIM_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE}; + /* read dig_x1 value */ + com_rslt = smi130_set_mag_read_addr( + SMI130_MAG_DIG_X1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_X1], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_x1 = v_data_u8[SMI130_BMM150_DIG_X1]; + /* read dig_y1 value */ + com_rslt += smi130_set_mag_read_addr( + SMI130_MAG_DIG_Y1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_Y1], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_y1 = v_data_u8[SMI130_BMM150_DIG_Y1]; + + /* read dig_x2 value */ + com_rslt += smi130_set_mag_read_addr( + SMI130_MAG_DIG_X2); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_X2], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_x2 = v_data_u8[SMI130_BMM150_DIG_X2]; + /* read dig_y2 value */ + com_rslt += smi130_set_mag_read_addr( + SMI130_MAG_DIG_Y2); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_Y3], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_y2 = v_data_u8[SMI130_BMM150_DIG_Y3]; + + /* read dig_xy1 value */ + com_rslt += smi130_set_mag_read_addr( + SMI130_MAG_DIG_XY1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_XY1], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_xy1 = v_data_u8[SMI130_BMM150_DIG_XY1]; + /* read dig_xy2 value */ + com_rslt += smi130_set_mag_read_addr( + SMI130_MAG_DIG_XY2); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 ls register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_XY2], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_xy2 = v_data_u8[SMI130_BMM150_DIG_XY2]; + + /* read dig_z1 lsb value */ + com_rslt += smi130_set_mag_read_addr( + SMI130_MAG_DIG_Z1_LSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_Z1_LSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* read dig_z1 msb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_Z1_MSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_Z1_MSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_z1 = + (u16)((((u32)((u8)v_data_u8[SMI130_BMM150_DIG_Z1_MSB])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_BMM150_DIG_Z1_LSB])); + + /* read dig_z2 lsb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_Z2_LSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_Z2_LSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* read dig_z2 msb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_Z2_MSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_Z2_MSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_z2 = + (s16)((((s32)((s8)v_data_u8[SMI130_BMM150_DIG_Z2_MSB])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_BMM150_DIG_Z2_LSB])); + + /* read dig_z3 lsb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_Z3_LSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_DIG_Z3_LSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* read dig_z3 msb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_Z3_MSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_DIG_Z3_MSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_z3 = + (s16)((((s32)((s8)v_data_u8[SMI130_BMM150_DIG_DIG_Z3_MSB])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_BMM150_DIG_DIG_Z3_LSB])); + + /* read dig_z4 lsb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_Z4_LSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_DIG_Z4_LSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* read dig_z4 msb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_Z4_MSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_DIG_Z4_MSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_z4 = + (s16)((((s32)((s8)v_data_u8[SMI130_BMM150_DIG_DIG_Z4_MSB])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_BMM150_DIG_DIG_Z4_LSB])); + + /* read dig_xyz1 lsb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_XYZ1_LSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_DIG_XYZ1_LSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* read dig_xyz1 msb value */ + com_rslt += smi130_set_mag_read_addr(SMI130_MAG_DIG_XYZ1_MSB); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[SMI130_BMM150_DIG_DIG_XYZ1_MSB], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + mag_trim_mbl.dig_xyz1 = + (u16)((((u32)((u8)v_data_u8[SMI130_BMM150_DIG_DIG_XYZ1_MSB])) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[SMI130_BMM150_DIG_DIG_XYZ1_LSB])); + + return com_rslt; +} + /*! + * @brief This function used for initialize + * the AKM09911 and AKM09912 sensor + * + * + * @param v_akm_i2c_address_u8: The value of device address + * AKM sensor | Slave address + * --------------|--------------------- + * AKM09911 | AKM09911_I2C_ADDR_1 + * - | and AKM09911_I2C_ADDR_2 + * AKM09912 | AKM09912_I2C_ADDR_1 + * - | AKM09912_I2C_ADDR_2 + * - | AKM09912_I2C_ADDR_3 + * - | AKM09912_I2C_ADDR_4 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm_mag_interface_init( +u8 v_akm_i2c_address_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_pull_value_u8 = SMI130_INIT_VALUE; + u8 v_data_u8 = SMI130_INIT_VALUE; + u8 v_akm_chip_id_u8 = SMI130_INIT_VALUE; + /* accel operation mode to normal*/ + com_rslt = smi130_set_command_register(ACCEL_MODE_NORMAL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_command_register(MAG_MODE_NORMAL); + p_smi130->delay_msec(SMI130_AKM_INIT_DELAY); + smi130_get_mag_power_mode_stat(&v_data_u8); + /* register 0x7E write the 0x37, 0x9A and 0x30*/ + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_ONE); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_TWO); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_THREE); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /*switch the page1*/ + com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_target_page(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_paging_enable(SMI130_WRITE_ENABLE_PAGE1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_paging_enable(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* enable the pullup configuration from + the register 0x05 bit 4 and 5 to 10*/ + smi130_get_pullup_configuration(&v_pull_value_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + v_pull_value_u8 = v_pull_value_u8 | SMI130_PULL_UP_DATA; + com_rslt += smi130_set_pullup_configuration(v_pull_value_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + /*switch the page0*/ + com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE0); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_target_page(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Write the AKM09911 0r AKM09912 i2c address*/ + com_rslt += smi130_set_i2c_device_addr(v_akm_i2c_address_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* enable the mag interface to manual mode*/ + com_rslt += smi130_set_mag_manual_enable(SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_mag_manual_enable(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /*Enable the MAG interface */ + com_rslt += smi130_set_if_mode(SMI130_ENABLE_MAG_IF_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_if_mode(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + /* Set the AKM Fuse ROM mode */ + /* Set value for fuse ROM mode*/ + com_rslt += smi130_set_mag_write_data(AKM_FUSE_ROM_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* AKM mode address is 0x31*/ + com_rslt += smi130_set_mag_write_addr(AKM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Read the Fuse ROM v_data_u8 from registers + 0x60,0x61 and 0x62*/ + /* ASAX v_data_u8 */ + com_rslt += smi130_read_bosch_akm_sensitivity_data(); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* read the device id of the AKM sensor + if device id is 0x05 - AKM09911 + if device id is 0x04 - AKM09912*/ + com_rslt += smi130_set_mag_read_addr(AKM09912_CHIP_ID_REG); + /* 0x04 is mag_x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_akm_chip_id_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + printk(KERN_INFO "smi130,addr:0x%x, akm_chip_id:0x%x", + v_akm_i2c_address_u8, v_akm_chip_id_u8); + /* Set value power down mode mode*/ + com_rslt += smi130_set_mag_write_data(AKM_POWER_DOWN_MODE_DATA); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* AKM mode address is 0x31*/ + com_rslt += smi130_set_mag_write_addr(AKM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Set AKM Force mode*/ + com_rslt += smi130_set_mag_write_data( + AKM_SINGLE_MEASUREMENT_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* AKM mode address is 0x31*/ + com_rslt += smi130_set_mag_write_addr(AKM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Set the AKM read xyz v_data_u8 address*/ + com_rslt += smi130_set_mag_read_addr(AKM_DATA_REGISTER); + /* write the mag v_data_bw_u8 as 25Hz*/ + com_rslt += smi130_set_mag_output_data_rate( + SMI130_MAG_OUTPUT_DATA_RATE_25HZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Enable mag interface to auto mode*/ + com_rslt += smi130_set_mag_manual_enable(SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_mag_manual_enable(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + return com_rslt; +} + /*! + * @brief This function used for read the sensitivity data of + * AKM09911 and AKM09912 + * + * @note Before reading the mag sensitivity values + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_bosch_akm_sensitivity_data(void) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array holding the sensitivity ax,ay and az data*/ + u8 v_data_u8[SMI130_AKM_SENSITIVITY_DATA_SIZE] = { + SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* read asax value */ + com_rslt = smi130_set_mag_read_addr(SMI130_BST_AKM_ASAX); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[AKM_ASAX], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + akm_asa_data_mbl.asax = v_data_u8[AKM_ASAX]; + /* read asay value */ + com_rslt += smi130_set_mag_read_addr(SMI130_BST_AKM_ASAY); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[AKM_ASAY], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + akm_asa_data_mbl.asay = v_data_u8[AKM_ASAY]; + /* read asaz value */ + com_rslt += smi130_set_mag_read_addr(SMI130_BST_AKM_ASAZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[AKM_ASAZ], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + akm_asa_data_mbl.asaz = v_data_u8[AKM_ASAZ]; + + return com_rslt; +} +/*! + * @brief This API used to get the compensated X data + * of AKM09911 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 smi130_bosch_akm09911_compensate_X(s16 v_bosch_akm_x_s16) +{ + /*Return value of AKM x compensated v_data_u8*/ + s32 retval = SMI130_INIT_VALUE; + /* Convert raw v_data_u8 into compensated v_data_u8*/ + retval = (v_bosch_akm_x_s16 * + ((akm_asa_data_mbl.asax/AKM09911_SENSITIVITY_DIV) + + SMI130_GEN_READ_WRITE_DATA_LENGTH)); + return retval; +} +/*! + * @brief This API used to get the compensated Y data + * of AKM09911 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 smi130_bosch_akm09911_compensate_Y(s16 v_bosch_akm_y_s16) +{ + /*Return value of AKM y compensated v_data_u8*/ + s32 retval = SMI130_INIT_VALUE; + /* Convert raw v_data_u8 into compensated v_data_u8*/ + retval = (v_bosch_akm_y_s16 * + ((akm_asa_data_mbl.asay/AKM09911_SENSITIVITY_DIV) + + SMI130_GEN_READ_WRITE_DATA_LENGTH)); + return retval; +} +/*! + * @brief This API used to get the compensated Z data + * of AKM09911 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 smi130_bosch_akm09911_compensate_Z(s16 v_bosch_akm_z_s16) +{ + /*Return value of AKM z compensated v_data_u8*/ + s32 retval = SMI130_INIT_VALUE; + /* Convert raw v_data_u8 into compensated v_data_u8*/ + retval = (v_bosch_akm_z_s16 * + ((akm_asa_data_mbl.asaz/AKM09911_SENSITIVITY_DIV) + + SMI130_GEN_READ_WRITE_DATA_LENGTH)); + return retval; +} +/*! + * @brief This API used to get the compensated X data + * of AKM09912 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 smi130_bosch_akm09912_compensate_X(s16 v_bosch_akm_x_s16) +{ + /*Return value of AKM x compensated data*/ + s32 retval = SMI130_INIT_VALUE; + /* Convert raw data into compensated data*/ + retval = v_bosch_akm_x_s16 * + (akm_asa_data_mbl.asax + AKM09912_SENSITIVITY) + / AKM09912_SENSITIVITY_DIV; + return retval; +} +/*! + * @brief This API used to get the compensated Y data + * of AKM09912 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 smi130_bosch_akm09912_compensate_Y(s16 v_bosch_akm_y_s16) +{ + /*Return value of AKM y compensated data*/ + s32 retval = SMI130_INIT_VALUE; + /* Convert raw data into compensated data*/ + retval = v_bosch_akm_y_s16 * + (akm_asa_data_mbl.asax + AKM09912_SENSITIVITY) + / AKM09912_SENSITIVITY_DIV; + return retval; +} +/*! + * @brief This API used to get the compensated Z data + * of AKM09912 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 smi130_bosch_akm09912_compensate_Z(s16 v_bosch_akm_z_s16) +{ + /*Return value of AKM z compensated data*/ + s32 retval = SMI130_INIT_VALUE; + /* Convert raw data into compensated data*/ + retval = v_bosch_akm_z_s16 * + (akm_asa_data_mbl.asax + AKM09912_SENSITIVITY) + / AKM09912_SENSITIVITY_DIV; + return retval; +} + /*! + * @brief This function used for read the compensated value of + * AKM09911 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm09911_compensate_xyz( +struct smi130_mag_xyz_s32_t *bosch_akm_xyz) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + struct smi130_mag_t mag_xyz; + + com_rslt = smi130_read_mag_xyz(&mag_xyz, BST_AKM); + /* Compensation for X axis */ + bosch_akm_xyz->x = smi130_bosch_akm09911_compensate_X(mag_xyz.x); + + /* Compensation for Y axis */ + bosch_akm_xyz->y = smi130_bosch_akm09911_compensate_Y(mag_xyz.y); + + /* Compensation for Z axis */ + bosch_akm_xyz->z = smi130_bosch_akm09911_compensate_Z(mag_xyz.z); + + return com_rslt; +} + /*! + * @brief This function used for read the compensated value of + * AKM09912 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm09912_compensate_xyz( +struct smi130_mag_xyz_s32_t *bosch_akm_xyz) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + struct smi130_mag_t mag_xyz; + + com_rslt = smi130_read_mag_xyz(&mag_xyz, BST_AKM); + printk(KERN_INFO "akm09912_raw_x:%d, %d, %d, <%s>,<%d>", + mag_xyz.x, mag_xyz.y, mag_xyz.z, __func__, __LINE__); + /* Compensation for X axis */ + bosch_akm_xyz->x = smi130_bosch_akm09912_compensate_X(mag_xyz.x); + + /* Compensation for Y axis */ + bosch_akm_xyz->y = smi130_bosch_akm09912_compensate_Y(mag_xyz.y); + + /* Compensation for Z axis */ + bosch_akm_xyz->z = smi130_bosch_akm09912_compensate_Z(mag_xyz.z); + return com_rslt; +} + /*! + * @brief This function used for read the compensated value of + * AKM09912 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm09912_compensate_xyz_raw( +struct smi130_mag_xyz_s32_t *bosch_akm_xyz) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Compensation for X axis */ + bosch_akm_xyz->x = smi130_bosch_akm09912_compensate_X(bosch_akm_xyz->x); + + /* Compensation for Y axis */ + bosch_akm_xyz->y = smi130_bosch_akm09912_compensate_Y(bosch_akm_xyz->y); + + /* Compensation for Z axis */ + bosch_akm_xyz->z = smi130_bosch_akm09912_compensate_Z(bosch_akm_xyz->z); + + return com_rslt; +} +/*! + * @brief This function used for set the AKM09911 and AKM09912 + * power mode. + * @note Before set the AKM power mode + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @param v_akm_pow_mode_u8 : The value of akm power mode + * value | Description + * ---------|-------------------- + * 0 | AKM_POWER_DOWN_MODE + * 1 | AKM_SINGLE_MEAS_MODE + * 2 | FUSE_ROM_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm_set_powermode( +u8 v_akm_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + /* set mag interface manual mode*/ + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) { + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s>\n", + com_rslt, p_smi130->mag_manual_enable, __func__); + switch (v_akm_pow_mode_u8) { + case AKM_POWER_DOWN_MODE: + /* Set the power mode of AKM as power down mode*/ + com_rslt += smi130_set_mag_write_data(AKM_POWER_DOWN_MODE_DATA); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(AKM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + case AKM_SINGLE_MEAS_MODE: + /* Set the power mode of AKM as + single measurement mode*/ + com_rslt += smi130_set_mag_write_data + (AKM_SINGLE_MEASUREMENT_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(AKM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_read_addr(AKM_DATA_REGISTER); + break; + case FUSE_ROM_MODE: + /* Set the power mode of AKM as + Fuse ROM mode*/ + com_rslt += smi130_set_mag_write_data(AKM_FUSE_ROM_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(AKM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Sensitivity v_data_u8 */ + com_rslt += smi130_read_bosch_akm_sensitivity_data(); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* power down mode*/ + com_rslt += smi130_set_mag_write_data(AKM_POWER_DOWN_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(AKM_POWER_MODE_REG); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + /* set mag interface auto mode*/ + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) { + com_rslt += smi130_set_mag_manual_enable( + SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_smi130->mag_manual_enable, __func__, __LINE__); + return com_rslt; +} + /*! + * @brief This function used for set the magnetometer + * power mode of AKM09911 and AKM09912 + * @note Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of secondary if power mode + * value | Description + * ---------|-------------------- + * 0 | SMI130_MAG_FORCE_MODE + * 1 | SMI130_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_bosch_akm_and_secondary_if_powermode( +u8 v_mag_sec_if_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* accel operation mode to normal*/ + com_rslt = smi130_set_command_register(ACCEL_MODE_NORMAL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* set mag interface manual mode*/ + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) { + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + } + printk(KERN_ERR "com_rslt:%d, manual:%d,after setacc normal mode\n", + com_rslt, p_smi130->mag_manual_enable); + switch (v_mag_sec_if_pow_mode_u8) { + case SMI130_MAG_FORCE_MODE: + /* set the secondary mag power mode as NORMAL*/ + com_rslt += smi130_set_mag_interface_normal(); + /* set the akm power mode as single measurement mode*/ + com_rslt += smi130_bosch_akm_set_powermode(AKM_SINGLE_MEAS_MODE); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_read_addr(AKM_DATA_REGISTER); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + break; + case SMI130_MAG_SUSPEND_MODE: + /* set the akm power mode as power down mode*/ + com_rslt += smi130_bosch_akm_set_powermode(AKM_POWER_DOWN_MODE); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* set the secondary mag power mode as SUSPEND*/ + com_rslt += smi130_set_command_register(MAG_MODE_SUSPEND); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_SMI130_OUT_OF_RANGE; + break; + } + /* set mag interface auto mode*/ + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) + com_rslt += smi130_set_mag_manual_enable( + SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + return com_rslt; +} +/*! + * @brief This function used for read the YAMAH-YAS532 init + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas532_mag_interface_init( +void) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + u8 v_pull_value_u8 = SMI130_INIT_VALUE; + u8 v_data_u8 = SMI130_INIT_VALUE; + u8 i = SMI130_INIT_VALUE; + /* accel operation mode to normal*/ + com_rslt = smi130_set_command_register(ACCEL_MODE_NORMAL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* write mag power mode as NORMAL*/ + com_rslt += smi130_set_mag_interface_normal(); + /* register 0x7E write the 0x37, 0x9A and 0x30*/ + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_ONE); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_TWO); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_THREE); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /*switch the page1*/ + com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_target_page(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_paging_enable(SMI130_WRITE_ENABLE_PAGE1); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_paging_enable(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* enable the pullup configuration from + the register 0x05 bit 4 and 5 as 10*/ + smi130_get_pullup_configuration(&v_pull_value_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + v_pull_value_u8 = v_pull_value_u8 | SMI130_PULL_UP_DATA; + com_rslt += smi130_set_pullup_configuration(v_pull_value_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /*switch the page0*/ + com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE0); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_target_page(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Write the YAS532 i2c address*/ + com_rslt += smi130_set_i2c_device_addr(SMI130_AUX_YAS532_I2C_ADDRESS); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* enable the mag interface to manual mode*/ + com_rslt += smi130_set_mag_manual_enable(SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_mag_manual_enable(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /*Enable the MAG interface */ + com_rslt += smi130_set_if_mode(SMI130_ENABLE_MAG_IF_MODE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_if_mode(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + v_data_u8 = SMI130_MANUAL_DISABLE; + /* Read the YAS532 device id is 0x02*/ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS_DEVICE_ID_REG); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Read the YAS532 calibration data*/ + com_rslt += smi130_bosch_yamaha_yas532_calib_values(); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Assign the data acquisition mode*/ + yas532_data_mbl.measure_state = YAS532_MAG_STATE_INIT_COIL; + /* Set the default offset as invalid offset*/ + set_vector(yas532_data_mbl.v_hard_offset_s8, INVALID_OFFSET); + /* set the transform to zero */ + yas532_data_mbl.transform = SMI130_NULL; + /* Assign overflow as zero*/ + yas532_data_mbl.overflow = 0; + #if YAS532_MAG_LOG < YAS532_MAG_TEMPERATURE_LOG + yas532_data_mbl.temp_data.num = + yas532_data_mbl.temp_data.idx = 0; + #endif + /* Assign the coef value*/ + for (i = 0; i < 3; i++) { + yas532_data_mbl.coef[i] = yas532_version_ac_coef[i]; + yas532_data_mbl.last_raw[i] = 0; + } + yas532_data_mbl.last_raw[3] = 0; + /* Set the initial values of yas532*/ + com_rslt += smi130_bosch_yas532_set_initial_values(); + /* write the mag v_data_bw_u8 as 25Hz*/ + com_rslt += smi130_set_mag_output_data_rate( + SMI130_MAG_OUTPUT_DATA_RATE_25HZ); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Enable mag interface to auto mode*/ + com_rslt += smi130_set_mag_manual_enable( + SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + smi130_get_mag_manual_enable(&v_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + return com_rslt; +} +/*! + * @brief This function used to set the YAS532 initial values + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_set_initial_values(void) +{ +/* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* write testr1 as 0x00*/ + com_rslt = smi130_set_mag_write_data( + SMI130_YAS532_WRITE_TESTR1); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(SMI130_YAS532_TESTR1); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write testr2 as 0x00*/ + com_rslt += smi130_set_mag_write_data( + SMI130_YAS532_WRITE_TESTR2); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(SMI130_YAS532_TESTR2); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write Rcoil as 0x00*/ + com_rslt += smi130_set_mag_write_data( + SMI130_YAS532_WRITE_RCOIL); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(SMI130_YAS532_RCOIL); + p_smi130->delay_msec(SMI130_YAS532_SET_INITIAL_VALUE_DELAY); + /* check the valid offset*/ + if (is_valid_offset(yas532_data_mbl.v_hard_offset_s8)) { + com_rslt += smi130_bosch_yas532_set_offset( + yas532_data_mbl.v_hard_offset_s8); + yas532_data_mbl.measure_state = YAS532_MAG_STATE_NORMAL; + } else { + /* set the default offset as invalid offset*/ + set_vector(yas532_data_mbl.v_hard_offset_s8, INVALID_OFFSET); + /*Set the default measure state for offset correction*/ + yas532_data_mbl.measure_state = YAS532_MAG_STATE_MEASURE_OFFSET; + } + return com_rslt; +} +/*! + * @brief This function used for YAS532 offset correction + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_magnetic_measure_set_offset( +void) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* used for offset value set to the offset register*/ + s8 v_hard_offset_s8[SMI130_HARD_OFFSET_DATA_SIZE] = { + SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* offset correction factors*/ + static const u8 v_correct_u8[SMI130_YAS_CORRECT_DATA_SIZE] = { + 16, 8, 4, 2, 1}; + /* used for the temperature */ + u16 v_temp_u16 = SMI130_INIT_VALUE; + /* used for the xy1y2 read*/ + u16 v_xy1y2_u16[SMI130_YAS_XY1Y2_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* local flag for assign the values*/ + s32 v_flag_s32[SMI130_YAS_FLAG_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + u8 i, j, v_busy_u8, v_overflow_u8 = SMI130_INIT_VALUE; + + for (i = 0; i < 5; i++) { + /* set the offset values*/ + com_rslt = smi130_bosch_yas532_set_offset(v_hard_offset_s8); + /* read the sensor data*/ + com_rslt += smi130_bosch_yas532_normal_measurement_data( + SMI130_YAS532_ACQ_START, &v_busy_u8, &v_temp_u16, + v_xy1y2_u16, &v_overflow_u8); + /* check the sensor busy status*/ + if (v_busy_u8) + return E_SMI130_BUSY; + /* calculate the magnetic correction with + offset and assign the values + to the offset register */ + for (j = 0; j < 3; j++) { + if (YAS532_DATA_CENTER == v_xy1y2_u16[j]) + v_flag_s32[j] = 0; + if (YAS532_DATA_CENTER < v_xy1y2_u16[j]) + v_flag_s32[j] = 1; + if (v_xy1y2_u16[j] < YAS532_DATA_CENTER) + v_flag_s32[j] = -1; + } + for (j = 0; j < 3; j++) { + if (v_flag_s32[j]) + v_hard_offset_s8[j] = (s8)(v_hard_offset_s8[j] + + v_flag_s32[j] * v_correct_u8[i]); + } + } + /* set the offset */ + com_rslt += smi130_bosch_yas532_set_offset(v_hard_offset_s8); + return com_rslt; +} +/*! + * @brief This function used for read the + * YAMAHA YAS532 calibration data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas532_calib_values(void) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array holding the YAS532 calibration values */ + u8 v_data_u8[SMI130_YAS532_CALIB_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* Read the DX value */ + com_rslt = smi130_set_mag_read_addr(SMI130_YAS532_CALIB_CX); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[0], SMI130_GEN_READ_WRITE_DATA_LENGTH); + yas532_data_mbl.calib_yas532.cx = (s32)((v_data_u8[0] + * 10) - 1280); + /* Read the DY1 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB_CY1); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[1], SMI130_GEN_READ_WRITE_DATA_LENGTH); + yas532_data_mbl.calib_yas532.cy1 = + (s32)((v_data_u8[1] * 10) - 1280); + /* Read the DY2 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB_CY2); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[2], SMI130_GEN_READ_WRITE_DATA_LENGTH); + yas532_data_mbl.calib_yas532.cy2 = + (s32)((v_data_u8[2] * 10) - 1280); + /* Read the D2 and D3 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB1); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[3], SMI130_GEN_READ_WRITE_DATA_LENGTH); + yas532_data_mbl.calib_yas532.a2 = + (s32)(((v_data_u8[3] >> + SMI130_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x03F) - 32); + /* Read the D3 and D4 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB2); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[4], SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a3*/ + yas532_data_mbl.calib_yas532.a3 = (s32)((((v_data_u8[3] << + SMI130_SHIFT_BIT_POSITION_BY_02_BITS) & 0x0C) | + ((v_data_u8[4] + >> SMI130_SHIFT_BIT_POSITION_BY_06_BITS) + & 0x03)) - 8); + /* calculate a4*/ + yas532_data_mbl.calib_yas532.a4 = (s32)((v_data_u8[4] + & 0x3F) - 32); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* Read the D5 and D6 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB3); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[5], SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a5*/ + yas532_data_mbl.calib_yas532.a5 = + (s32)(((v_data_u8[5] + >> SMI130_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x3F) + 38); + /* Read the D6 and D7 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB4); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[6], SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a6*/ + yas532_data_mbl.calib_yas532.a6 = + (s32)((((v_data_u8[5] + << SMI130_SHIFT_BIT_POSITION_BY_04_BITS) + & 0x30) | ((v_data_u8[6] >> + SMI130_SHIFT_BIT_POSITION_BY_04_BITS) + & 0x0F)) - 32); + /* Read the D7 and D8 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB5); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[7], SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a7*/ + yas532_data_mbl.calib_yas532.a7 = (s32)((((v_data_u8[6] + << SMI130_SHIFT_BIT_POSITION_BY_03_BITS) + & 0x78) | + ((v_data_u8[7] + >> SMI130_SHIFT_BIT_POSITION_BY_05_BITS) & + 0x07)) - 64); + /* Read the D8 and D9 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CLAIB6); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[8], SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a8*/ + yas532_data_mbl.calib_yas532.a8 = (s32)((((v_data_u8[7] << + SMI130_GEN_READ_WRITE_DATA_LENGTH) & 0x3E) | + ((v_data_u8[8] >> + SMI130_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)) - + 32); + + /* Read the D8 and D9 value */ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB7); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[9], SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a9*/ + yas532_data_mbl.calib_yas532.a9 = (s32)(((v_data_u8[8] << + SMI130_GEN_READ_WRITE_DATA_LENGTH) & 0xFE) | + ((v_data_u8[9] >> + SMI130_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + /* calculate k*/ + yas532_data_mbl.calib_yas532.k = (s32)((v_data_u8[9] >> + SMI130_SHIFT_BIT_POSITION_BY_02_BITS) & 0x1F); + /* Read the value from register 0x9A*/ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB8); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[10], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* Read the value from register 0x9B*/ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIIB9); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[11], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* Read the value from register 0x9C*/ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB10); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[12], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* Read the value from register 0x9D*/ + com_rslt += smi130_set_mag_read_addr(SMI130_YAS532_CALIB11); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, + &v_data_u8[13], + SMI130_GEN_READ_WRITE_DATA_LENGTH); + /* Calculate the fxy1y2 and rxy1y1*/ + yas532_data_mbl.calib_yas532.fxy1y2[0] = + (u8)(((v_data_u8[10] + & 0x01) + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) + | ((v_data_u8[11] >> + SMI130_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + yas532_data_mbl.calib_yas532.rxy1y2[0] = + ((s8)(((v_data_u8[10] + >> SMI130_SHIFT_BIT_POSITION_BY_01_BIT) & 0x3F) + << SMI130_SHIFT_BIT_POSITION_BY_02_BITS)) + >> SMI130_SHIFT_BIT_POSITION_BY_02_BITS; + yas532_data_mbl.calib_yas532.fxy1y2[1] = + (u8)(((v_data_u8[11] & 0x01) + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) + | ((v_data_u8[12] >> + SMI130_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + yas532_data_mbl.calib_yas532.rxy1y2[1] = + ((s8)(((v_data_u8[11] + >> SMI130_SHIFT_BIT_POSITION_BY_01_BIT) & 0x3F) + << SMI130_SHIFT_BIT_POSITION_BY_02_BITS)) + >> SMI130_SHIFT_BIT_POSITION_BY_02_BITS; + yas532_data_mbl.calib_yas532.fxy1y2[2] = + (u8)(((v_data_u8[12] & 0x01) + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) + | ((v_data_u8[13] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + yas532_data_mbl.calib_yas532.rxy1y2[2] = + ((s8)(((v_data_u8[12] + >> SMI130_SHIFT_BIT_POSITION_BY_01_BIT) & 0x3F) + << SMI130_SHIFT_BIT_POSITION_BY_02_BITS)) + >> SMI130_SHIFT_BIT_POSITION_BY_02_BITS; + + return com_rslt; +} +/*! + * @brief This function used for calculate the + * YAS532 read the linear data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_xy1y2_to_linear( +u16 *v_xy1y2_u16, s32 *xy1y2_linear) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SUCCESS; + static const u16 v_calib_data[] = { + 3721, 3971, 4221, 4471}; + u8 i = SMI130_INIT_VALUE; + + for (i = 0; i < 3; i++) + xy1y2_linear[i] = v_xy1y2_u16[i] - + v_calib_data[yas532_data_mbl.calib_yas532.fxy1y2[i]] + + (yas532_data_mbl.v_hard_offset_s8[i] - + yas532_data_mbl.calib_yas532.rxy1y2[i]) + * yas532_data_mbl.coef[i]; + return com_rslt; +} +/*! + * @brief This function used for read the YAS532 sensor data + * @param v_acquisition_command_u8: used to set the data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param v_busy_u8 : used to get the busy flay for sensor data read + * @param v_temp_u16 : used to get the temperature data + * @param v_xy1y2_u16 : used to get the sensor xy1y2 data + * @param v_overflow_u8 : used to get the overflow data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_normal_measurement_data( +u8 v_acquisition_command_u8, u8 *v_busy_u8, +u16 *v_temp_u16, u16 *v_xy1y2_u16, u8 *v_overflow_u8) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + /* Array holding the YAS532 xyy1 data*/ + u8 v_data_u8[SMI130_YAS_XY1Y2T_DATA_SIZE] = { + SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + u8 i = SMI130_INIT_VALUE; + /* check the p_smi130 structure as NULL*/ + if (p_smi130 == SMI130_NULL) { + return E_SMI130_NULL_PTR; + } else { + /* read the sensor data */ + com_rslt = smi130_bosch_yas532_acquisition_command_register( + v_acquisition_command_u8); + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_MAG_X_LSB__REG, + v_data_u8, SMI130_MAG_YAS_DATA_LENGTH); + /* read the xyy1 data*/ + *v_busy_u8 = + ((v_data_u8[0] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01); + *v_temp_u16 = + (u16)((((s32)v_data_u8[0] + << SMI130_SHIFT_BIT_POSITION_BY_03_BITS) + & 0x3F8) | ((v_data_u8[1] + >> SMI130_SHIFT_BIT_POSITION_BY_05_BITS) & 0x07)); + v_xy1y2_u16[0] = + (u16)((((s32)v_data_u8[2] + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS) & 0x1FC0) + | ((v_data_u8[3] >> + SMI130_SHIFT_BIT_POSITION_BY_02_BITS) & 0x3F)); + v_xy1y2_u16[1] = + (u16)((((s32)v_data_u8[4] + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS) + & 0x1FC0) + | ((v_data_u8[5] + >> SMI130_SHIFT_BIT_POSITION_BY_02_BITS) & 0x3F)); + v_xy1y2_u16[2] = + (u16)((((s32)v_data_u8[6] + << SMI130_SHIFT_BIT_POSITION_BY_06_BITS) + & 0x1FC0) + | ((v_data_u8[7] + >> SMI130_SHIFT_BIT_POSITION_BY_02_BITS) & 0x3F)); + *v_overflow_u8 = 0; + for (i = 0; i < 3; i++) { + if (v_xy1y2_u16[i] == YAS532_DATA_OVERFLOW) + *v_overflow_u8 |= (1 << (i * 2)); + if (v_xy1y2_u16[i] == YAS532_DATA_UNDERFLOW) + *v_overflow_u8 |= (1 << (i * 2 + 1)); + } + } + return com_rslt; +} +/*! + * @brief This function used for YAS532 sensor data + * @param v_acquisition_command_u8 : the value of CMDR + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param xyz_data : the vector xyz output + * @param v_overflow_s8 : the value of overflow + * @param v_temp_correction_u8 : the value of temperate correction enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_measurement_xyz_data( +struct yas532_vector *xyz_data, u8 *v_overflow_s8, u8 v_temp_correction_u8, +u8 v_acquisition_command_u8) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = SMI130_INIT_VALUE; + /* Array holding the linear calculation output*/ + s32 v_xy1y2_linear_s32[SMI130_YAS_XY1Y2_DATA_SIZE] = { + SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* Array holding the temperature data */ + s32 v_xyz_tmp_s32[SMI130_YAS_TEMP_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + s32 tmp = SMI130_INIT_VALUE; + s32 sx, sy1, sy2, sy, sz = SMI130_INIT_VALUE; + u8 i, v_busy_u8 = SMI130_INIT_VALUE; + u16 v_temp_u16 = SMI130_INIT_VALUE; + /* Array holding the xyy1 sensor raw data*/ + u16 v_xy1y2_u16[SMI130_YAS_XY1Y2_DATA_SIZE] = {SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + #if YAS532_MAG_LOG < YAS532_MAG_TEMPERATURE_LOG + s32 sum = SMI130_INIT_VALUE; + #endif + *v_overflow_s8 = SMI130_INIT_VALUE; + switch (yas532_data_mbl.measure_state) { + case YAS532_MAG_STATE_INIT_COIL: + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + /* write Rcoil*/ + com_rslt += smi130_set_mag_write_data( + SMI130_YAS_DISABLE_RCOIL); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(SMI130_YAS532_RCOIL); + p_smi130->delay_msec(SMI130_YAS532_MEASUREMENT_DELAY); + if (!yas532_data_mbl.overflow && is_valid_offset( + yas532_data_mbl.v_hard_offset_s8)) + yas532_data_mbl.measure_state = 0; + break; + case YAS532_MAG_STATE_MEASURE_OFFSET: + com_rslt = smi130_bosch_yas532_magnetic_measure_set_offset(); + yas532_data_mbl.measure_state = 0; + break; + default: + break; + } + /* Read sensor data*/ + com_rslt += smi130_bosch_yas532_normal_measurement_data( + v_acquisition_command_u8, &v_busy_u8, &v_temp_u16, + v_xy1y2_u16, v_overflow_s8); + /* Calculate the linear data*/ + com_rslt += smi130_bosch_yas532_xy1y2_to_linear(v_xy1y2_u16, + v_xy1y2_linear_s32); + /* Calculate temperature correction */ + #if YAS532_MAG_LOG < YAS532_MAG_TEMPERATURE_LOG + yas532_data_mbl.temp_data.log[yas532_data_mbl.temp_data.idx++] = + v_temp_u16; + if (YAS532_MAG_TEMPERATURE_LOG <= yas532_data_mbl.temp_data.idx) + yas532_data_mbl.temp_data.idx = 0; + yas532_data_mbl.temp_data.num++; + if (YAS532_MAG_TEMPERATURE_LOG <= yas532_data_mbl.temp_data.num) + yas532_data_mbl.temp_data.num = YAS532_MAG_TEMPERATURE_LOG; + for (i = 0; i < yas532_data_mbl.temp_data.num; i++) + sum += yas532_data_mbl.temp_data.log[i]; + tmp = sum * 10 / yas532_data_mbl.temp_data.num + - YAS532_TEMP20DEGREE_TYPICAL * 10; + #else + tmp = (v_temp_u16 - YAS532_TEMP20DEGREE_TYPICAL) + * 10; + #endif + sx = v_xy1y2_linear_s32[0]; + sy1 = v_xy1y2_linear_s32[1]; + sy2 = v_xy1y2_linear_s32[2]; + /* Temperature correction */ + if (v_temp_correction_u8) { + sx -= (yas532_data_mbl.calib_yas532.cx * tmp) + / 1000; + sy1 -= (yas532_data_mbl.calib_yas532.cy1 * tmp) + / 1000; + sy2 -= (yas532_data_mbl.calib_yas532.cy2 * tmp) + / 1000; + } + sy = sy1 - sy2; + sz = -sy1 - sy2; + + xyz_data->yas532_vector_xyz[0] = yas532_data_mbl.calib_yas532.k * + ((100 * sx + yas532_data_mbl.calib_yas532.a2 * sy + + yas532_data_mbl.calib_yas532.a3 * sz) / 10); + xyz_data->yas532_vector_xyz[1] = yas532_data_mbl.calib_yas532.k * + ((yas532_data_mbl.calib_yas532.a4 * sx + yas532_data_mbl.calib_yas532.a5 * sy + + yas532_data_mbl.calib_yas532.a6 * sz) / 10); + xyz_data->yas532_vector_xyz[2] = yas532_data_mbl.calib_yas532.k * + ((yas532_data_mbl.calib_yas532.a7 * sx + yas532_data_mbl.calib_yas532.a8 * sy + + yas532_data_mbl.calib_yas532.a9 * sz) / 10); + if (yas532_data_mbl.transform != SMI130_NULL) { + for (i = 0; i < 3; i++) { + v_xyz_tmp_s32[i] = yas532_data_mbl.transform[i + * 3] * + xyz_data->yas532_vector_xyz[0] + + yas532_data_mbl.transform[i * 3 + 1] * + xyz_data->yas532_vector_xyz[1] + + yas532_data_mbl.transform[i * 3 + 2] * + xyz_data->yas532_vector_xyz[2]; + } + set_vector(xyz_data->yas532_vector_xyz, v_xyz_tmp_s32); + } + for (i = 0; i < 3; i++) { + xyz_data->yas532_vector_xyz[i] -= + xyz_data->yas532_vector_xyz[i] % 10; + if (*v_overflow_s8 & (1 + << (i * 2))) + xyz_data->yas532_vector_xyz[i] += + 1; /* set overflow */ + if (*v_overflow_s8 & (1 << + (i * 2 + 1))) + xyz_data->yas532_vector_xyz[i] += 2; /* set underflow */ + } + + +if (v_busy_u8) + return com_rslt; + if (0 < *v_overflow_s8) { + if (!yas532_data_mbl.overflow) + yas532_data_mbl.overflow = 1; + yas532_data_mbl.measure_state = YAS532_MAG_STATE_INIT_COIL; + } else + yas532_data_mbl.overflow = 0; + for (i = 0; i < 3; i++) + yas532_data_mbl.last_raw[i] = v_xy1y2_u16[i]; + yas532_data_mbl.last_raw[i] = v_temp_u16; + return com_rslt; +} +/*! + * @brief This function used for YAS532 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_acquisition_command_register( +u8 v_command_reg_data_u8) +{ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + + com_rslt = smi130_set_mag_write_data(v_command_reg_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* YAMAHA YAS532-0x82*/ + com_rslt += smi130_set_mag_write_addr( + SMI130_YAS532_COMMAND_REGISTER); + p_smi130->delay_msec(SMI130_YAS_ACQ_COMMAND_DELAY); + com_rslt += smi130_set_mag_read_addr( + SMI130_YAS532_DATA_REGISTER); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) + com_rslt += smi130_set_mag_manual_enable(SMI130_MANUAL_DISABLE); + + return com_rslt; + +} +/*! + * @brief This function used write offset of YAS532 + * + * @param p_offset_s8 : The value of offset to write + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_set_offset( +const s8 *p_offset_s8) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) + com_rslt = smi130_set_mag_manual_enable(SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_YAS532_OFFSET_DELAY); + + /* Write offset X data*/ + com_rslt = smi130_set_mag_write_data(p_offset_s8[0]); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* YAS532 offset x write*/ + com_rslt += smi130_set_mag_write_addr(SMI130_YAS532_OFFSET_X); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + /* Write offset Y data*/ + com_rslt = smi130_set_mag_write_data(p_offset_s8[1]); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* YAS532 offset y write*/ + com_rslt += smi130_set_mag_write_addr(SMI130_YAS532_OFFSET_Y); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + /* Write offset Z data*/ + com_rslt = smi130_set_mag_write_data(p_offset_s8[2]); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* YAS532 offset z write*/ + com_rslt += smi130_set_mag_write_addr(SMI130_YAS532_OFFSET_Z); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + set_vector(yas532_data_mbl.v_hard_offset_s8, p_offset_s8); + + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) + com_rslt = smi130_set_mag_manual_enable(SMI130_MANUAL_DISABLE); + return com_rslt; +} +/*! + * @brief This function used to init the YAMAH-YAS537 + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_mag_interface_init( +void) +{ +/* This variable used for provide the communication +results*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +u8 v_pull_value_u8 = SMI130_INIT_VALUE; +u8 v_data_u8 = SMI130_INIT_VALUE; +u8 i = SMI130_INIT_VALUE; +/* accel operation mode to normal*/ +com_rslt = smi130_set_command_register(ACCEL_MODE_NORMAL); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* write mag power mode as NORMAL*/ +com_rslt += smi130_set_mag_interface_normal(); +/* register 0x7E write the 0x37, 0x9A and 0x30*/ +com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_ONE); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_TWO); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_command_register(SMI130_COMMAND_REG_THREE); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/*switch the page1*/ +com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE1); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +smi130_get_target_page(&v_data_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_paging_enable(SMI130_WRITE_ENABLE_PAGE1); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +smi130_get_paging_enable(&v_data_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* enable the pullup configuration from +the register 0x05 bit 4 and 5 as 10*/ +smi130_get_pullup_configuration(&v_pull_value_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +v_pull_value_u8 = v_pull_value_u8 | SMI130_PULL_UP_DATA; +com_rslt += smi130_set_pullup_configuration(v_pull_value_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/*switch the page0*/ +com_rslt += smi130_set_target_page(SMI130_WRITE_TARGET_PAGE0); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +smi130_get_target_page(&v_data_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* Write the YAS532 i2c address*/ +com_rslt += smi130_set_i2c_device_addr(SMI130_YAS537_I2C_ADDRESS); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* enable the mag interface to manual mode*/ +com_rslt += smi130_set_mag_manual_enable(SMI130_MANUAL_ENABLE); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +smi130_get_mag_manual_enable(&v_data_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/*Enable the MAG interface */ +com_rslt += smi130_set_if_mode(SMI130_ENABLE_MAG_IF_MODE); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +smi130_get_if_mode(&v_data_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +v_data_u8 = SMI130_MANUAL_DISABLE; +/* Read the YAS537 device id*/ +com_rslt += smi130_set_mag_read_addr(SMI130_YAS_DEVICE_ID_REG); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&v_data_u8, SMI130_GEN_READ_WRITE_DATA_LENGTH); +yas537_data_mbl.dev_id = v_data_u8; +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* Read the YAS532 calibration data*/ +com_rslt += +smi130_bosch_yamaha_yas537_calib_values( +SMI130_GEN_READ_WRITE_DATA_LENGTH); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* set the mode to NORMAL*/ +yas537_data_mbl.measure_state = YAS537_MAG_STATE_NORMAL; +/* set the transform to zero */ +yas537_data_mbl.transform = SMI130_NULL; +yas537_data_mbl.average = 32; +for (i = 0; i < 3; i++) { + yas537_data_mbl.hard_offset[i] = -128; + yas537_data_mbl.last_after_rcoil[i] = 0; +} +for (i = 0; i < 4; i++) + yas537_data_mbl.last_raw[i] = 0; +/* write the mag bandwidth as 25Hz*/ +com_rslt += smi130_set_mag_output_data_rate( +SMI130_MAG_OUTPUT_DATA_RATE_25HZ); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* Enable mag interface to auto mode*/ +com_rslt += smi130_set_mag_manual_enable( +SMI130_MANUAL_DISABLE); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +smi130_get_mag_manual_enable(&v_data_u8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +return com_rslt; +} +/*! +* @brief This function used for read the +* YAMAHA YAS537 calibration data +* +* +* @param v_rcoil_u8 : The value of r coil +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_calib_values( +u8 v_rcoil_u8) +{ +/* This variable used for provide the communication +results*/ +SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; +/* Array holding the YAS532 calibration values */ +u8 a_data_u8[SMI130_YAS537_CALIB_DATA_SIZE] = { +SMI130_INIT_VALUE, SMI130_INIT_VALUE, +SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, +SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, +SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, +SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, +SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, +}; +static const u8 v_avrr_u8[] = {0x50, 0x60, 0x70}; +u8 v_cal_valid_u8 = SMI130_INIT_VALUE, i; +/* write soft reset as 0x02*/ +com_rslt = smi130_set_mag_write_data( +YAS537_SRSTR_DATA); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_mag_write_addr(YAS537_REG_SRSTR); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* Read the DX value */ +com_rslt = smi130_set_mag_read_addr(YAS537_REG_CALR_C0); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[0], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the DY1 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C1); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[1], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the DY2 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C2); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[2], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D2 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C3); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[3], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D3 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C4); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[4], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D4 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C5); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[5], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D5 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C6); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[6], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D6 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C7); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[7], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D7 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C8); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[8], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D8 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_C9); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[9], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D9 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_CA); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[10], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RX value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_CB); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[11], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RY1 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_CC); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[12], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RY2 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_CD); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[13], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RY2 value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_CE); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[14], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the CHF value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_CF); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[15], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* Read the VER value */ +com_rslt += smi130_set_mag_read_addr(YAS537_REG_CALR_DO); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += smi130_read_reg(SMI130_MAG_DATA_READ_REG, +&a_data_u8[16], SMI130_GEN_READ_WRITE_DATA_LENGTH); +/* get the calib ver*/ +yas537_data_mbl.calib_yas537.ver = +(a_data_u8[16] >> SMI130_SHIFT_BIT_POSITION_BY_06_BITS); +for (i = 0; i < 17; i++) { + if (((i < 16 && a_data_u8[i]) != 0)) + v_cal_valid_u8 = 1; + if ((i < 16 && + (a_data_u8[i] & 0x3F)) != 0) + v_cal_valid_u8 = 1; +} +if (!v_cal_valid_u8) + return ERROR; +if (yas537_data_mbl.calib_yas537.ver == 0) { + for (i = 0; i < 17; i++) { + if (i < 12) { + /* write offset*/ + com_rslt += smi130_set_mag_write_data( + a_data_u8[i]); + p_smi130->delay_msec( + SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + YAS537_REG_MTCR + i); + p_smi130->delay_msec( + SMI130_GEN_READ_WRITE_DELAY); + } else if (i < 15) { + /* write offset correction*/ + com_rslt += smi130_set_mag_write_data( + a_data_u8[i]); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(( + (YAS537_REG_OXR + i) - 12)); + p_smi130->delay_msec( + SMI130_GEN_READ_WRITE_DELAY); + yas537_data_mbl.hard_offset[i - 12] + = a_data_u8[i]; + } else { + /* write offset correction*/ + com_rslt += smi130_set_mag_write_data( + a_data_u8[i]); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(( + (YAS537_REG_OXR + i) - 11)); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + } + +} +} else if (yas537_data_mbl.calib_yas537.ver == 1) { + for (i = 0; i < 3; i++) { + /* write offset*/ + com_rslt += smi130_set_mag_write_data( + a_data_u8[i]); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + YAS537_REG_MTCR + i); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + if (com_rslt == SUCCESS) { + /* write offset*/ + com_rslt += smi130_set_mag_write_data( + a_data_u8[i + 12]); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + YAS537_REG_OXR + i); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + yas537_data_mbl.hard_offset[i] = + a_data_u8[i + 12]; + } else { + com_rslt = ERROR; + } + } + /* write offset*/ + com_rslt += smi130_set_mag_write_data( + ((a_data_u8[i] & 0xE0) | 0x10)); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr( + YAS537_REG_MTCR + i); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write offset*/ + com_rslt += smi130_set_mag_write_data( + ((a_data_u8[15] + >> SMI130_SHIFT_BIT_POSITION_BY_03_BITS) + & 0x1E)); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(YAS537_REG_HCKR); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write offset*/ + com_rslt += smi130_set_mag_write_data( + ((a_data_u8[15] << 1) & 0x1E)); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(YAS537_REG_LCKR); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write offset*/ + com_rslt += smi130_set_mag_write_data( + (a_data_u8[16] & 0x3F)); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(YAS537_REG_OCR); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + + /* Assign the calibration values*/ + /* a2 */ + yas537_data_mbl.calib_yas537.a2 = + ((((a_data_u8[3] + << SMI130_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x7C) + | (a_data_u8[4] + >> SMI130_SHIFT_BIT_POSITION_BY_06_BITS)) - 64); + /* a3 */ + yas537_data_mbl.calib_yas537.a3 = + ((((a_data_u8[4] << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) + & 0x7E) + | (a_data_u8[5] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS)) - 64); + /* a4 */ + yas537_data_mbl.calib_yas537.a4 = + ((((a_data_u8[5] + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) + & 0xFE) + | (a_data_u8[6] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS)) + - 128); + /* a5 */ + yas537_data_mbl.calib_yas537.a5 = + ((((a_data_u8[6] + << SMI130_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x1FC) + | (a_data_u8[7] + >> SMI130_SHIFT_BIT_POSITION_BY_06_BITS)) + - 112); + /* a6 */ + yas537_data_mbl.calib_yas537.a6 = + ((((a_data_u8[7] + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) + & 0x7E) + | (a_data_u8[8] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS)) - 64); + /* a7 */ + yas537_data_mbl.calib_yas537.a7 = + ((((a_data_u8[8] + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) + & 0xFE) + | (a_data_u8[9] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS)) + - 128); + /* a8 */ + yas537_data_mbl.calib_yas537.a8 = ((a_data_u8[9] & + 0x7F) - 64); + /* a9 */ + yas537_data_mbl.calib_yas537.a9 = ((((a_data_u8[10] + << SMI130_SHIFT_BIT_POSITION_BY_01_BIT) & 0x1FE) + | (a_data_u8[11] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS)) + - 112); + /* k */ + yas537_data_mbl.calib_yas537.k = ( + a_data_u8[11] & 0x7F); + } else { + return ERROR; + } +/* write A/D converter*/ +com_rslt += smi130_set_mag_write_data( +YAS537_WRITE_A_D_CONVERTER); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_mag_write_addr(YAS537_REG_ADCCALR); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* write A/D converter second register*/ +com_rslt += smi130_set_mag_write_data( +YAS537_WRITE_A_D_CONVERTER2); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_mag_write_addr(YAS537_REG_ADCCALR_ONE); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* write temperature calibration register*/ +com_rslt += smi130_set_mag_write_data(YAS537_WRITE_TEMP_CALIB); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_mag_write_addr(YAS537_REG_TRMR); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* write average filter register*/ +com_rslt += smi130_set_mag_write_data( +v_avrr_u8[yas537_data_mbl.average]); +p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); +com_rslt += smi130_set_mag_write_addr(YAS537_REG_AVRR); +p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +if (v_rcoil_u8) { + /* write average; filter register*/ + com_rslt += smi130_set_mag_write_data( + YAS537_WRITE_FILTER); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(YAS537_REG_CONFR); + p_smi130->delay_msec( + SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +} + +return com_rslt; + +} +/*! + * @brief This function used for YAS537 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas537_acquisition_command_register( +u8 v_command_reg_data_u8) +{ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + com_rslt = smi130_set_mag_write_data(v_command_reg_data_u8); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + /* YAMAHA YAS532-0x82*/ + com_rslt += smi130_set_mag_write_addr( + SMI130_REG_YAS537_CMDR); + /* set the mode to RECORD*/ + yas537_data_mbl.measure_state = YAS537_MAG_STATE_RECORD_DATA; + p_smi130->delay_msec(SMI130_YAS_ACQ_COMMAND_DELAY); + com_rslt += smi130_set_mag_read_addr( + YAS537_REG_TEMPERATURE_0); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) + com_rslt += smi130_set_mag_manual_enable( + SMI130_MANUAL_DISABLE); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + + return com_rslt; + +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param xy1y2: The value of raw xy1y2 data + * @param xyz: The value of xyz data + * + * + * @return None + * + * + */ +static void xy1y2_to_xyz(u16 *xy1y2, s32 *xyz) +{ + xyz[0] = ((xy1y2[0] - 8192) + * 300); + xyz[1] = (((xy1y2[1] - xy1y2[2]) + * 1732) / 10); + xyz[2] = (((-xy1y2[2] - xy1y2[2]) + + 16384) * 300); +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_coil_stat_u8: The value of R coil status + * @param v_busy_u8: The value of busy status + * @param v_temperature_u16: The value of temperature + * @param xy1y2: The value of raw xy1y2 data + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_read_xy1y2_data( +u8 *v_coil_stat_u8, u8 *v_busy_u8, +u16 *v_temperature_u16, u16 *xy1y2, u8 *v_ouflow_u8) +{ + /* This variable used for provide the communication + results*/ + SMI130_RETURN_FUNCTION_TYPE com_rslt = E_SMI130_COMM_RES; + /* Array holding the YAS532 calibration values */ + u8 a_data_u8[SMI130_YAS_XY1Y2T_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE, + }; + u8 i = SMI130_INIT_VALUE; + s32 a_h_s32[SMI130_YAS_H_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + s32 a_s_s32[SMI130_YAS_S_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + /* set command register*/ + com_rslt = smi130_bosch_yas537_acquisition_command_register( + YAS537_SET_COMMAND_REGISTER); + /* read the yas537 sensor data of xy1y2*/ + com_rslt += + p_smi130->SMI130_BUS_READ_FUNC(p_smi130->dev_addr, + SMI130_USER_DATA_MAG_X_LSB__REG, + a_data_u8, SMI130_MAG_YAS_DATA_LENGTH); + /* read the busy flag*/ + *v_busy_u8 = a_data_u8[2] + >> SMI130_SHIFT_BIT_POSITION_BY_07_BITS; + /* read the coil status*/ + *v_coil_stat_u8 = + ((a_data_u8[2] >> + SMI130_SHIFT_BIT_POSITION_BY_06_BITS) & 0X01); + /* read temperature data*/ + *v_temperature_u16 = (u16)((a_data_u8[0] + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | a_data_u8[1]); + /* read x data*/ + xy1y2[0] = (u16)(((a_data_u8[2] & + 0x3F) + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8[3])); + /* read y1 data*/ + xy1y2[1] = (u16)((a_data_u8[4] + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | a_data_u8[5]); + /* read y2 data*/ + xy1y2[2] = (u16)((a_data_u8[6] + << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) + | a_data_u8[7]); + for (i = 0; i < 3; i++) + yas537_data_mbl.last_raw[i] = xy1y2[i]; + yas537_data_mbl.last_raw[i] = *v_temperature_u16; + if (yas537_data_mbl.calib_yas537.ver == 1) { + for (i = 0; i < 3; i++) + a_s_s32[i] = xy1y2[i] - 8192; + /* read hx*/ + a_h_s32[0] = ((yas537_data_mbl.calib_yas537.k * ( + (128 * a_s_s32[0]) + + (yas537_data_mbl.calib_yas537.a2 * a_s_s32[1]) + + (yas537_data_mbl.calib_yas537.a3 * a_s_s32[2]))) + / (8192)); + /* read hy1*/ + a_h_s32[1] = ((yas537_data_mbl.calib_yas537.k * ( + (yas537_data_mbl.calib_yas537.a4 * a_s_s32[0]) + + (yas537_data_mbl.calib_yas537.a5 * a_s_s32[1]) + + (yas537_data_mbl.calib_yas537.a6 * a_s_s32[2]))) + / (8192)); + /* read hy2*/ + a_h_s32[2] = ((yas537_data_mbl.calib_yas537.k * ( + (yas537_data_mbl.calib_yas537.a7 * a_s_s32[0]) + + (yas537_data_mbl.calib_yas537.a8 * a_s_s32[1]) + + (yas537_data_mbl.calib_yas537.a9 * a_s_s32[2]))) + / (8192)); + + for (i = 0; i < 3; i++) { + if (a_h_s32[i] < -8192) + a_h_s32[i] = -8192; + + if (8192 < a_h_s32[i]) + a_h_s32[i] = 8192; + + xy1y2[i] = a_h_s32[i] + 8192; + + } + } + *v_ouflow_u8 = 0; + for (i = 0; i < 3; i++) { + if (YAS537_DATA_OVERFLOW <= xy1y2[i]) + *v_ouflow_u8 |= (1 << (i * 2)); + if (xy1y2[i] == YAS537_DATA_UNDERFLOW) + *v_ouflow_u8 |= (1 << (i * 2 + 1)); + } + + return com_rslt; + +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +static SMI130_RETURN_FUNCTION_TYPE invalid_magnetic_field( +u16 *v_cur_u16, u16 *v_last_u16) +{ + s16 invalid_thresh[] = {1500, 1500, 1500}; + u8 i = SMI130_INIT_VALUE; + + for (i = 0; i < 3; i++) + if (invalid_thresh[i] < ABS(v_cur_u16[i] - v_last_u16[i])) + return 1; + return 0; +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_measure_xyz_data( +u8 *v_ouflow_u8, struct yas_vector *vector_xyz) +{ + s32 a_xyz_tmp_s32[SMI130_YAS_TEMP_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + u8 i = SMI130_INIT_VALUE; + s8 com_rslt = SMI130_INIT_VALUE; + u8 v_busy_u8 = SMI130_INIT_VALUE; + u8 v_rcoil_u8 = SMI130_INIT_VALUE; + u16 v_temperature_u16 = SMI130_INIT_VALUE; + u16 a_xy1y2_u16[SMI130_YAS_XY1Y2_DATA_SIZE] = { + SMI130_INIT_VALUE, SMI130_INIT_VALUE, SMI130_INIT_VALUE}; + *v_ouflow_u8 = 0; + /* read the yas537 xy1y2 data*/ + com_rslt = smi130_bosch_yamaha_yas537_read_xy1y2_data( + &v_rcoil_u8, &v_busy_u8, + &v_temperature_u16, a_xy1y2_u16, v_ouflow_u8); + /* linear calculation*/ + xy1y2_to_xyz(a_xy1y2_u16, vector_xyz->yas537_vector_xyz); + if (yas537_data_mbl.transform != SMI130_NULL) { + for (i = 0; i < 3; i++) { + a_xyz_tmp_s32[i] = (( + yas537_data_mbl.transform[i + 3] + * vector_xyz->yas537_vector_xyz[0]) + + (yas537_data_mbl.transform[ + i * 3 + 1] + * vector_xyz->yas537_vector_xyz[1]) + + (yas537_data_mbl.transform[ + i * 3 + 2] + * vector_xyz->yas537_vector_xyz[2])); + } + yas537_set_vector( + vector_xyz->yas537_vector_xyz, a_xyz_tmp_s32); + } + for (i = 0; i < 3; i++) { + vector_xyz->yas537_vector_xyz[i] -= + vector_xyz->yas537_vector_xyz[i] % 10; + if (*v_ouflow_u8 & (1 << + (i * 2))) + vector_xyz->yas537_vector_xyz[i] += + 1; /* set overflow */ + if (*v_ouflow_u8 & (1 << (i * 2 + 1))) + /* set underflow */ + vector_xyz->yas537_vector_xyz[i] += 2; + } + if (v_busy_u8) + return ERROR; + switch (yas537_data_mbl.measure_state) { + case YAS537_MAG_STATE_INIT_COIL: + if (p_smi130->mag_manual_enable != SMI130_MANUAL_ENABLE) + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_ENABLE); + com_rslt += smi130_set_mag_write_data(YAS537_WRITE_CONFR); + p_smi130->delay_msec(SMI130_GEN_READ_WRITE_DELAY); + com_rslt += smi130_set_mag_write_addr(YAS537_REG_CONFR); + p_smi130->delay_msec(SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + yas537_data_mbl.measure_state = YAS537_MAG_STATE_RECORD_DATA; + if (p_smi130->mag_manual_enable == SMI130_MANUAL_ENABLE) + com_rslt = smi130_set_mag_manual_enable( + SMI130_MANUAL_DISABLE); + break; + case YAS537_MAG_STATE_RECORD_DATA: + if (v_rcoil_u8) + break; + yas537_set_vector(yas537_data_mbl.last_after_rcoil, a_xy1y2_u16); + yas537_data_mbl.measure_state = YAS537_MAG_STATE_NORMAL; + break; + case YAS537_MAG_STATE_NORMAL: + if (SMI130_INIT_VALUE < v_ouflow_u8 + || invalid_magnetic_field(a_xy1y2_u16, + yas537_data_mbl.last_after_rcoil)) { + yas537_data_mbl.measure_state = YAS537_MAG_STATE_INIT_COIL; + for (i = 0; i < 3; i++) { + if (!*v_ouflow_u8) + vector_xyz->yas537_vector_xyz[i] += 3; + } + } + break; + } + + return com_rslt; +} +/*! + * @brief This function used for reading + * smi130_t structure + * + * @return the reference and values of smi130_t + * + * +*/ +struct smi130_t *smi130_get_ptr(void) +{ + return p_smi130; +} diff --git a/drivers/input/sensors/smi130/smi130.h b/drivers/input/sensors/smi130/smi130.h new file mode 100644 index 0000000000000000000000000000000000000000..c62f65cd927e01ee0737a75cb8cc0cefddde3a6b --- /dev/null +++ b/drivers/input/sensors/smi130/smi130.h @@ -0,0 +1,11851 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. +* +* smi130.h +* Date : 2015/04/02 +* @id 836294d +* Revision : 2.0.9 $ +* @brief +* The head file of SMI130API +* + +**************************************************************************/ +/*! \file smi130.h + \brief SMI130 Sensor Driver Support Header File */ +/* user defined code to be added here ... */ +#ifndef __SMI130_H__ +#define __SMI130_H__ + +/*! +* @brief The following definition uses for define the data types +* +* @note While porting the API please consider the following +* @note Please check the version of C standard +* @note Are you using Linux platform +*/ + +/*! +* @brief For the Linux platform support +* Please use the types.h for your data types definitions +*/ +#ifdef __KERNEL__ + +#include + +#else /* ! __KERNEL__ */ +/********************************************************** +* These definition uses for define the C +* standard version data types +***********************************************************/ +# if !defined(__STDC_VERSION__) + +/************************************************ + * compiler is C11 C standard +************************************************/ +#if (__STDC_VERSION__ == 201112L) + +/************************************************/ +#include +/************************************************/ + +/*unsigned integer types*/ +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + +/*signed integer types*/ +#define s8 int8_t +#define s16 int16_t +#define s32 int32_t +#define s64 int64_t +/************************************************ + * compiler is C99 C standard +************************************************/ + +#elif (__STDC_VERSION__ == 199901L) + +/* stdint.h is a C99 supported c library. +which is used to fixed the integer size*/ +/************************************************/ +#include +/************************************************/ + +/*unsigned integer types*/ +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + +/*signed integer types*/ +#define s8 int8_t +#define s16 int16_t +#define s32 int32_t +#define s64 int64_t +/************************************************ + * compiler is C89 or other C standard +************************************************/ +#else /* !defined(__STDC_VERSION__) */ +/* By default it is defined as 32 bit machine configuration*/ +/* define the definition based on your machine configuration*/ +/* define the data types based on your + machine/compiler/controller configuration*/ +#define MACHINE_32_BIT + +/* If your machine support 16 bit +define the MACHINE_16_BIT*/ +#ifdef MACHINE_16_BIT +#include +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed long int + +#if defined(LONG_MAX) && LONG_MAX == 0x7fffffffffffffffL +#define s64 long int +#define u64 unsigned long int +#elif defined(LLONG_MAX) && (LLONG_MAX == 0x7fffffffffffffffLL) +#define s64 long long int +#define u64 unsigned long long int +#else +#warning Either the correct data type for signed 64 bit integer \ +could not be found, or 64 bit integers are not supported in your environment. +#warning If 64 bit integers are supported on your platform, \ +please set s64 manually. +#endif + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned long int + +/* If your machine support 32 bit +define the MACHINE_32_BIT*/ +#elif defined MACHINE_32_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long long int + +/* If your machine support 64 bit +define the MACHINE_64_BIT*/ +#elif defined MACHINE_64_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long int + +#else +#warning The data types defined above which not supported \ +define the data types manually +#endif +#endif + +/*** This else will execute for the compilers + * which are not supported the C standards + * Like C89/C99/C11***/ +#else +/* By default it is defined as 32 bit machine configuration*/ +/* define the definition based on your machine configuration*/ +/* define the data types based on your + machine/compiler/controller configuration*/ +#define MACHINE_32_BIT + +/* If your machine support 16 bit +define the MACHINE_16_BIT*/ +#ifdef MACHINE_16_BIT +#include +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed long int + +#if defined(LONG_MAX) && LONG_MAX == 0x7fffffffffffffffL +#define s64 long int +#define u64 unsigned long int +#elif defined(LLONG_MAX) && (LLONG_MAX == 0x7fffffffffffffffLL) +#define s64 long long int +#define u64 unsigned long long int +#else +#warning Either the correct data type for signed 64 bit integer \ +could not be found, or 64 bit integers are not supported in your environment. +#warning If 64 bit integers are supported on your platform, \ +please set s64 manually. +#endif + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned long int + +/* If your machine support 32 bit +define the MACHINE_32_BIT*/ +#elif defined MACHINE_32_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long long int + +/* If your machine support 64 bit +define the MACHINE_64_BIT*/ +#elif defined MACHINE_64_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long int + +#else +#warning The data types defined above which not supported \ +define the data types manually +#endif +#endif +#endif +/***************************************************************/ +/**\name BUS READ AND WRITE FUNCTION POINTERS */ +/***************************************************************/ +/*! + @brief Define the calling convention of YOUR bus communication routine. + @note This includes types of parameters. This example shows the + configuration for an SPI bus link. + + If your communication function looks like this: + + write_my_bus_xy(u8 device_addr, u8 register_addr, + u8 * data, u8 length); + + The SMI130_WR_FUNC_PTR would equal: + + SMI130_WR_FUNC_PTR s8 (* bus_write)(u8, + u8, u8 *, u8) + + Parameters can be mixed as needed refer to the + @ref SMI130_BUS_WRITE_FUNC macro. + + +*/ +#define SMI130_WR_FUNC_PTR s8 (*bus_write)(u8, u8,\ +u8 *, u8) +/**< link macro between API function calls and bus write function + @note The bus write function can change since this is a + system dependant issue. + + If the bus_write parameter calling order is like: reg_addr, + reg_data, wr_len it would be as it is here. + + If the parameters are differently ordered or your communication + function like I2C need to know the device address, + you can change this macro accordingly. + + + SMI130_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_write(dev_addr, reg_addr, reg_data, wr_len) + + This macro lets all API functions call YOUR communication routine in a + way that equals your definition in the + @ref SMI130_WR_FUNC_PTR definition. + +*/ +#define SMI130_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_write(dev_addr, reg_addr, reg_data, wr_len) + +/**< Define the calling convention of YOUR bus communication routine. + @note This includes types of parameters. This example shows the + configuration for an SPI bus link. + + If your communication function looks like this: + + read_my_bus_xy(u8 device_addr, u8 register_addr, + u8 * data, u8 length); + + The SMI130_RD_FUNC_PTR would equal: + + SMI130_RD_FUNC_PTR s8 (* bus_read)(u8, + u8, u8 *, u8) + + Parameters can be mixed as needed refer to the + refer SMI130_BUS_READ_FUNC macro. + +*/ +#define SMI130_SPI_RD_MASK (0x80) /* for spi read transactions on SPI the + MSB has to be set */ +#define SMI130_RD_FUNC_PTR s8 (*bus_read)(u8,\ + u8, u8 *, u8) + +#define SMI130_BRD_FUNC_PTR s8 \ +(*burst_read)(u8, u8, u8 *, u32) + +/**< link macro between API function calls and bus read function + @note The bus write function can change since this is a + system dependant issue. + + If the bus_read parameter calling order is like: reg_addr, + reg_data, wr_len it would be as it is here. + + If the parameters are differently ordered or your communication + function like I2C need to know the device address, + you can change this macro accordingly. + + + SMI130_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_read(dev_addr, reg_addr, reg_data, wr_len) + + This macro lets all API functions call YOUR communication routine in a + way that equals your definition in the + refer SMI130_WR_FUNC_PTR definition. + + @note: this macro also includes the "MSB='1' + for reading SMI130 addresses. + +*/ +#define SMI130_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, r_len)\ + bus_read(dev_addr, reg_addr, reg_data, r_len) + +#define SMI130_BURST_READ_FUNC(device_addr, \ +register_addr, register_data, rd_len)\ +burst_read(device_addr, register_addr, register_data, rd_len) + + +#define SMI130_MDELAY_DATA_TYPE u32 + +/***************************************************************/ +/**\name BUS READ AND WRITE FUNCTION POINTERS */ +/***************************************************************/ +#define SMI130_I2C_ADDR1 0x68 /**< I2C Address needs to be changed */ +#define SMI130_I2C_ADDR2 0x69 /**< I2C Address needs to be changed */ +#define SMI130_AUX_BMM150_I2C_ADDRESS (0x10) +#define SMI130_AUX_YAS532_I2C_ADDRESS (0x2E) +/**< I2C address of YAS532*/ +#define SMI130_AKM09911_I2C_ADDRESS 0x0C/**< I2C address of AKM09911*/ +/**< I2C address of AKM09911*/ +#define SMI130_AUX_AKM09911_I2C_ADDR_2 (0x0D) +/**< I2C address of AKM09911*/ +#define SMI130_AUX_AKM09912_I2C_ADDR_1 (0x0C) +/**< I2C address of AKM09912*/ +#define SMI130_AUX_AKM09912_I2C_ADDR_2 (0x0D) +/**< I2C address of AKM09912*/ +#define SMI130_AUX_AKM09912_I2C_ADDR_3 (0x0E) +/**< I2C address of AKM09912*/ +#define SMI130_AKM09912_I2C_ADDRESS 0x0F/**< I2C address of akm09912*/ + +#define SMI130_YAS532_I2C_ADDRESS 0x2E/**< I2C address of YAS532*/ +/*******************************************/ +/**\name CONSTANTS */ +/******************************************/ +#define SMI130_INIT_VALUE (0) +#define SMI130_GEN_READ_WRITE_DATA_LENGTH (1) +#define SMI130_MAXIMUM_TIMEOUT (10) +/* output data rate condition check*/ +#define SMI130_OUTPUT_DATA_RATE0 (0) +#define SMI130_OUTPUT_DATA_RATE1 (1) +#define SMI130_OUTPUT_DATA_RATE2 (2) +#define SMI130_OUTPUT_DATA_RATE3 (3) +#define SMI130_OUTPUT_DATA_RATE4 (4) +#define SMI130_OUTPUT_DATA_RATE5 (5) +#define SMI130_OUTPUT_DATA_RATE6 (14) +#define SMI130_OUTPUT_DATA_RATE7 (15) +/* accel range check*/ +#define SMI130_ACCEL_RANGE0 (3) +#define SMI130_ACCEL_RANGE1 (5) +#define SMI130_ACCEL_RANGE3 (8) +#define SMI130_ACCEL_RANGE4 (12) +/* check the status of registers*/ +#define SMI130_FOC_STAT_HIGH (1) +#define SMI130_SIG_MOTION_STAT_HIGH (1) +#define SMI130_STEP_DET_STAT_HIGH (1) + +/*condition check for reading and writing data*/ +#define SMI130_MAX_VALUE_SIGNIFICANT_MOTION (1) +#define SMI130_MAX_VALUE_FIFO_FILTER (1) +#define SMI130_MAX_VALUE_FIFO_TIME (1) +#define SMI130_MAX_VALUE_FIFO_INTR (1) +#define SMI130_MAX_VALUE_FIFO_HEADER (1) +#define SMI130_MAX_VALUE_FIFO_MAG (1) +#define SMI130_MAX_VALUE_FIFO_ACCEL (1) +#define SMI130_MAX_VALUE_FIFO_GYRO (1) +#define SMI130_MAX_VALUE_SOURCE_INTR (1) +#define SMI130_MAX_VALUE_LOW_G_MODE (1) +#define SMI130_MAX_VALUE_NO_MOTION (1) +#define SMI130_MAX_VALUE_TAP_SHOCK (1) +#define SMI130_MAX_VALUE_TAP_QUIET (1) +#define SMI130_MAX_VALUE_ORIENT_UD (1) +#define SMI130_MAX_VALUE_ORIENT_AXES (1) +#define SMI130_MAX_VALUE_NVM_PROG (1) +#define SMI130_MAX_VALUE_SPI3 (1) +#define SMI130_MAX_VALUE_PAGE (1) +#define SMI130_MAX_VALUE_I2C_WDT (1) +#define SMI130_MAX_VALUE_SLEEP_STATE (1) +#define SMI130_MAX_VALUE_WAKEUP_INTR (1) +#define SMI130_MAX_VALUE_SELFTEST_SIGN (1) +#define SMI130_MAX_VALUE_SELFTEST_AMP (1) +#define SMI130_MAX_VALUE_SELFTEST_START (1) +#define SMI130_MAX_GYRO_WAKEUP_TRIGGER (3) +#define SMI130_MAX_ACCEL_SELFTEST_AXIS (3) +#define SMI130_MAX_GYRO_STEP_COUNTER (1) +#define SMI130_MAX_GYRO_BW (3) +#define SMI130_MAX_ACCEL_BW (7) +#define SMI130_MAX_ORIENT_MODE (3) +#define SMI130_MAX_ORIENT_BLOCKING (3) +#define SMI130_MAX_FLAT_HOLD (3) +#define SMI130_MAX_ACCEL_FOC (3) +#define SMI130_MAX_IF_MODE (3) +#define SMI130_MAX_TARGET_PAGE (3) +#define SMI130_MAX_GYRO_RANGE (4) +#define SMI130_MAX_GYRO_SLEEP_TIGGER (7) +#define SMI130_MAX_TAP_TURN (7) +#define SMI130_MAX_UNDER_SAMPLING (1) +#define SMI130_MAX_UNDER_SIG_MOTION (3) +#define SMI130_MAX_ACCEL_OUTPUT_DATA_RATE (12) +#define SMI130_MAX_LATCH_INTR (15) +#define SMI130_MAX_FLAT_HYST (15) +#define SMI130_MAX_ORIENT_THETA (63) +#define SMI130_MAX_FLAT_THETA (63) + +/* FIFO index definitions*/ +#define SMI130_FIFO_X_LSB_DATA (0) +#define SMI130_FIFO_X_MSB_DATA (1) +#define SMI130_FIFO_Y_LSB_DATA (2) +#define SMI130_FIFO_Y_MSB_DATA (3) +#define SMI130_FIFO_Z_LSB_DATA (4) +#define SMI130_FIFO_Z_MSB_DATA (5) +#define SMI130_FIFO_R_LSB_DATA (6) +#define SMI130_FIFO_R_MSB_DATA (7) +/* FIFO gyro definition*/ +#define SMI130_GA_FIFO_G_X_LSB (0) +#define SMI130_GA_FIFO_G_X_MSB (1) +#define SMI130_GA_FIFO_G_Y_LSB (2) +#define SMI130_GA_FIFO_G_Y_MSB (3) +#define SMI130_GA_FIFO_G_Z_LSB (4) +#define SMI130_GA_FIFO_G_Z_MSB (5) +#define SMI130_GA_FIFO_A_X_LSB (6) +#define SMI130_GA_FIFO_A_X_MSB (7) +#define SMI130_GA_FIFO_A_Y_LSB (8) +#define SMI130_GA_FIFO_A_Y_MSB (9) +#define SMI130_GA_FIFO_A_Z_LSB (10) +#define SMI130_GA_FIFO_A_Z_MSB (11) +/* FIFO mag/gyro/accel definition*/ +#define SMI130_MGA_FIFO_M_X_LSB (0) +#define SMI130_MGA_FIFO_M_X_MSB (1) +#define SMI130_MGA_FIFO_M_Y_LSB (2) +#define SMI130_MGA_FIFO_M_Y_MSB (3) +#define SMI130_MGA_FIFO_M_Z_LSB (4) +#define SMI130_MGA_FIFO_M_Z_MSB (5) +#define SMI130_MGA_FIFO_M_R_LSB (6) +#define SMI130_MGA_FIFO_M_R_MSB (7) +#define SMI130_MGA_FIFO_G_X_LSB (8) +#define SMI130_MGA_FIFO_G_X_MSB (9) +#define SMI130_MGA_FIFO_G_Y_LSB (10) +#define SMI130_MGA_FIFO_G_Y_MSB (11) +#define SMI130_MGA_FIFO_G_Z_LSB (12) +#define SMI130_MGA_FIFO_G_Z_MSB (13) +#define SMI130_MGA_FIFO_A_X_LSB (14) +#define SMI130_MGA_FIFO_A_X_MSB (15) +#define SMI130_MGA_FIFO_A_Y_LSB (16) +#define SMI130_MGA_FIFO_A_Y_MSB (17) +#define SMI130_MGA_FIFO_A_Z_LSB (18) +#define SMI130_MGA_FIFO_A_Z_MSB (19) +/* FIFO mag definition*/ +#define SMI130_MA_FIFO_M_X_LSB (0) +#define SMI130_MA_FIFO_M_X_MSB (1) +#define SMI130_MA_FIFO_M_Y_LSB (2) +#define SMI130_MA_FIFO_M_Y_MSB (3) +#define SMI130_MA_FIFO_M_Z_LSB (4) +#define SMI130_MA_FIFO_M_Z_MSB (5) +#define SMI130_MA_FIFO_M_R_LSB (6) +#define SMI130_MA_FIFO_M_R_MSB (7) +#define SMI130_MA_FIFO_A_X_LSB (8) +#define SMI130_MA_FIFO_A_X_MSB (9) +#define SMI130_MA_FIFO_A_Y_LSB (10) +#define SMI130_MA_FIFO_A_Y_MSB (11) +#define SMI130_MA_FIFO_A_Z_LSB (12) +#define SMI130_MA_FIFO_A_Z_MSB (13) +/* FIFO mag/gyro definition*/ +#define SMI130_MG_FIFO_M_X_LSB (0) +#define SMI130_MG_FIFO_M_X_MSB (1) +#define SMI130_MG_FIFO_M_Y_LSB (2) +#define SMI130_MG_FIFO_M_Y_MSB (3) +#define SMI130_MG_FIFO_M_Z_LSB (4) +#define SMI130_MG_FIFO_M_Z_MSB (5) +#define SMI130_MG_FIFO_M_R_LSB (6) +#define SMI130_MG_FIFO_M_R_MSB (7) +#define SMI130_MG_FIFO_G_X_LSB (8) +#define SMI130_MG_FIFO_G_X_MSB (9) +#define SMI130_MG_FIFO_G_Y_LSB (10) +#define SMI130_MG_FIFO_G_Y_MSB (11) +#define SMI130_MG_FIFO_G_Z_LSB (12) +#define SMI130_MG_FIFO_G_Z_MSB (13) +/* FIFO length definitions*/ +#define SMI130_FIFO_SENSOR_TIME_LSB (0) +#define SMI130_FIFO_SENSOR_TIME_XLSB (1) +#define SMI130_FIFO_SENSOR_TIME_MSB (2) +#define SMI130_FIFO_SENSOR_TIME_LENGTH (3) +#define SMI130_FIFO_A_LENGTH (6) +#define SMI130_FIFO_G_LENGTH (6) +#define SMI130_FIFO_M_LENGTH (8) +#define SMI130_FIFO_AG_LENGTH (12) +#define SMI130_FIFO_AMG_LENGTH (20) +#define SMI130_FIFO_MA_OR_MG_LENGTH (14) + +/* bus read and write length for mag, accel and gyro*/ +#define SMI130_MAG_X_DATA_LENGTH (2) +#define SMI130_MAG_Y_DATA_LENGTH (2) +#define SMI130_MAG_Z_DATA_LENGTH (2) +#define SMI130_MAG_R_DATA_LENGTH (2) +#define SMI130_MAG_XYZ_DATA_LENGTH (6) +#define SMI130_MAG_XYZR_DATA_LENGTH (8) +#define SMI130_MAG_YAS_DATA_LENGTH (8) +#define SMI130_GYRO_DATA_LENGTH (2) +#define SMI130_GYRO_XYZ_DATA_LENGTH (6) +#define SMI130_ACCEL_DATA_LENGTH (2) +#define SMI130_ACCEL_XYZ_DATA_LENGTH (6) +#define SMI130_TEMP_DATA_LENGTH (2) +#define SMI130_FIFO_DATA_LENGTH (2) +#define SMI130_STEP_COUNTER_LENGTH (2) +#define SMI130_SENSOR_TIME_LENGTH (3) + +/* Delay definitions*/ +#define SMI130_SEC_INTERFACE_GEN_READ_WRITE_DELAY (5) +#define SMI130_BMM150_WAKEUP_DELAY1 (2) +#define SMI130_BMM150_WAKEUP_DELAY2 (3) +#define SMI130_BMM150_WAKEUP_DELAY3 (1) +#define SMI130_YAS532_OFFSET_DELAY (2) +#define SMI130_GEN_READ_WRITE_DELAY (1) +#define SMI130_YAS532_MEASUREMENT_DELAY (25) +#define SMI130_YAS_ACQ_COMMAND_DELAY (50) +#define SMI130_YAS532_SET_INITIAL_VALUE_DELAY (200) +#define SMI130_AKM_INIT_DELAY (60) +/****************************************************/ +/**\name ARRAY SIZE DEFINITIONS */ +/***************************************************/ +#define SMI130_ACCEL_X_DATA_SIZE (2) +#define SMI130_ACCEL_Y_DATA_SIZE (2) +#define SMI130_ACCEL_Z_DATA_SIZE (2) +#define SMI130_ACCEL_XYZ_DATA_SIZE (6) + +#define SMI130_GYRO_X_DATA_SIZE (2) +#define SMI130_GYRO_Y_DATA_SIZE (2) +#define SMI130_GYRO_Z_DATA_SIZE (2) +#define SMI130_GYRO_XYZ_DATA_SIZE (6) + +#define SMI130_MAG_X_DATA_SIZE (2) +#define SMI130_MAG_Y_DATA_SIZE (2) +#define SMI130_MAG_Z_DATA_SIZE (2) +#define SMI130_MAG_R_DATA_SIZE (2) +#define SMI130_MAG_XYZ_DATA_SIZE (6) +#define SMI130_MAG_XYZR_DATA_SIZE (8) +#define SMI130_MAG_TRIM_DATA_SIZE (16) + + +#define SMI130_TEMP_DATA_SIZE (2) +#define SMI130_FIFO_DATA_SIZE (2) +#define SMI130_STEP_COUNT_DATA_SIZE (2) + +#define SMI130_SENSOR_TIME_DATA_SIZE (3) +#define SMI130_AKM_SENSITIVITY_DATA_SIZE (3) +#define SMI130_HARD_OFFSET_DATA_SIZE (3) +#define SMI130_YAS_XY1Y2_DATA_SIZE (3) +#define SMI130_YAS_FLAG_DATA_SIZE (3) +#define SMI130_YAS_TEMP_DATA_SIZE (3) +#define SMI130_YAS_H_DATA_SIZE (3) +#define SMI130_YAS_S_DATA_SIZE (3) +#define SMI130_YAS_CORRECT_DATA_SIZE (5) +#define SMI130_YAS_XY1Y2T_DATA_SIZE (8) +#define SMI130_YAS537_CALIB_DATA_SIZE (17) +#define SMI130_YAS532_CALIB_DATA_SIZE (14) +/****************************************************/ +/**\name ARRAY PARAMETER DEFINITIONS */ +/***************************************************/ +#define SMI130_SENSOR_TIME_MSB_BYTE (2) +#define SMI130_SENSOR_TIME_XLSB_BYTE (1) +#define SMI130_SENSOR_TIME_LSB_BYTE (0) + +#define SMI130_MAG_X_LSB_BYTE (0) +#define SMI130_MAG_X_MSB_BYTE (1) +#define SMI130_MAG_Y_LSB_BYTE (0) +#define SMI130_MAG_Y_MSB_BYTE (1) +#define SMI130_MAG_Z_LSB_BYTE (0) +#define SMI130_MAG_Z_MSB_BYTE (1) +#define SMI130_MAG_R_LSB_BYTE (0) +#define SMI130_MAG_R_MSB_BYTE (1) +#define SMI130_DATA_FRAME_MAG_X_LSB_BYTE (0) +#define SMI130_DATA_FRAME_MAG_X_MSB_BYTE (1) +#define SMI130_DATA_FRAME_MAG_Y_LSB_BYTE (2) +#define SMI130_DATA_FRAME_MAG_Y_MSB_BYTE (3) +#define SMI130_DATA_FRAME_MAG_Z_LSB_BYTE (4) +#define SMI130_DATA_FRAME_MAG_Z_MSB_BYTE (5) +#define SMI130_DATA_FRAME_MAG_R_LSB_BYTE (6) +#define SMI130_DATA_FRAME_MAG_R_MSB_BYTE (7) + +#define SMI130_GYRO_X_LSB_BYTE (0) +#define SMI130_GYRO_X_MSB_BYTE (1) +#define SMI130_GYRO_Y_LSB_BYTE (0) +#define SMI130_GYRO_Y_MSB_BYTE (1) +#define SMI130_GYRO_Z_LSB_BYTE (0) +#define SMI130_GYRO_Z_MSB_BYTE (1) +#define SMI130_DATA_FRAME_GYRO_X_LSB_BYTE (0) +#define SMI130_DATA_FRAME_GYRO_X_MSB_BYTE (1) +#define SMI130_DATA_FRAME_GYRO_Y_LSB_BYTE (2) +#define SMI130_DATA_FRAME_GYRO_Y_MSB_BYTE (3) +#define SMI130_DATA_FRAME_GYRO_Z_LSB_BYTE (4) +#define SMI130_DATA_FRAME_GYRO_Z_MSB_BYTE (5) + +#define SMI130_ACCEL_X_LSB_BYTE (0) +#define SMI130_ACCEL_X_MSB_BYTE (1) +#define SMI130_ACCEL_Y_LSB_BYTE (0) +#define SMI130_ACCEL_Y_MSB_BYTE (1) +#define SMI130_ACCEL_Z_LSB_BYTE (0) +#define SMI130_ACCEL_Z_MSB_BYTE (1) +#define SMI130_DATA_FRAME_ACCEL_X_LSB_BYTE (0) +#define SMI130_DATA_FRAME_ACCEL_X_MSB_BYTE (1) +#define SMI130_DATA_FRAME_ACCEL_Y_LSB_BYTE (2) +#define SMI130_DATA_FRAME_ACCEL_Y_MSB_BYTE (3) +#define SMI130_DATA_FRAME_ACCEL_Z_LSB_BYTE (4) +#define SMI130_DATA_FRAME_ACCEL_Z_MSB_BYTE (5) + +#define SMI130_TEMP_LSB_BYTE (0) +#define SMI130_TEMP_MSB_BYTE (1) + +#define SMI130_FIFO_LENGTH_LSB_BYTE (0) +#define SMI130_FIFO_LENGTH_MSB_BYTE (1) + +#define SMI130_STEP_COUNT_LSB_BYTE (0) +#define SMI130_STEP_COUNT_MSB_BYTE (1) +/****************************************************/ +/**\name ERROR CODES */ +/***************************************************/ + +#define E_SMI130_NULL_PTR ((s8)-127) +#define E_SMI130_COMM_RES ((s8)-1) +#define E_SMI130_OUT_OF_RANGE ((s8)-2) +#define E_SMI130_BUSY ((s8)-3) +#define SUCCESS ((u8)0) +#define ERROR ((s8)-1) + +/* Constants */ +#define SMI130_NULL (0) +#define SMI130_DELAY_SETTLING_TIME (5) +/*This refers SMI130 return type as s8 */ +#define SMI130_RETURN_FUNCTION_TYPE s8 +/****************************************************/ +/**\name REGISTER DEFINITIONS */ +/***************************************************/ +/*******************/ +/**\name CHIP ID */ +/*******************/ +#define SMI130_USER_CHIP_ID_ADDR (0x00) +/*******************/ +/**\name ERROR STATUS */ +/*******************/ +#define SMI130_USER_ERROR_ADDR (0X02) +/*******************/ +/**\name POWER MODE STATUS */ +/*******************/ +#define SMI130_USER_PMU_STAT_ADDR (0X03) +/*******************/ +/**\name MAG DATA REGISTERS */ +/*******************/ +#define SMI130_USER_DATA_0_ADDR (0X04) +#define SMI130_USER_DATA_1_ADDR (0X05) +#define SMI130_USER_DATA_2_ADDR (0X06) +#define SMI130_USER_DATA_3_ADDR (0X07) +#define SMI130_USER_DATA_4_ADDR (0X08) +#define SMI130_USER_DATA_5_ADDR (0X09) +#define SMI130_USER_DATA_6_ADDR (0X0A) +#define SMI130_USER_DATA_7_ADDR (0X0B) +/*******************/ +/**\name GYRO DATA REGISTERS */ +/*******************/ +#define SMI130_USER_DATA_8_ADDR (0X0C) +#define SMI130_USER_DATA_9_ADDR (0X0D) +#define SMI130_USER_DATA_10_ADDR (0X0E) +#define SMI130_USER_DATA_11_ADDR (0X0F) +#define SMI130_USER_DATA_12_ADDR (0X10) +#define SMI130_USER_DATA_13_ADDR (0X11) +#define SMI130_USER_DATA_14_ADDR (0X12) +#define SMI130_USER_DATA_15_ADDR (0X13) +/*******************/ +/**\name ACCEL DATA REGISTERS */ +/*******************/ +#define SMI130_USER_DATA_16_ADDR (0X14) +#define SMI130_USER_DATA_17_ADDR (0X15) +#define SMI130_USER_DATA_18_ADDR (0X16) +#define SMI130_USER_DATA_19_ADDR (0X17) +/*******************/ +/**\name SENSOR TIME REGISTERS */ +/*******************/ +#define SMI130_USER_SENSORTIME_0_ADDR (0X18) +#define SMI130_USER_SENSORTIME_1_ADDR (0X19) +#define SMI130_USER_SENSORTIME_2_ADDR (0X1A) +/*******************/ +/**\name STATUS REGISTER FOR SENSOR STATUS FLAG */ +/*******************/ +#define SMI130_USER_STAT_ADDR (0X1B) +/*******************/ +/**\name INTERRUPY STATUS REGISTERS */ +/*******************/ +#define SMI130_USER_INTR_STAT_0_ADDR (0X1C) +#define SMI130_USER_INTR_STAT_1_ADDR (0X1D) +#define SMI130_USER_INTR_STAT_2_ADDR (0X1E) +#define SMI130_USER_INTR_STAT_3_ADDR (0X1F) +/*******************/ +/**\name TEMPERATURE REGISTERS */ +/*******************/ +#define SMI130_USER_TEMPERATURE_0_ADDR (0X20) +#define SMI130_USER_TEMPERATURE_1_ADDR (0X21) +/*******************/ +/**\name FIFO REGISTERS */ +/*******************/ +#define SMI130_USER_FIFO_LENGTH_0_ADDR (0X22) +#define SMI130_USER_FIFO_LENGTH_1_ADDR (0X23) +#define SMI130_USER_FIFO_DATA_ADDR (0X24) +/***************************************************/ +/**\name ACCEL CONFIG REGISTERS FOR ODR, BANDWIDTH AND UNDERSAMPLING*/ +/******************************************************/ +#define SMI130_USER_ACCEL_CONFIG_ADDR (0X40) +/*******************/ +/**\name ACCEL RANGE */ +/*******************/ +#define SMI130_USER_ACCEL_RANGE_ADDR (0X41) +/***************************************************/ +/**\name GYRO CONFIG REGISTERS FOR ODR AND BANDWIDTH */ +/******************************************************/ +#define SMI130_USER_GYRO_CONFIG_ADDR (0X42) +/*******************/ +/**\name GYRO RANGE */ +/*******************/ +#define SMI130_USER_GYRO_RANGE_ADDR (0X43) +/***************************************************/ +/**\name MAG CONFIG REGISTERS FOR ODR*/ +/******************************************************/ +#define SMI130_USER_MAG_CONFIG_ADDR (0X44) +/***************************************************/ +/**\name REGISTER FOR GYRO AND ACCEL DOWNSAMPLING RATES FOR FIFO*/ +/******************************************************/ +#define SMI130_USER_FIFO_DOWN_ADDR (0X45) +/***************************************************/ +/**\name FIFO CONFIG REGISTERS*/ +/******************************************************/ +#define SMI130_USER_FIFO_CONFIG_0_ADDR (0X46) +#define SMI130_USER_FIFO_CONFIG_1_ADDR (0X47) +/***************************************************/ +/**\name MAG INTERFACE REGISTERS*/ +/******************************************************/ +#define SMI130_USER_MAG_IF_0_ADDR (0X4B) +#define SMI130_USER_MAG_IF_1_ADDR (0X4C) +#define SMI130_USER_MAG_IF_2_ADDR (0X4D) +#define SMI130_USER_MAG_IF_3_ADDR (0X4E) +#define SMI130_USER_MAG_IF_4_ADDR (0X4F) +/***************************************************/ +/**\name INTERRUPT ENABLE REGISTERS*/ +/******************************************************/ +#define SMI130_USER_INTR_ENABLE_0_ADDR (0X50) +#define SMI130_USER_INTR_ENABLE_1_ADDR (0X51) +#define SMI130_USER_INTR_ENABLE_2_ADDR (0X52) +#define SMI130_USER_INTR_OUT_CTRL_ADDR (0X53) +/***************************************************/ +/**\name LATCH DURATION REGISTERS*/ +/******************************************************/ +#define SMI130_USER_INTR_LATCH_ADDR (0X54) +/***************************************************/ +/**\name MAP INTERRUPT 1 and 2 REGISTERS*/ +/******************************************************/ +#define SMI130_USER_INTR_MAP_0_ADDR (0X55) +#define SMI130_USER_INTR_MAP_1_ADDR (0X56) +#define SMI130_USER_INTR_MAP_2_ADDR (0X57) +/***************************************************/ +/**\name DATA SOURCE REGISTERS*/ +/******************************************************/ +#define SMI130_USER_INTR_DATA_0_ADDR (0X58) +#define SMI130_USER_INTR_DATA_1_ADDR (0X59) +/***************************************************/ +/**\name +INTERRUPT THRESHOLD, HYSTERESIS, DURATION, MODE CONFIGURATION REGISTERS*/ +/******************************************************/ +#define SMI130_USER_INTR_LOWHIGH_0_ADDR (0X5A) +#define SMI130_USER_INTR_LOWHIGH_1_ADDR (0X5B) +#define SMI130_USER_INTR_LOWHIGH_2_ADDR (0X5C) +#define SMI130_USER_INTR_LOWHIGH_3_ADDR (0X5D) +#define SMI130_USER_INTR_LOWHIGH_4_ADDR (0X5E) +#define SMI130_USER_INTR_MOTION_0_ADDR (0X5F) +#define SMI130_USER_INTR_MOTION_1_ADDR (0X60) +#define SMI130_USER_INTR_MOTION_2_ADDR (0X61) +#define SMI130_USER_INTR_MOTION_3_ADDR (0X62) +#define SMI130_USER_INTR_TAP_0_ADDR (0X63) +#define SMI130_USER_INTR_TAP_1_ADDR (0X64) +#define SMI130_USER_INTR_ORIENT_0_ADDR (0X65) +#define SMI130_USER_INTR_ORIENT_1_ADDR (0X66) +#define SMI130_USER_INTR_FLAT_0_ADDR (0X67) +#define SMI130_USER_INTR_FLAT_1_ADDR (0X68) +/***************************************************/ +/**\name FAST OFFSET CONFIGURATION REGISTER*/ +/******************************************************/ +#define SMI130_USER_FOC_CONFIG_ADDR (0X69) +/***************************************************/ +/**\name MISCELLANEOUS CONFIGURATION REGISTER*/ +/******************************************************/ +#define SMI130_USER_CONFIG_ADDR (0X6A) +/***************************************************/ +/**\name SERIAL INTERFACE SETTINGS REGISTER*/ +/******************************************************/ +#define SMI130_USER_IF_CONFIG_ADDR (0X6B) +/***************************************************/ +/**\name GYRO POWER MODE TRIGGER REGISTER */ +/******************************************************/ +#define SMI130_USER_PMU_TRIGGER_ADDR (0X6C) +/***************************************************/ +/**\name SELF_TEST REGISTER*/ +/******************************************************/ +#define SMI130_USER_SELF_TEST_ADDR (0X6D) +/***************************************************/ +/**\name SPI,I2C SELECTION REGISTER*/ +/******************************************************/ +#define SMI130_USER_NV_CONFIG_ADDR (0x70) +/***************************************************/ +/**\name ACCEL AND GYRO OFFSET REGISTERS*/ +/******************************************************/ +#define SMI130_USER_OFFSET_0_ADDR (0X71) +#define SMI130_USER_OFFSET_1_ADDR (0X72) +#define SMI130_USER_OFFSET_2_ADDR (0X73) +#define SMI130_USER_OFFSET_3_ADDR (0X74) +#define SMI130_USER_OFFSET_4_ADDR (0X75) +#define SMI130_USER_OFFSET_5_ADDR (0X76) +#define SMI130_USER_OFFSET_6_ADDR (0X77) +/***************************************************/ +/**\name STEP COUNTER INTERRUPT REGISTERS*/ +/******************************************************/ +#define SMI130_USER_STEP_COUNT_0_ADDR (0X78) +#define SMI130_USER_STEP_COUNT_1_ADDR (0X79) +/***************************************************/ +/**\name STEP COUNTER CONFIGURATION REGISTERS*/ +/******************************************************/ +#define SMI130_USER_STEP_CONFIG_0_ADDR (0X7A) +#define SMI130_USER_STEP_CONFIG_1_ADDR (0X7B) +/***************************************************/ +/**\name COMMAND REGISTER*/ +/******************************************************/ +#define SMI130_CMD_COMMANDS_ADDR (0X7E) +/***************************************************/ +/**\name PAGE REGISTERS*/ +/******************************************************/ +#define SMI130_CMD_EXT_MODE_ADDR (0X7F) +#define SMI130_COM_C_TRIM_FIVE_ADDR (0X05) + +/****************************************************/ +/**\name SHIFT VALUE DEFINITION */ +/***************************************************/ +#define SMI130_SHIFT_BIT_POSITION_BY_01_BIT (1) +#define SMI130_SHIFT_BIT_POSITION_BY_02_BITS (2) +#define SMI130_SHIFT_BIT_POSITION_BY_03_BITS (3) +#define SMI130_SHIFT_BIT_POSITION_BY_04_BITS (4) +#define SMI130_SHIFT_BIT_POSITION_BY_05_BITS (5) +#define SMI130_SHIFT_BIT_POSITION_BY_06_BITS (6) +#define SMI130_SHIFT_BIT_POSITION_BY_07_BITS (7) +#define SMI130_SHIFT_BIT_POSITION_BY_08_BITS (8) +#define SMI130_SHIFT_BIT_POSITION_BY_09_BITS (9) +#define SMI130_SHIFT_BIT_POSITION_BY_12_BITS (12) +#define SMI130_SHIFT_BIT_POSITION_BY_13_BITS (13) +#define SMI130_SHIFT_BIT_POSITION_BY_14_BITS (14) +#define SMI130_SHIFT_BIT_POSITION_BY_15_BITS (15) +#define SMI130_SHIFT_BIT_POSITION_BY_16_BITS (16) + +/****************************************************/ +/**\name DEFINITIONS USED FOR YAMAHA-YAS532 */ +/***************************************************/ +#define YAS532_MAG_STATE_NORMAL (0) +#define YAS532_MAG_STATE_INIT_COIL (1) +#define YAS532_MAG_STATE_MEASURE_OFFSET (2) +#define YAS532_MAG_INITCOIL_TIMEOUT (1000) +#define YAS532_MAG_NOTRANS_POSITION (3) +#define YAS532_DEFAULT_SENSOR_DELAY (50) +#define YAS532_DATA_OVERFLOW (8190) +#define YAS532_DATA_UNDERFLOW (0) +#define YAS532_MAG_LOG (20) +#define YAS532_MAG_TEMPERATURE_LOG (10) +#define YAS532_TEMP20DEGREE_TYPICAL (390) +#define YAS532_VERSION_AC_COEF_X (850) +#define YAS532_VERSION_AC_COEF_Y1 (750) +#define YAS532_VERSION_AC_COEF_Y2 (750) +#define YAS532_DATA_CENTER (4096) +/****************************************************/ +/**\name YAMAHA-YAS532 OFFSET DEFINITION */ +/***************************************************/ +static const s8 INVALID_OFFSET[] = {0x7f, 0x7f, 0x7f}; +#define set_vector(to, from) \ + {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } +#define is_valid_offset(a) \ + (((a)[0] <= 31) && ((a)[1] <= 31) && ((a)[2] <= 31) \ + && (-31 <= (a)[0]) && (-31 <= (a)[1]) && (-31 <= (a)[2])) + +/**************************************************/ +/**\name YAS532 CALIB DATA DEFINITIONS */ +/*************************************************/ + + +/* register address of YAS532*/ +#define SMI130_YAS532_TESTR1 (0x88) +#define SMI130_YAS532_TESTR2 (0x89) +#define SMI130_YAS532_RCOIL (0x81) +#define SMI130_YAS532_COMMAND_REGISTER (0x82) +#define SMI130_YAS532_DATA_REGISTER (0xB0) +/* calib data register definition*/ +#define SMI130_YAS532_CALIB_CX (0x90) +#define SMI130_YAS532_CALIB_CY1 (0x91) +#define SMI130_YAS532_CALIB_CY2 (0x92) +#define SMI130_YAS532_CALIB1 (0x93) +#define SMI130_YAS532_CALIB2 (0x94) +#define SMI130_YAS532_CALIB3 (0x95) +#define SMI130_YAS532_CALIB4 (0x96) +#define SMI130_YAS532_CALIB5 (0x97) +#define SMI130_YAS532_CLAIB6 (0x98) +#define SMI130_YAS532_CALIB7 (0x99) +#define SMI130_YAS532_CALIB8 (0x9A) +#define SMI130_YAS532_CALIIB9 (0x9B) +#define SMI130_YAS532_CALIB10 (0x9C) +#define SMI130_YAS532_CALIB11 (0x9D) +/* offset definition */ +#define SMI130_YAS532_OFFSET_X (0x85) +#define SMI130_YAS532_OFFSET_Y (0x86) +#define SMI130_YAS532_OFFSET_Z (0x87) +/* data to write register for yas532*/ +#define SMI130_YAS532_WRITE_TESTR1 (0x00) +#define SMI130_YAS532_WRITE_TESTR2 (0x00) +#define SMI130_YAS532_WRITE_RCOIL (0x00) +/**************************************************/ +/**\name YAS537 DEFINITION */ +/*************************************************/ + +#define YAS537_SRSTR_DATA (0x02) +#define YAS537_WRITE_A_D_CONVERTER (0x03) +#define YAS537_WRITE_A_D_CONVERTER2 (0xF8) +#define YAS537_WRITE_FILTER (0x08) +#define YAS537_WRITE_CONFR (0x08) +#define YAS537_WRITE_TEMP_CALIB (0xFF) +#define YAS537_SET_COMMAND_REGISTER (0x01) + +/**************************************************/ +/**\name YAS537 REGISTER DEFINITION */ +/*************************************************/ +#define YAS537_REG_SRSTR (0x90) +#define YAS537_REG_CALR_C0 (0xC0) +#define YAS537_REG_CALR_C1 (0xC1) +#define YAS537_REG_CALR_C2 (0xC2) +#define YAS537_REG_CALR_C3 (0xC3) +#define YAS537_REG_CALR_C4 (0xC4) +#define YAS537_REG_CALR_C5 (0xC5) +#define YAS537_REG_CALR_C6 (0xC6) +#define YAS537_REG_CALR_C7 (0xC7) +#define YAS537_REG_CALR_C8 (0xC8) +#define YAS537_REG_CALR_C9 (0xC9) +#define YAS537_REG_CALR_CA (0xCA) +#define YAS537_REG_CALR_CB (0xCB) +#define YAS537_REG_CALR_CC (0xCC) +#define YAS537_REG_CALR_CD (0xCD) +#define YAS537_REG_CALR_CE (0xCE) +#define YAS537_REG_CALR_CF (0xCF) +#define YAS537_REG_CALR_DO (0xD0) +#define YAS537_REG_MTCR (0x93) +#define YAS537_REG_CONFR (0x82) +#define SMI130_REG_YAS537_CMDR (0x81) +#define YAS537_REG_OXR (0x84) +#define YAS537_REG_AVRR (0x87) +#define YAS537_REG_HCKR (0x88) +#define YAS537_REG_LCKR (0x89) +#define YAS537_REG_ADCCALR (0x91) +#define YAS537_REG_ADCCALR_ONE (0x92) +#define YAS537_REG_OCR (0x9E) +#define YAS537_REG_TRMR (0x9F) +#define YAS537_REG_TEMPERATURE_0 (0xB0) +#define YAS537_REG_TEMPERATURE_1 (0xB1) +#define YAS537_REG_DATA_X_0 (0xB2) +#define YAS537_REG_DATA_X_1 (0xB3) +#define YAS537_REG_DATA_Y1_0 (0xB4) +#define YAS537_REG_DATA_Y1_1 (0xB5) +#define YAS537_REG_DATA_Y2_0 (0xB6) +#define YAS537_REG_DATA_Y2_1 (0xB7) +#define YAS537_MAG_STATE_NORMAL (0) +#define YAS537_MAG_STATE_INIT_COIL (1) +#define YAS537_MAG_STATE_RECORD_DATA (2) +#define YAS537_DATA_UNDERFLOW (0) +#define YAS537_DATA_OVERFLOW (16383) +/****************************************************/ +/**\name YAS537_set vector */ +/***************************************************/ +#define yas537_set_vector(to, from) \ + {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } + +#ifndef ABS +#define ABS(a) ((a) > 0 ? (a) : -(a)) /*!< Absolute value */ +#endif +/****************************************************/ +/**\name AKM09911 AND AKM09912 DEFINITION */ +/***************************************************/ +#define AKM09912_SENSITIVITY_DIV (256) +#define AKM09912_SENSITIVITY (128) +#define AKM09911_SENSITIVITY_DIV (128) +#define AKM_ASAX (0) +#define AKM_ASAY (1) +#define AKM_ASAZ (2) +#define AKM_POWER_DOWN_MODE_DATA (0x00) +#define AKM_FUSE_ROM_MODE (0x1F) +#define AKM_POWER_MODE_REG (0x31) +#define AKM_SINGLE_MEASUREMENT_MODE (0x01) +#define AKM_DATA_REGISTER (0x11) +/*! AKM09912 Register definition */ +#define AKM09912_CHIP_ID_REG (0x01) +/****************************************************/ +/**\name BMM150 DEFINITION */ +/***************************************************/ +#define SMI130_BMM150_SET_POWER_CONTROL (0x01) +#define SMI130_BMM150_MAX_RETRY_WAKEUP (5) +#define SMI130_BMM150_POWER_ON (0x01) +#define SMI130_BMM150_POWER_OFF (0x00) +#define SMI130_BMM150_FORCE_MODE (0x02) +#define SMI130_BMM150_POWER_ON_SUCCESS (0) +#define SMI130_BMM150_POWER_ON_FAIL ((s8)-1) + +#define SMI130_BMM150_DIG_X1 (0) +#define SMI130_BMM150_DIG_Y1 (1) +#define SMI130_BMM150_DIG_X2 (2) +#define SMI130_BMM150_DIG_Y3 (3) +#define SMI130_BMM150_DIG_XY1 (4) +#define SMI130_BMM150_DIG_XY2 (5) +#define SMI130_BMM150_DIG_Z1_LSB (6) +#define SMI130_BMM150_DIG_Z1_MSB (7) +#define SMI130_BMM150_DIG_Z2_LSB (8) +#define SMI130_BMM150_DIG_Z2_MSB (9) +#define SMI130_BMM150_DIG_DIG_Z3_LSB (10) +#define SMI130_BMM150_DIG_DIG_Z3_MSB (11) +#define SMI130_BMM150_DIG_DIG_Z4_LSB (12) +#define SMI130_BMM150_DIG_DIG_Z4_MSB (13) +#define SMI130_BMM150_DIG_DIG_XYZ1_LSB (14) +#define SMI130_BMM150_DIG_DIG_XYZ1_MSB (15) + +/**************************************************************/ +/**\name STRUCTURE DEFINITIONS */ +/**************************************************************/ +/*! +* @brief smi130 structure +* This structure holds all relevant information about smi130 +*/ +struct smi130_t { +u8 chip_id;/**< chip id of SMI130 */ +u8 dev_addr;/**< device address of SMI130 */ +s8 mag_manual_enable;/**< used for check the mag manual/auto mode status */ +SMI130_WR_FUNC_PTR;/**< bus write function pointer */ +SMI130_RD_FUNC_PTR;/**< bus read function pointer */ +SMI130_BRD_FUNC_PTR;/**< burst write function pointer */ +void (*delay_msec)(SMI130_MDELAY_DATA_TYPE);/**< delay function pointer */ +}; +/*! + * @brief Structure containing bmm150 and akm09911 + * magnetometer values for x,y and + * z-axis in s16 + */ +struct smi130_mag_t { +s16 x;/**< BMM150 and AKM09911 and AKM09912 X raw data*/ +s16 y;/**< BMM150 and AKM09911 and AKM09912 Y raw data*/ +s16 z;/**< BMM150 and AKM09911 and AKM09912 Z raw data*/ +}; +/*! + * @brief Structure containing bmm150 xyz data and temperature + */ +struct smi130_mag_xyzr_t { +s16 x;/**< BMM150 X raw data*/ +s16 y;/**< BMM150 Y raw data*/ +s16 z;/** (0x00), Bit --> 0...7 */ +#define SMI130_USER_CHIP_ID__POS (0) +#define SMI130_USER_CHIP_ID__MSK (0xFF) +#define SMI130_USER_CHIP_ID__LEN (8) +#define SMI130_USER_CHIP_ID__REG (SMI130_USER_CHIP_ID_ADDR) +/**************************************************************/ +/**\name ERROR STATUS LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Error Description - Reg Addr --> (0x02), Bit --> 0 */ +#define SMI130_USER_ERR_STAT__POS (0) +#define SMI130_USER_ERR_STAT__LEN (8) +#define SMI130_USER_ERR_STAT__MSK (0xFF) +#define SMI130_USER_ERR_STAT__REG (SMI130_USER_ERROR_ADDR) + +#define SMI130_USER_FATAL_ERR__POS (0) +#define SMI130_USER_FATAL_ERR__LEN (1) +#define SMI130_USER_FATAL_ERR__MSK (0x01) +#define SMI130_USER_FATAL_ERR__REG (SMI130_USER_ERROR_ADDR) + +/* Error Description - Reg Addr --> (0x02), Bit --> 1...4 */ +#define SMI130_USER_ERR_CODE__POS (1) +#define SMI130_USER_ERR_CODE__LEN (4) +#define SMI130_USER_ERR_CODE__MSK (0x1E) +#define SMI130_USER_ERR_CODE__REG (SMI130_USER_ERROR_ADDR) + +/* Error Description - Reg Addr --> (0x02), Bit --> 5 */ +#define SMI130_USER_I2C_FAIL_ERR__POS (5) +#define SMI130_USER_I2C_FAIL_ERR__LEN (1) +#define SMI130_USER_I2C_FAIL_ERR__MSK (0x20) +#define SMI130_USER_I2C_FAIL_ERR__REG (SMI130_USER_ERROR_ADDR) + +/* Error Description - Reg Addr --> (0x02), Bit --> 6 */ +#define SMI130_USER_DROP_CMD_ERR__POS (6) +#define SMI130_USER_DROP_CMD_ERR__LEN (1) +#define SMI130_USER_DROP_CMD_ERR__MSK (0x40) +#define SMI130_USER_DROP_CMD_ERR__REG (SMI130_USER_ERROR_ADDR) +/**************************************************************/ +/**\name MAG DATA READY LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Error Description - Reg Addr --> (0x02), Bit --> 7 */ +#define SMI130_USER_MAG_DADA_RDY_ERR__POS (7) +#define SMI130_USER_MAG_DADA_RDY_ERR__LEN (1) +#define SMI130_USER_MAG_DADA_RDY_ERR__MSK (0x80) +#define SMI130_USER_MAG_DADA_RDY_ERR__REG (SMI130_USER_ERROR_ADDR) +/**************************************************************/ +/**\name MAG POWER MODE LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* PMU_Status Description of MAG - Reg Addr --> (0x03), Bit --> 1..0 */ +#define SMI130_USER_MAG_POWER_MODE_STAT__POS (0) +#define SMI130_USER_MAG_POWER_MODE_STAT__LEN (2) +#define SMI130_USER_MAG_POWER_MODE_STAT__MSK (0x03) +#define SMI130_USER_MAG_POWER_MODE_STAT__REG \ +(SMI130_USER_PMU_STAT_ADDR) +/**************************************************************/ +/**\name GYRO POWER MODE LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* PMU_Status Description of GYRO - Reg Addr --> (0x03), Bit --> 3...2 */ +#define SMI130_USER_GYRO_POWER_MODE_STAT__POS (2) +#define SMI130_USER_GYRO_POWER_MODE_STAT__LEN (2) +#define SMI130_USER_GYRO_POWER_MODE_STAT__MSK (0x0C) +#define SMI130_USER_GYRO_POWER_MODE_STAT__REG \ +(SMI130_USER_PMU_STAT_ADDR) +/**************************************************************/ +/**\name ACCEL POWER MODE LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* PMU_Status Description of ACCEL - Reg Addr --> (0x03), Bit --> 5...4 */ +#define SMI130_USER_ACCEL_POWER_MODE_STAT__POS (4) +#define SMI130_USER_ACCEL_POWER_MODE_STAT__LEN (2) +#define SMI130_USER_ACCEL_POWER_MODE_STAT__MSK (0x30) +#define SMI130_USER_ACCEL_POWER_MODE_STAT__REG \ +(SMI130_USER_PMU_STAT_ADDR) +/**************************************************************/ +/**\name MAG DATA XYZ LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Mag_X(LSB) Description - Reg Addr --> (0x04), Bit --> 0...7 */ +#define SMI130_USER_DATA_0_MAG_X_LSB__POS (0) +#define SMI130_USER_DATA_0_MAG_X_LSB__LEN (8) +#define SMI130_USER_DATA_0_MAG_X_LSB__MSK (0xFF) +#define SMI130_USER_DATA_0_MAG_X_LSB__REG (SMI130_USER_DATA_0_ADDR) + +/* Mag_X(LSB) Description - Reg Addr --> (0x04), Bit --> 3...7 */ +#define SMI130_USER_DATA_MAG_X_LSB__POS (3) +#define SMI130_USER_DATA_MAG_X_LSB__LEN (5) +#define SMI130_USER_DATA_MAG_X_LSB__MSK (0xF8) +#define SMI130_USER_DATA_MAG_X_LSB__REG (SMI130_USER_DATA_0_ADDR) + +/* Mag_X(MSB) Description - Reg Addr --> (0x05), Bit --> 0...7 */ +#define SMI130_USER_DATA_1_MAG_X_MSB__POS (0) +#define SMI130_USER_DATA_1_MAG_X_MSB__LEN (8) +#define SMI130_USER_DATA_1_MAG_X_MSB__MSK (0xFF) +#define SMI130_USER_DATA_1_MAG_X_MSB__REG (SMI130_USER_DATA_1_ADDR) + +/* Mag_Y(LSB) Description - Reg Addr --> (0x06), Bit --> 0...7 */ +#define SMI130_USER_DATA_2_MAG_Y_LSB__POS (0) +#define SMI130_USER_DATA_2_MAG_Y_LSB__LEN (8) +#define SMI130_USER_DATA_2_MAG_Y_LSB__MSK (0xFF) +#define SMI130_USER_DATA_2_MAG_Y_LSB__REG (SMI130_USER_DATA_2_ADDR) + +/* Mag_Y(LSB) Description - Reg Addr --> (0x06), Bit --> 3...7 */ +#define SMI130_USER_DATA_MAG_Y_LSB__POS (3) +#define SMI130_USER_DATA_MAG_Y_LSB__LEN (5) +#define SMI130_USER_DATA_MAG_Y_LSB__MSK (0xF8) +#define SMI130_USER_DATA_MAG_Y_LSB__REG (SMI130_USER_DATA_2_ADDR) + +/* Mag_Y(MSB) Description - Reg Addr --> (0x07), Bit --> 0...7 */ +#define SMI130_USER_DATA_3_MAG_Y_MSB__POS (0) +#define SMI130_USER_DATA_3_MAG_Y_MSB__LEN (8) +#define SMI130_USER_DATA_3_MAG_Y_MSB__MSK (0xFF) +#define SMI130_USER_DATA_3_MAG_Y_MSB__REG (SMI130_USER_DATA_3_ADDR) + +/* Mag_Z(LSB) Description - Reg Addr --> (0x08), Bit --> 0...7 */ +#define SMI130_USER_DATA_4_MAG_Z_LSB__POS (0) +#define SMI130_USER_DATA_4_MAG_Z_LSB__LEN (8) +#define SMI130_USER_DATA_4_MAG_Z_LSB__MSK (0xFF) +#define SMI130_USER_DATA_4_MAG_Z_LSB__REG (SMI130_USER_DATA_4_ADDR) + +/* Mag_X(LSB) Description - Reg Addr --> (0x08), Bit --> 3...7 */ +#define SMI130_USER_DATA_MAG_Z_LSB__POS (1) +#define SMI130_USER_DATA_MAG_Z_LSB__LEN (7) +#define SMI130_USER_DATA_MAG_Z_LSB__MSK (0xFE) +#define SMI130_USER_DATA_MAG_Z_LSB__REG (SMI130_USER_DATA_4_ADDR) + +/* Mag_Z(MSB) Description - Reg Addr --> (0x09), Bit --> 0...7 */ +#define SMI130_USER_DATA_5_MAG_Z_MSB__POS (0) +#define SMI130_USER_DATA_5_MAG_Z_MSB__LEN (8) +#define SMI130_USER_DATA_5_MAG_Z_MSB__MSK (0xFF) +#define SMI130_USER_DATA_5_MAG_Z_MSB__REG (SMI130_USER_DATA_5_ADDR) + +/* RHALL(LSB) Description - Reg Addr --> (0x0A), Bit --> 0...7 */ +#define SMI130_USER_DATA_6_RHALL_LSB__POS (0) +#define SMI130_USER_DATA_6_RHALL_LSB__LEN (8) +#define SMI130_USER_DATA_6_RHALL_LSB__MSK (0xFF) +#define SMI130_USER_DATA_6_RHALL_LSB__REG (SMI130_USER_DATA_6_ADDR) + +/* Mag_R(LSB) Description - Reg Addr --> (0x0A), Bit --> 3...7 */ +#define SMI130_USER_DATA_MAG_R_LSB__POS (2) +#define SMI130_USER_DATA_MAG_R_LSB__LEN (6) +#define SMI130_USER_DATA_MAG_R_LSB__MSK (0xFC) +#define SMI130_USER_DATA_MAG_R_LSB__REG (SMI130_USER_DATA_6_ADDR) + +/* RHALL(MSB) Description - Reg Addr --> (0x0B), Bit --> 0...7 */ +#define SMI130_USER_DATA_7_RHALL_MSB__POS (0) +#define SMI130_USER_DATA_7_RHALL_MSB__LEN (8) +#define SMI130_USER_DATA_7_RHALL_MSB__MSK (0xFF) +#define SMI130_USER_DATA_7_RHALL_MSB__REG (SMI130_USER_DATA_7_ADDR) +/**************************************************************/ +/**\name GYRO DATA XYZ LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* GYR_X (LSB) Description - Reg Addr --> (0x0C), Bit --> 0...7 */ +#define SMI130_USER_DATA_8_GYRO_X_LSB__POS (0) +#define SMI130_USER_DATA_8_GYRO_X_LSB__LEN (8) +#define SMI130_USER_DATA_8_GYRO_X_LSB__MSK (0xFF) +#define SMI130_USER_DATA_8_GYRO_X_LSB__REG (SMI130_USER_DATA_8_ADDR) + +/* GYR_X (MSB) Description - Reg Addr --> (0x0D), Bit --> 0...7 */ +#define SMI130_USER_DATA_9_GYRO_X_MSB__POS (0) +#define SMI130_USER_DATA_9_GYRO_X_MSB__LEN (8) +#define SMI130_USER_DATA_9_GYRO_X_MSB__MSK (0xFF) +#define SMI130_USER_DATA_9_GYRO_X_MSB__REG (SMI130_USER_DATA_9_ADDR) + +/* GYR_Y (LSB) Description - Reg Addr --> 0x0E, Bit --> 0...7 */ +#define SMI130_USER_DATA_10_GYRO_Y_LSB__POS (0) +#define SMI130_USER_DATA_10_GYRO_Y_LSB__LEN (8) +#define SMI130_USER_DATA_10_GYRO_Y_LSB__MSK (0xFF) +#define SMI130_USER_DATA_10_GYRO_Y_LSB__REG (SMI130_USER_DATA_10_ADDR) + +/* GYR_Y (MSB) Description - Reg Addr --> (0x0F), Bit --> 0...7 */ +#define SMI130_USER_DATA_11_GYRO_Y_MSB__POS (0) +#define SMI130_USER_DATA_11_GYRO_Y_MSB__LEN (8) +#define SMI130_USER_DATA_11_GYRO_Y_MSB__MSK (0xFF) +#define SMI130_USER_DATA_11_GYRO_Y_MSB__REG (SMI130_USER_DATA_11_ADDR) + +/* GYR_Z (LSB) Description - Reg Addr --> (0x10), Bit --> 0...7 */ +#define SMI130_USER_DATA_12_GYRO_Z_LSB__POS (0) +#define SMI130_USER_DATA_12_GYRO_Z_LSB__LEN (8) +#define SMI130_USER_DATA_12_GYRO_Z_LSB__MSK (0xFF) +#define SMI130_USER_DATA_12_GYRO_Z_LSB__REG (SMI130_USER_DATA_12_ADDR) + +/* GYR_Z (MSB) Description - Reg Addr --> (0x11), Bit --> 0...7 */ +#define SMI130_USER_DATA_13_GYRO_Z_MSB__POS (0) +#define SMI130_USER_DATA_13_GYRO_Z_MSB__LEN (8) +#define SMI130_USER_DATA_13_GYRO_Z_MSB__MSK (0xFF) +#define SMI130_USER_DATA_13_GYRO_Z_MSB__REG (SMI130_USER_DATA_13_ADDR) +/**************************************************************/ +/**\name ACCEL DATA XYZ LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* ACC_X (LSB) Description - Reg Addr --> (0x12), Bit --> 0...7 */ +#define SMI130_USER_DATA_14_ACCEL_X_LSB__POS (0) +#define SMI130_USER_DATA_14_ACCEL_X_LSB__LEN (8) +#define SMI130_USER_DATA_14_ACCEL_X_LSB__MSK (0xFF) +#define SMI130_USER_DATA_14_ACCEL_X_LSB__REG (SMI130_USER_DATA_14_ADDR) + +/* ACC_X (MSB) Description - Reg Addr --> 0x13, Bit --> 0...7 */ +#define SMI130_USER_DATA_15_ACCEL_X_MSB__POS (0) +#define SMI130_USER_DATA_15_ACCEL_X_MSB__LEN (8) +#define SMI130_USER_DATA_15_ACCEL_X_MSB__MSK (0xFF) +#define SMI130_USER_DATA_15_ACCEL_X_MSB__REG (SMI130_USER_DATA_15_ADDR) + +/* ACC_Y (LSB) Description - Reg Addr --> (0x14), Bit --> 0...7 */ +#define SMI130_USER_DATA_16_ACCEL_Y_LSB__POS (0) +#define SMI130_USER_DATA_16_ACCEL_Y_LSB__LEN (8) +#define SMI130_USER_DATA_16_ACCEL_Y_LSB__MSK (0xFF) +#define SMI130_USER_DATA_16_ACCEL_Y_LSB__REG (SMI130_USER_DATA_16_ADDR) + +/* ACC_Y (MSB) Description - Reg Addr --> (0x15), Bit --> 0...7 */ +#define SMI130_USER_DATA_17_ACCEL_Y_MSB__POS (0) +#define SMI130_USER_DATA_17_ACCEL_Y_MSB__LEN (8) +#define SMI130_USER_DATA_17_ACCEL_Y_MSB__MSK (0xFF) +#define SMI130_USER_DATA_17_ACCEL_Y_MSB__REG (SMI130_USER_DATA_17_ADDR) + +/* ACC_Z (LSB) Description - Reg Addr --> 0x16, Bit --> 0...7 */ +#define SMI130_USER_DATA_18_ACCEL_Z_LSB__POS (0) +#define SMI130_USER_DATA_18_ACCEL_Z_LSB__LEN (8) +#define SMI130_USER_DATA_18_ACCEL_Z_LSB__MSK (0xFF) +#define SMI130_USER_DATA_18_ACCEL_Z_LSB__REG (SMI130_USER_DATA_18_ADDR) + +/* ACC_Z (MSB) Description - Reg Addr --> (0x17), Bit --> 0...7 */ +#define SMI130_USER_DATA_19_ACCEL_Z_MSB__POS (0) +#define SMI130_USER_DATA_19_ACCEL_Z_MSB__LEN (8) +#define SMI130_USER_DATA_19_ACCEL_Z_MSB__MSK (0xFF) +#define SMI130_USER_DATA_19_ACCEL_Z_MSB__REG (SMI130_USER_DATA_19_ADDR) +/**************************************************************/ +/**\name SENSOR TIME LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* SENSORTIME_0 (LSB) Description - Reg Addr --> (0x18), Bit --> 0...7 */ +#define SMI130_USER_SENSORTIME_0_SENSOR_TIME_LSB__POS (0) +#define SMI130_USER_SENSORTIME_0_SENSOR_TIME_LSB__LEN (8) +#define SMI130_USER_SENSORTIME_0_SENSOR_TIME_LSB__MSK (0xFF) +#define SMI130_USER_SENSORTIME_0_SENSOR_TIME_LSB__REG \ + (SMI130_USER_SENSORTIME_0_ADDR) + +/* SENSORTIME_1 (MSB) Description - Reg Addr --> (0x19), Bit --> 0...7 */ +#define SMI130_USER_SENSORTIME_1_SENSOR_TIME_MSB__POS (0) +#define SMI130_USER_SENSORTIME_1_SENSOR_TIME_MSB__LEN (8) +#define SMI130_USER_SENSORTIME_1_SENSOR_TIME_MSB__MSK (0xFF) +#define SMI130_USER_SENSORTIME_1_SENSOR_TIME_MSB__REG \ + (SMI130_USER_SENSORTIME_1_ADDR) + +/* SENSORTIME_2 (MSB) Description - Reg Addr --> (0x1A), Bit --> 0...7 */ +#define SMI130_USER_SENSORTIME_2_SENSOR_TIME_MSB__POS (0) +#define SMI130_USER_SENSORTIME_2_SENSOR_TIME_MSB__LEN (8) +#define SMI130_USER_SENSORTIME_2_SENSOR_TIME_MSB__MSK (0xFF) +#define SMI130_USER_SENSORTIME_2_SENSOR_TIME_MSB__REG \ + (SMI130_USER_SENSORTIME_2_ADDR) +/**************************************************************/ +/**\name GYRO SELF TEST LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 1 */ +#define SMI130_USER_STAT_GYRO_SELFTEST_OK__POS (1) +#define SMI130_USER_STAT_GYRO_SELFTEST_OK__LEN (1) +#define SMI130_USER_STAT_GYRO_SELFTEST_OK__MSK (0x02) +#define SMI130_USER_STAT_GYRO_SELFTEST_OK__REG \ + (SMI130_USER_STAT_ADDR) +/**************************************************************/ +/**\name MAG MANUAL OPERATION LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 2 */ +#define SMI130_USER_STAT_MAG_MANUAL_OPERATION__POS (2) +#define SMI130_USER_STAT_MAG_MANUAL_OPERATION__LEN (1) +#define SMI130_USER_STAT_MAG_MANUAL_OPERATION__MSK (0x04) +#define SMI130_USER_STAT_MAG_MANUAL_OPERATION__REG \ + (SMI130_USER_STAT_ADDR) +/**************************************************************/ +/**\name FOC STATUS LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 3 */ +#define SMI130_USER_STAT_FOC_RDY__POS (3) +#define SMI130_USER_STAT_FOC_RDY__LEN (1) +#define SMI130_USER_STAT_FOC_RDY__MSK (0x08) +#define SMI130_USER_STAT_FOC_RDY__REG (SMI130_USER_STAT_ADDR) +/**************************************************************/ +/**\name NVM READY LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 4 */ +#define SMI130_USER_STAT_NVM_RDY__POS (4) +#define SMI130_USER_STAT_NVM_RDY__LEN (1) +#define SMI130_USER_STAT_NVM_RDY__MSK (0x10) +#define SMI130_USER_STAT_NVM_RDY__REG (SMI130_USER_STAT_ADDR) +/**************************************************************/ +/**\name DATA READY LENGTH, POSITION AND MASK FOR ACCEL, MAG AND GYRO*/ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 5 */ +#define SMI130_USER_STAT_DATA_RDY_MAG__POS (5) +#define SMI130_USER_STAT_DATA_RDY_MAG__LEN (1) +#define SMI130_USER_STAT_DATA_RDY_MAG__MSK (0x20) +#define SMI130_USER_STAT_DATA_RDY_MAG__REG (SMI130_USER_STAT_ADDR) + +/* Status Description - Reg Addr --> 0x1B, Bit --> 6 */ +#define SMI130_USER_STAT_DATA_RDY_GYRO__POS (6) +#define SMI130_USER_STAT_DATA_RDY_GYRO__LEN (1) +#define SMI130_USER_STAT_DATA_RDY_GYRO__MSK (0x40) +#define SMI130_USER_STAT_DATA_RDY_GYRO__REG (SMI130_USER_STAT_ADDR) + +/* Status Description - Reg Addr --> 0x1B, Bit --> 7 */ +#define SMI130_USER_STAT_DATA_RDY_ACCEL__POS (7) +#define SMI130_USER_STAT_DATA_RDY_ACCEL__LEN (1) +#define SMI130_USER_STAT_DATA_RDY_ACCEL__MSK (0x80) +#define SMI130_USER_STAT_DATA_RDY_ACCEL__REG (SMI130_USER_STAT_ADDR) +/**************************************************************/ +/**\name INTERRUPT STATUS LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 0 */ +#define SMI130_USER_INTR_STAT_0_STEP_INTR__POS (0) +#define SMI130_USER_INTR_STAT_0_STEP_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_0_STEP_INTR__MSK (0x01) +#define SMI130_USER_INTR_STAT_0_STEP_INTR__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name SIGNIFICANT INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 1 */ +#define SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR__POS (1) +#define SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR__MSK (0x02) +#define SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name ANY_MOTION INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 2 */ +#define SMI130_USER_INTR_STAT_0_ANY_MOTION__POS (2) +#define SMI130_USER_INTR_STAT_0_ANY_MOTION__LEN (1) +#define SMI130_USER_INTR_STAT_0_ANY_MOTION__MSK (0x04) +#define SMI130_USER_INTR_STAT_0_ANY_MOTION__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name PMU TRIGGER INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 3 */ +#define SMI130_USER_INTR_STAT_0_PMU_TRIGGER__POS 3 +#define SMI130_USER_INTR_STAT_0_PMU_TRIGGER__LEN (1) +#define SMI130_USER_INTR_STAT_0_PMU_TRIGGER__MSK (0x08) +#define SMI130_USER_INTR_STAT_0_PMU_TRIGGER__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name DOUBLE TAP INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 4 */ +#define SMI130_USER_INTR_STAT_0_DOUBLE_TAP_INTR__POS 4 +#define SMI130_USER_INTR_STAT_0_DOUBLE_TAP_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_0_DOUBLE_TAP_INTR__MSK (0x10) +#define SMI130_USER_INTR_STAT_0_DOUBLE_TAP_INTR__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name SINGLE TAP INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 5 */ +#define SMI130_USER_INTR_STAT_0_SINGLE_TAP_INTR__POS 5 +#define SMI130_USER_INTR_STAT_0_SINGLE_TAP_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_0_SINGLE_TAP_INTR__MSK (0x20) +#define SMI130_USER_INTR_STAT_0_SINGLE_TAP_INTR__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name ORIENT INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 6 */ +#define SMI130_USER_INTR_STAT_0_ORIENT__POS (6) +#define SMI130_USER_INTR_STAT_0_ORIENT__LEN (1) +#define SMI130_USER_INTR_STAT_0_ORIENT__MSK (0x40) +#define SMI130_USER_INTR_STAT_0_ORIENT__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name FLAT INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 7 */ +#define SMI130_USER_INTR_STAT_0_FLAT__POS (7) +#define SMI130_USER_INTR_STAT_0_FLAT__LEN (1) +#define SMI130_USER_INTR_STAT_0_FLAT__MSK (0x80) +#define SMI130_USER_INTR_STAT_0_FLAT__REG \ + (SMI130_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name HIGH_G INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 2 */ +#define SMI130_USER_INTR_STAT_1_HIGH_G_INTR__POS (2) +#define SMI130_USER_INTR_STAT_1_HIGH_G_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_1_HIGH_G_INTR__MSK (0x04) +#define SMI130_USER_INTR_STAT_1_HIGH_G_INTR__REG \ + (SMI130_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name LOW_G INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 3 */ +#define SMI130_USER_INTR_STAT_1_LOW_G_INTR__POS (3) +#define SMI130_USER_INTR_STAT_1_LOW_G_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_1_LOW_G_INTR__MSK (0x08) +#define SMI130_USER_INTR_STAT_1_LOW_G_INTR__REG \ + (SMI130_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name DATA READY INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 4 */ +#define SMI130_USER_INTR_STAT_1_DATA_RDY_INTR__POS (4) +#define SMI130_USER_INTR_STAT_1_DATA_RDY_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_1_DATA_RDY_INTR__MSK (0x10) +#define SMI130_USER_INTR_STAT_1_DATA_RDY_INTR__REG \ + (SMI130_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name FIFO FULL INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 5 */ +#define SMI130_USER_INTR_STAT_1_FIFO_FULL_INTR__POS (5) +#define SMI130_USER_INTR_STAT_1_FIFO_FULL_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_1_FIFO_FULL_INTR__MSK (0x20) +#define SMI130_USER_INTR_STAT_1_FIFO_FULL_INTR__REG \ + (SMI130_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name FIFO WATERMARK INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 6 */ +#define SMI130_USER_INTR_STAT_1_FIFO_WM_INTR__POS (6) +#define SMI130_USER_INTR_STAT_1_FIFO_WM_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_1_FIFO_WM_INTR__MSK (0x40) +#define SMI130_USER_INTR_STAT_1_FIFO_WM_INTR__REG \ + (SMI130_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name NO MOTION INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 7 */ +#define SMI130_USER_INTR_STAT_1_NOMOTION_INTR__POS (7) +#define SMI130_USER_INTR_STAT_1_NOMOTION_INTR__LEN (1) +#define SMI130_USER_INTR_STAT_1_NOMOTION_INTR__MSK (0x80) +#define SMI130_USER_INTR_STAT_1_NOMOTION_INTR__REG \ + (SMI130_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name ANY MOTION-XYZ AXIS INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 0 */ +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__POS (0) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__LEN (1) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__MSK (0x01) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 1 */ +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__POS (1) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__LEN (1) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__MSK (0x02) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 2 */ +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__POS (2) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__LEN (1) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__MSK (0x04) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name ANY MOTION SIGN LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 3 */ +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN__POS (3) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN__LEN (1) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN__MSK (0x08) +#define SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name TAP_XYZ AND SIGN LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 4 */ +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_X__POS (4) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_X__LEN (1) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_X__MSK (0x10) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_X__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 5 */ +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Y__POS (5) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Y__LEN (1) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Y__MSK (0x20) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Y__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 6 */ +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Z__POS (6) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Z__LEN (1) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Z__MSK (0x40) +#define SMI130_USER_INTR_STAT_2_TAP_FIRST_Z__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 7 */ +#define SMI130_USER_INTR_STAT_2_TAP_SIGN__POS (7) +#define SMI130_USER_INTR_STAT_2_TAP_SIGN__LEN (1) +#define SMI130_USER_INTR_STAT_2_TAP_SIGN__MSK (0x80) +#define SMI130_USER_INTR_STAT_2_TAP_SIGN__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT SATAUS FOR WHOLE 0x1E LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 0...7 */ +#define SMI130_USER_INTR_STAT_2__POS (0) +#define SMI130_USER_INTR_STAT_2__LEN (8) +#define SMI130_USER_INTR_STAT_2__MSK (0xFF) +#define SMI130_USER_INTR_STAT_2__REG \ + (SMI130_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name HIGH_G-XYZ AND SIGN LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 0 */ +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_X__POS (0) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_X__LEN (1) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_X__MSK (0x01) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_X__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> 0x1E, Bit --> 1 */ +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Y__POS (1) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Y__LEN (1) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Y__MSK (0x02) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Y__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 2 */ +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Z__POS (2) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Z__LEN (1) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Z__MSK (0x04) +#define SMI130_USER_INTR_STAT_3_HIGH_G_FIRST_Z__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 3 */ +#define SMI130_USER_INTR_STAT_3_HIGH_G_SIGN__POS (3) +#define SMI130_USER_INTR_STAT_3_HIGH_G_SIGN__LEN (1) +#define SMI130_USER_INTR_STAT_3_HIGH_G_SIGN__MSK (0x08) +#define SMI130_USER_INTR_STAT_3_HIGH_G_SIGN__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name ORIENT XY and Z AXIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 4...5 */ +#define SMI130_USER_INTR_STAT_3_ORIENT_XY__POS (4) +#define SMI130_USER_INTR_STAT_3_ORIENT_XY__LEN (2) +#define SMI130_USER_INTR_STAT_3_ORIENT_XY__MSK (0x30) +#define SMI130_USER_INTR_STAT_3_ORIENT_XY__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 6 */ +#define SMI130_USER_INTR_STAT_3_ORIENT_Z__POS (6) +#define SMI130_USER_INTR_STAT_3_ORIENT_Z__LEN (1) +#define SMI130_USER_INTR_STAT_3_ORIENT_Z__MSK (0x40) +#define SMI130_USER_INTR_STAT_3_ORIENT_Z__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name FLAT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 7 */ +#define SMI130_USER_INTR_STAT_3_FLAT__POS (7) +#define SMI130_USER_INTR_STAT_3_FLAT__LEN (1) +#define SMI130_USER_INTR_STAT_3_FLAT__MSK (0x80) +#define SMI130_USER_INTR_STAT_3_FLAT__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name (0x1F) LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 0...7 */ +#define SMI130_USER_INTR_STAT_3__POS (0) +#define SMI130_USER_INTR_STAT_3__LEN (8) +#define SMI130_USER_INTR_STAT_3__MSK (0xFF) +#define SMI130_USER_INTR_STAT_3__REG \ + (SMI130_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name TEMPERATURE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Temperature Description - LSB Reg Addr --> (0x20), Bit --> 0...7 */ +#define SMI130_USER_TEMP_LSB_VALUE__POS (0) +#define SMI130_USER_TEMP_LSB_VALUE__LEN (8) +#define SMI130_USER_TEMP_LSB_VALUE__MSK (0xFF) +#define SMI130_USER_TEMP_LSB_VALUE__REG \ + (SMI130_USER_TEMPERATURE_0_ADDR) + +/* Temperature Description - LSB Reg Addr --> 0x21, Bit --> 0...7 */ +#define SMI130_USER_TEMP_MSB_VALUE__POS (0) +#define SMI130_USER_TEMP_MSB_VALUE__LEN (8) +#define SMI130_USER_TEMP_MSB_VALUE__MSK (0xFF) +#define SMI130_USER_TEMP_MSB_VALUE__REG \ + (SMI130_USER_TEMPERATURE_1_ADDR) +/**************************************************************/ +/**\name FIFO BYTE COUNTER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Length0 Description - Reg Addr --> 0x22, Bit --> 0...7 */ +#define SMI130_USER_FIFO_BYTE_COUNTER_LSB__POS (0) +#define SMI130_USER_FIFO_BYTE_COUNTER_LSB__LEN (8) +#define SMI130_USER_FIFO_BYTE_COUNTER_LSB__MSK (0xFF) +#define SMI130_USER_FIFO_BYTE_COUNTER_LSB__REG \ + (SMI130_USER_FIFO_LENGTH_0_ADDR) + +/*Fifo_Length1 Description - Reg Addr --> 0x23, Bit --> 0...2 */ +#define SMI130_USER_FIFO_BYTE_COUNTER_MSB__POS (0) +#define SMI130_USER_FIFO_BYTE_COUNTER_MSB__LEN 3 +#define SMI130_USER_FIFO_BYTE_COUNTER_MSB__MSK (0x07) +#define SMI130_USER_FIFO_BYTE_COUNTER_MSB__REG \ + (SMI130_USER_FIFO_LENGTH_1_ADDR) + +/**************************************************************/ +/**\name FIFO DATA LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Data Description - Reg Addr --> 0x24, Bit --> 0...7 */ +#define SMI130_USER_FIFO_DATA__POS (0) +#define SMI130_USER_FIFO_DATA__LEN (8) +#define SMI130_USER_FIFO_DATA__MSK (0xFF) +#define SMI130_USER_FIFO_DATA__REG (SMI130_USER_FIFO_DATA_ADDR) + +/**************************************************************/ +/**\name ACCEL CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Acc_Conf Description - Reg Addr --> (0x40), Bit --> 0...3 */ +#define SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__POS (0) +#define SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__LEN (4) +#define SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__MSK (0x0F) +#define SMI130_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG \ +(SMI130_USER_ACCEL_CONFIG_ADDR) + +/* Acc_Conf Description - Reg Addr --> (0x40), Bit --> 4...6 */ +#define SMI130_USER_ACCEL_CONFIG_ACCEL_BW__POS (4) +#define SMI130_USER_ACCEL_CONFIG_ACCEL_BW__LEN (3) +#define SMI130_USER_ACCEL_CONFIG_ACCEL_BW__MSK (0x70) +#define SMI130_USER_ACCEL_CONFIG_ACCEL_BW__REG (SMI130_USER_ACCEL_CONFIG_ADDR) + +/* Acc_Conf Description - Reg Addr --> (0x40), Bit --> 7 */ +#define SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__POS (7) +#define SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__LEN (1) +#define SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__MSK (0x80) +#define SMI130_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG \ +(SMI130_USER_ACCEL_CONFIG_ADDR) + +/* Acc_Range Description - Reg Addr --> 0x41, Bit --> 0...3 */ +#define SMI130_USER_ACCEL_RANGE__POS (0) +#define SMI130_USER_ACCEL_RANGE__LEN (4) +#define SMI130_USER_ACCEL_RANGE__MSK (0x0F) +#define SMI130_USER_ACCEL_RANGE__REG \ +(SMI130_USER_ACCEL_RANGE_ADDR) +/**************************************************************/ +/**\name GYRO CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Gyro_Conf Description - Reg Addr --> (0x42), Bit --> 0...3 */ +#define SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__POS (0) +#define SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__LEN (4) +#define SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__MSK (0x0F) +#define SMI130_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG \ +(SMI130_USER_GYRO_CONFIG_ADDR) + +/* Gyro_Conf Description - Reg Addr --> (0x42), Bit --> 4...5 */ +#define SMI130_USER_GYRO_CONFIG_BW__POS (4) +#define SMI130_USER_GYRO_CONFIG_BW__LEN (2) +#define SMI130_USER_GYRO_CONFIG_BW__MSK (0x30) +#define SMI130_USER_GYRO_CONFIG_BW__REG \ +(SMI130_USER_GYRO_CONFIG_ADDR) + +/* Gyr_Range Description - Reg Addr --> 0x43, Bit --> 0...2 */ +#define SMI130_USER_GYRO_RANGE__POS (0) +#define SMI130_USER_GYRO_RANGE__LEN (3) +#define SMI130_USER_GYRO_RANGE__MSK (0x07) +#define SMI130_USER_GYRO_RANGE__REG (SMI130_USER_GYRO_RANGE_ADDR) +/**************************************************************/ +/**\name MAG CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Mag_Conf Description - Reg Addr --> (0x44), Bit --> 0...3 */ +#define SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE__POS (0) +#define SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE__LEN (4) +#define SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE__MSK (0x0F) +#define SMI130_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG \ +(SMI130_USER_MAG_CONFIG_ADDR) +/**************************************************************/ +/**\name FIFO DOWNS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Downs Description - Reg Addr --> 0x45, Bit --> 0...2 */ +#define SMI130_USER_FIFO_DOWN_GYRO__POS (0) +#define SMI130_USER_FIFO_DOWN_GYRO__LEN (3) +#define SMI130_USER_FIFO_DOWN_GYRO__MSK (0x07) +#define SMI130_USER_FIFO_DOWN_GYRO__REG (SMI130_USER_FIFO_DOWN_ADDR) +/**************************************************************/ +/**\name FIFO FILTER FOR ACCEL AND GYRO LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_filt Description - Reg Addr --> 0x45, Bit --> 3 */ +#define SMI130_USER_FIFO_FILTER_GYRO__POS (3) +#define SMI130_USER_FIFO_FILTER_GYRO__LEN (1) +#define SMI130_USER_FIFO_FILTER_GYRO__MSK (0x08) +#define SMI130_USER_FIFO_FILTER_GYRO__REG (SMI130_USER_FIFO_DOWN_ADDR) + +/* Fifo_Downs Description - Reg Addr --> 0x45, Bit --> 4...6 */ +#define SMI130_USER_FIFO_DOWN_ACCEL__POS (4) +#define SMI130_USER_FIFO_DOWN_ACCEL__LEN (3) +#define SMI130_USER_FIFO_DOWN_ACCEL__MSK (0x70) +#define SMI130_USER_FIFO_DOWN_ACCEL__REG (SMI130_USER_FIFO_DOWN_ADDR) + +/* Fifo_FILT Description - Reg Addr --> 0x45, Bit --> 7 */ +#define SMI130_USER_FIFO_FILTER_ACCEL__POS (7) +#define SMI130_USER_FIFO_FILTER_ACCEL__LEN (1) +#define SMI130_USER_FIFO_FILTER_ACCEL__MSK (0x80) +#define SMI130_USER_FIFO_FILTER_ACCEL__REG (SMI130_USER_FIFO_DOWN_ADDR) +/**************************************************************/ +/**\name FIFO WATER MARK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_0 Description - Reg Addr --> 0x46, Bit --> 0...7 */ +#define SMI130_USER_FIFO_WM__POS (0) +#define SMI130_USER_FIFO_WM__LEN (8) +#define SMI130_USER_FIFO_WM__MSK (0xFF) +#define SMI130_USER_FIFO_WM__REG (SMI130_USER_FIFO_CONFIG_0_ADDR) +/**************************************************************/ +/**\name FIFO TIME LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 1 */ +#define SMI130_USER_FIFO_TIME_ENABLE__POS (1) +#define SMI130_USER_FIFO_TIME_ENABLE__LEN (1) +#define SMI130_USER_FIFO_TIME_ENABLE__MSK (0x02) +#define SMI130_USER_FIFO_TIME_ENABLE__REG (SMI130_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO TAG INTERRUPT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 2 */ +#define SMI130_USER_FIFO_TAG_INTR2_ENABLE__POS (2) +#define SMI130_USER_FIFO_TAG_INTR2_ENABLE__LEN (1) +#define SMI130_USER_FIFO_TAG_INTR2_ENABLE__MSK (0x04) +#define SMI130_USER_FIFO_TAG_INTR2_ENABLE__REG (SMI130_USER_FIFO_CONFIG_1_ADDR) + +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 3 */ +#define SMI130_USER_FIFO_TAG_INTR1_ENABLE__POS (3) +#define SMI130_USER_FIFO_TAG_INTR1_ENABLE__LEN (1) +#define SMI130_USER_FIFO_TAG_INTR1_ENABLE__MSK (0x08) +#define SMI130_USER_FIFO_TAG_INTR1_ENABLE__REG (SMI130_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO HEADER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 4 */ +#define SMI130_USER_FIFO_HEADER_ENABLE__POS (4) +#define SMI130_USER_FIFO_HEADER_ENABLE__LEN (1) +#define SMI130_USER_FIFO_HEADER_ENABLE__MSK (0x10) +#define SMI130_USER_FIFO_HEADER_ENABLE__REG \ +(SMI130_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO MAG ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 5 */ +#define SMI130_USER_FIFO_MAG_ENABLE__POS (5) +#define SMI130_USER_FIFO_MAG_ENABLE__LEN (1) +#define SMI130_USER_FIFO_MAG_ENABLE__MSK (0x20) +#define SMI130_USER_FIFO_MAG_ENABLE__REG \ +(SMI130_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO ACCEL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 6 */ +#define SMI130_USER_FIFO_ACCEL_ENABLE__POS (6) +#define SMI130_USER_FIFO_ACCEL_ENABLE__LEN (1) +#define SMI130_USER_FIFO_ACCEL_ENABLE__MSK (0x40) +#define SMI130_USER_FIFO_ACCEL_ENABLE__REG \ +(SMI130_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO GYRO ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 7 */ +#define SMI130_USER_FIFO_GYRO_ENABLE__POS (7) +#define SMI130_USER_FIFO_GYRO_ENABLE__LEN (1) +#define SMI130_USER_FIFO_GYRO_ENABLE__MSK (0x80) +#define SMI130_USER_FIFO_GYRO_ENABLE__REG \ +(SMI130_USER_FIFO_CONFIG_1_ADDR) + +/**************************************************************/ +/**\name MAG I2C ADDRESS SELECTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ + +/* Mag_IF_0 Description - Reg Addr --> 0x4b, Bit --> 1...7 */ +#define SMI130_USER_I2C_DEVICE_ADDR__POS (1) +#define SMI130_USER_I2C_DEVICE_ADDR__LEN (7) +#define SMI130_USER_I2C_DEVICE_ADDR__MSK (0xFE) +#define SMI130_USER_I2C_DEVICE_ADDR__REG (SMI130_USER_MAG_IF_0_ADDR) +/**************************************************************/ +/**\name MAG CONFIGURATION FOR SECONDARY + INTERFACE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Mag_IF_1 Description - Reg Addr --> 0x4c, Bit --> 0...1 */ +#define SMI130_USER_MAG_BURST__POS (0) +#define SMI130_USER_MAG_BURST__LEN (2) +#define SMI130_USER_MAG_BURST__MSK (0x03) +#define SMI130_USER_MAG_BURST__REG (SMI130_USER_MAG_IF_1_ADDR) + +/* Mag_IF_1 Description - Reg Addr --> 0x4c, Bit --> 2...5 */ +#define SMI130_USER_MAG_OFFSET__POS (2) +#define SMI130_USER_MAG_OFFSET__LEN (4) +#define SMI130_USER_MAG_OFFSET__MSK (0x3C) +#define SMI130_USER_MAG_OFFSET__REG (SMI130_USER_MAG_IF_1_ADDR) + +/* Mag_IF_1 Description - Reg Addr --> 0x4c, Bit --> 7 */ +#define SMI130_USER_MAG_MANUAL_ENABLE__POS (7) +#define SMI130_USER_MAG_MANUAL_ENABLE__LEN (1) +#define SMI130_USER_MAG_MANUAL_ENABLE__MSK (0x80) +#define SMI130_USER_MAG_MANUAL_ENABLE__REG \ +(SMI130_USER_MAG_IF_1_ADDR) + +/* Mag_IF_2 Description - Reg Addr --> 0x4d, Bit -->0... 7 */ +#define SMI130_USER_READ_ADDR__POS (0) +#define SMI130_USER_READ_ADDR__LEN (8) +#define SMI130_USER_READ_ADDR__MSK (0xFF) +#define SMI130_USER_READ_ADDR__REG (SMI130_USER_MAG_IF_2_ADDR) + +/* Mag_IF_3 Description - Reg Addr --> 0x4e, Bit -->0... 7 */ +#define SMI130_USER_WRITE_ADDR__POS (0) +#define SMI130_USER_WRITE_ADDR__LEN (8) +#define SMI130_USER_WRITE_ADDR__MSK (0xFF) +#define SMI130_USER_WRITE_ADDR__REG (SMI130_USER_MAG_IF_3_ADDR) + +/* Mag_IF_4 Description - Reg Addr --> 0x4f, Bit -->0... 7 */ +#define SMI130_USER_WRITE_DATA__POS (0) +#define SMI130_USER_WRITE_DATA__LEN (8) +#define SMI130_USER_WRITE_DATA__MSK (0xFF) +#define SMI130_USER_WRITE_DATA__REG (SMI130_USER_MAG_IF_4_ADDR) +/**************************************************************/ +/**\name ANY MOTION XYZ AXIS ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->0 */ +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__POS (0) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__MSK (0x01) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_0_ADDR) + +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->1 */ +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__POS (1) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__MSK (0x02) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_0_ADDR) + +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->2 */ +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__POS (2) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__MSK (0x04) +#define SMI130_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name DOUBLE TAP ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->4 */ +#define SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__POS (4) +#define SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__MSK (0x10) +#define SMI130_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name SINGLE TAP ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->5 */ +#define SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__POS (5) +#define SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__MSK (0x20) +#define SMI130_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name ORIENT ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->6 */ +#define SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE__POS (6) +#define SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE__MSK (0x40) +#define SMI130_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name FLAT ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->7 */ +#define SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE__POS (7) +#define SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE__MSK (0x80) +#define SMI130_USER_INTR_ENABLE_0_FLAT_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name HIGH_G XYZ ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->0 */ +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__POS (0) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__MSK (0x01) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_1_ADDR) + +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->1 */ +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__POS (1) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__MSK (0x02) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_1_ADDR) + +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->2 */ +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__POS (2) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__MSK (0x04) +#define SMI130_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name LOW_G ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->3 */ +#define SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__POS (3) +#define SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__MSK (0x08) +#define SMI130_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name DATA READY ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->4 */ +#define SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__POS (4) +#define SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__MSK (0x10) +#define SMI130_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name FIFO FULL AND WATER MARK ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->5 */ +#define SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__POS (5) +#define SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__MSK (0x20) +#define SMI130_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_1_ADDR) + +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->6 */ +#define SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__POS (6) +#define SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__MSK (0x40) +#define SMI130_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name NO MOTION XYZ ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->0 */ +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__POS (0) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__MSK (0x01) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_2_ADDR) + +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->1 */ +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__POS (1) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__MSK (0x02) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_2_ADDR) + +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->2 */ +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__POS (2) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__MSK (0x04) +#define SMI130_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_2_ADDR) +/**************************************************************/ +/**\name STEP DETECTOR ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->3 */ +#define SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__POS (3) +#define SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__LEN (1) +#define SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__MSK (0x08) +#define SMI130_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG \ +(SMI130_USER_INTR_ENABLE_2_ADDR) +/**************************************************************/ +/**\name EDGE CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->0 */ +#define SMI130_USER_INTR1_EDGE_CTRL__POS (0) +#define SMI130_USER_INTR1_EDGE_CTRL__LEN (1) +#define SMI130_USER_INTR1_EDGE_CTRL__MSK (0x01) +#define SMI130_USER_INTR1_EDGE_CTRL__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name LEVEL CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->1 */ +#define SMI130_USER_INTR1_LEVEL__POS (1) +#define SMI130_USER_INTR1_LEVEL__LEN (1) +#define SMI130_USER_INTR1_LEVEL__MSK (0x02) +#define SMI130_USER_INTR1_LEVEL__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name OUTPUT TYPE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->2 */ +#define SMI130_USER_INTR1_OUTPUT_TYPE__POS (2) +#define SMI130_USER_INTR1_OUTPUT_TYPE__LEN (1) +#define SMI130_USER_INTR1_OUTPUT_TYPE__MSK (0x04) +#define SMI130_USER_INTR1_OUTPUT_TYPE__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name OUTPUT TYPE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->3 */ +#define SMI130_USER_INTR1_OUTPUT_ENABLE__POS (3) +#define SMI130_USER_INTR1_OUTPUT_ENABLE__LEN (1) +#define SMI130_USER_INTR1_OUTPUT_ENABLE__MSK (0x08) +#define SMI130_USER_INTR1_OUTPUT_ENABLE__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name EDGE CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->4 */ +#define SMI130_USER_INTR2_EDGE_CTRL__POS (4) +#define SMI130_USER_INTR2_EDGE_CTRL__LEN (1) +#define SMI130_USER_INTR2_EDGE_CTRL__MSK (0x10) +#define SMI130_USER_INTR2_EDGE_CTRL__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name LEVEL CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->5 */ +#define SMI130_USER_INTR2_LEVEL__POS (5) +#define SMI130_USER_INTR2_LEVEL__LEN (1) +#define SMI130_USER_INTR2_LEVEL__MSK (0x20) +#define SMI130_USER_INTR2_LEVEL__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name OUTPUT TYPE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->6 */ +#define SMI130_USER_INTR2_OUTPUT_TYPE__POS (6) +#define SMI130_USER_INTR2_OUTPUT_TYPE__LEN (1) +#define SMI130_USER_INTR2_OUTPUT_TYPE__MSK (0x40) +#define SMI130_USER_INTR2_OUTPUT_TYPE__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) + +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->7 */ +#define SMI130_USER_INTR2_OUTPUT_EN__POS (7) +#define SMI130_USER_INTR2_OUTPUT_EN__LEN (1) +#define SMI130_USER_INTR2_OUTPUT_EN__MSK (0x80) +#define SMI130_USER_INTR2_OUTPUT_EN__REG \ +(SMI130_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name LATCH INTERRUPT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Latch Description - Reg Addr --> 0x54, Bit -->0...3 */ +#define SMI130_USER_INTR_LATCH__POS (0) +#define SMI130_USER_INTR_LATCH__LEN (4) +#define SMI130_USER_INTR_LATCH__MSK (0x0F) +#define SMI130_USER_INTR_LATCH__REG (SMI130_USER_INTR_LATCH_ADDR) +/**************************************************************/ +/**\name INPUT ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Latch Description - Reg Addr --> 0x54, Bit -->4 */ +#define SMI130_USER_INTR1_INPUT_ENABLE__POS (4) +#define SMI130_USER_INTR1_INPUT_ENABLE__LEN (1) +#define SMI130_USER_INTR1_INPUT_ENABLE__MSK (0x10) +#define SMI130_USER_INTR1_INPUT_ENABLE__REG \ +(SMI130_USER_INTR_LATCH_ADDR) + +/* Int_Latch Description - Reg Addr --> 0x54, Bit -->5*/ +#define SMI130_USER_INTR2_INPUT_ENABLE__POS (5) +#define SMI130_USER_INTR2_INPUT_ENABLE__LEN (1) +#define SMI130_USER_INTR2_INPUT_ENABLE__MSK (0x20) +#define SMI130_USER_INTR2_INPUT_ENABLE__REG \ +(SMI130_USER_INTR_LATCH_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF LOW_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->0 */ +#define SMI130_USER_INTR_MAP_0_INTR1_LOW_G__POS (0) +#define SMI130_USER_INTR_MAP_0_INTR1_LOW_G__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_LOW_G__MSK (0x01) +#define SMI130_USER_INTR_MAP_0_INTR1_LOW_G__REG (SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF HIGH_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->1 */ +#define SMI130_USER_INTR_MAP_0_INTR1_HIGH_G__POS (1) +#define SMI130_USER_INTR_MAP_0_INTR1_HIGH_G__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_HIGH_G__MSK (0x02) +#define SMI130_USER_INTR_MAP_0_INTR1_HIGH_G__REG \ +(SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT MAPPIONG OF ANY MOTION_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->2 */ +#define SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__POS (2) +#define SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__MSK (0x04) +#define SMI130_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG \ +(SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF NO MOTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->3 */ +#define SMI130_USER_INTR_MAP_0_INTR1_NOMOTION__POS (3) +#define SMI130_USER_INTR_MAP_0_INTR1_NOMOTION__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_NOMOTION__MSK (0x08) +#define SMI130_USER_INTR_MAP_0_INTR1_NOMOTION__REG (SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF DOUBLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->4 */ +#define SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__POS (4) +#define SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__MSK (0x10) +#define SMI130_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG \ +(SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF SINGLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->5 */ +#define SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP__POS (5) +#define SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP__MSK (0x20) +#define SMI130_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG \ +(SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF ORIENT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->6 */ +#define SMI130_USER_INTR_MAP_0_INTR1_ORIENT__POS (6) +#define SMI130_USER_INTR_MAP_0_INTR1_ORIENT__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_ORIENT__MSK (0x40) +#define SMI130_USER_INTR_MAP_0_INTR1_ORIENT__REG \ +(SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT MAPPIONG OF FLAT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x56, Bit -->7 */ +#define SMI130_USER_INTR_MAP_0_INTR1_FLAT__POS (7) +#define SMI130_USER_INTR_MAP_0_INTR1_FLAT__LEN (1) +#define SMI130_USER_INTR_MAP_0_INTR1_FLAT__MSK (0x80) +#define SMI130_USER_INTR_MAP_0_INTR1_FLAT__REG (SMI130_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF PMU TRIGGER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->0 */ +#define SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG__POS (0) +#define SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG__MSK (0x01) +#define SMI130_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG (SMI130_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF FIFO FULL AND + WATER MARK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->1 */ +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL__POS (1) +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL__MSK (0x02) +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG \ +(SMI130_USER_INTR_MAP_1_ADDR) + +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->2 */ +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM__POS (2) +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM__MSK (0x04) +#define SMI130_USER_INTR_MAP_1_INTR2_FIFO_WM__REG \ +(SMI130_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF DATA READY LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->3 */ +#define SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY__POS (3) +#define SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY__MSK (0x08) +#define SMI130_USER_INTR_MAP_1_INTR2_DATA_RDY__REG \ +(SMI130_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF PMU TRIGGER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->4 */ +#define SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG__POS (4) +#define SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG__MSK (0x10) +#define SMI130_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG (SMI130_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF FIFO FULL AND + WATER MARK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->5 */ +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL__POS (5) +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL__MSK (0x20) +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG \ +(SMI130_USER_INTR_MAP_1_ADDR) + +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->6 */ +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM__POS (6) +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM__MSK (0x40) +#define SMI130_USER_INTR_MAP_1_INTR1_FIFO_WM__REG \ +(SMI130_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF DATA READY LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->7 */ +#define SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY__POS (7) +#define SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY__LEN (1) +#define SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY__MSK (0x80) +#define SMI130_USER_INTR_MAP_1_INTR1_DATA_RDY__REG \ +(SMI130_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF LOW_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->0 */ +#define SMI130_USER_INTR_MAP_2_INTR2_LOW_G__POS (0) +#define SMI130_USER_INTR_MAP_2_INTR2_LOW_G__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_LOW_G__MSK (0x01) +#define SMI130_USER_INTR_MAP_2_INTR2_LOW_G__REG (SMI130_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF HIGH_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->1 */ +#define SMI130_USER_INTR_MAP_2_INTR2_HIGH_G__POS (1) +#define SMI130_USER_INTR_MAP_2_INTR2_HIGH_G__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_HIGH_G__MSK (0x02) +#define SMI130_USER_INTR_MAP_2_INTR2_HIGH_G__REG \ +(SMI130_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF ANY MOTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->2 */ +#define SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__POS (2) +#define SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__MSK (0x04) +#define SMI130_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG \ +(SMI130_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF NO MOTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->3 */ +#define SMI130_USER_INTR_MAP_2_INTR2_NOMOTION__POS (3) +#define SMI130_USER_INTR_MAP_2_INTR2_NOMOTION__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_NOMOTION__MSK (0x08) +#define SMI130_USER_INTR_MAP_2_INTR2_NOMOTION__REG (SMI130_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF DOUBLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->4 */ +#define SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__POS (4) +#define SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__MSK (0x10) +#define SMI130_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG \ +(SMI130_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF SINGLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->5 */ +#define SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP__POS (5) +#define SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP__MSK (0x20) +#define SMI130_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG \ +(SMI130_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF ORIENT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->6 */ +#define SMI130_USER_INTR_MAP_2_INTR2_ORIENT__POS (6) +#define SMI130_USER_INTR_MAP_2_INTR2_ORIENT__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_ORIENT__MSK (0x40) +#define SMI130_USER_INTR_MAP_2_INTR2_ORIENT__REG \ +(SMI130_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF FLAT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->7 */ +#define SMI130_USER_INTR_MAP_2_INTR2_FLAT__POS (7) +#define SMI130_USER_INTR_MAP_2_INTR2_FLAT__LEN (1) +#define SMI130_USER_INTR_MAP_2_INTR2_FLAT__MSK (0x80) +#define SMI130_USER_INTR_MAP_2_INTR2_FLAT__REG (SMI130_USER_INTR_MAP_2_ADDR) + +/**************************************************************/ +/**\name TAP SOURCE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Data_0 Description - Reg Addr --> 0x58, Bit --> 3 */ +#define SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE__POS (3) +#define SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE__LEN (1) +#define SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE__MSK (0x08) +#define SMI130_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG \ +(SMI130_USER_INTR_DATA_0_ADDR) + +/**************************************************************/ +/**\name HIGH SOURCE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Data_0 Description - Reg Addr --> 0x58, Bit --> 7 */ +#define SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__POS (7) +#define SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__LEN (1) +#define SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__MSK (0x80) +#define SMI130_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG \ +(SMI130_USER_INTR_DATA_0_ADDR) + +/**************************************************************/ +/**\name MOTION SOURCE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Data_1 Description - Reg Addr --> 0x59, Bit --> 7 */ +#define SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE__POS (7) +#define SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE__LEN (1) +#define SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE__MSK (0x80) +#define SMI130_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG \ + (SMI130_USER_INTR_DATA_1_ADDR) +/**************************************************************/ +/**\name LOW HIGH DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_0 Description - Reg Addr --> 0x5a, Bit --> 0...7 */ +#define SMI130_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__POS (0) +#define SMI130_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__LEN (8) +#define SMI130_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__MSK (0xFF) +#define SMI130_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__REG \ + (SMI130_USER_INTR_LOWHIGH_0_ADDR) +/**************************************************************/ +/**\name LOW THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_1 Description - Reg Addr --> 0x5b, Bit --> 0...7 */ +#define SMI130_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__POS (0) +#define SMI130_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__LEN (8) +#define SMI130_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__MSK (0xFF) +#define SMI130_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__REG \ + (SMI130_USER_INTR_LOWHIGH_1_ADDR) +/**************************************************************/ +/**\name LOW HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_2 Description - Reg Addr --> 0x5c, Bit --> 0...1 */ +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__POS (0) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__LEN (2) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__MSK (0x03) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG \ + (SMI130_USER_INTR_LOWHIGH_2_ADDR) +/**************************************************************/ +/**\name LOW MODE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_2 Description - Reg Addr --> 0x5c, Bit --> 2 */ +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__POS (2) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__LEN (1) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__MSK (0x04) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG \ + (SMI130_USER_INTR_LOWHIGH_2_ADDR) +/**************************************************************/ +/**\name HIGH_G HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_2 Description - Reg Addr --> 0x5c, Bit --> 6...7 */ +#define SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__POS (6) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__LEN (2) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__MSK (0xC0) +#define SMI130_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG \ + (SMI130_USER_INTR_LOWHIGH_2_ADDR) +/**************************************************************/ +/**\name HIGH_G DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_3 Description - Reg Addr --> 0x5d, Bit --> 0...7 */ +#define SMI130_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__POS (0) +#define SMI130_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__LEN (8) +#define SMI130_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__MSK (0xFF) +#define SMI130_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__REG \ + (SMI130_USER_INTR_LOWHIGH_3_ADDR) +/**************************************************************/ +/**\name HIGH_G THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_4 Description - Reg Addr --> 0x5e, Bit --> 0...7 */ +#define SMI130_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__POS (0) +#define SMI130_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__LEN (8) +#define SMI130_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__MSK (0xFF) +#define SMI130_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__REG \ + (SMI130_USER_INTR_LOWHIGH_4_ADDR) +/**************************************************************/ +/**\name ANY MOTION DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_0 Description - Reg Addr --> 0x5f, Bit --> 0...1 */ +#define SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__POS (0) +#define SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__LEN (2) +#define SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__MSK (0x03) +#define SMI130_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG \ + (SMI130_USER_INTR_MOTION_0_ADDR) +/**************************************************************/ +/**\name SLOW/NO MOTION DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ + /* Int_Motion_0 Description - Reg Addr --> 0x5f, Bit --> 2...7 */ +#define SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__POS (2) +#define SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__LEN (6) +#define SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__MSK (0xFC) +#define SMI130_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG \ + (SMI130_USER_INTR_MOTION_0_ADDR) +/**************************************************************/ +/**\name ANY MOTION THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_1 Description - Reg Addr --> (0x60), Bit --> 0...7 */ +#define SMI130_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__POS (0) +#define SMI130_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__LEN (8) +#define SMI130_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__MSK (0xFF) +#define SMI130_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__REG \ + (SMI130_USER_INTR_MOTION_1_ADDR) +/**************************************************************/ +/**\name SLOW/NO MOTION THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_2 Description - Reg Addr --> 0x61, Bit --> 0...7 */ +#define SMI130_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__POS (0) +#define SMI130_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__LEN (8) +#define SMI130_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__MSK (0xFF) +#define SMI130_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__REG \ + (SMI130_USER_INTR_MOTION_2_ADDR) +/**************************************************************/ +/**\name SLOW/NO MOTION SELECT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 0 */ +#define SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__POS (0) +#define SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__LEN (1) +#define SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__MSK (0x01) +#define SMI130_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG \ +(SMI130_USER_INTR_MOTION_3_ADDR) +/**************************************************************/ +/**\name SIGNIFICANT MOTION SELECT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 1 */ +#define SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT__POS (1) +#define SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT__LEN (1) +#define SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT__MSK (0x02) +#define SMI130_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG \ + (SMI130_USER_INTR_MOTION_3_ADDR) + +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 3..2 */ +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP__POS (2) +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP__LEN (2) +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP__MSK (0x0C) +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG \ + (SMI130_USER_INTR_MOTION_3_ADDR) + +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 5..4 */ +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF__POS (4) +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF__LEN (2) +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF__MSK (0x30) +#define SMI130_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG \ + (SMI130_USER_INTR_MOTION_3_ADDR) +/**************************************************************/ +/**\name TAP DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* INT_TAP_0 Description - Reg Addr --> (0x63), Bit --> 0..2*/ +#define SMI130_USER_INTR_TAP_0_INTR_TAP_DURN__POS (0) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_DURN__LEN (3) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_DURN__MSK (0x07) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_DURN__REG \ +(SMI130_USER_INTR_TAP_0_ADDR) +/**************************************************************/ +/**\name TAP SHOCK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Tap_0 Description - Reg Addr --> (0x63), Bit --> 6 */ +#define SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK__POS (6) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK__LEN (1) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK__MSK (0x40) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG (SMI130_USER_INTR_TAP_0_ADDR) +/**************************************************************/ +/**\name TAP QUIET LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Tap_0 Description - Reg Addr --> (0x63), Bit --> 7 */ +#define SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET__POS (7) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET__LEN (1) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET__MSK (0x80) +#define SMI130_USER_INTR_TAP_0_INTR_TAP_QUIET__REG (SMI130_USER_INTR_TAP_0_ADDR) +/**************************************************************/ +/**\name TAP THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Tap_1 Description - Reg Addr --> (0x64), Bit --> 0...4 */ +#define SMI130_USER_INTR_TAP_1_INTR_TAP_THRES__POS (0) +#define SMI130_USER_INTR_TAP_1_INTR_TAP_THRES__LEN (5) +#define SMI130_USER_INTR_TAP_1_INTR_TAP_THRES__MSK (0x1F) +#define SMI130_USER_INTR_TAP_1_INTR_TAP_THRES__REG (SMI130_USER_INTR_TAP_1_ADDR) +/**************************************************************/ +/**\name ORIENT MODE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_0 Description - Reg Addr --> (0x65), Bit --> 0...1 */ +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__POS (0) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__LEN (2) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__MSK (0x03) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG \ + (SMI130_USER_INTR_ORIENT_0_ADDR) +/**************************************************************/ +/**\name ORIENT BLOCKING LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_0 Description - Reg Addr --> (0x65), Bit --> 2...3 */ +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__POS (2) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__LEN (2) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__MSK (0x0C) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG \ + (SMI130_USER_INTR_ORIENT_0_ADDR) +/**************************************************************/ +/**\name ORIENT HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_0 Description - Reg Addr --> (0x65), Bit --> 4...7 */ +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__POS (4) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__LEN (4) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__MSK (0xF0) +#define SMI130_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG \ + (SMI130_USER_INTR_ORIENT_0_ADDR) +/**************************************************************/ +/**\name ORIENT THETA LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_1 Description - Reg Addr --> 0x66, Bit --> 0...5 */ +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__POS (0) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__LEN (6) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__MSK (0x3F) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG \ + (SMI130_USER_INTR_ORIENT_1_ADDR) +/**************************************************************/ +/**\name ORIENT UD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_1 Description - Reg Addr --> 0x66, Bit --> 6 */ +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__POS (6) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__LEN (1) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__MSK (0x40) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG \ + (SMI130_USER_INTR_ORIENT_1_ADDR) +/**************************************************************/ +/**\name ORIENT AXIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_1 Description - Reg Addr --> 0x66, Bit --> 7 */ +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__POS (7) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__LEN (1) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__MSK (0x80) +#define SMI130_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG \ + (SMI130_USER_INTR_ORIENT_1_ADDR) +/**************************************************************/ +/**\name FLAT THETA LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Flat_0 Description - Reg Addr --> 0x67, Bit --> 0...5 */ +#define SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA__POS (0) +#define SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA__LEN (6) +#define SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA__MSK (0x3F) +#define SMI130_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG \ + (SMI130_USER_INTR_FLAT_0_ADDR) +/**************************************************************/ +/**\name FLAT HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Flat_1 Description - Reg Addr --> (0x68), Bit --> 0...3 */ +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST__POS (0) +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST__LEN (4) +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST__MSK (0x0F) +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG \ +(SMI130_USER_INTR_FLAT_1_ADDR) +/**************************************************************/ +/**\name FLAT HOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Flat_1 Description - Reg Addr --> (0x68), Bit --> 4...5 */ +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD__POS (4) +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD__LEN (2) +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD__MSK (0x30) +#define SMI130_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG \ +(SMI130_USER_INTR_FLAT_1_ADDR) +/**************************************************************/ +/**\name FOC ACCEL XYZ LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 0...1 */ +#define SMI130_USER_FOC_ACCEL_Z__POS (0) +#define SMI130_USER_FOC_ACCEL_Z__LEN (2) +#define SMI130_USER_FOC_ACCEL_Z__MSK (0x03) +#define SMI130_USER_FOC_ACCEL_Z__REG (SMI130_USER_FOC_CONFIG_ADDR) + +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 2...3 */ +#define SMI130_USER_FOC_ACCEL_Y__POS (2) +#define SMI130_USER_FOC_ACCEL_Y__LEN (2) +#define SMI130_USER_FOC_ACCEL_Y__MSK (0x0C) +#define SMI130_USER_FOC_ACCEL_Y__REG (SMI130_USER_FOC_CONFIG_ADDR) + +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 4...5 */ +#define SMI130_USER_FOC_ACCEL_X__POS (4) +#define SMI130_USER_FOC_ACCEL_X__LEN (2) +#define SMI130_USER_FOC_ACCEL_X__MSK (0x30) +#define SMI130_USER_FOC_ACCEL_X__REG (SMI130_USER_FOC_CONFIG_ADDR) +/**************************************************************/ +/**\name FOC GYRO LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 6 */ +#define SMI130_USER_FOC_GYRO_ENABLE__POS (6) +#define SMI130_USER_FOC_GYRO_ENABLE__LEN (1) +#define SMI130_USER_FOC_GYRO_ENABLE__MSK (0x40) +#define SMI130_USER_FOC_GYRO_ENABLE__REG \ +(SMI130_USER_FOC_CONFIG_ADDR) +/**************************************************************/ +/**\name NVM PROGRAM LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* CONF Description - Reg Addr --> (0x6A), Bit --> 1 */ +#define SMI130_USER_CONFIG_NVM_PROG_ENABLE__POS (1) +#define SMI130_USER_CONFIG_NVM_PROG_ENABLE__LEN (1) +#define SMI130_USER_CONFIG_NVM_PROG_ENABLE__MSK (0x02) +#define SMI130_USER_CONFIG_NVM_PROG_ENABLE__REG \ +(SMI130_USER_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x6B), Bit --> 0 */ + +#define SMI130_USER_IF_CONFIG_SPI3__POS (0) +#define SMI130_USER_IF_CONFIG_SPI3__LEN (1) +#define SMI130_USER_IF_CONFIG_SPI3__MSK (0x01) +#define SMI130_USER_IF_CONFIG_SPI3__REG \ +(SMI130_USER_IF_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x6B), Bit --> 5..4 */ +#define SMI130_USER_IF_CONFIG_IF_MODE__POS (4) +#define SMI130_USER_IF_CONFIG_IF_MODE__LEN (2) +#define SMI130_USER_IF_CONFIG_IF_MODE__MSK (0x30) +#define SMI130_USER_IF_CONFIG_IF_MODE__REG \ +(SMI130_USER_IF_CONFIG_ADDR) +/**************************************************************/ +/**\name GYRO SLEEP CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 0...2 */ +#define SMI130_USER_GYRO_SLEEP_TRIGGER__POS (0) +#define SMI130_USER_GYRO_SLEEP_TRIGGER__LEN (3) +#define SMI130_USER_GYRO_SLEEP_TRIGGER__MSK (0x07) +#define SMI130_USER_GYRO_SLEEP_TRIGGER__REG (SMI130_USER_PMU_TRIGGER_ADDR) + +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 3...4 */ +#define SMI130_USER_GYRO_WAKEUP_TRIGGER__POS (3) +#define SMI130_USER_GYRO_WAKEUP_TRIGGER__LEN (2) +#define SMI130_USER_GYRO_WAKEUP_TRIGGER__MSK (0x18) +#define SMI130_USER_GYRO_WAKEUP_TRIGGER__REG (SMI130_USER_PMU_TRIGGER_ADDR) + +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 5 */ +#define SMI130_USER_GYRO_SLEEP_STATE__POS (5) +#define SMI130_USER_GYRO_SLEEP_STATE__LEN (1) +#define SMI130_USER_GYRO_SLEEP_STATE__MSK (0x20) +#define SMI130_USER_GYRO_SLEEP_STATE__REG (SMI130_USER_PMU_TRIGGER_ADDR) + +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 6 */ +#define SMI130_USER_GYRO_WAKEUP_INTR__POS (6) +#define SMI130_USER_GYRO_WAKEUP_INTR__LEN (1) +#define SMI130_USER_GYRO_WAKEUP_INTR__MSK (0x40) +#define SMI130_USER_GYRO_WAKEUP_INTR__REG (SMI130_USER_PMU_TRIGGER_ADDR) +/**************************************************************/ +/**\name ACCEL SELF TEST LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 0...1 */ +#define SMI130_USER_ACCEL_SELFTEST_AXIS__POS (0) +#define SMI130_USER_ACCEL_SELFTEST_AXIS__LEN (2) +#define SMI130_USER_ACCEL_SELFTEST_AXIS__MSK (0x03) +#define SMI130_USER_ACCEL_SELFTEST_AXIS__REG (SMI130_USER_SELF_TEST_ADDR) + +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 2 */ +#define SMI130_USER_ACCEL_SELFTEST_SIGN__POS (2) +#define SMI130_USER_ACCEL_SELFTEST_SIGN__LEN (1) +#define SMI130_USER_ACCEL_SELFTEST_SIGN__MSK (0x04) +#define SMI130_USER_ACCEL_SELFTEST_SIGN__REG (SMI130_USER_SELF_TEST_ADDR) + +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 3 */ +#define SMI130_USER_SELFTEST_AMP__POS (3) +#define SMI130_USER_SELFTEST_AMP__LEN (1) +#define SMI130_USER_SELFTEST_AMP__MSK (0x08) +#define SMI130_USER_SELFTEST_AMP__REG (SMI130_USER_SELF_TEST_ADDR) +/**************************************************************/ +/**\name GYRO SELF TEST LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 4 */ +#define SMI130_USER_GYRO_SELFTEST_START__POS (4) +#define SMI130_USER_GYRO_SELFTEST_START__LEN (1) +#define SMI130_USER_GYRO_SELFTEST_START__MSK (0x10) +#define SMI130_USER_GYRO_SELFTEST_START__REG \ +(SMI130_USER_SELF_TEST_ADDR) +/**************************************************************/ +/**\name NV_CONFIG LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* NV_CONF Description - Reg Addr --> (0x70), Bit --> 0 */ +#define SMI130_USER_NV_CONFIG_SPI_ENABLE__POS (0) +#define SMI130_USER_NV_CONFIG_SPI_ENABLE__LEN (1) +#define SMI130_USER_NV_CONFIG_SPI_ENABLE__MSK (0x01) +#define SMI130_USER_NV_CONFIG_SPI_ENABLE__REG (SMI130_USER_NV_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x70), Bit --> 1 */ +#define SMI130_USER_IF_CONFIG_I2C_WDT_SELECT__POS (1) +#define SMI130_USER_IF_CONFIG_I2C_WDT_SELECT__LEN (1) +#define SMI130_USER_IF_CONFIG_I2C_WDT_SELECT__MSK (0x02) +#define SMI130_USER_IF_CONFIG_I2C_WDT_SELECT__REG \ +(SMI130_USER_NV_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x70), Bit --> 2 */ +#define SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE__POS (2) +#define SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE__LEN (1) +#define SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE__MSK (0x04) +#define SMI130_USER_IF_CONFIG_I2C_WDT_ENABLE__REG \ +(SMI130_USER_NV_CONFIG_ADDR) + +/* NV_CONF Description - Reg Addr --> (0x70), Bit --> 3 */ +#define SMI130_USER_NV_CONFIG_SPARE0__POS (3) +#define SMI130_USER_NV_CONFIG_SPARE0__LEN (1) +#define SMI130_USER_NV_CONFIG_SPARE0__MSK (0x08) +#define SMI130_USER_NV_CONFIG_SPARE0__REG (SMI130_USER_NV_CONFIG_ADDR) + +/* NV_CONF Description - Reg Addr --> (0x70), Bit --> 4...7 */ +#define SMI130_USER_NV_CONFIG_NVM_COUNTER__POS (4) +#define SMI130_USER_NV_CONFIG_NVM_COUNTER__LEN (4) +#define SMI130_USER_NV_CONFIG_NVM_COUNTER__MSK (0xF0) +#define SMI130_USER_NV_CONFIG_NVM_COUNTER__REG (SMI130_USER_NV_CONFIG_ADDR) +/**************************************************************/ +/**\name ACCEL MANUAL OFFSET LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_0 Description - Reg Addr --> (0x71), Bit --> 0...7 */ +#define SMI130_USER_OFFSET_0_ACCEL_OFF_X__POS (0) +#define SMI130_USER_OFFSET_0_ACCEL_OFF_X__LEN (8) +#define SMI130_USER_OFFSET_0_ACCEL_OFF_X__MSK (0xFF) +#define SMI130_USER_OFFSET_0_ACCEL_OFF_X__REG (SMI130_USER_OFFSET_0_ADDR) + +/* Offset_1 Description - Reg Addr --> 0x72, Bit --> 0...7 */ +#define SMI130_USER_OFFSET_1_ACCEL_OFF_Y__POS (0) +#define SMI130_USER_OFFSET_1_ACCEL_OFF_Y__LEN (8) +#define SMI130_USER_OFFSET_1_ACCEL_OFF_Y__MSK (0xFF) +#define SMI130_USER_OFFSET_1_ACCEL_OFF_Y__REG (SMI130_USER_OFFSET_1_ADDR) + +/* Offset_2 Description - Reg Addr --> 0x73, Bit --> 0...7 */ +#define SMI130_USER_OFFSET_2_ACCEL_OFF_Z__POS (0) +#define SMI130_USER_OFFSET_2_ACCEL_OFF_Z__LEN (8) +#define SMI130_USER_OFFSET_2_ACCEL_OFF_Z__MSK (0xFF) +#define SMI130_USER_OFFSET_2_ACCEL_OFF_Z__REG (SMI130_USER_OFFSET_2_ADDR) +/**************************************************************/ +/**\name GYRO MANUAL OFFSET LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_3 Description - Reg Addr --> 0x74, Bit --> 0...7 */ +#define SMI130_USER_OFFSET_3_GYRO_OFF_X__POS (0) +#define SMI130_USER_OFFSET_3_GYRO_OFF_X__LEN (8) +#define SMI130_USER_OFFSET_3_GYRO_OFF_X__MSK (0xFF) +#define SMI130_USER_OFFSET_3_GYRO_OFF_X__REG (SMI130_USER_OFFSET_3_ADDR) + +/* Offset_4 Description - Reg Addr --> 0x75, Bit --> 0...7 */ +#define SMI130_USER_OFFSET_4_GYRO_OFF_Y__POS (0) +#define SMI130_USER_OFFSET_4_GYRO_OFF_Y__LEN (8) +#define SMI130_USER_OFFSET_4_GYRO_OFF_Y__MSK (0xFF) +#define SMI130_USER_OFFSET_4_GYRO_OFF_Y__REG (SMI130_USER_OFFSET_4_ADDR) + +/* Offset_5 Description - Reg Addr --> 0x76, Bit --> 0...7 */ +#define SMI130_USER_OFFSET_5_GYRO_OFF_Z__POS (0) +#define SMI130_USER_OFFSET_5_GYRO_OFF_Z__LEN (8) +#define SMI130_USER_OFFSET_5_GYRO_OFF_Z__MSK (0xFF) +#define SMI130_USER_OFFSET_5_GYRO_OFF_Z__REG (SMI130_USER_OFFSET_5_ADDR) + + +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 0..1 */ +#define SMI130_USER_OFFSET_6_GYRO_OFF_X__POS (0) +#define SMI130_USER_OFFSET_6_GYRO_OFF_X__LEN (2) +#define SMI130_USER_OFFSET_6_GYRO_OFF_X__MSK (0x03) +#define SMI130_USER_OFFSET_6_GYRO_OFF_X__REG (SMI130_USER_OFFSET_6_ADDR) + +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 2...3 */ +#define SMI130_USER_OFFSET_6_GYRO_OFF_Y__POS (2) +#define SMI130_USER_OFFSET_6_GYRO_OFF_Y__LEN (2) +#define SMI130_USER_OFFSET_6_GYRO_OFF_Y__MSK (0x0C) +#define SMI130_USER_OFFSET_6_GYRO_OFF_Y__REG (SMI130_USER_OFFSET_6_ADDR) + +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 4...5 */ +#define SMI130_USER_OFFSET_6_GYRO_OFF_Z__POS (4) +#define SMI130_USER_OFFSET_6_GYRO_OFF_Z__LEN (2) +#define SMI130_USER_OFFSET_6_GYRO_OFF_Z__MSK (0x30) +#define SMI130_USER_OFFSET_6_GYRO_OFF_Z__REG (SMI130_USER_OFFSET_6_ADDR) +/**************************************************************/ +/**\name ACCEL OFFSET ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 6 */ +#define SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE__POS (6) +#define SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE__LEN (1) +#define SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE__MSK (0x40) +#define SMI130_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG \ +(SMI130_USER_OFFSET_6_ADDR) +/**************************************************************/ +/**\name GYRO OFFSET ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 7 */ +#define SMI130_USER_OFFSET_6_GYRO_OFF_EN__POS (7) +#define SMI130_USER_OFFSET_6_GYRO_OFF_EN__LEN (1) +#define SMI130_USER_OFFSET_6_GYRO_OFF_EN__MSK (0x80) +#define SMI130_USER_OFFSET_6_GYRO_OFF_EN__REG (SMI130_USER_OFFSET_6_ADDR) +/**************************************************************/ +/**\name STEP COUNTER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* STEP_CNT_0 Description - Reg Addr --> 0x78, Bit --> 0 to 7 */ +#define SMI130_USER_STEP_COUNT_LSB__POS (0) +#define SMI130_USER_STEP_COUNT_LSB__LEN (7) +#define SMI130_USER_STEP_COUNT_LSB__MSK (0xFF) +#define SMI130_USER_STEP_COUNT_LSB__REG (SMI130_USER_STEP_COUNT_0_ADDR) + +/* STEP_CNT_1 Description - Reg Addr --> 0x79, Bit --> 0 to 7 */ +#define SMI130_USER_STEP_COUNT_MSB__POS (0) +#define SMI130_USER_STEP_COUNT_MSB__LEN (7) +#define SMI130_USER_STEP_COUNT_MSB__MSK (0xFF) +#define SMI130_USER_STEP_COUNT_MSB__REG (SMI130_USER_STEP_COUNT_1_ADDR) +/**************************************************************/ +/**\name STEP COUNTER CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* STEP_CONFIG_0 Description - Reg Addr --> 0x7A, Bit --> 0 to 7 */ +#define SMI130_USER_STEP_CONFIG_ZERO__POS (0) +#define SMI130_USER_STEP_CONFIG_ZERO__LEN (7) +#define SMI130_USER_STEP_CONFIG_ZERO__MSK (0xFF) +#define SMI130_USER_STEP_CONFIG_ZERO__REG \ +(SMI130_USER_STEP_CONFIG_0_ADDR) + + +/* STEP_CONFIG_1 Description - Reg Addr --> 0x7B, Bit --> 0 to 2 and +4 to 7 */ +#define SMI130_USER_STEP_CONFIG_ONE_CNF1__POS (0) +#define SMI130_USER_STEP_CONFIG_ONE_CNF1__LEN (3) +#define SMI130_USER_STEP_CONFIG_ONE_CNF1__MSK (0x07) +#define SMI130_USER_STEP_CONFIG_ONE_CNF1__REG \ +(SMI130_USER_STEP_CONFIG_1_ADDR) + +#define SMI130_USER_STEP_CONFIG_ONE_CNF2__POS (4) +#define SMI130_USER_STEP_CONFIG_ONE_CNF2__LEN (4) +#define SMI130_USER_STEP_CONFIG_ONE_CNF2__MSK (0xF0) +#define SMI130_USER_STEP_CONFIG_ONE_CNF2__REG \ +(SMI130_USER_STEP_CONFIG_1_ADDR) +/**************************************************************/ +/**\name STEP COUNTER ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* STEP_CONFIG_1 Description - Reg Addr --> 0x7B, Bit --> 0 to 2 */ +#define SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__POS (3) +#define SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__LEN (1) +#define SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__MSK (0x08) +#define SMI130_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG \ +(SMI130_USER_STEP_CONFIG_1_ADDR) + +/* USER REGISTERS DEFINITION END */ +/**************************************************************************/ +/* CMD REGISTERS DEFINITION START */ +/**************************************************************/ +/**\name COMMAND REGISTER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Command description address - Reg Addr --> 0x7E, Bit --> 0....7 */ +#define SMI130_CMD_COMMANDS__POS (0) +#define SMI130_CMD_COMMANDS__LEN (8) +#define SMI130_CMD_COMMANDS__MSK (0xFF) +#define SMI130_CMD_COMMANDS__REG (SMI130_CMD_COMMANDS_ADDR) +/**************************************************************/ +/**\name PAGE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Target page address - Reg Addr --> 0x7F, Bit --> 4....5 */ +#define SMI130_CMD_TARGET_PAGE__POS (4) +#define SMI130_CMD_TARGET_PAGE__LEN (2) +#define SMI130_CMD_TARGET_PAGE__MSK (0x30) +#define SMI130_CMD_TARGET_PAGE__REG (SMI130_CMD_EXT_MODE_ADDR) + +/* Target page address - Reg Addr --> 0x7F, Bit --> 4....5 */ +#define SMI130_CMD_PAGING_EN__POS (7) +#define SMI130_CMD_PAGING_EN__LEN (1) +#define SMI130_CMD_PAGING_EN__MSK (0x80) +#define SMI130_CMD_PAGING_EN__REG (SMI130_CMD_EXT_MODE_ADDR) + +/* Target page address - Reg Addr --> 0x7F, Bit --> 4....5 */ +#define SMI130_COM_C_TRIM_FIVE__POS (0) +#define SMI130_COM_C_TRIM_FIVE__LEN (8) +#define SMI130_COM_C_TRIM_FIVE__MSK (0xFF) +#define SMI130_COM_C_TRIM_FIVE__REG (SMI130_COM_C_TRIM_FIVE_ADDR) + +/**************************************************************************/ +/* CMD REGISTERS DEFINITION END */ + +/**************************************************/ +/**\name FIFO FRAME COUNT DEFINITION */ +/*************************************************/ +#define FIFO_FRAME (1024) +#define FIFO_CONFIG_CHECK1 (0x00) +#define FIFO_CONFIG_CHECK2 (0x80) +/**************************************************/ +/**\name MAG SENSOR SELECT */ +/*************************************************/ +#define BST_BMM (0) +#define BST_AKM (1) +#define SMI130_YAS537_I2C_ADDRESS (0x2E) +/**************************************************/ +/**\name ACCEL RANGE */ +/*************************************************/ +#define SMI130_ACCEL_RANGE_2G (0X03) +#define SMI130_ACCEL_RANGE_4G (0X05) +#define SMI130_ACCEL_RANGE_8G (0X08) +#define SMI130_ACCEL_RANGE_16G (0X0C) +/**************************************************/ +/**\name ACCEL ODR */ +/*************************************************/ +#define SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED (0x00) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_0_78HZ (0x01) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_1_56HZ (0x02) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_3_12HZ (0x03) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_6_25HZ (0x04) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_12_5HZ (0x05) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_25HZ (0x06) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_50HZ (0x07) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_100HZ (0x08) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_200HZ (0x09) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_400HZ (0x0A) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_800HZ (0x0B) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_1600HZ (0x0C) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED0 (0x0D) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED1 (0x0E) +#define SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED2 (0x0F) +/**************************************************/ +/**\name ACCEL BANDWIDTH PARAMETER */ +/*************************************************/ +#define SMI130_ACCEL_OSR4_AVG1 (0x00) +#define SMI130_ACCEL_OSR2_AVG2 (0x01) +#define SMI130_ACCEL_NORMAL_AVG4 (0x02) +#define SMI130_ACCEL_CIC_AVG8 (0x03) +#define SMI130_ACCEL_RES_AVG16 (0x04) +#define SMI130_ACCEL_RES_AVG32 (0x05) +#define SMI130_ACCEL_RES_AVG64 (0x06) +#define SMI130_ACCEL_RES_AVG128 (0x07) +/**************************************************/ +/**\name GYRO ODR */ +/*************************************************/ +#define SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED (0x00) +#define SMI130_GYRO_OUTPUT_DATA_RATE_25HZ (0x06) +#define SMI130_GYRO_OUTPUT_DATA_RATE_50HZ (0x07) +#define SMI130_GYRO_OUTPUT_DATA_RATE_100HZ (0x08) +#define SMI130_GYRO_OUTPUT_DATA_RATE_200HZ (0x09) +#define SMI130_GYRO_OUTPUT_DATA_RATE_400HZ (0x0A) +#define SMI130_GYRO_OUTPUT_DATA_RATE_800HZ (0x0B) +#define SMI130_GYRO_OUTPUT_DATA_RATE_1600HZ (0x0C) +#define SMI130_GYRO_OUTPUT_DATA_RATE_3200HZ (0x0D) +/**************************************************/ +/**\name GYRO BANDWIDTH PARAMETER */ +/*************************************************/ +#define SMI130_GYRO_OSR4_MODE (0x00) +#define SMI130_GYRO_OSR2_MODE (0x01) +#define SMI130_GYRO_NORMAL_MODE (0x02) +#define SMI130_GYRO_CIC_MODE (0x03) +/**************************************************/ +/**\name GYROSCOPE RANGE PARAMETER */ +/*************************************************/ +#define SMI130_GYRO_RANGE_2000_DEG_SEC (0x00) +#define SMI130_GYRO_RANGE_1000_DEG_SEC (0x01) +#define SMI130_GYRO_RANGE_500_DEG_SEC (0x02) +#define SMI130_GYRO_RANGE_250_DEG_SEC (0x03) +#define SMI130_GYRO_RANGE_125_DEG_SEC (0x04) +/**************************************************/ +/**\name MAG ODR */ +/*************************************************/ +#define SMI130_MAG_OUTPUT_DATA_RATE_RESERVED (0x00) +#define SMI130_MAG_OUTPUT_DATA_RATE_0_78HZ (0x01) +#define SMI130_MAG_OUTPUT_DATA_RATE_1_56HZ (0x02) +#define SMI130_MAG_OUTPUT_DATA_RATE_3_12HZ (0x03) +#define SMI130_MAG_OUTPUT_DATA_RATE_6_25HZ (0x04) +#define SMI130_MAG_OUTPUT_DATA_RATE_12_5HZ (0x05) +#define SMI130_MAG_OUTPUT_DATA_RATE_25HZ (0x06) +#define SMI130_MAG_OUTPUT_DATA_RATE_50HZ (0x07) +#define SMI130_MAG_OUTPUT_DATA_RATE_100HZ (0x08) +#define SMI130_MAG_OUTPUT_DATA_RATE_200HZ (0x09) +#define SMI130_MAG_OUTPUT_DATA_RATE_400HZ (0x0A) +#define SMI130_MAG_OUTPUT_DATA_RATE_800HZ (0x0B) +#define SMI130_MAG_OUTPUT_DATA_RATE_1600HZ (0x0C) +#define SMI130_MAG_OUTPUT_DATA_RATE_RESERVED0 (0x0D) +#define SMI130_MAG_OUTPUT_DATA_RATE_RESERVED1 (0x0E) +#define SMI130_MAG_OUTPUT_DATA_RATE_RESERVED2 (0x0F) + +/**************************************************/ +/**\name ENABLE/DISABLE SELECTIONS */ +/*************************************************/ + +/* Enable accel and gyro offset */ +#define ACCEL_OFFSET_ENABLE (0x01) +#define GYRO_OFFSET_ENABLE (0x01) + +/* command register definition */ +#define START_FOC_ACCEL_GYRO (0X03) + + /* INT ENABLE 1 */ +#define SMI130_ANY_MOTION_X_ENABLE (0) +#define SMI130_ANY_MOTION_Y_ENABLE (1) +#define SMI130_ANY_MOTION_Z_ENABLE (2) +#define SMI130_DOUBLE_TAP_ENABLE (4) +#define SMI130_SINGLE_TAP_ENABLE (5) +#define SMI130_ORIENT_ENABLE (6) +#define SMI130_FLAT_ENABLE (7) + +/* INT ENABLE 1 */ +#define SMI130_HIGH_G_X_ENABLE (0) +#define SMI130_HIGH_G_Y_ENABLE (1) +#define SMI130_HIGH_G_Z_ENABLE (2) +#define SMI130_LOW_G_ENABLE (3) +#define SMI130_DATA_RDY_ENABLE (4) +#define SMI130_FIFO_FULL_ENABLE (5) +#define SMI130_FIFO_WM_ENABLE (6) + +/* INT ENABLE 2 */ +#define SMI130_NOMOTION_X_ENABLE (0) +#define SMI130_NOMOTION_Y_ENABLE (1) +#define SMI130_NOMOTION_Z_ENABLE (2) +#define SMI130_STEP_DETECTOR_EN (3) + +/* FOC axis selection for accel*/ +#define FOC_X_AXIS (0) +#define FOC_Y_AXIS (1) +#define FOC_Z_AXIS (2) + +/* IN OUT CONTROL */ +#define SMI130_INTR1_EDGE_CTRL (0) +#define SMI130_INTR2_EDGE_CTRL (1) +#define SMI130_INTR1_LEVEL (0) +#define SMI130_INTR2_LEVEL (1) +#define SMI130_INTR1_OUTPUT_TYPE (0) +#define SMI130_INTR2_OUTPUT_TYPE (1) +#define SMI130_INTR1_OUTPUT_ENABLE (0) +#define SMI130_INTR2_OUTPUT_ENABLE (1) + +#define SMI130_INTR1_INPUT_ENABLE (0) +#define SMI130_INTR2_INPUT_ENABLE (1) + +/* INTERRUPT MAPS */ +#define SMI130_INTR1_MAP_LOW_G (0) +#define SMI130_INTR2_MAP_LOW_G (1) +#define SMI130_INTR1_MAP_HIGH_G (0) +#define SMI130_INTR2_MAP_HIGH_G (1) +#define SMI130_INTR1_MAP_ANY_MOTION (0) +#define SMI130_INTR2_MAP_ANY_MOTION (1) +#define SMI130_INTR1_MAP_NOMO (0) +#define SMI130_INTR2_MAP_NOMO (1) +#define SMI130_INTR1_MAP_DOUBLE_TAP (0) +#define SMI130_INTR2_MAP_DOUBLE_TAP (1) +#define SMI130_INTR1_MAP_SINGLE_TAP (0) +#define SMI130_INTR2_MAP_SINGLE_TAP (1) +#define SMI130_INTR1_MAP_ORIENT (0) +#define SMI130_INTR2_MAP_ORIENT (1) +#define SMI130_INTR1_MAP_FLAT (0) +#define SMI130_INTR2_MAP_FLAT (1) +#define SMI130_INTR1_MAP_DATA_RDY (0) +#define SMI130_INTR2_MAP_DATA_RDY (1) +#define SMI130_INTR1_MAP_FIFO_WM (0) +#define SMI130_INTR2_MAP_FIFO_WM (1) +#define SMI130_INTR1_MAP_FIFO_FULL (0) +#define SMI130_INTR2_MAP_FIFO_FULL (1) +#define SMI130_INTR1_MAP_PMUTRIG (0) +#define SMI130_INTR2_MAP_PMUTRIG (1) + +/* Interrupt mapping*/ +#define SMI130_MAP_INTR1 (0) +#define SMI130_MAP_INTR2 (1) +/**************************************************/ +/**\name TAP DURATION */ +/*************************************************/ +#define SMI130_TAP_DURN_50MS (0x00) +#define SMI130_TAP_DURN_100MS (0x01) +#define SMI130_TAP_DURN_150MS (0x02) +#define SMI130_TAP_DURN_200MS (0x03) +#define SMI130_TAP_DURN_250MS (0x04) +#define SMI130_TAP_DURN_375MS (0x05) +#define SMI130_TAP_DURN_500MS (0x06) +#define SMI130_TAP_DURN_700MS (0x07) +/**************************************************/ +/**\name TAP SHOCK */ +/*************************************************/ +#define SMI130_TAP_SHOCK_50MS (0x00) +#define SMI130_TAP_SHOCK_75MS (0x01) +/**************************************************/ +/**\name TAP QUIET */ +/*************************************************/ +#define SMI130_TAP_QUIET_30MS (0x00) +#define SMI130_TAP_QUIET_20MS (0x01) +/**************************************************/ +/**\name STEP DETECTION SELECTION MODES */ +/*************************************************/ +#define SMI130_STEP_NORMAL_MODE (0) +#define SMI130_STEP_SENSITIVE_MODE (1) +#define SMI130_STEP_ROBUST_MODE (2) +/**************************************************/ +/**\name STEP CONFIGURATION SELECT MODE */ +/*************************************************/ +#define STEP_CONFIG_NORMAL (0X315) +#define STEP_CONFIG_SENSITIVE (0X2D) +#define STEP_CONFIG_ROBUST (0X71D) +/**************************************************/ +/**\name BMM150 TRIM DATA DEFINITIONS */ +/*************************************************/ +#define SMI130_MAG_DIG_X1 (0x5D) +#define SMI130_MAG_DIG_Y1 (0x5E) +#define SMI130_MAG_DIG_Z4_LSB (0x62) +#define SMI130_MAG_DIG_Z4_MSB (0x63) +#define SMI130_MAG_DIG_X2 (0x64) +#define SMI130_MAG_DIG_Y2 (0x65) +#define SMI130_MAG_DIG_Z2_LSB (0x68) +#define SMI130_MAG_DIG_Z2_MSB (0x69) +#define SMI130_MAG_DIG_Z1_LSB (0x6A) +#define SMI130_MAG_DIG_Z1_MSB (0x6B) +#define SMI130_MAG_DIG_XYZ1_LSB (0x6C) +#define SMI130_MAG_DIG_XYZ1_MSB (0x6D) +#define SMI130_MAG_DIG_Z3_LSB (0x6E) +#define SMI130_MAG_DIG_Z3_MSB (0x6F) +#define SMI130_MAG_DIG_XY2 (0x70) +#define SMI130_MAG_DIG_XY1 (0x71) +/**************************************************/ +/**\name BMM150 PRE-SET MODE DEFINITIONS */ +/*************************************************/ +#define SMI130_MAG_PRESETMODE_LOWPOWER (1) +#define SMI130_MAG_PRESETMODE_REGULAR (2) +#define SMI130_MAG_PRESETMODE_HIGHACCURACY (3) +#define SMI130_MAG_PRESETMODE_ENHANCED (4) +/**************************************************/ +/**\name BMM150 PRESET MODES - DATA RATES */ +/*************************************************/ +#define SMI130_MAG_LOWPOWER_DR (0x02) +#define SMI130_MAG_REGULAR_DR (0x02) +#define SMI130_MAG_HIGHACCURACY_DR (0x2A) +#define SMI130_MAG_ENHANCED_DR (0x02) +/**************************************************/ +/**\name BMM150 PRESET MODES - REPETITIONS-XY RATES */ +/*************************************************/ +#define SMI130_MAG_LOWPOWER_REPXY (1) +#define SMI130_MAG_REGULAR_REPXY (4) +#define SMI130_MAG_HIGHACCURACY_REPXY (23) +#define SMI130_MAG_ENHANCED_REPXY (7) +/**************************************************/ +/**\name BMM150 PRESET MODES - REPETITIONS-Z RATES */ +/*************************************************/ +#define SMI130_MAG_LOWPOWER_REPZ (2) +#define SMI130_MAG_REGULAR_REPZ (14) +#define SMI130_MAG_HIGHACCURACY_REPZ (82) +#define SMI130_MAG_ENHANCED_REPZ (26) +#define SMI130_MAG_NOAMRL_SWITCH_TIMES (5) +#define MAG_INTERFACE_PMU_ENABLE (1) +#define MAG_INTERFACE_PMU_DISABLE (0) +/**************************************************/ +/**\name USED FOR MAG OVERFLOW CHECK FOR BMM150 */ +/*************************************************/ +#define SMI130_MAG_OVERFLOW_OUTPUT ((s16)-32768) +#define SMI130_MAG_OVERFLOW_OUTPUT_S32 ((s32)(-2147483647-1)) +#define SMI130_MAG_NEGATIVE_SATURATION_Z ((s16)-32767) +#define SMI130_MAG_POSITIVE_SATURATION_Z ((u16)32767) +#define SMI130_MAG_FLIP_OVERFLOW_ADCVAL ((s16)-4096) +#define SMI130_MAG_HALL_OVERFLOW_ADCVAL ((s16)-16384) +/**************************************************/ +/**\name BMM150 REGISTER DEFINITION */ +/*************************************************/ +#define SMI130_BMM150_CHIP_ID (0x40) +#define SMI130_BMM150_POWE_CONTROL_REG (0x4B) +#define SMI130_BMM150_POWE_MODE_REG (0x4C) +#define SMI130_BMM150_DATA_REG (0x42) +#define SMI130_BMM150_XY_REP (0x51) +#define SMI130_BMM150_Z_REP (0x52) +/**************************************************/ +/**\name AKM COMPENSATING DATA REGISTERS */ +/*************************************************/ +#define SMI130_BST_AKM_ASAX (0x60) +#define SMI130_BST_AKM_ASAY (0x61) +#define SMI130_BST_AKM_ASAZ (0x62) +/**************************************************/ +/**\name AKM POWER MODE SELECTION */ +/*************************************************/ +#define AKM_POWER_DOWN_MODE (0) +#define AKM_SINGLE_MEAS_MODE (1) +#define FUSE_ROM_MODE (2) +/**************************************************/ +/**\name SECONDARY_MAG POWER MODE SELECTION */ +/*************************************************/ +#define SMI130_MAG_FORCE_MODE (0) +#define SMI130_MAG_SUSPEND_MODE (1) +/**************************************************/ +/**\name MAG POWER MODE SELECTION */ +/*************************************************/ +#define FORCE_MODE (0) +#define SUSPEND_MODE (1) +#define NORMAL_MODE (2) +#define MAG_SUSPEND_MODE (1) +/**************************************************/ +/**\name FIFO CONFIGURATIONS */ +/*************************************************/ +#define FIFO_HEADER_ENABLE (0x01) +#define FIFO_MAG_ENABLE (0x01) +#define FIFO_ACCEL_ENABLE (0x01) +#define FIFO_GYRO_ENABLE (0x01) +#define FIFO_TIME_ENABLE (0x01) +#define FIFO_STOPONFULL_ENABLE (0x01) +#define FIFO_WM_INTERRUPT_ENABLE (0x01) +#define SMI130_FIFO_INDEX_LENGTH (1) +#define SMI130_FIFO_TAG_INTR_MASK (0xFC) + +/**************************************************/ +/**\name ACCEL POWER MODE */ +/*************************************************/ +#define ACCEL_MODE_NORMAL (0x11) +#define ACCEL_LOWPOWER (0X12) +#define ACCEL_SUSPEND (0X10) +/**************************************************/ +/**\name GYRO POWER MODE */ +/*************************************************/ +#define GYRO_MODE_SUSPEND (0x14) +#define GYRO_MODE_NORMAL (0x15) +#define GYRO_MODE_FASTSTARTUP (0x17) +/**************************************************/ +/**\name MAG POWER MODE */ +/*************************************************/ +#define MAG_MODE_SUSPEND (0x18) +#define MAG_MODE_NORMAL (0x19) +#define MAG_MODE_LOWPOWER (0x1A) +/**************************************************/ +/**\name ENABLE/DISABLE BIT VALUES */ +/*************************************************/ +#define SMI130_ENABLE (0x01) +#define SMI130_DISABLE (0x00) +/**************************************************/ +/**\name INTERRUPT EDGE TRIGGER ENABLE */ +/*************************************************/ +#define SMI130_EDGE (0x01) +#define SMI130_LEVEL (0x00) +/**************************************************/ +/**\name INTERRUPT LEVEL ENABLE */ +/*************************************************/ +#define SMI130_LEVEL_LOW (0x00) +#define SMI130_LEVEL_HIGH (0x01) +/**************************************************/ +/**\name INTERRUPT OUTPUT ENABLE */ +/*************************************************/ +#define SMI130_OPEN_DRAIN (0x01) +#define SMI130_PUSH_PULL (0x00) + +/* interrupt output enable*/ +#define SMI130_INPUT (0x01) +#define SMI130_OUTPUT (0x00) + +/**************************************************/ +/**\name INTERRUPT TAP SOURCE ENABLE */ +/*************************************************/ +#define FILTER_DATA (0x00) +#define UNFILTER_DATA (0x01) +/**************************************************/ +/**\name SLOW MOTION/ NO MOTION SELECT */ +/*************************************************/ +#define SLOW_MOTION (0x00) +#define NO_MOTION (0x01) +/**************************************************/ +/**\name SIGNIFICANT MOTION SELECTION */ +/*************************************************/ +#define ANY_MOTION (0x00) +#define SIGNIFICANT_MOTION (0x01) +/**************************************************/ +/**\name LATCH DURATION */ +/*************************************************/ +#define SMI130_LATCH_DUR_NONE (0x00) +#define SMI130_LATCH_DUR_312_5_MICRO_SEC (0x01) +#define SMI130_LATCH_DUR_625_MICRO_SEC (0x02) +#define SMI130_LATCH_DUR_1_25_MILLI_SEC (0x03) +#define SMI130_LATCH_DUR_2_5_MILLI_SEC (0x04) +#define SMI130_LATCH_DUR_5_MILLI_SEC (0x05) +#define SMI130_LATCH_DUR_10_MILLI_SEC (0x06) +#define SMI130_LATCH_DUR_20_MILLI_SEC (0x07) +#define SMI130_LATCH_DUR_40_MILLI_SEC (0x08) +#define SMI130_LATCH_DUR_80_MILLI_SEC (0x09) +#define SMI130_LATCH_DUR_160_MILLI_SEC (0x0A) +#define SMI130_LATCH_DUR_320_MILLI_SEC (0x0B) +#define SMI130_LATCH_DUR_640_MILLI_SEC (0x0C) +#define SMI130_LATCH_DUR_1_28_SEC (0x0D) +#define SMI130_LATCH_DUR_2_56_SEC (0x0E) +#define SMI130_LATCHED (0x0F) +/**************************************************/ +/**\name GYRO OFFSET MASK DEFINITION */ +/*************************************************/ +#define SMI130_GYRO_MANUAL_OFFSET_0_7 (0x00FF) +#define SMI130_GYRO_MANUAL_OFFSET_8_9 (0x0300) +/**************************************************/ +/**\name STEP CONFIGURATION MASK DEFINITION */ +/*************************************************/ +#define SMI130_STEP_CONFIG_0_7 (0x00FF) +#define SMI130_STEP_CONFIG_8_10 (0x0700) +#define SMI130_STEP_CONFIG_11_14 (0xF000) +/**************************************************/ +/**\name DEFINITION USED FOR DIFFERENT WRITE */ +/*************************************************/ +#define SMI130_WRITE_TARGET_PAGE0 (0x00) +#define SMI130_WRITE_TARGET_PAGE1 (0x01) +#define SMI130_WRITE_ENABLE_PAGE1 (0x01) +#define SMI130_MANUAL_DISABLE (0x00) +#define SMI130_MANUAL_ENABLE (0x01) +#define SMI130_YAS_DISABLE_RCOIL (0x00) +#define SMI130_ENABLE_MAG_IF_MODE (0x02) +#define SMI130_ENABLE_ANY_MOTION_INTR1 (0x04) +#define SMI130_ENABLE_ANY_MOTION_INTR2 (0x04) +#define SMI130_MAG_DATA_READ_REG (0x04) +#define SMI130_BMM_POWER_MODE_REG (0x06) +#define SMI130_ENABLE_ANY_MOTION_AXIS (0x07) +#define SMI130_ENABLE_LOW_G (0x08) +#define SMI130_YAS532_ACQ_START (0x11) +#define SMI130_YAS_DEVICE_ID_REG (0x80) +#define SMI130_FIFO_GYRO_ENABLE (0x80) +#define SMI130_SIG_MOTION_INTR_ENABLE (0x01) +#define SMI130_STEP_DETECT_INTR_ENABLE (0x01) +#define SMI130_LOW_G_INTR_STAT (0x01) +#define SMI130_PULL_UP_DATA (0x30) +#define SMI130_FIFO_M_G_A_ENABLE (0xE0) +#define SMI130_FIFO_M_G_ENABLE (0xA0) +#define SMI130_FIFO_M_A_ENABLE (0x60) +#define SMI130_FIFO_G_A_ENABLE (0xC0) +#define SMI130_FIFO_A_ENABLE (0x40) +#define SMI130_FIFO_M_ENABLE (0x20) +/**************************************************/ +/**\name MAG INIT DEFINITION */ +/*************************************************/ +#define SMI130_COMMAND_REG_ONE (0x37) +#define SMI130_COMMAND_REG_TWO (0x9A) +#define SMI130_COMMAND_REG_THREE (0xC0) +#define RESET_STEP_COUNTER (0xB2) +/**************************************************/ +/**\name BIT SLICE GET AND SET FUNCTIONS */ +/*************************************************/ +#define SMI130_GET_BITSLICE(regvar, bitname)\ + ((regvar & bitname##__MSK) >> bitname##__POS) + + +#define SMI130_SET_BITSLICE(regvar, bitname, val)\ + ((regvar & ~bitname##__MSK) | \ + ((val< Success + * @retval -1 -> Error + * + * @note + * While changing the parameter of the smi130_t + * consider the following point: + * Changing the reference value of the parameter + * will changes the local copy or local reference + * make sure your changes will not + * affect the reference value of the parameter + * (Better case don't change the reference value of the parameter) + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_init(struct smi130_t *smi130); +/**************************************************/ +/**\name FUNCTION FOR READ AND WRITE REGISTERS */ +/*************************************************/ +/*! + * @brief + * This API write the data to + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_write_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8); +/*! + * @brief + * This API reads the data from + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_read_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8); +/**************************************************/ +/**\name FUNCTION FOR ERROR CODES */ +/*************************************************/ +/*! + * @brief This API used to reads the fatal error + * from the Register 0x02 bit 0 + * This flag will be reset only by power-on-reset and soft reset + * + * + * @param v_fatal_err_u8 : The status of fatal error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fatal_err(u8 +*v_fatal_err_u8); +/*! + * @brief This API used to read the error code + * from register 0x02 bit 1 to 4 + * + * + * @param v_err_code_u8 : The status of error codes + * error_code | description + * ------------|--------------- + * 0x00 |no error + * 0x01 |ACC_CONF error (accel ODR and bandwidth not compatible) + * 0x02 |GYR_CONF error (Gyroscope ODR and bandwidth not compatible) + * 0x03 |Under sampling mode and interrupt uses pre filtered data + * 0x04 |reserved + * 0x05 |Selected trigger-readout offset in + * - |MAG_IF greater than selected ODR + * 0x06 |FIFO configuration error for header less mode + * 0x07 |Under sampling mode and pre filtered data as FIFO source + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_err_code(u8 +*v_error_code_u8); +/*! + * @brief This API Reads the i2c error code from the + * Register 0x02 bit 5. + * This error occurred in I2C master detected + * + * @param v_i2c_err_code_u8 : The status of i2c fail error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_fail_err(u8 +*v_i2c_error_code_u8); + /*! + * @brief This API Reads the dropped command error + * from the register 0x02 bit 6 + * + * + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_drop_cmd_err(u8 +*v_drop_cmd_err_u8); +/*! + * @brief This API reads the magnetometer data ready + * interrupt not active. + * It reads from the error register 0x0x2 bit 7 + * + * + * + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_dada_rdy_err(u8 +*v_mag_data_rdy_err_u8); +/*! + * @brief This API reads the error status + * from the error register 0x02 bit 0 to 7 + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * @param v_fatal_er_u8r : The status of fatal error + * @param v_err_code_u8 : The status of error code + * @param v_i2c_fail_err_u8 : The status of I2C fail error + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_error_status(u8 *v_fatal_er_u8r, +u8 *v_err_code_u8, u8 *v_i2c_fail_err_u8, +u8 *v_drop_cmd_err_u8, u8 *v_mag_data_rdy_err_u8); +/******************************************************************/ +/**\name FUNCTIONS FOR MAG,ACCEL AND GYRO POWER MODE STATUS */ +/*****************************************************************/ +/*! + * @brief This API reads the magnetometer power mode from + * PMU status register 0x03 bit 0 and 1 + * + * @param v_mag_power_mode_stat_u8 : The value of mag power mode + * mag_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x02 + * + * + * @note The power mode of mag set by the 0x7E command register + * @note using the function "smi130_set_command_register()" + * value | mode + * ---------|---------------- + * 0x18 | MAG_MODE_SUSPEND + * 0x19 | MAG_MODE_NORMAL + * 0x1A | MAG_MODE_LOWPOWER + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_power_mode_stat(u8 +*v_mag_power_mode_stat_u8); +/*! + * @brief This API reads the gyroscope power mode from + * PMU status register 0x03 bit 2 and 3 + * + * @param v_gyro_power_mode_stat_u8 : The value of gyro power mode + * gyro_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * FAST POWER UP | 0x03 + * + * @note The power mode of gyro set by the 0x7E command register + * @note using the function "smi130_set_command_register()" + * value | mode + * ---------|---------------- + * 0x14 | GYRO_MODE_SUSPEND + * 0x15 | GYRO_MODE_NORMAL + * 0x17 | GYRO_MODE_FASTSTARTUP + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_power_mode_stat(u8 +*v_gyro_power_mode_stat_u8); +/*! + * @brief This API reads the accelerometer power mode from + * PMU status register 0x03 bit 4 and 5 + * + * + * @param v_accel_power_mode_stat_u8 : The value of accel power mode + * accel_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x03 + * + * @note The power mode of accel set by the 0x7E command register + * @note using the function "smi130_set_command_register()" + * value | mode + * ---------|---------------- + * 0x11 | ACCEL_MODE_NORMAL + * 0x12 | ACCEL_LOWPOWER + * 0x10 | ACCEL_SUSPEND + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_power_mode_stat(u8 +*v_accel_power_mode_stat_u8); +/*! + * @brief This API switch mag interface to normal mode + * and confirm whether the mode switching done successfully or not +* + * @return results of bus communication function and current MAG_PMU result + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_interface_normal(void); +/**************************************************/ +/**\name FUNCTION FOR Mag XYZ data read */ +/*************************************************/ +/*! + * @brief This API reads magnetometer data X values + * from the register 0x04 and 0x05 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_x_s16 : The value of mag x + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_x(s16 *v_mag_x_s16, +u8 v_sensor_select_u8); +/*! + * @brief This API reads magnetometer data Y values + * from the register 0x06 and 0x07 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_y_s16 : The value of mag y + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_y(s16 *v_mag_y_s16, +u8 v_sensor_select_u8); +/*! + * @brief This API reads magnetometer data Z values + * from the register 0x08 and 0x09 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_z_s16 : The value of mag z + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_z(s16 *v_mag_z_s16, +u8 v_sensor_select_u8); +/*! + * @brief This API reads magnetometer data RHALL values + * from the register 0x0A and 0x0B + * + * + * @param v_mag_r_s16 : The value of BMM150 r data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_r( +s16 *v_mag_r_s16); +/*! + * @brief This API reads magnetometer data X,Y,Z values + * from the register 0x04 to 0x09 + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag xyz data + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_xyz( +struct smi130_mag_t *mag, u8 v_sensor_select_u8); + /*!* + * @brief This API reads magnetometer data X,Y,Z,r + * values from the register 0x04 to 0x0B + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag-BMM150 xyzr data + * + * @note For mag data output rate configuration use the following function + * @note smi130_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_mag_xyzr( +struct smi130_mag_xyzr_t *mag); +/**************************************************/ +/**\name FUNCTION FOR GYRO XYZ DATA READ */ +/*************************************************/ +/*! + * @brief This API reads gyro data X values + * form the register 0x0C and 0x0D + * + * + * + * + * @param v_gyro_x_s16 : The value of gyro x data + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_x( +s16 *v_gyro_x_s16); +/*! + * @brief This API reads gyro data Y values + * form the register 0x0E and 0x0F + * + * + * + * + * @param v_gyro_y_s16 : The value of gyro y data + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error result of communication routines + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_y( +s16 *v_gyro_y_s16); +/*! + * @brief This API reads gyro data Z values + * form the register 0x10 and 0x11 + * + * + * + * + * @param v_gyro_z_s16 : The value of gyro z data + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_z( +s16 *v_gyro_z_s16); +/*! + * @brief This API reads gyro data X,Y,Z values + * from the register 0x0C to 0x11 + * + * + * + * + * @param gyro : The value of gyro xyz + * + * @note Gyro Configuration use the following function + * @note smi130_set_gyro_output_data_rate() + * @note smi130_set_gyro_bw() + * @note smi130_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_gyro_xyz( +struct smi130_gyro_t *gyro); +/**************************************************/ +/**\name FUNCTION FOR ACCEL XYZ DATA READ */ +/*************************************************/ +/*! + * @brief This API reads accelerometer data X values + * form the register 0x12 and 0x13 + * + * + * + * + * @param v_accel_x_s16 : The value of accel x + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_x( +s16 *v_accel_x_s16); +/*! + * @brief This API reads accelerometer data Y values + * form the register 0x14 and 0x15 + * + * + * + * + * @param v_accel_y_s16 : The value of accel y + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_y( +s16 *v_accel_y_s16); +/*! + * @brief This API reads accelerometer data Z values + * form the register 0x16 and 0x17 + * + * + * + * + * @param v_accel_z_s16 : The value of accel z + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_z( +s16 *v_accel_z_s16); +/*! + * @brief This API reads accelerometer data X,Y,Z values + * from the register 0x12 to 0x17 + * + * + * + * + * @param accel :The value of accel xyz + * + * @note For accel configuration use the following functions + * @note smi130_set_accel_output_data_rate() + * @note smi130_set_accel_bw() + * @note smi130_set_accel_under_sampling_parameter() + * @note smi130_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_accel_xyz( +struct smi130_accel_t *accel); +/**************************************************/ +/**\name FUNCTION FOR SENSOR TIME */ +/*************************************************/ +/*! + * @brief This API reads sensor_time from the register + * 0x18 to 0x1A + * + * + * @param v_sensor_time_u32 : The value of sensor time + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_sensor_time( +u32 *v_sensor_time_u32); +/**************************************************/ +/**\name FUNCTION FOR GYRO SLEF TEST */ +/*************************************************/ +/*! + * @brief This API reads the Gyroscope self test + * status from the register 0x1B bit 1 + * + * + * @param v_gyro_selftest_u8 : The value of gyro self test status + * value | status + * ---------|---------------- + * 0 | Gyroscope self test is running or failed + * 1 | Gyroscope self test completed successfully + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_selftest(u8 +*v_gyro_selftest_u8); +/**************************************************/ +/**\name FUNCTION FOR MANUAL INTERFACE */ +/*************************************************/ +/*! + * @brief This API reads the status of + * mag manual interface operation form the register 0x1B bit 2 + * + * + * + * @param v_mag_manual_stat_u8 : The value of mag manual operation status + * value | status + * ---------|---------------- + * 0 | Indicates no manual magnetometer + * - | interface operation is ongoing + * 1 | Indicates manual magnetometer + * - | interface operation is ongoing + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_manual_operation_stat(u8 +*v_mag_manual_stat_u8); +/**************************************************/ +/**\name FUNCTION FOR FAST OFFSET READY */ +/*************************************************/ +/*! + * @brief This API reads the fast offset compensation + * status form the register 0x1B bit 3 + * + * + * @param v_foc_rdy_u8 : The status of fast compensation + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_rdy(u8 +*v_foc_rdy_u8); +/**************************************************/ +/**\name FUNCTION FOR NVM READY */ +/*************************************************/ +/*! + * @brief This API Reads the nvm_rdy status from the + * resister 0x1B bit 4 + * + * + * @param v_nvm_rdy_u8 : The value of NVM ready status + * value | status + * ---------|---------------- + * 0 | NVM write operation in progress + * 1 | NVM is ready to accept a new write trigger + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_nvm_rdy(u8 +*v_nvm_rdy_u8); +/**************************************************/ +/**\name FUNCTION FOR DATA READY FOR MAG, GYRO, AND ACCEL */ +/*************************************************/ +/*! + * @brief This API reads the status of mag data ready + * from the register 0x1B bit 5 + * The status get reset when one mag data register is read out + * + * @param v_data_rdy_u8 : The value of mag data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_data_rdy_mag(u8 +*v_data_rdy_u8); +/*! + * @brief This API reads the status of gyro data ready form the + * register 0x1B bit 6 + * The status get reset when gyro data register read out + * + * + * @param v_data_rdy_u8 : The value of gyro data ready + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_data_rdy(u8 +*v_data_rdy_u8); +/*! + * @brief This API reads the status of accel data ready form the + * register 0x1B bit 7 + * The status get reset when accel data register read out + * + * + * @param v_data_rdy_u8 : The value of accel data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_data_rdy(u8 +*drdy_acc); +/**************************************************/ +/**\name FUNCTION FOR STEP INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the step detector interrupt status + * from the register 0x1C bit 0 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_step_intr_u8 : The status of step detector interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_step_intr(u8 +*v_step_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR SIGNIFICANT INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the + * significant motion interrupt status + * from the register 0x1C bit 1 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_significant_intr_u8 : The status of step + * motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_significant_intr(u8 +*sigmot_intr); +/**************************************************/ +/**\name FUNCTION FOR ANY MOTION INTERRUPT STATUS */ +/*************************************************/ + /*! + * @brief This API reads the any motion interrupt status + * from the register 0x1C bit 2 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * @param v_any_motion_intr_u8 : The status of any-motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_any_motion_intr(u8 +*v_any_motion_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR PMU TRIGGER INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the power mode trigger interrupt status + * from the register 0x1C bit 3 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_pmu_trigger_intr_u8 : The status of power mode trigger interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_pmu_trigger_intr(u8 +*v_pmu_trigger_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR DOUBLE TAB STATUS */ +/*************************************************/ +/*! + * @brief This API reads the double tab status + * from the register 0x1C bit 4 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_double_tap_intr_u8 :The status of double tab interrupt + * + * @note Double tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note smi130_set_intr_double_tap() + * @note AXIS MAPPING + * @note smi130_get_stat2_tap_first_x() + * @note smi130_get_stat2_tap_first_y() + * @note smi130_get_stat2_tap_first_z() + * @note DURATION + * @note smi130_set_intr_tap_durn() + * @note THRESHOLD + * @note smi130_set_intr_tap_thres() + * @note TAP QUIET + * @note smi130_set_intr_tap_quiet() + * @note TAP SHOCK + * @note smi130_set_intr_tap_shock() + * @note TAP SOURCE + * @note smi130_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_double_tap_intr(u8 +*v_double_tap_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR SINGLE TAB STATUS */ +/*************************************************/ +/*! + * @brief This API reads the single tab status + * from the register 0x1C bit 5 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_single_tap_intr_u8 :The status of single tap interrupt + * + * @note Single tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note smi130_set_intr_single_tap() + * @note AXIS MAPPING + * @note smi130_get_stat2_tap_first_x() + * @note smi130_get_stat2_tap_first_y() + * @note smi130_get_stat2_tap_first_z() + * @note DURATION + * @note smi130_set_intr_tap_durn() + * @note THRESHOLD + * @note smi130_set_intr_tap_thres() + * @note TAP QUIET + * @note smi130_set_intr_tap_quiet() + * @note TAP SHOCK + * @note smi130_set_intr_tap_shock() + * @note TAP SOURCE + * @note smi130_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_single_tap_intr(u8 +*v_single_tap_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR ORIENT INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the orient_mbl status + * from the register 0x1C bit 6 + * flag is associated with a specific interrupt function. + * It is set when the orient_mbl interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_orient_mbl_intr_u8 : The status of orient_mbl interrupt + * + * @note For orient_mbl interrupt configuration use the following functions + * @note STATUS + * @note smi130_get_stat0_orient_mbl_intr() + * @note AXIS MAPPING + * @note smi130_get_stat3_orient_mbl_xy() + * @note smi130_get_stat3_orient_mbl_z() + * @note smi130_set_intr_orient_mbl_axes_enable() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_orient_mbl() + * @note INTERRUPT OUTPUT + * @note smi130_set_intr_orient_mbl_ud_enable() + * @note THETA + * @note smi130_set_intr_orient_mbl_theta() + * @note HYSTERESIS + * @note smi130_set_intr_orient_mbl_hyst() + * @note BLOCKING + * @note smi130_set_intr_orient_mbl_blocking() + * @note MODE + * @note smi130_set_intr_orient_mbl_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_orient_mbl_intr(u8 +*v_orient_mbl_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR FLAT INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the flat interrupt status + * from the register 0x1C bit 7 + * flag is associated with a specific interrupt function. + * It is set when the flat interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_flat_intr_u8 : The status of flat interrupt + * + * @note For flat configuration use the following functions + * @note STATS + * @note smi130_get_stat0_flat_intr() + * @note smi130_get_stat3_flat() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_flat() + * @note THETA + * @note smi130_set_intr_flat_theta() + * @note HOLD TIME + * @note smi130_set_intr_flat_hold() + * @note HYSTERESIS + * @note smi130_set_intr_flat_hyst() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat0_flat_intr(u8 +*v_flat_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR HIGH_G INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the high_g interrupt status + * from the register 0x1D bit 2 + * flag is associated with a specific interrupt function. + * It is set when the high g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_high_g_intr_u8 : The status of high_g interrupt + * + * @note High_g interrupt configured by following functions + * @note STATUS + * @note smi130_get_stat1_high_g_intr() + * @note AXIS MAPPING + * @note smi130_get_stat3_high_g_first_x() + * @note smi130_get_stat3_high_g_first_y() + * @note smi130_get_stat3_high_g_first_z() + * @note SIGN MAPPING + * @note smi130_get_stat3_high_g_first_sign() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_high_g() + * @note HYSTERESIS + * @note smi130_set_intr_high_g_hyst() + * @note DURATION + * @note smi130_set_intr_high_g_durn() + * @note THRESHOLD + * @note smi130_set_intr_high_g_thres() + * @note SOURCE + * @note smi130_set_intr_low_high_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_high_g_intr(u8 +*v_high_g_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR LOW_G INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the low g interrupt status + * from the register 0x1D bit 3 + * flag is associated with a specific interrupt function. + * It is set when the low g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_low_g_intr_u8 : The status of low_g interrupt + * + * @note Low_g interrupt configured by following functions + * @note STATUS + * @note smi130_get_stat1_low_g_intr() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_low_g() + * @note SOURCE + * @note smi130_set_intr_low_high_source() + * @note DURATION + * @note smi130_set_intr_low_g_durn() + * @note THRESHOLD + * @note smi130_set_intr_low_g_thres() + * @note HYSTERESIS + * @note smi130_set_intr_low_g_hyst() + * @note MODE + * @note smi130_set_intr_low_g_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_low_g_intr(u8 +*v_low_g_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR DATA READY INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads data ready interrupt status + * from the register 0x1D bit 4 + * flag is associated with a specific interrupt function. + * It is set when the data ready interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_data_rdy_intr_u8 : The status of data ready interrupt + * + * @note Data ready interrupt configured by following functions + * @note STATUS + * @note smi130_get_stat1_data_rdy_intr() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_data_rdy() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_data_rdy_intr(u8 +*v_data_rdy_intr_u8); +/**************************************************/ +/**\name FUNCTIONS FOR FIFO FULL AND WATER MARK INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads data ready FIFO full interrupt status + * from the register 0x1D bit 5 + * flag is associated with a specific interrupt function. + * It is set when the FIFO full interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will + * be permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_full_intr_u8 : The status of fifo full interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note smi130_set_intr_fifo_full() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_fifo_full_intr(u8 +*v_fifo_full_intr_u8); +/*! + * @brief This API reads data + * ready FIFO watermark interrupt status + * from the register 0x1D bit 6 + * flag is associated with a specific interrupt function. + * It is set when the FIFO watermark interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_wm_intr_u8 : The status of fifo water mark interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note smi130_set_intr_fifo_wm() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_fifo_wm_intr(u8 +*v_fifo_wm_intr_u8); +/**************************************************/ +/**\name FUNCTIONS FOR NO MOTION INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads data ready no motion interrupt status + * from the register 0x1D bit 7 + * flag is associated with a specific interrupt function. + * It is set when the no motion interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_nomotion_intr_u8 : The status of no motion interrupt + * + * @note No motion interrupt can be configured by following function + * @note STATUS + * @note smi130_get_stat1_nomotion_intr() + * @note INTERRUPT MAPPING + * @note smi130_set_intr_nomotion() + * @note DURATION + * @note smi130_set_intr_slow_no_motion_durn() + * @note THRESHOLD + * @note smi130_set_intr_slow_no_motion_thres() + * @note SLOW/NO MOTION SELECT + * @note smi130_set_intr_slow_no_motion_select() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat1_nomotion_intr(u8 +*nomo_intr); +/**************************************************/ +/**\name FUNCTIONS FOR ANY MOTION FIRST XYZ AND SIGN INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the status of any motion first x + * from the register 0x1E bit 0 + * + * + * @param v_anymotion_first_x_u8 : The status of any motion first x interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_first_x(u8 +*v_anymotion_first_x_u8); +/*! + * @brief This API reads the status of any motion first y interrupt + * from the register 0x1E bit 1 + * + * + * + *@param v_any_motion_first_y_u8 : The status of any motion first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_first_y(u8 +*v_any_motion_first_y_u8); +/*! + * @brief This API reads the status of any motion first z interrupt + * from the register 0x1E bit 2 + * + * + * + * + *@param v_any_motion_first_z_u8 : The status of any motion first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_first_z(u8 +*v_any_motion_first_z_u8); +/*! + * @brief This API reads the any motion sign status from the + * register 0x1E bit 3 + * + * + * + * + * @param v_anymotion_sign_u8 : The status of any motion sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_any_motion_sign(u8 +*v_anymotion_sign_u8); +/**************************************************/ +/**\name FUNCTIONS FOR TAP FIRST XYZ AND SIGN INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the any motion tap first x status from the + * register 0x1E bit 4 + * + * + * + * + * @param v_tap_first_x_u8 :The status of any motion tap first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_first_x(u8 +*v_tap_first_x_u8); +/*! + * @brief This API reads the tap first y interrupt status from the + * register 0x1E bit 5 + * + * + * + * + * @param v_tap_first_y_u8 :The status of tap first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_first_y(u8 +*v_tap_first_y_u8); +/*! + * @brief This API reads the tap first z interrupt status from the + * register 0x1E bit 6 + * + * + * + * + * @param v_tap_first_z_u8 :The status of tap first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_first_z(u8 +*v_tap_first_z_u8); +/*! + * @brief This API reads the tap sign status from the + * register 0x1E bit 7 + * + * + * + * + * @param v_tap_sign_u8 : The status of tap sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat2_tap_sign(u8 +*tap_sign); +/**************************************************/ +/**\name FUNCTIONS FOR HIGH_G FIRST XYZ AND SIGN INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the high_g first x status from the + * register 0x1F bit 0 + * + * + * + * + * @param v_high_g_first_x_u8 :The status of high_g first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_first_x(u8 +*v_high_g_first_x_u8); +/*! + * @brief This API reads the high_g first y status from the + * register 0x1F bit 1 + * + * + * + * + * @param v_high_g_first_y_u8 : The status of high_g first y + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_first_y(u8 +*v_high_g_first_y_u8); +/*! + * @brief This API reads the high_g first z status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_first_z_u8 : The status of high_g first z + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_first_z(u8 +*v_high_g_first_z_u8); +/*! + * @brief This API reads the high sign status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_sign_u8 :The status of high sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_high_g_sign(u8 +*v_high_g_sign_u8); +/**************************************************/ +/**\name FUNCTIONS FOR ORIENT XY AND Z INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the status of orient_mbl_xy plane + * from the register 0x1F bit 4 and 5 + * + * + * @param v_orient_mbl_xy_u8 :The status of orient_mbl_xy plane + * value | status + * -----------|------------- + * 0x00 | portrait upright + * 0x01 | portrait upside down + * 0x02 | landscape left + * 0x03 | landscape right + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_orient_mbl_xy(u8 +*v_orient_mbl_xy_u8); +/*! + * @brief This API reads the status of orient_mbl z plane + * from the register 0x1F bit 6 + * + * + * @param v_orient_mbl_z_u8 :The status of orient_mbl z + * value | status + * -----------|------------- + * 0x00 | upward looking + * 0x01 | downward looking + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_orient_mbl_z(u8 +*v_orient_mbl_z_u8); +/**************************************************/ +/**\name FUNCTIONS FOR FLAT INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the flat status from the register + * 0x1F bit 7 + * + * + * @param v_flat_u8 : The status of flat interrupt + * value | status + * -----------|------------- + * 0x00 | non flat + * 0x01 | flat position + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_stat3_flat(u8 +*flat); +/**************************************************/ +/**\name FUNCTION FOR TEMPERATUE READ */ +/*************************************************/ +/*! + * @brief This API reads the temperature of the sensor + * from the register 0x21 bit 0 to 7 + * + * + * + * @param v_temp_s16 : The value of temperature + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_temp(s16 +*v_temp_s16); +/**************************************************/ +/**\name FUNCTION FOR FIFO LENGTH AND FIFO DATA READ */ +/*************************************************/ +/*! + * @brief This API reads the of the sensor + * form the register 0x23 and 0x24 bit 0 to 7 and 0 to 2 + * @brief this byte counter is updated each time a complete frame + * was read or writtern + * + * + * @param v_fifo_length_u32 : The value of fifo byte counter + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_fifo_length( +u32 *v_fifo_length_u32); +/*! + * @brief This API reads the fifo data of the sensor + * from the register 0x24 + * @brief Data format depends on the setting of register FIFO_CONFIG + * + * + * + * @param v_fifodata_u8 : Pointer holding the fifo data + * + * @note For reading FIFO data use the following functions + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_fifo_data( +u8 *v_fifodata_u8, u16 v_fifo_length_u16); +/**************************************************/ +/**\name FUNCTION FOR ACCEL CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API is used to get the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | SMI130_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | SMI130_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | SMI130_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | SMI130_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | SMI130_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | SMI130_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | SMI130_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | SMI130_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | SMI130_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | SMI130_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | SMI130_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | SMI130_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_output_data_rate( +u8 *v_output_data_rate_u8); +/*! + * @brief This API is used to set the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | SMI130_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | SMI130_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | SMI130_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | SMI130_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | SMI130_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | SMI130_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | SMI130_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | SMI130_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | SMI130_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | SMI130_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | SMI130_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | SMI130_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | SMI130_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_output_data_rate(u8 odr); +/*! + * @brief This API is used to get the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "SMI130_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_bw(u8 *v_bw_u8); +/*! + * @brief This API is used to set the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "SMI130_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_bw(u8 v_bw_u8); +/*! + * @brief This API is used to get the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_under_sampling_parameter( +u8 *v_accel_under_sampling_u8); +/*! + * @brief This API is used to set the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_under_sampling_parameter( +u8 v_accel_under_sampling_u8); +/*! + * @brief This API is used to get the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | SMI130_ACCEL_RANGE_2G + * 0x05 | SMI130_ACCEL_RANGE_4G + * 0x08 | SMI130_ACCEL_RANGE_8G + * 0x0C | SMI130_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_range( +u8 *v_range_u8); +/*! + * @brief This API is used to set the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | SMI130_ACCEL_RANGE_2G + * 0x05 | SMI130_ACCEL_RANGE_4G + * 0x08 | SMI130_ACCEL_RANGE_8G + * 0x0C | SMI130_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_range( +u8 v_range_u8); +/**************************************************/ +/**\name FUNCTION FOR GYRO CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API is used to get the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | SMI130_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | SMI130_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | SMI130_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | SMI130_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | SMI130_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | SMI130_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | SMI130_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | SMI130_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_output_data_rate( +u8 *gyro_output_typer); +/*! + * @brief This API is used to set the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | SMI130_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | SMI130_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | SMI130_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | SMI130_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | SMI130_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | SMI130_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | SMI130_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | SMI130_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | SMI130_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_output_data_rate( +u8 gyro_output_typer); +/*! + * @brief This API is used to get the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | SMI130_GYRO_OSR4_MODE + * 0x01 | SMI130_GYRO_OSR2_MODE + * 0x02 | SMI130_GYRO_NORMAL_MODE + * 0x03 | SMI130_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_bw(u8 *v_bw_u8); +/*! + * @brief This API is used to set the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | SMI130_GYRO_OSR4_MODE + * 0x01 | SMI130_GYRO_OSR2_MODE + * 0x02 | SMI130_GYRO_NORMAL_MODE + * 0x03 | SMI130_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_bw(u8 v_bw_u8); +/*! + * @brief This API reads the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | SMI130_GYRO_RANGE_2000_DEG_SEC + * 0x01 | SMI130_GYRO_RANGE_1000_DEG_SEC + * 0x02 | SMI130_GYRO_RANGE_500_DEG_SEC + * 0x03 | SMI130_GYRO_RANGE_250_DEG_SEC + * 0x04 | SMI130_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_range( +u8 *v_range_u8); +/*! + * @brief This API set the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | SMI130_GYRO_RANGE_2000_DEG_SEC + * 0x01 | SMI130_GYRO_RANGE_1000_DEG_SEC + * 0x02 | SMI130_GYRO_RANGE_500_DEG_SEC + * 0x03 | SMI130_GYRO_RANGE_250_DEG_SEC + * 0x04 | SMI130_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_range( +u8 v_range_u8); +/**************************************************/ +/**\name FUNCTION FOR MAG CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API is used to get the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |SMI130_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |SMI130_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |SMI130_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |SMI130_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |SMI130_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |SMI130_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |SMI130_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |SMI130_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |SMI130_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |SMI130_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |SMI130_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |SMI130_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_output_data_rate(u8 *odr); +/*! + * @brief This API is used to set the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |SMI130_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |SMI130_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |SMI130_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |SMI130_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |SMI130_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |SMI130_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |SMI130_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |SMI130_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |SMI130_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |SMI130_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |SMI130_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |SMI130_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |SMI130_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_output_data_rate(u8 odr); +/**************************************************/ +/**\name FUNCTION FOR FIFO CONFIGURATIONS */ +/*************************************************/ + /*! + * @brief This API is used to read Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_down_gyro( +u8 *v_fifo_down_gyro_u8); + /*! + * @brief This API is used to set Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_down_gyro( +u8 v_fifo_down_gyro_u8); +/*! + * @brief This API is used to read gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_fifo_filter_data( +u8 *v_gyro_fifo_filter_data_u8); +/*! + * @brief This API is used to set gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_fifo_filter_data( +u8 v_gyro_fifo_filter_data_u8); +/*! + * @brief This API is used to read Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_down_accel( +u8 *v_fifo_down_u8); + /*! + * @brief This API is used to set Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_down_accel( +u8 v_fifo_down_u8); +/*! + * @brief This API is used to read accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_fifo_filter_data( +u8 *v_accel_fifo_filter_u8); +/*! + * @brief This API is used to set accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_fifo_filter_data( +u8 v_accel_fifo_filter_u8); +/**************************************************/ +/**\name FUNCTION FOR FIFO WATER MARK ENABLE */ +/*************************************************/ +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_wm( +u8 *v_fifo_wm_u8); +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_wm( +u8 v_fifo_wm_u8); +/**************************************************/ +/**\name FUNCTION FOR FIFO CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API reads fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_time_enable( +u8 *v_fifo_time_enable_u8); +/*! + * @brief This API set fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_time_enable( +u8 v_fifo_time_enable_u8); +/*! + * @brief This API reads FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_tag_intr2_enable( +u8 *v_fifo_tag_intr2_u8); +/*! + * @brief This API set FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_tag_intr2_enable( +u8 v_fifo_tag_intr2_u8); +/*! + * @brief This API get FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_tag_intr1_enable( +u8 *v_fifo_tag_intr1_u8); +/*! + * @brief This API set FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_tag_intr1_enable( +u8 v_fifo_tag_intr1_u8); +/*! + * @brief This API reads FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_header_enable( +u8 *v_fifo_header_u8); +/*! + * @brief This API set FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_header_enable( +u8 v_fifo_header_u8); +/*! + * @brief This API is used to read stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_mag_enable( +u8 *v_fifo_mag_u8); +/*! + * @brief This API is used to set stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_mag_enable( +u8 v_fifo_mag_u8); +/*! + * @brief This API is used to read stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_accel_enable( +u8 *v_fifo_accel_u8); +/*! + * @brief This API is used to set stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_accel_enable( +u8 v_fifo_accel_u8); +/*! + * @brief This API is used to read stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_fifo_gyro_enable( +u8 *v_fifo_gyro_u8); +/*! + * @brief This API is used to set stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_fifo_gyro_enable( +u8 v_fifo_gyro_u8); +/***************************************************************/ +/**\name FUNCTION FOR MAG I2C ADDRESS SELECTION */ +/***************************************************************/ +/*! + * @brief This API is used to read + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_device_addr( +u8 *v_i2c_device_addr_u8); +/*! + * @brief This API is used to set + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_i2c_device_addr( +u8 v_i2c_device_addr_u8); +/*! + * @brief This API is used to read + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_burst( +u8 *v_mag_burst_u8); +/*! + * @brief This API is used to set + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_burst( +u8 v_mag_burst_u8); +/***************************************************************/ +/**\name FUNCTION FOR MAG OFFSET */ +/***************************************************************/ +/*! + * @brief This API is used to read + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_offset( +u8 *v_mag_offset_u8); +/*! + * @brief This API is used to set + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_offset( +u8 v_mag_offset_u8); +/***************************************************************/ +/**\name FUNCTION FOR MAG MANUAL/AUTO MODE SELECTION */ +/***************************************************************/ +/*! + * @brief This API is used to read + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_manual_enable( +u8 *v_mag_manual_u8); +/*! + * @brief This API is used to set + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_manual_enable( +u8 v_mag_manual_u8); +/***************************************************************/ +/**\name FUNCTIONS FOR MAG READ, WRITE AND WRITE DATA ADDRESS */ +/***************************************************************/ +/*! + * @brief This API is used to read data + * magnetometer address to read from the register 0x4D bit 0 to 7 + * @brief It used to provide mag read address of auxiliary mag + * + * + * + * + * @param v_mag_read_addr_u8 : The value of address need to be read + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_read_addr( +u8 *v_mag_read_addr_u8); +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4D bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_read_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_read_addr( +u8 v_mag_read_addr_u8); +/*! + * @brief This API is used to read + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_write_addr( +u8 *v_mag_write_addr_u8); +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_write_addr( +u8 v_mag_write_addr_u8); +/*! + * @brief This API is used to read magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_mag_write_data( +u8 *v_mag_write_data_u8); +/*! + * @brief This API is used to set magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_mag_write_data( +u8 v_mag_write_data_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF +ANY-MOTION XYZ, DOUBLE AND SINGLE TAP, ORIENT AND FLAT */ +/***************************************************************/ +/*! + * @brief This API is used to read + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_ANY_MOTION_X_ENABLE + * 1 | SMI130_ANY_MOTION_Y_ENABLE + * 2 | SMI130_ANY_MOTION_Z_ENABLE + * 3 | SMI130_DOUBLE_TAP_ENABLE + * 4 | SMI130_SINGLE_TAP_ENABLE + * 5 | SMI130_ORIENT_ENABLE + * 6 | SMI130_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_enable_0( +u8 enable, u8 *v_intr_enable_zero_u8); +/*! + * @brief This API is used to set + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_ANY_MOTION_X_ENABLE + * 1 | SMI130_ANY_MOTION_Y_ENABLE + * 2 | SMI130_ANY_MOTION_Z_ENABLE + * 3 | SMI130_DOUBLE_TAP_ENABLE + * 4 | SMI130_SINGLE_TAP_ENABLE + * 5 | SMI130_ORIENT_ENABLE + * 6 | SMI130_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_enable_0( +u8 enable, u8 v_intr_enable_zero_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF +HIGH_G XYZ, LOW_G, DATA READY, FIFO FULL AND FIFO WATER MARK */ +/***************************************************************/ +/*! + * @brief This API is used to read + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_HIGH_G_X_ENABLE + * 1 | SMI130_HIGH_G_Y_ENABLE + * 2 | SMI130_HIGH_G_Z_ENABLE + * 3 | SMI130_LOW_G_ENABLE + * 4 | SMI130_DATA_RDY_ENABLE + * 5 | SMI130_FIFO_FULL_ENABLE + * 6 | SMI130_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_enable_1( +u8 enable, u8 *v_intr_enable_1_u8); +/*! + * @brief This API is used to set + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_HIGH_G_X_ENABLE + * 1 | SMI130_HIGH_G_Y_ENABLE + * 2 | SMI130_HIGH_G_Z_ENABLE + * 3 | SMI130_LOW_G_ENABLE + * 4 | SMI130_DATA_RDY_ENABLE + * 5 | SMI130_FIFO_FULL_ENABLE + * 6 | SMI130_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_enable_1( +u8 enable, u8 v_intr_enable_1_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF +NO MOTION XYZ */ +/***************************************************************/ +/*! + * @brief This API is used to read + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_NOMOTION_X_ENABLE + * 1 | SMI130_NOMOTION_Y_ENABLE + * 2 | SMI130_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_enable_2( +u8 enable, u8 *v_intr_enable_2_u8); +/*! + * @brief This API is used to set + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_NOMOTION_X_ENABLE + * 1 | SMI130_NOMOTION_Y_ENABLE + * 2 | SMI130_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_enable_2( +u8 enable, u8 v_intr_enable_2_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF + STEP DETECTOR */ +/***************************************************************/ + /*! + * @brief This API is used to read + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_step_detector_enable( +u8 *v_step_intr_u8); + /*! + * @brief This API is used to set + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_detector_enable( +u8 v_step_intr_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT CONTROL */ +/***************************************************************/ +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | SMI130_INTR1_EDGE_CTRL + * 1 | SMI130_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_EDGE + * 0x00 | SMI130_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_edge_ctrl( +u8 v_channel_u8, u8 *v_intr_edge_ctrl_u8); +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | SMI130_INTR1_EDGE_CTRL + * 1 | SMI130_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_EDGE + * 0x00 | SMI130_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_edge_ctrl( +u8 v_channel_u8, u8 v_intr_edge_ctrl_u8); +/*! + * @brief API used for get the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_LEVEL + * 1 | SMI130_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_LEVEL_HIGH + * 0x00 | SMI130_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_level( +u8 v_channel_u8, u8 *v_intr_level_u8); +/*! + * @brief API used for set the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_LEVEL + * 1 | SMI130_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_LEVEL_HIGH + * 0x00 | SMI130_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_level( +u8 v_channel_u8, u8 v_intr_level_u8); +/*! + * @brief API used to get configured output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_OPEN_DRAIN + * 0x00 | SMI130_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_output_type( +u8 v_channel_u8, u8 *v_intr_output_type_u8); +/*! + * @brief API used to set output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_OPEN_DRAIN + * 0x00 | SMI130_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_output_type( +u8 v_channel_u8, u8 v_intr_output_type_u8); + /*! + * @brief API used to get the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_output_enable( +u8 v_channel_u8, u8 *v_output_enable_u8); + /*! + * @brief API used to set the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | SMI130_INTR1_OUTPUT_TYPE + * 1 | SMI130_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_output_enable( +u8 v_channel_u8, u8 v_output_enable_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT LATCH INTERRUPT */ +/***************************************************************/ +/*! +* @brief This API is used to get the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orient_mblation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* SMI130_LATCH_DUR_NONE | 0x00 +* SMI130_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* SMI130_LATCH_DUR_625_MICRO_SEC | 0x02 +* SMI130_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* SMI130_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* SMI130_LATCH_DUR_5_MILLI_SEC | 0x05 +* SMI130_LATCH_DUR_10_MILLI_SEC | 0x06 +* SMI130_LATCH_DUR_20_MILLI_SEC | 0x07 +* SMI130_LATCH_DUR_40_MILLI_SEC | 0x08 +* SMI130_LATCH_DUR_80_MILLI_SEC | 0x09 +* SMI130_LATCH_DUR_160_MILLI_SEC | 0x0A +* SMI130_LATCH_DUR_320_MILLI_SEC | 0x0B +* SMI130_LATCH_DUR_640_MILLI_SEC | 0x0C +* SMI130_LATCH_DUR_1_28_SEC | 0x0D +* SMI130_LATCH_DUR_2_56_SEC | 0x0E +* SMI130_LATCHED | 0x0F +* +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_latch_intr( +u8 *v_latch_intr_u8); +/*! +* @brief This API is used to set the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orient_mblation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* SMI130_LATCH_DUR_NONE | 0x00 +* SMI130_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* SMI130_LATCH_DUR_625_MICRO_SEC | 0x02 +* SMI130_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* SMI130_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* SMI130_LATCH_DUR_5_MILLI_SEC | 0x05 +* SMI130_LATCH_DUR_10_MILLI_SEC | 0x06 +* SMI130_LATCH_DUR_20_MILLI_SEC | 0x07 +* SMI130_LATCH_DUR_40_MILLI_SEC | 0x08 +* SMI130_LATCH_DUR_80_MILLI_SEC | 0x09 +* SMI130_LATCH_DUR_160_MILLI_SEC | 0x0A +* SMI130_LATCH_DUR_320_MILLI_SEC | 0x0B +* SMI130_LATCH_DUR_640_MILLI_SEC | 0x0C +* SMI130_LATCH_DUR_1_28_SEC | 0x0D +* SMI130_LATCH_DUR_2_56_SEC | 0x0E +* SMI130_LATCHED | 0x0F +* +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_latch_intr( +u8 v_latch_intr_u8); +/*! + * @brief API used to get input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | SMI130_INTR1_INPUT_ENABLE + * 1 | SMI130_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_input_enable( +u8 v_channel_u8, u8 *v_input_en_u8); +/*! + * @brief API used to set input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | SMI130_INTR1_INPUT_ENABLE + * 1 | SMI130_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | SMI130_INPUT + * 0x00 | SMI130_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_input_enable( +u8 v_channel_u8, u8 v_input_en_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT1 AND INTERRUPT2 MAPPING */ +/***************************************************************/ + /*! + * @brief reads the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_LOW_G + * 1 | SMI130_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g( +u8 v_channel_u8, u8 *v_intr_low_g_u8); + /*! + * @brief set the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_LOW_G + * 1 | SMI130_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g( +u8 v_channel_u8, u8 v_intr_low_g_u8); +/*! + * @brief Reads the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_HIGH_G + * 1 | SMI130_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g( +u8 v_channel_u8, u8 *v_intr_high_g_u8); +/*! + * @brief Write the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_HIGH_G + * 1 | SMI130_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g( +u8 v_channel_u8, u8 v_intr_high_g_u8); +/*! + * @brief Reads the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ANY_MOTION + * 1 | SMI130_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_any_motion( +u8 v_channel_u8, u8 *v_intr_any_motion_u8); +/*! + * @brief Write the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ANY_MOTION + * 1 | SMI130_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_any_motion( +u8 v_channel_u8, u8 v_intr_any_motion_u8); +/*! + * @brief Reads the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_NOMO + * 1 | SMI130_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_nomotion( +u8 v_channel_u8, u8 *v_intr_nomotion_u8); +/*! + * @brief Write the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_NOMO + * 1 | SMI130_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_nomotion( +u8 v_channel_u8, u8 v_intr_nomotion_u8); +/*! + * @brief Reads the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DOUBLE_TAP + * 1 | SMI130_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_double_tap( +u8 v_channel_u8, u8 *v_intr_double_tap_u8); +/*! + * @brief Write the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DOUBLE_TAP + * 1 | SMI130_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_double_tap( +u8 v_channel_u8, u8 v_intr_double_tap_u8); +/*! + * @brief Reads the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_SINGLE_TAP + * 1 | SMI130_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_single_tap( +u8 v_channel_u8, u8 *v_intr_single_tap_u8); +/*! + * @brief Write the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_SINGLE_TAP + * 1 | SMI130_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_single_tap( +u8 v_channel_u8, u8 v_intr_single_tap_u8); +/*! + * @brief Reads the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient_mbl interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ORIENT + * 1 | SMI130_INTR2_MAP_ORIENT + * + * @param v_intr_orient_mbl_u8 : The value of orient_mbl enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl( +u8 v_channel_u8, u8 *v_intr_orient_mbl_u8); +/*! + * @brief Write the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient_mbl interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_ORIENT + * 1 | SMI130_INTR2_MAP_ORIENT + * + * @param v_intr_orient_mbl_u8 : The value of orient_mbl enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl( +u8 v_channel_u8, u8 v_intr_orient_mbl_u8); + /*! + * @brief Reads the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FLAT + * 1 | SMI130_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat( +u8 v_channel_u8, u8 *v_intr_flat_u8); + /*! + * @brief Write the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FLAT + * 1 | SMI130_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat( +u8 v_channel_u8, u8 v_intr_flat_u8); +/*! + * @brief Reads PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_PMUTRIG + * 1 | SMI130_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_pmu_trig( +u8 v_channel_u8, u8 *v_intr_pmu_trig_u8); +/*! + * @brief Write PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_PMUTRIG + * 1 | SMI130_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | trigger enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_pmu_trig( +u8 v_channel_u8, u8 v_intr_pmu_trig_u8); +/*! + * @brief Reads FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_FULL + * 1 | SMI130_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_fifo_full( +u8 v_channel_u8, u8 *v_intr_fifo_full_u8); +/*! + * @brief Write FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_FULL + * 1 | SMI130_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_fifo_full( +u8 v_channel_u8, u8 v_intr_fifo_full_u8); +/*! + * @brief Reads FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_WM + * 1 | SMI130_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_fifo_wm( +u8 v_channel_u8, u8 *v_intr_fifo_wm_u8); +/*! + * @brief Write FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_FIFO_WM + * 1 | SMI130_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_fifo_wm( +u8 v_channel_u8, u8 v_intr_fifo_wm_u8); +/*! + * @brief Reads Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DATA_RDY + * 1 | SMI130_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_data_rdy( +u8 v_channel_u8, u8 *v_intr_data_rdy_u8); +/*! + * @brief Write Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | SMI130_INTR1_MAP_DATA_RDY + * 1 | SMI130_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | SMI130_ENABLE + * 0x00 | SMI130_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_data_rdy( +u8 v_channel_u8, u8 v_intr_data_rdy_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP SOURCE CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API reads data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_source( +u8 *v_tap_source_u8); + /*! + * @brief This API write data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_source( +u8 v_tap_source_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G AND HIGH_G SOURCE CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API Reads Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_high_source( +u8 *v_low_high_source_u8); + /*! + * @brief This API write Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_high_source( +u8 v_low_high_source_u8); +/***************************************************************/ +/**\name FUNCTION FOR MOTION SOURCE CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API reads Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_motion_source( +u8 *v_motion_source_u8); + /*! + * @brief This API write Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_motion_source( +u8 v_motion_source_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G DURATION CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_durn( +u8 *v_low_durn_u8); + /*! + * @brief This API is used to write the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_durn( +u8 v_low_durn_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G THRESH CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_thres( +u8 *v_low_g_thres_u8); +/*! + * @brief This API is used to write Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_thres( +u8 v_low_g_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G HYSTERESIS CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API Reads Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_hyst( +u8 *v_low_hyst_u8); + /*! + * @brief This API write Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_hyst( +u8 v_low_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G MODE CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API reads Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_low_g_mode( +u8 *v_low_g_mode_u8); +/*! + * @brief This API write Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_low_g_mode( +u8 v_low_g_mode_u8); +/***************************************************************/ +/**\name FUNCTION FOR HIGH_G HYST CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API reads High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g_hyst( +u8 *v_high_g_hyst_u8); +/*! + * @brief This API write High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g_hyst( +u8 v_high_g_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FOR HIGH_G DURATION CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g_durn( +u8 *v_high_g_durn_u8); +/*! + * @brief This API is used to write Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g_durn( +u8 v_high_g_durn_u8); +/***************************************************************/ +/**\name FUNCTION FOR HIGH_G THRESHOLD CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_high_g_thres( +u8 *v_high_g_thres_u8); +/*! + * @brief This API is used to write Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_high_g_thres( +u8 v_high_g_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR ANY MOTION DURATION CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API reads any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_any_motion_durn( +u8 *v_any_motion_durn_u8); +/*! + * @brief This API write any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_any_motion_durn( +u8 nomotion); +/***************************************************************/ +/**\name FUNCTION FOR SLOW NO MOTION DURATION CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API read Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_slow_no_motion_durn( +u8 *v_slow_no_motion_u8); + /*! + * @brief This API write Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_slow_no_motion_durn( +u8 v_slow_no_motion_u8); +/***************************************************************/ +/**\name FUNCTION FOR ANY MOTION THRESHOLD CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_any_motion_thres( +u8 *v_any_motion_thres_u8); +/*! + * @brief This API is used to write threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_any_motion_thres( +u8 v_any_motion_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR SLO/NO MOTION THRESHOLD CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API is used to read threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_slow_no_motion_thres( +u8 *v_slow_no_motion_thres_u8); + /*! + * @brief This API is used to write threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_slow_no_motion_thres( +u8 v_slow_no_motion_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR SLO/NO MOTION SELECT CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API is used to read + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_slow_no_motion_select( +u8 *v_intr_slow_no_motion_select_u8); + /*! + * @brief This API is used to write + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_slow_no_motion_select( +u8 v_intr_slow_no_motion_select_u8); +/***************************************************************/ +/**\name FUNCTION FOR SIGNIFICANT MOTION SELECT CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API is used to select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_significant_motion_select( +u8 *int_sig_mot_sel); + /*! + * @brief This API is used to write, select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_significant_motion_select( +u8 int_sig_mot_sel); + /*! + * @brief This API is used to read + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_significant_motion_skip( +u8 *v_int_sig_mot_skip_u8); + /*! + * @brief This API is used to write + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_significant_motion_skip( +u8 v_int_sig_mot_skip_u8); + /*! + * @brief This API is used to read + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_significant_motion_proof( +u8 *int_sig_mot_proof); + /*! + * @brief This API is used to write + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_significant_motion_proof( +u8 int_sig_mot_proof); +/***************************************************************/ +/**\name FUNCTION FOR TAP DURATION CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API is used to get the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_DURN_50MS + * 0x01 | SMI130_TAP_DURN_100MS + * 0x03 | SMI130_TAP_DURN_150MS + * 0x04 | SMI130_TAP_DURN_200MS + * 0x05 | SMI130_TAP_DURN_250MS + * 0x06 | SMI130_TAP_DURN_375MS + * 0x07 | SMI130_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_durn( +u8 *v_tap_durn_u8); +/*! + * @brief This API is used to write the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_DURN_50MS + * 0x01 | SMI130_TAP_DURN_100MS + * 0x03 | SMI130_TAP_DURN_150MS + * 0x04 | SMI130_TAP_DURN_200MS + * 0x05 | SMI130_TAP_DURN_250MS + * 0x06 | SMI130_TAP_DURN_375MS + * 0x07 | SMI130_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_durn( +u8 v_tap_durn_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP SHOCK CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_SHOCK_50MS + * 0x01 | SMI130_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_shock( +u8 *v_tap_shock_u8); + /*! + * @brief This API write the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_SHOCK_50MS + * 0x01 | SMI130_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_shock( +u8 v_tap_shock_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP QUIET CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_QUIET_30MS + * 0x01 | SMI130_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_quiet( +u8 *v_tap_quiet_u8); +/*! + * @brief This API write + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | SMI130_TAP_QUIET_30MS + * 0x01 | SMI130_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_quiet( +u8 v_tap_quiet_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP THRESHOLD CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_tap_thres( +u8 *v_tap_thres_u8); + /*! + * @brief This API write Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_tap_thres( +u8 v_tap_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT MODE CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read the threshold for orient_mblation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mbl_mode_u8 : The value of threshold for orient_mblation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_mode( +u8 *v_orient_mbl_mode_u8); + /*! + * @brief This API write the threshold for orient_mblation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mbl_mode_u8 : The value of threshold for orient_mblation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_mode( +u8 v_orient_mbl_mode_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT BLOCKING CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read the orient_mbl blocking mode + * that is used for the generation of the orient_mblation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_mbl_blocking_u8 : The value of orient_mbl blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient_mbl is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_blocking( +u8 *v_orient_mbl_blocking_u8); +/*! + * @brief This API write the orient_mbl blocking mode + * that is used for the generation of the orient_mblation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_mbl_blocking_u8 : The value of orient_mbl blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient_mbl is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_blocking( +u8 v_orient_mbl_blocking_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT HYSTERESIS CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_mbl_hyst_u8 : The value of orient_mbl hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_hyst( +u8 *v_orient_mbl_hyst_u8); +/*! + * @brief This API write Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_mbl_hyst_u8 : The value of orient_mbl hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_hyst( +u8 v_orient_mbl_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT THETA CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_mbl_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_theta( +u8 *v_orient_mbl_theta_u8); + /*! + * @brief This API write Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_mbl_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_theta( +u8 v_orient_mbl_theta_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT OUTPUT ENABLE CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read orient_mbl change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_mbl_ud_u8 : The value of orient_mbl change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orient_mblation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_ud_enable( +u8 *v_orient_mbl_ud_u8); +/*! + * @brief This API write orient_mbl change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_mbl_ud_u8 : The value of orient_mbl change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orient_mblation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_ud_enable( +u8 v_orient_mbl_ud_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT AXIS ENABLE CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read orient_mblation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_mbl_axes_u8 : The value of orient_mbl axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_mbl_ax_noex + * 0x01 | x = y, y = z, z = x|orient_mbl_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_orient_mbl_axes_enable( +u8 *v_orient_mbl_axes_u8); + /*! + * @brief This API write orient_mblation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_mbl_axes_u8 : The value of orient_mbl axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_mbl_ax_noex + * 0x01 | x = y, y = z, z = x|orient_mbl_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_orient_mbl_axes_enable( +u8 v_orient_mbl_axes_u8); +/***************************************************************/ +/**\name FUNCTION FOR FLAT THETA CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat_theta( +u8 *v_flat_theta_u8); + /*! + * @brief This API write Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat_theta( +u8 v_flat_theta_u8); +/***************************************************************/ +/**\name FUNCTION FOR FLAT HOLD CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat_hold( +u8 *v_flat_hold_u8); +/*! + * @brief This API write Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat_hold( +u8 v_flat_hold_u8); +/***************************************************************/ +/**\name FUNCTION FOR FLAT HYSTERESIS CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_intr_flat_hyst( +u8 *v_flat_hyst_u8); +/*! + * @brief This API write flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_intr_flat_hyst( +u8 v_flat_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FAST OFFSET COMPENSATION FOR ACCEL */ +/***************************************************************/ + /*! + * @brief This API read accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_accel_z( +u8 *v_foc_accel_z_u8); + /*! + * @brief This API write accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_accel_z( +u8 v_foc_accel_z_u8); +/*! + * @brief This API read accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_accel_y( +u8 *v_foc_accel_y_u8); +/*! + * @brief This API write accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_accel_y( +u8 v_foc_accel_y_u8); +/*! + * @brief This API read accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_accel_x( +u8 *v_foc_accel_x_u8); +/*! + * @brief This API write accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_accel_x( +u8 v_foc_accel_x_u8); +/***************************************************************/ +/**\name FUNCTION FAST OFFSET COMPENSATION FOR GYRO */ +/***************************************************************/ +/*! + * @brief This API write gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * @param v_gyro_off_x_s16 : The value of gyro fast offset x axis data + * @param v_gyro_off_y_s16 : The value of gyro fast offset y axis data + * @param v_gyro_off_z_s16 : The value of gyro fast offset z axis data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_foc_gyro_enable( +u8 v_foc_gyro_u8, s16 *v_gyro_off_x_s16, +s16 *v_gyro_off_y_s16, s16 *v_gyro_off_z_s16); +/***************************************************/ +/**\name FUNCTION FOR NVM*/ +/***************************************************/ + /*! + * @brief This API read NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_nvm_prog_enable( +u8 *v_nvm_prog_u8); + /*! + * @brief This API write NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_nvm_prog_enable( +u8 v_nvm_prog_u8); +/***************************************************/ +/**\name FUNCTION FOR SPI MODE*/ +/***************************************************/ +/*! + * @brief This API read to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_get_spi3( +u8 *v_spi3_u8); +/*! + * @brief This API write to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_spi3( +u8 v_spi3_u8); +/***************************************************/ +/**\name FUNCTION FOR FOC GYRO */ +/***************************************************/ +/*! + * @brief This API read gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_foc_gyro_enable( +u8 *v_foc_gyro_u8); +/***************************************************/ +/**\name FUNCTION FOR I2C WATCHDOG TIMBER */ +/***************************************************/ +/*! + * @brief This API read I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_wdt_select( +u8 *v_i2c_wdt_u8); +/*! + * @brief This API write I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE +smi130_set_i2c_wdt_select(u8 v_i2c_wdt_u8); +/*! + * @brief This API read I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_i2c_wdt_enable( +u8 *v_i2c_wdt_u8); +/*! + * @brief This API write I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_i2c_wdt_enable( +u8 v_i2c_wdt_u8); +/***************************************************/ +/**\name FUNCTION FOR IF MODE*/ +/***************************************************/ +/*! + * @brief This API read I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_if_mode( +u8 *v_if_mode_u8); +/*! + * @brief This API write I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_if_mode( +u8 v_if_mode_u8); +/***************************************************/ +/**\name FUNCTION FOR GYRO SLEEP TRIGGER INTERRUPT CONFIGURATION*/ +/***************************************************/ +/*! + * @brief This API read gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_sleep_trigger( +u8 *v_gyro_sleep_trigger_u8); +/*! + * @brief This API write gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_sleep_trigger( +u8 v_gyro_sleep_trigger_u8); +/*! + * @brief This API read gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_wakeup_trigger( +u8 *v_gyro_wakeup_trigger_u8); +/*! + * @brief This API write gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_wakeup_trigger( +u8 v_gyro_wakeup_trigger_u8); +/*! + * @brief This API read Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_sleep_state( +u8 *v_gyro_sleep_state_u8); +/*! + * @brief This API write Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_sleep_state( +u8 v_gyro_sleep_state_u8); +/*! + * @brief This API read gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_wakeup_intr( +u8 *v_gyro_wakeup_intr_u8); +/*! + * @brief This API write gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_wakeup_intr( +u8 v_gyro_wakeup_intr_u8); +/***************************************************/ +/**\name FUNCTION FOR ACCEL SELF TEST */ +/***************************************************/ +/*! + * @brief This API read accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_selftest_axis( +u8 *acc_selftest_axis); +/*! + * @brief This API write accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_selftest_axis( +u8 acc_selftest_axis); +/*! + * @brief This API read accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_selftest_sign( +u8 *acc_selftest_sign); +/*! + * @brief This API write accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_selftest_sign( +u8 acc_selftest_sign); +/*! + * @brief This API read accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_selftest_amp( +u8 *acc_selftest_amp); +/*! + * @brief This API write accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_selftest_amp( +u8 acc_selftest_amp); +/***************************************************/ +/**\name FUNCTION FOR GYRO SELF TEST */ +/***************************************************/ +/*! + * @brief This API read gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_selftest_start( +u8 *v_gyro_selftest_start_u8); +/*! + * @brief This API write gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_selftest_start( +u8 v_gyro_selftest_start_u8); +/***************************************************/ +/**\name FUNCTION FOR SPI/I2C ENABLE */ +/***************************************************/ + /*! + * @brief This API read primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_spi_enable( +u8 *v_spi_enable_u8); + /*! + * @brief This API write primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_spi_enable( +u8 v_spi_enable_u8); + /*! + * @brief This API read the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_spare0_trim +(u8 *v_spare0_trim_u8); + /*! + * @brief This API write the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_spare0_trim +(u8 v_spare0_trim_u8); +/***************************************************/ +/**\name FUNCTION FOR NVM COUNTER */ +/***************************************************/ + /*! + * @brief This API read the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_nvm_counter( +u8 *v_nvm_counter_u8); + /*! + * @brief This API write the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_nvm_counter( +u8 v_nvm_counter_u8); +/***************************************************/ +/**\name FUNCTION FOR ACCEL MANUAL OFFSET COMPENSATION */ +/***************************************************/ +/*! + * @brief This API read accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_compensation_xaxis( +s8 *v_accel_off_x_s8); +/*! + * @brief This API write accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_compensation_xaxis( +s8 v_accel_off_x_s8); +/*! + * @brief This API read accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_compensation_yaxis( +s8 *v_accel_off_y_s8); +/*! + * @brief This API write accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_compensation_yaxis( +s8 v_accel_off_y_s8); +/*! + * @brief This API read accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_compensation_zaxis( +s8 *v_accel_off_z_s8); +/*! + * @brief This API write accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_compensation_zaxis( +s8 v_accel_off_z_s8); +/***************************************************/ +/**\name FUNCTION FOR GYRO MANUAL OFFSET COMPENSATION */ +/***************************************************/ +/*! + * @brief This API read gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_compensation_xaxis( +s16 *v_gyro_off_x_s16); +/*! + * @brief This API write gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_compensation_xaxis( +s16 v_gyro_off_x_s16); +/*! + * @brief This API read gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_compensation_yaxis( +s16 *v_gyro_off_y_s16); +/*! + * @brief This API write gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_compensation_yaxis( +s16 v_gyro_off_y_s16); +/*! + * @brief This API read gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_compensation_zaxis( +s16 *v_gyro_off_z_s16); +/*! + * @brief This API write gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_compensation_zaxis( +s16 v_gyro_off_z_s16); +/*! + * @brief This API writes accel fast offset compensation + * from the register 0x69 bit 0 to 5 + * @brief This API writes each axis individually + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_u8: The value of accel offset compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_axis_u8: The value of accel offset axis selection + * value | axis + * ----------|------------------- + * 0 | FOC_X_AXIS + * 1 | FOC_Y_AXIS + * 2 | FOC_Z_AXIS + * + * @param v_accel_offset_s8: The accel offset value + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_foc_trigger(u8 axis, +u8 foc_acc, s8 *accel_offset); +/*! + * @brief This API write fast accel offset compensation + * it writes all axis together.To the register 0x69 bit 0 to 5 + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_x_u8: The value of accel offset x compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_y_u8: The value of accel offset y compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_z_u8: The value of accel offset z compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_accel_off_x_s8: The value of accel offset x axis + * @param v_accel_off_y_s8: The value of accel offset y axis + * @param v_accel_off_z_s8: The value of accel offset z axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_accel_foc_trigger_xyz(u8 v_foc_accel_x_u8, +u8 v_foc_accel_y_u8, u8 v_foc_accel_z_u8, +s8 *acc_off_x, s8 *acc_off_y, s8 *acc_off_z); +/***************************************************/ +/**\name FUNCTION FOR ACEL AND GYRO OFFSET ENABLE */ +/***************************************************/ +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_accel_offset_enable( +u8 *acc_off_en); +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_accel_offset_enable( +u8 acc_off_en); +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_gyro_offset_enable( +u8 *v_gyro_off_enable_u8); +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_gyro_offset_enable( +u8 v_gyro_off_enable_u8); +/***************************************************/ +/**\name FUNCTION FOR STEP COUNTER INTERRUPT */ +/***************************************************/ +/*! + * @brief This API reads step counter value + * form the register 0x78 and 0x79 + * + * + * + * + * @param v_step_cnt_s16 : The value of step counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_read_step_count(u16 *v_step_cnt_s16); + /*! + * @brief This API Reads + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : The value of step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_step_config( +u16 *v_step_config_u16); + /*! + * @brief This API write + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : + * the value of Enable step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_config( +u16 v_step_config_u16); + /*! + * @brief This API read enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_step_counter_enable( +u8 *v_step_counter_u8); + /*! + * @brief This API write enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_counter_enable( +u8 v_step_counter_u8); + /*! + * @brief This API set Step counter modes + * + * + * @param v_step_mode_u8 : The value of step counter mode + * value | mode + * ----------|----------- + * 0 | SMI130_STEP_NORMAL_MODE + * 1 | SMI130_STEP_SENSITIVE_MODE + * 2 | SMI130_STEP_ROBUST_MODE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_step_mode(u8 v_step_mode_u8); +/*! + * @brief This API used to trigger the signification motion + * interrupt + * + * + * @param v_significant_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | SMI130_MAP_INTR1 + * 1 | SMI130_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_map_significant_motion_intr( +u8 v_significant_u8); +/*! + * @brief This API used to trigger the step detector + * interrupt + * + * + * @param v_step_detector_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | SMI130_MAP_INTR1 + * 1 | SMI130_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_map_step_detector_intr( +u8 v_step_detector_u8); + /*! + * @brief This API used to clear the step counter interrupt + * interrupt + * + * + * @param : None + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_clear_step_counter(void); +/***************************************************/ +/**\name FUNCTION FOR STEP COMMAND REGISTER WRITE */ +/***************************************************/ + /*! + * @brief This API writes value to the register 0x7E bit 0 to 7 + * + * + * @param v_command_reg_u8 : The value to write command register + * value | Description + * ---------|-------------------------------------------------------- + * 0x00 | Reserved + * 0x03 | Starts fast offset calibration for the accel and gyro + * 0x10 | Sets the PMU mode for the Accelerometer to suspend + * 0x11 | Sets the PMU mode for the Accelerometer to normal + * 0x12 | Sets the PMU mode for the Accelerometer Lowpower + * 0x14 | Sets the PMU mode for the Gyroscope to suspend + * 0x15 | Sets the PMU mode for the Gyroscope to normal + * 0x16 | Reserved + * 0x17 | Sets the PMU mode for the Gyroscope to fast start-up + * 0x18 | Sets the PMU mode for the Magnetometer to suspend + * 0x19 | Sets the PMU mode for the Magnetometer to normal + * 0x1A | Sets the PMU mode for the Magnetometer to Lowpower + * 0xB0 | Clears all data in the FIFO + * 0xB1 | Resets the interrupt engine + * 0xB2 | step_cnt_clr Clears the step counter + * 0xB6 | Triggers a reset + * 0x37 | See extmode_en_last + * 0x9A | See extmode_en_last + * 0xC0 | Enable the extended mode + * 0xC4 | Erase NVM cell + * 0xC8 | Load NVM cell + * 0xF0 | Reset acceleration data path + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_command_register( +u8 v_command_reg_u8); +/***************************************************/ +/**\name FUNCTION FOR PAGE ENABLE */ +/***************************************************/ + /*! + * @brief This API read target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_target_page( +u8 *v_target_page_u8); + /*! + * @brief This API write target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_target_page( +u8 v_target_page_u8); + /*! + * @brief This API read page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_paging_enable( +u8 *v_page_enable_u8); + /*! + * @brief This API write page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_paging_enable( +u8 v_page_enable_u8); + /*! + * @brief This API read + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_get_pullup_configuration( +u8 *v_control_pullup_u8); + /*! + * @brief This API write + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_pullup_configuration( +u8 v_control_pullup_u8); +/***************************************************/ +/**\name FUNCTION FOR BMM150 */ +/***************************************************/ + /*! + * @brief This function used for initialize the bmm150 sensor + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_interface_init(void); + /*! + * @brief This function used for set the mag power control + * bit enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_wakeup(void); + /*! + * @brief This function used for read the trim values of magnetometer + * + * @note + * Before reading the mag trimming values + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_bmm150_mag_trim_mbl(void); + /*! + * @brief This function used for read the compensated value of mag + * Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_compensate_xyz( +struct smi130_mag_xyz_s32_t *mag_comp_xyz); +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_compensate_xyz_raw( +struct smi130_mag_xyz_s32_t *mag_comp_xyz, struct smi130_mag_xyzr_t mag_xyzr); + +/*! + * @brief This API used to get the compensated BMM150-X data + * the out put of X as s32 + * Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_x_s16 : The value of mag raw X data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated X data value output as s32 + * + */ +s32 smi130_bmm150_mag_compensate_X(s16 v_mag_data_x_s16, u16 v_data_r_u16); +/*! + * @brief This API used to get the compensated BMM150-Y data + * the out put of Y as s32 + * Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_y_s16 : The value of mag raw Y data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Y data value output as s32 + */ +s32 smi130_bmm150_mag_compensate_Y(s16 v_mag_data_y_s16, u16 v_data_r_u16); +/*! + * @brief This API used to get the compensated BMM150-Z data + * the out put of Z as s32 + * Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_z_s16 : The value of mag raw Z data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Z data value output as s32 + */ +s32 smi130_bmm150_mag_compensate_Z(s16 v_mag_data_z_s16, u16 v_data_r_u16); +/*! + * @brief This API used to set the pre-set modes of bmm150 + * The pre-set mode setting is depend on data rate and xy and z repetitions + * + * @note + * Before set the mag preset mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_mode_u8: The value of pre-set mode selection value + * value | pre_set mode + * ----------|------------ + * 1 | SMI130_MAG_PRESETMODE_LOWPOWER + * 2 | SMI130_MAG_PRESETMODE_REGULAR + * 3 | SMI130_MAG_PRESETMODE_HIGHACCURACY + * 4 | SMI130_MAG_PRESETMODE_ENHANCED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_set_bmm150_mag_presetmode(u8 mode); +/*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @param v_mag_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | FORCE_MODE + * 1 | SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bmm150_mag_set_power_mode(u8 mag_pow_mode); + /*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | SMI130_MAG_FORCE_MODE + * 1 | SMI130_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_bmm150_mag_and_secondary_if_power_mode( +u8 v_mag_sec_if_pow_mode_u8); +/***************************************************/ +/**\name FUNCTIONS FOR AKM09911 AND AKM09912*/ +/***************************************************/ + /*! + * @brief This function used for initialize + * the AKM09911 and AKM09912 sensor + * + * + * @param v_akm_i2c_address_u8: The value of device address + * AKM sensor | Slave address + * --------------|--------------------- + * AKM09911 | AKM09911_I2C_ADDR_1 + * - | and AKM09911_I2C_ADDR_2 + * AKM09912 | AKM09912_I2C_ADDR_1 + * - | AKM09912_I2C_ADDR_2 + * - | AKM09912_I2C_ADDR_3 + * - | AKM09912_I2C_ADDR_4 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm_mag_interface_init( +u8 v_akm_i2c_address_u8); + /*! + * @brief This function used for read the sensitivity data of + * AKM09911 and AKM09912 + * + * @note Before reading the mag sensitivity values + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_read_bosch_akm_sensitivity_data(void); +/*! + * @brief This API used to get the compensated X data + * of AKM09911 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 smi130_bosch_akm09911_compensate_X(s16 v_bosch_akm_x_s16); +/*! + * @brief This API used to get the compensated Y data + * of AKM09911 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 smi130_bosch_akm09911_compensate_Y(s16 v_bosch_akm_y_s16); +/*! + * @brief This API used to get the compensated Z data + * of AKM09911 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 smi130_bosch_akm09911_compensate_Z(s16 v_bosch_akm_z_s16); +/*! + * @brief This API used to get the compensated X data + * of AKM09912 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 smi130_bosch_akm09912_compensate_X(s16 v_bosch_akm_x_s16); +/*! + * @brief This API used to get the compensated Y data + * of AKM09912 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 smi130_bosch_akm09912_compensate_Y(s16 v_bosch_akm_y_s16); +/*! + * @brief This API used to get the compensated Z data + * of AKM09912 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * + * @param v_bosch_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 smi130_bosch_akm09912_compensate_Z(s16 v_bosch_akm_z_s16); + /*! + * @brief This function used for read the compensated value of + * AKM09911 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm09911_compensate_xyz( +struct smi130_mag_xyz_s32_t *bosch_akm_xyz); + /*! + * @brief This function used for read the compensated value of + * AKM09912 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm09912_compensate_xyz( +struct smi130_mag_xyz_s32_t *bosch_akm_xyz); +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm09912_compensate_xyz_raw( +struct smi130_mag_xyz_s32_t *bosch_akm_xyz); +/*! + * @brief This function used for set the AKM09911 and AKM09912 + * power mode. + * @note Before set the AKM power mode + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function smi130_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * smi130_set_command_register(0x19) function. + * + * @param v_akm_pow_mode_u8 : The value of akm power mode + * value | Description + * ---------|-------------------- + * 0 | AKM_POWER_DOWN_MODE + * 1 | AKM_SINGLE_MEAS_MODE + * 2 | FUSE_ROM_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_akm_set_powermode(u8 v_akm_pow_mode_u8); + /*! + * @brief This function used for set the magnetometer + * power mode of AKM09911 and AKM09912 + * @note Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the smi130_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function smi130_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of secondary if power mode + * value | Description + * ---------|-------------------- + * 0 | SMI130_MAG_FORCE_MODE + * 1 | SMI130_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_set_bosch_akm_and_secondary_if_powermode( +u8 v_mag_sec_if_pow_mode_u8); +/***************************************************/ +/**\name FUNCTIONS FOR YAMAH-YAS532 */ +/***************************************************/ +/*! + * @brief This function used for read the YAMAH-YAS532 init + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas532_mag_interface_init( +void); +/*! + * @brief This function used to set the YAS532 initial values + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_set_initial_values(void); +/*! + * @brief This function used for YAS532 offset correction + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_magnetic_measure_set_offset( +void); +/*! + * @brief This function used for read the + * YAMAHA YAS532 calibration data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas532_calib_values(void); +/*! + * @brief This function used for calculate the + * YAS532 read the linear data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_xy1y2_to_linear( +u16 *v_xy1y2_u16, s32 *xy1y2_linear); +/*! + * @brief This function used for read the YAS532 sensor data + * @param v_acquisition_command_u8: used to set the data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param v_busy_u8 : used to get the busy flay for sensor data read + * @param v_temp_u16 : used to get the temperature data + * @param v_xy1y2_u16 : used to get the sensor xy1y2 data + * @param v_overflow_u8 : used to get the overflow data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_normal_measurement_data( +u8 v_acquisition_command_u8, u8 *v_busy_u8, +u16 *v_temp_u16, u16 *v_xy1y2_u16, u8 *v_overflow_u8); +/*! + * @brief This function used for YAS532 sensor data + * @param v_acquisition_command_u8 : the value of CMDR + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param xyz_data : the vector xyz output + * @param v_overflow_s8 : the value of overflow + * @param v_temp_correction_u8 : the value of temperate correction enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_measurement_xyz_data( +struct yas532_vector *xyz_data, u8 *v_overflow_s8, u8 v_temp_correction_u8, +u8 v_acquisition_command_u8); +/*! + * @brief This function used for YAS532 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_acquisition_command_register( +u8 v_command_reg_data_u8); +/*! + * @brief This function used write offset of YAS532 + * + * @param p_offset_s8 : The value of offset to write + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas532_set_offset( +const s8 *p_offset_s8); +/*! + * @brief This function used to init the YAMAH-YAS537 + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_mag_interface_init( +void); +/*! + * @brief This function used for read the + * YAMAHA YAS537 calibration data + * + * + * @param v_rcoil_u8 : The value of r coil + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_calib_values( +u8 v_rcoil_u8); +/*! + * @brief This function used for YAS537 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yas537_acquisition_command_register( +u8 v_command_reg_data_u8); + +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_coil_stat_u8: The value of R coil status + * @param v_busy_u8: The value of busy status + * @param v_temperature_u16: The value of temperature + * @param xy1y2: The value of raw xy1y2 data + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_read_xy1y2_data( +u8 *v_coil_stat_u8, u8 *v_busy_u8, +u16 *v_temperature_u16, u16 *xy1y2, u8 *v_ouflow_u8); +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_bosch_yamaha_yas537_measure_xyz_data( +u8 *v_ouflow_u8, struct yas_vector *vector_xyz); + +/***************************************************/ +/**\name FUNCTIONS FOR FIFO DATA READ */ +/***************************************************/ +/*! + * @brief This function used for reading the + * fifo data of header less mode + * + * + * + * @note Configure the below functions for FIFO header less mode + * @note 1. smi130_set_fifo_down_gyro + * @note 2. smi130_set_gyro_fifo_filter_data + * @note 3. smi130_set_fifo_down_accel + * @note 4. smi130_set_accel_fifo_filter_dat + * @note 5. smi130_set_fifo_mag_enable + * @note 6. smi130_set_fifo_accel_enable + * @note 7. smi130_set_fifo_gyro_enable + * @note For interrupt configuration + * @note 1. smi130_set_intr_fifo_full + * @note 2. smi130_set_intr_fifo_wm + * @note 3. smi130_set_fifo_tag_intr2_enable + * @note 4. smi130_set_fifo_tag_intr1_enable + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_read_fifo_headerless_mode( +void); +/*! + * @brief This function used for reading the + * fifo data of header less mode for using user defined length + * + * + * @param v_fifo_user_length_u16: The value of length of fifo read data + * + * @note Configure the below functions for FIFO header less mode + * @note 1. smi130_set_fifo_down_gyro + * @note 2. smi130_set_gyro_fifo_filter_data + * @note 3. smi130_set_fifo_down_accel + * @note 4. smi130_set_accel_fifo_filter_dat + * @note 5. smi130_set_fifo_mag_enable + * @note 6. smi130_set_fifo_accel_enable + * @note 7. smi130_set_fifo_gyro_enable + * @note For interrupt configuration + * @note 1. smi130_set_intr_fifo_full + * @note 2. smi130_set_intr_fifo_wm + * @note 3. smi130_set_fifo_tag_intr2_enable + * @note 4. smi130_set_fifo_tag_intr1_enable + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE +smi130_read_fifo_headerless_mode_user_defined_length( +u16 v_fifo_user_length_u16); +/*! + * @brief This function used for reading the + * fifo data of header mode + * + * + * @note Configure the below functions for FIFO header mode + * @note 1. smi130_set_fifo_down_gyro() + * @note 2. smi130_set_gyro_fifo_filter_data() + * @note 3. smi130_set_fifo_down_accel() + * @note 4. smi130_set_accel_fifo_filter_dat() + * @note 5. smi130_set_fifo_mag_enable() + * @note 6. smi130_set_fifo_accel_enable() + * @note 7. smi130_set_fifo_gyro_enable() + * @note 8. smi130_set_fifo_header_enable() + * @note For interrupt configuration + * @note 1. smi130_set_intr_fifo_full() + * @note 2. smi130_set_intr_fifo_wm() + * @note 3. smi130_set_fifo_tag_intr2_enable() + * @note 4. smi130_set_fifo_tag_intr1_enable() + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_read_fifo_header_data( +void); +/*! + * @brief This function used for reading the + * fifo data of header mode for using user defined length + * + * + * @note Configure the below functions for FIFO header mode + * @note 1. smi130_set_fifo_down_gyro() + * @note 2. smi130_set_gyro_fifo_filter_data() + * @note 3. smi130_set_fifo_down_accel() + * @note 4. smi130_set_accel_fifo_filter_dat() + * @note 5. smi130_set_fifo_mag_enable() + * @note 6. smi130_set_fifo_accel_enable() + * @note 7. smi130_set_fifo_gyro_enable() + * @note 8. smi130_set_fifo_header_enable() + * @note For interrupt configuration + * @note 1. smi130_set_intr_fifo_full() + * @note 2. smi130_set_intr_fifo_wm() + * @note 3. smi130_set_fifo_tag_intr2_enable() + * @note 4. smi130_set_fifo_tag_intr1_enable() + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +SMI130_RETURN_FUNCTION_TYPE smi130_read_fifo_header_data_user_defined_length( +u16 v_fifo_user_length_u16); +/*! + * @brief This function used for reading + * smi130_t structure + * + * @return the reference and values of smi130_t + * + * +*/ +struct smi130_t *smi130_get_ptr(void); + +#endif + diff --git a/drivers/input/sensors/smi130/smi130_acc.c b/drivers/input/sensors/smi130/smi130_acc.c new file mode 100644 index 0000000000000000000000000000000000000000..22645399549214fe3bcbad82ac46c9f962526884 --- /dev/null +++ b/drivers/input/sensors/smi130/smi130_acc.c @@ -0,0 +1,7835 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename smi130_acc.c + * @date 2015/11/17 10:32 + * @Modification Date 2018/08/28 18:20 + * @id "836294d" + * @version 2.1.2 + * + * @brief + * This file contains all function implementations for the SMI_ACC2X2 in linux +*/ + +#ifdef CONFIG_SIG_MOTION +#undef CONFIG_HAS_EARLYSUSPEND +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#else +#include +#include +#include +#endif + +#include "boschclass.h" +#include "bs_log.h" +#define DRIVER_VERSION "0.0.53.0" +#define ACC_NAME "ACC" +#define SMI_ACC2X2_ENABLE_INT2 1 +#define CONFIG_SMI_ACC_ENABLE_NEWDATA_INT 1 + +#define SENSOR_NAME "smi130_acc" +#define SMI130_ACC_USE_BASIC_I2C_FUNC 1 +#define SMI130_HRTIMER 1 +#define MSC_TIME 6 +#define ABSMIN -512 +#define ABSMAX 512 +#define SLOPE_THRESHOLD_VALUE 32 +#define SLOPE_DURATION_VALUE 1 +#define INTERRUPT_LATCH_MODE 13 +#define INTERRUPT_ENABLE 1 +#define INTERRUPT_DISABLE 0 +#define MAP_SLOPE_INTERRUPT 2 +#define SLOPE_X_INDEX 5 +#define SLOPE_Y_INDEX 6 +#define SLOPE_Z_INDEX 7 +#define SMI_ACC2X2_MAX_DELAY 200 +#define SMI_ACC2X2_RANGE_SET 3 /* +/- 2G */ +#define SMI_ACC2X2_BW_SET 12 /* 125HZ */ + +#define LOW_G_INTERRUPT REL_Z +#define HIGH_G_INTERRUPT REL_HWHEEL +#define SLOP_INTERRUPT REL_DIAL +#define DOUBLE_TAP_INTERRUPT REL_WHEEL +#define SINGLE_TAP_INTERRUPT REL_MISC +#define ORIENT_INTERRUPT ABS_PRESSURE +#define FLAT_INTERRUPT ABS_DISTANCE +#define SLOW_NO_MOTION_INTERRUPT REL_Y + +#define HIGH_G_INTERRUPT_X_HAPPENED 1 +#define HIGH_G_INTERRUPT_Y_HAPPENED 2 +#define HIGH_G_INTERRUPT_Z_HAPPENED 3 +#define HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED 4 +#define HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED 5 +#define HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED 6 +#define SLOPE_INTERRUPT_X_HAPPENED 7 +#define SLOPE_INTERRUPT_Y_HAPPENED 8 +#define SLOPE_INTERRUPT_Z_HAPPENED 9 +#define SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED 10 +#define SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED 11 +#define SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED 12 +#define DOUBLE_TAP_INTERRUPT_HAPPENED 13 +#define SINGLE_TAP_INTERRUPT_HAPPENED 14 +#define UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 15 +#define UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 16 +#define UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 17 +#define UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 18 +#define DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 19 +#define DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 20 +#define DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 21 +#define DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 22 +#define FLAT_INTERRUPT_TURE_HAPPENED 23 +#define FLAT_INTERRUPT_FALSE_HAPPENED 24 +#define LOW_G_INTERRUPT_HAPPENED 25 +#define SLOW_NO_MOTION_INTERRUPT_HAPPENED 26 + +#define PAD_LOWG 0 +#define PAD_HIGHG 1 +#define PAD_SLOP 2 +#define PAD_DOUBLE_TAP 3 +#define PAD_SINGLE_TAP 4 +#define PAD_ORIENT 5 +#define PAD_FLAT 6 +#define PAD_SLOW_NO_MOTION 7 + +#define SMI_ACC2X2_EEP_OFFSET 0x16 +#define SMI_ACC2X2_IMAGE_BASE 0x38 +#define SMI_ACC2X2_IMAGE_LEN 22 + +#define SMI_ACC2X2_CHIP_ID_REG 0x00 +#define SMI_ACC2X2_VERSION_REG 0x01 +#define SMI_ACC2X2_X_AXIS_LSB_REG 0x02 +#define SMI_ACC2X2_X_AXIS_MSB_REG 0x03 +#define SMI_ACC2X2_Y_AXIS_LSB_REG 0x04 +#define SMI_ACC2X2_Y_AXIS_MSB_REG 0x05 +#define SMI_ACC2X2_Z_AXIS_LSB_REG 0x06 +#define SMI_ACC2X2_Z_AXIS_MSB_REG 0x07 +#define SMI_ACC2X2_TEMPERATURE_REG 0x08 +#define SMI_ACC2X2_STATUS1_REG 0x09 +#define SMI_ACC2X2_STATUS2_REG 0x0A +#define SMI_ACC2X2_STATUS_TAP_SLOPE_REG 0x0B +#define SMI_ACC2X2_STATUS_ORIENT_HIGH_REG 0x0C +#define SMI_ACC2X2_STATUS_FIFO_REG 0x0E +#define SMI_ACC2X2_RANGE_SEL_REG 0x0F +#define SMI_ACC2X2_BW_SEL_REG 0x10 +#define SMI_ACC2X2_MODE_CTRL_REG 0x11 +#define SMI_ACC2X2_LOW_NOISE_CTRL_REG 0x12 +#define SMI_ACC2X2_DATA_CTRL_REG 0x13 +#define SMI_ACC2X2_RESET_REG 0x14 +#define SMI_ACC2X2_INT_ENABLE1_REG 0x16 +#define SMI_ACC2X2_INT_ENABLE2_REG 0x17 +#define SMI_ACC2X2_INT_SLO_NO_MOT_REG 0x18 +#define SMI_ACC2X2_INT1_PAD_SEL_REG 0x19 +#define SMI_ACC2X2_INT_DATA_SEL_REG 0x1A +#define SMI_ACC2X2_INT2_PAD_SEL_REG 0x1B +#define SMI_ACC2X2_INT_SRC_REG 0x1E +#define SMI_ACC2X2_INT_SET_REG 0x20 +#define SMI_ACC2X2_INT_CTRL_REG 0x21 +#define SMI_ACC2X2_LOW_DURN_REG 0x22 +#define SMI_ACC2X2_LOW_THRES_REG 0x23 +#define SMI_ACC2X2_LOW_HIGH_HYST_REG 0x24 +#define SMI_ACC2X2_HIGH_DURN_REG 0x25 +#define SMI_ACC2X2_HIGH_THRES_REG 0x26 +#define SMI_ACC2X2_SLOPE_DURN_REG 0x27 +#define SMI_ACC2X2_SLOPE_THRES_REG 0x28 +#define SMI_ACC2X2_SLO_NO_MOT_THRES_REG 0x29 +#define SMI_ACC2X2_TAP_PARAM_REG 0x2A +#define SMI_ACC2X2_TAP_THRES_REG 0x2B +#define SMI_ACC2X2_ORIENT_PARAM_REG 0x2C +#define SMI_ACC2X2_THETA_BLOCK_REG 0x2D +#define SMI_ACC2X2_THETA_FLAT_REG 0x2E +#define SMI_ACC2X2_FLAT_HOLD_TIME_REG 0x2F +#define SMI_ACC2X2_FIFO_WML_TRIG 0x30 +#define SMI_ACC2X2_SELF_TEST_REG 0x32 +#define SMI_ACC2X2_EEPROM_CTRL_REG 0x33 +#define SMI_ACC2X2_SERIAL_CTRL_REG 0x34 +#define SMI_ACC2X2_EXTMODE_CTRL_REG 0x35 +#define SMI_ACC2X2_OFFSET_CTRL_REG 0x36 +#define SMI_ACC2X2_OFFSET_PARAMS_REG 0x37 +#define SMI_ACC2X2_OFFSET_X_AXIS_REG 0x38 +#define SMI_ACC2X2_OFFSET_Y_AXIS_REG 0x39 +#define SMI_ACC2X2_OFFSET_Z_AXIS_REG 0x3A +#define SMI_ACC2X2_GP0_REG 0x3B +#define SMI_ACC2X2_GP1_REG 0x3C +#define SMI_ACC2X2_FIFO_MODE_REG 0x3E +#define SMI_ACC2X2_FIFO_DATA_OUTPUT_REG 0x3F + +#define SMI_ACC2X2_CHIP_ID__POS 0 +#define SMI_ACC2X2_CHIP_ID__MSK 0xFF +#define SMI_ACC2X2_CHIP_ID__LEN 8 +#define SMI_ACC2X2_CHIP_ID__REG SMI_ACC2X2_CHIP_ID_REG + +#define SMI_ACC2X2_VERSION__POS 0 +#define SMI_ACC2X2_VERSION__LEN 8 +#define SMI_ACC2X2_VERSION__MSK 0xFF +#define SMI_ACC2X2_VERSION__REG SMI_ACC2X2_VERSION_REG + +#define SMI130_ACC_SLO_NO_MOT_DUR__POS 2 +#define SMI130_ACC_SLO_NO_MOT_DUR__LEN 6 +#define SMI130_ACC_SLO_NO_MOT_DUR__MSK 0xFC +#define SMI130_ACC_SLO_NO_MOT_DUR__REG SMI_ACC2X2_SLOPE_DURN_REG + +#define SMI_ACC2X2_NEW_DATA_X__POS 0 +#define SMI_ACC2X2_NEW_DATA_X__LEN 1 +#define SMI_ACC2X2_NEW_DATA_X__MSK 0x01 +#define SMI_ACC2X2_NEW_DATA_X__REG SMI_ACC2X2_X_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_X14_LSB__POS 2 +#define SMI_ACC2X2_ACC_X14_LSB__LEN 6 +#define SMI_ACC2X2_ACC_X14_LSB__MSK 0xFC +#define SMI_ACC2X2_ACC_X14_LSB__REG SMI_ACC2X2_X_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_X12_LSB__POS 4 +#define SMI_ACC2X2_ACC_X12_LSB__LEN 4 +#define SMI_ACC2X2_ACC_X12_LSB__MSK 0xF0 +#define SMI_ACC2X2_ACC_X12_LSB__REG SMI_ACC2X2_X_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_X10_LSB__POS 6 +#define SMI_ACC2X2_ACC_X10_LSB__LEN 2 +#define SMI_ACC2X2_ACC_X10_LSB__MSK 0xC0 +#define SMI_ACC2X2_ACC_X10_LSB__REG SMI_ACC2X2_X_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_X8_LSB__POS 0 +#define SMI_ACC2X2_ACC_X8_LSB__LEN 0 +#define SMI_ACC2X2_ACC_X8_LSB__MSK 0x00 +#define SMI_ACC2X2_ACC_X8_LSB__REG SMI_ACC2X2_X_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_X_MSB__POS 0 +#define SMI_ACC2X2_ACC_X_MSB__LEN 8 +#define SMI_ACC2X2_ACC_X_MSB__MSK 0xFF +#define SMI_ACC2X2_ACC_X_MSB__REG SMI_ACC2X2_X_AXIS_MSB_REG + +#define SMI_ACC2X2_NEW_DATA_Y__POS 0 +#define SMI_ACC2X2_NEW_DATA_Y__LEN 1 +#define SMI_ACC2X2_NEW_DATA_Y__MSK 0x01 +#define SMI_ACC2X2_NEW_DATA_Y__REG SMI_ACC2X2_Y_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Y14_LSB__POS 2 +#define SMI_ACC2X2_ACC_Y14_LSB__LEN 6 +#define SMI_ACC2X2_ACC_Y14_LSB__MSK 0xFC +#define SMI_ACC2X2_ACC_Y14_LSB__REG SMI_ACC2X2_Y_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Y12_LSB__POS 4 +#define SMI_ACC2X2_ACC_Y12_LSB__LEN 4 +#define SMI_ACC2X2_ACC_Y12_LSB__MSK 0xF0 +#define SMI_ACC2X2_ACC_Y12_LSB__REG SMI_ACC2X2_Y_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Y10_LSB__POS 6 +#define SMI_ACC2X2_ACC_Y10_LSB__LEN 2 +#define SMI_ACC2X2_ACC_Y10_LSB__MSK 0xC0 +#define SMI_ACC2X2_ACC_Y10_LSB__REG SMI_ACC2X2_Y_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Y8_LSB__POS 0 +#define SMI_ACC2X2_ACC_Y8_LSB__LEN 0 +#define SMI_ACC2X2_ACC_Y8_LSB__MSK 0x00 +#define SMI_ACC2X2_ACC_Y8_LSB__REG SMI_ACC2X2_Y_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Y_MSB__POS 0 +#define SMI_ACC2X2_ACC_Y_MSB__LEN 8 +#define SMI_ACC2X2_ACC_Y_MSB__MSK 0xFF +#define SMI_ACC2X2_ACC_Y_MSB__REG SMI_ACC2X2_Y_AXIS_MSB_REG + +#define SMI_ACC2X2_NEW_DATA_Z__POS 0 +#define SMI_ACC2X2_NEW_DATA_Z__LEN 1 +#define SMI_ACC2X2_NEW_DATA_Z__MSK 0x01 +#define SMI_ACC2X2_NEW_DATA_Z__REG SMI_ACC2X2_Z_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Z14_LSB__POS 2 +#define SMI_ACC2X2_ACC_Z14_LSB__LEN 6 +#define SMI_ACC2X2_ACC_Z14_LSB__MSK 0xFC +#define SMI_ACC2X2_ACC_Z14_LSB__REG SMI_ACC2X2_Z_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Z12_LSB__POS 4 +#define SMI_ACC2X2_ACC_Z12_LSB__LEN 4 +#define SMI_ACC2X2_ACC_Z12_LSB__MSK 0xF0 +#define SMI_ACC2X2_ACC_Z12_LSB__REG SMI_ACC2X2_Z_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Z10_LSB__POS 6 +#define SMI_ACC2X2_ACC_Z10_LSB__LEN 2 +#define SMI_ACC2X2_ACC_Z10_LSB__MSK 0xC0 +#define SMI_ACC2X2_ACC_Z10_LSB__REG SMI_ACC2X2_Z_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Z8_LSB__POS 0 +#define SMI_ACC2X2_ACC_Z8_LSB__LEN 0 +#define SMI_ACC2X2_ACC_Z8_LSB__MSK 0x00 +#define SMI_ACC2X2_ACC_Z8_LSB__REG SMI_ACC2X2_Z_AXIS_LSB_REG + +#define SMI_ACC2X2_ACC_Z_MSB__POS 0 +#define SMI_ACC2X2_ACC_Z_MSB__LEN 8 +#define SMI_ACC2X2_ACC_Z_MSB__MSK 0xFF +#define SMI_ACC2X2_ACC_Z_MSB__REG SMI_ACC2X2_Z_AXIS_MSB_REG + +#define SMI_ACC2X2_TEMPERATURE__POS 0 +#define SMI_ACC2X2_TEMPERATURE__LEN 8 +#define SMI_ACC2X2_TEMPERATURE__MSK 0xFF +#define SMI_ACC2X2_TEMPERATURE__REG SMI_ACC2X2_TEMP_RD_REG + +#define SMI_ACC2X2_LOWG_INT_S__POS 0 +#define SMI_ACC2X2_LOWG_INT_S__LEN 1 +#define SMI_ACC2X2_LOWG_INT_S__MSK 0x01 +#define SMI_ACC2X2_LOWG_INT_S__REG SMI_ACC2X2_STATUS1_REG + +#define SMI_ACC2X2_HIGHG_INT_S__POS 1 +#define SMI_ACC2X2_HIGHG_INT_S__LEN 1 +#define SMI_ACC2X2_HIGHG_INT_S__MSK 0x02 +#define SMI_ACC2X2_HIGHG_INT_S__REG SMI_ACC2X2_STATUS1_REG + +#define SMI_ACC2X2_SLOPE_INT_S__POS 2 +#define SMI_ACC2X2_SLOPE_INT_S__LEN 1 +#define SMI_ACC2X2_SLOPE_INT_S__MSK 0x04 +#define SMI_ACC2X2_SLOPE_INT_S__REG SMI_ACC2X2_STATUS1_REG + + +#define SMI_ACC2X2_SLO_NO_MOT_INT_S__POS 3 +#define SMI_ACC2X2_SLO_NO_MOT_INT_S__LEN 1 +#define SMI_ACC2X2_SLO_NO_MOT_INT_S__MSK 0x08 +#define SMI_ACC2X2_SLO_NO_MOT_INT_S__REG SMI_ACC2X2_STATUS1_REG + +#define SMI_ACC2X2_DOUBLE_TAP_INT_S__POS 4 +#define SMI_ACC2X2_DOUBLE_TAP_INT_S__LEN 1 +#define SMI_ACC2X2_DOUBLE_TAP_INT_S__MSK 0x10 +#define SMI_ACC2X2_DOUBLE_TAP_INT_S__REG SMI_ACC2X2_STATUS1_REG + +#define SMI_ACC2X2_SINGLE_TAP_INT_S__POS 5 +#define SMI_ACC2X2_SINGLE_TAP_INT_S__LEN 1 +#define SMI_ACC2X2_SINGLE_TAP_INT_S__MSK 0x20 +#define SMI_ACC2X2_SINGLE_TAP_INT_S__REG SMI_ACC2X2_STATUS1_REG + +#define SMI_ACC2X2_ORIENT_INT_S__POS 6 +#define SMI_ACC2X2_ORIENT_INT_S__LEN 1 +#define SMI_ACC2X2_ORIENT_INT_S__MSK 0x40 +#define SMI_ACC2X2_ORIENT_INT_S__REG SMI_ACC2X2_STATUS1_REG + +#define SMI_ACC2X2_FLAT_INT_S__POS 7 +#define SMI_ACC2X2_FLAT_INT_S__LEN 1 +#define SMI_ACC2X2_FLAT_INT_S__MSK 0x80 +#define SMI_ACC2X2_FLAT_INT_S__REG SMI_ACC2X2_STATUS1_REG + +#define SMI_ACC2X2_FIFO_FULL_INT_S__POS 5 +#define SMI_ACC2X2_FIFO_FULL_INT_S__LEN 1 +#define SMI_ACC2X2_FIFO_FULL_INT_S__MSK 0x20 +#define SMI_ACC2X2_FIFO_FULL_INT_S__REG SMI_ACC2X2_STATUS2_REG + +#define SMI_ACC2X2_FIFO_WM_INT_S__POS 6 +#define SMI_ACC2X2_FIFO_WM_INT_S__LEN 1 +#define SMI_ACC2X2_FIFO_WM_INT_S__MSK 0x40 +#define SMI_ACC2X2_FIFO_WM_INT_S__REG SMI_ACC2X2_STATUS2_REG + +#define SMI_ACC2X2_DATA_INT_S__POS 7 +#define SMI_ACC2X2_DATA_INT_S__LEN 1 +#define SMI_ACC2X2_DATA_INT_S__MSK 0x80 +#define SMI_ACC2X2_DATA_INT_S__REG SMI_ACC2X2_STATUS2_REG + +#define SMI_ACC2X2_SLOPE_FIRST_X__POS 0 +#define SMI_ACC2X2_SLOPE_FIRST_X__LEN 1 +#define SMI_ACC2X2_SLOPE_FIRST_X__MSK 0x01 +#define SMI_ACC2X2_SLOPE_FIRST_X__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_SLOPE_FIRST_Y__POS 1 +#define SMI_ACC2X2_SLOPE_FIRST_Y__LEN 1 +#define SMI_ACC2X2_SLOPE_FIRST_Y__MSK 0x02 +#define SMI_ACC2X2_SLOPE_FIRST_Y__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_SLOPE_FIRST_Z__POS 2 +#define SMI_ACC2X2_SLOPE_FIRST_Z__LEN 1 +#define SMI_ACC2X2_SLOPE_FIRST_Z__MSK 0x04 +#define SMI_ACC2X2_SLOPE_FIRST_Z__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_SLOPE_SIGN_S__POS 3 +#define SMI_ACC2X2_SLOPE_SIGN_S__LEN 1 +#define SMI_ACC2X2_SLOPE_SIGN_S__MSK 0x08 +#define SMI_ACC2X2_SLOPE_SIGN_S__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_TAP_FIRST_X__POS 4 +#define SMI_ACC2X2_TAP_FIRST_X__LEN 1 +#define SMI_ACC2X2_TAP_FIRST_X__MSK 0x10 +#define SMI_ACC2X2_TAP_FIRST_X__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_TAP_FIRST_Y__POS 5 +#define SMI_ACC2X2_TAP_FIRST_Y__LEN 1 +#define SMI_ACC2X2_TAP_FIRST_Y__MSK 0x20 +#define SMI_ACC2X2_TAP_FIRST_Y__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_TAP_FIRST_Z__POS 6 +#define SMI_ACC2X2_TAP_FIRST_Z__LEN 1 +#define SMI_ACC2X2_TAP_FIRST_Z__MSK 0x40 +#define SMI_ACC2X2_TAP_FIRST_Z__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_TAP_SIGN_S__POS 7 +#define SMI_ACC2X2_TAP_SIGN_S__LEN 1 +#define SMI_ACC2X2_TAP_SIGN_S__MSK 0x80 +#define SMI_ACC2X2_TAP_SIGN_S__REG SMI_ACC2X2_STATUS_TAP_SLOPE_REG + +#define SMI_ACC2X2_HIGHG_FIRST_X__POS 0 +#define SMI_ACC2X2_HIGHG_FIRST_X__LEN 1 +#define SMI_ACC2X2_HIGHG_FIRST_X__MSK 0x01 +#define SMI_ACC2X2_HIGHG_FIRST_X__REG SMI_ACC2X2_STATUS_ORIENT_HIGH_REG + +#define SMI_ACC2X2_HIGHG_FIRST_Y__POS 1 +#define SMI_ACC2X2_HIGHG_FIRST_Y__LEN 1 +#define SMI_ACC2X2_HIGHG_FIRST_Y__MSK 0x02 +#define SMI_ACC2X2_HIGHG_FIRST_Y__REG SMI_ACC2X2_STATUS_ORIENT_HIGH_REG + +#define SMI_ACC2X2_HIGHG_FIRST_Z__POS 2 +#define SMI_ACC2X2_HIGHG_FIRST_Z__LEN 1 +#define SMI_ACC2X2_HIGHG_FIRST_Z__MSK 0x04 +#define SMI_ACC2X2_HIGHG_FIRST_Z__REG SMI_ACC2X2_STATUS_ORIENT_HIGH_REG + +#define SMI_ACC2X2_HIGHG_SIGN_S__POS 3 +#define SMI_ACC2X2_HIGHG_SIGN_S__LEN 1 +#define SMI_ACC2X2_HIGHG_SIGN_S__MSK 0x08 +#define SMI_ACC2X2_HIGHG_SIGN_S__REG SMI_ACC2X2_STATUS_ORIENT_HIGH_REG + +#define SMI_ACC2X2_ORIENT_S__POS 4 +#define SMI_ACC2X2_ORIENT_S__LEN 3 +#define SMI_ACC2X2_ORIENT_S__MSK 0x70 +#define SMI_ACC2X2_ORIENT_S__REG SMI_ACC2X2_STATUS_ORIENT_HIGH_REG + +#define SMI_ACC2X2_FLAT_S__POS 7 +#define SMI_ACC2X2_FLAT_S__LEN 1 +#define SMI_ACC2X2_FLAT_S__MSK 0x80 +#define SMI_ACC2X2_FLAT_S__REG SMI_ACC2X2_STATUS_ORIENT_HIGH_REG + +#define SMI_ACC2X2_FIFO_FRAME_COUNTER_S__POS 0 +#define SMI_ACC2X2_FIFO_FRAME_COUNTER_S__LEN 7 +#define SMI_ACC2X2_FIFO_FRAME_COUNTER_S__MSK 0x7F +#define SMI_ACC2X2_FIFO_FRAME_COUNTER_S__REG SMI_ACC2X2_STATUS_FIFO_REG + +#define SMI_ACC2X2_FIFO_OVERRUN_S__POS 7 +#define SMI_ACC2X2_FIFO_OVERRUN_S__LEN 1 +#define SMI_ACC2X2_FIFO_OVERRUN_S__MSK 0x80 +#define SMI_ACC2X2_FIFO_OVERRUN_S__REG SMI_ACC2X2_STATUS_FIFO_REG + +#define SMI_ACC2X2_RANGE_SEL__POS 0 +#define SMI_ACC2X2_RANGE_SEL__LEN 4 +#define SMI_ACC2X2_RANGE_SEL__MSK 0x0F +#define SMI_ACC2X2_RANGE_SEL__REG SMI_ACC2X2_RANGE_SEL_REG + +#define SMI_ACC2X2_BANDWIDTH__POS 0 +#define SMI_ACC2X2_BANDWIDTH__LEN 5 +#define SMI_ACC2X2_BANDWIDTH__MSK 0x1F +#define SMI_ACC2X2_BANDWIDTH__REG SMI_ACC2X2_BW_SEL_REG + +#define SMI_ACC2X2_SLEEP_DUR__POS 1 +#define SMI_ACC2X2_SLEEP_DUR__LEN 4 +#define SMI_ACC2X2_SLEEP_DUR__MSK 0x1E +#define SMI_ACC2X2_SLEEP_DUR__REG SMI_ACC2X2_MODE_CTRL_REG + +#define SMI_ACC2X2_MODE_CTRL__POS 5 +#define SMI_ACC2X2_MODE_CTRL__LEN 3 +#define SMI_ACC2X2_MODE_CTRL__MSK 0xE0 +#define SMI_ACC2X2_MODE_CTRL__REG SMI_ACC2X2_MODE_CTRL_REG + +#define SMI_ACC2X2_DEEP_SUSPEND__POS 5 +#define SMI_ACC2X2_DEEP_SUSPEND__LEN 1 +#define SMI_ACC2X2_DEEP_SUSPEND__MSK 0x20 +#define SMI_ACC2X2_DEEP_SUSPEND__REG SMI_ACC2X2_MODE_CTRL_REG + +#define SMI_ACC2X2_EN_LOW_POWER__POS 6 +#define SMI_ACC2X2_EN_LOW_POWER__LEN 1 +#define SMI_ACC2X2_EN_LOW_POWER__MSK 0x40 +#define SMI_ACC2X2_EN_LOW_POWER__REG SMI_ACC2X2_MODE_CTRL_REG + +#define SMI_ACC2X2_EN_SUSPEND__POS 7 +#define SMI_ACC2X2_EN_SUSPEND__LEN 1 +#define SMI_ACC2X2_EN_SUSPEND__MSK 0x80 +#define SMI_ACC2X2_EN_SUSPEND__REG SMI_ACC2X2_MODE_CTRL_REG + +#define SMI_ACC2X2_SLEEP_TIMER__POS 5 +#define SMI_ACC2X2_SLEEP_TIMER__LEN 1 +#define SMI_ACC2X2_SLEEP_TIMER__MSK 0x20 +#define SMI_ACC2X2_SLEEP_TIMER__REG SMI_ACC2X2_LOW_NOISE_CTRL_REG + +#define SMI_ACC2X2_LOW_POWER_MODE__POS 6 +#define SMI_ACC2X2_LOW_POWER_MODE__LEN 1 +#define SMI_ACC2X2_LOW_POWER_MODE__MSK 0x40 +#define SMI_ACC2X2_LOW_POWER_MODE__REG SMI_ACC2X2_LOW_NOISE_CTRL_REG + +#define SMI_ACC2X2_EN_LOW_NOISE__POS 7 +#define SMI_ACC2X2_EN_LOW_NOISE__LEN 1 +#define SMI_ACC2X2_EN_LOW_NOISE__MSK 0x80 +#define SMI_ACC2X2_EN_LOW_NOISE__REG SMI_ACC2X2_LOW_NOISE_CTRL_REG + +#define SMI_ACC2X2_DIS_SHADOW_PROC__POS 6 +#define SMI_ACC2X2_DIS_SHADOW_PROC__LEN 1 +#define SMI_ACC2X2_DIS_SHADOW_PROC__MSK 0x40 +#define SMI_ACC2X2_DIS_SHADOW_PROC__REG SMI_ACC2X2_DATA_CTRL_REG + +#define SMI_ACC2X2_EN_DATA_HIGH_BW__POS 7 +#define SMI_ACC2X2_EN_DATA_HIGH_BW__LEN 1 +#define SMI_ACC2X2_EN_DATA_HIGH_BW__MSK 0x80 +#define SMI_ACC2X2_EN_DATA_HIGH_BW__REG SMI_ACC2X2_DATA_CTRL_REG + +#define SMI_ACC2X2_EN_SOFT_RESET__POS 0 +#define SMI_ACC2X2_EN_SOFT_RESET__LEN 8 +#define SMI_ACC2X2_EN_SOFT_RESET__MSK 0xFF +#define SMI_ACC2X2_EN_SOFT_RESET__REG SMI_ACC2X2_RESET_REG + +#define SMI_ACC2X2_EN_SOFT_RESET_VALUE 0xB6 + +#define SMI_ACC2X2_EN_SLOPE_X_INT__POS 0 +#define SMI_ACC2X2_EN_SLOPE_X_INT__LEN 1 +#define SMI_ACC2X2_EN_SLOPE_X_INT__MSK 0x01 +#define SMI_ACC2X2_EN_SLOPE_X_INT__REG SMI_ACC2X2_INT_ENABLE1_REG + +#define SMI_ACC2X2_EN_SLOPE_Y_INT__POS 1 +#define SMI_ACC2X2_EN_SLOPE_Y_INT__LEN 1 +#define SMI_ACC2X2_EN_SLOPE_Y_INT__MSK 0x02 +#define SMI_ACC2X2_EN_SLOPE_Y_INT__REG SMI_ACC2X2_INT_ENABLE1_REG + +#define SMI_ACC2X2_EN_SLOPE_Z_INT__POS 2 +#define SMI_ACC2X2_EN_SLOPE_Z_INT__LEN 1 +#define SMI_ACC2X2_EN_SLOPE_Z_INT__MSK 0x04 +#define SMI_ACC2X2_EN_SLOPE_Z_INT__REG SMI_ACC2X2_INT_ENABLE1_REG + +#define SMI_ACC2X2_EN_DOUBLE_TAP_INT__POS 4 +#define SMI_ACC2X2_EN_DOUBLE_TAP_INT__LEN 1 +#define SMI_ACC2X2_EN_DOUBLE_TAP_INT__MSK 0x10 +#define SMI_ACC2X2_EN_DOUBLE_TAP_INT__REG SMI_ACC2X2_INT_ENABLE1_REG + +#define SMI_ACC2X2_EN_SINGLE_TAP_INT__POS 5 +#define SMI_ACC2X2_EN_SINGLE_TAP_INT__LEN 1 +#define SMI_ACC2X2_EN_SINGLE_TAP_INT__MSK 0x20 +#define SMI_ACC2X2_EN_SINGLE_TAP_INT__REG SMI_ACC2X2_INT_ENABLE1_REG + +#define SMI_ACC2X2_EN_ORIENT_INT__POS 6 +#define SMI_ACC2X2_EN_ORIENT_INT__LEN 1 +#define SMI_ACC2X2_EN_ORIENT_INT__MSK 0x40 +#define SMI_ACC2X2_EN_ORIENT_INT__REG SMI_ACC2X2_INT_ENABLE1_REG + +#define SMI_ACC2X2_EN_FLAT_INT__POS 7 +#define SMI_ACC2X2_EN_FLAT_INT__LEN 1 +#define SMI_ACC2X2_EN_FLAT_INT__MSK 0x80 +#define SMI_ACC2X2_EN_FLAT_INT__REG SMI_ACC2X2_INT_ENABLE1_REG + +#define SMI_ACC2X2_EN_HIGHG_X_INT__POS 0 +#define SMI_ACC2X2_EN_HIGHG_X_INT__LEN 1 +#define SMI_ACC2X2_EN_HIGHG_X_INT__MSK 0x01 +#define SMI_ACC2X2_EN_HIGHG_X_INT__REG SMI_ACC2X2_INT_ENABLE2_REG + +#define SMI_ACC2X2_EN_HIGHG_Y_INT__POS 1 +#define SMI_ACC2X2_EN_HIGHG_Y_INT__LEN 1 +#define SMI_ACC2X2_EN_HIGHG_Y_INT__MSK 0x02 +#define SMI_ACC2X2_EN_HIGHG_Y_INT__REG SMI_ACC2X2_INT_ENABLE2_REG + +#define SMI_ACC2X2_EN_HIGHG_Z_INT__POS 2 +#define SMI_ACC2X2_EN_HIGHG_Z_INT__LEN 1 +#define SMI_ACC2X2_EN_HIGHG_Z_INT__MSK 0x04 +#define SMI_ACC2X2_EN_HIGHG_Z_INT__REG SMI_ACC2X2_INT_ENABLE2_REG + +#define SMI_ACC2X2_EN_LOWG_INT__POS 3 +#define SMI_ACC2X2_EN_LOWG_INT__LEN 1 +#define SMI_ACC2X2_EN_LOWG_INT__MSK 0x08 +#define SMI_ACC2X2_EN_LOWG_INT__REG SMI_ACC2X2_INT_ENABLE2_REG + +#define SMI_ACC2X2_EN_NEW_DATA_INT__POS 4 +#define SMI_ACC2X2_EN_NEW_DATA_INT__LEN 1 +#define SMI_ACC2X2_EN_NEW_DATA_INT__MSK 0x10 +#define SMI_ACC2X2_EN_NEW_DATA_INT__REG SMI_ACC2X2_INT_ENABLE2_REG + +#define SMI_ACC2X2_INT_FFULL_EN_INT__POS 5 +#define SMI_ACC2X2_INT_FFULL_EN_INT__LEN 1 +#define SMI_ACC2X2_INT_FFULL_EN_INT__MSK 0x20 +#define SMI_ACC2X2_INT_FFULL_EN_INT__REG SMI_ACC2X2_INT_ENABLE2_REG + +#define SMI_ACC2X2_INT_FWM_EN_INT__POS 6 +#define SMI_ACC2X2_INT_FWM_EN_INT__LEN 1 +#define SMI_ACC2X2_INT_FWM_EN_INT__MSK 0x40 +#define SMI_ACC2X2_INT_FWM_EN_INT__REG SMI_ACC2X2_INT_ENABLE2_REG + +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_X_INT__POS 0 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_X_INT__LEN 1 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_X_INT__MSK 0x01 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_X_INT__REG SMI_ACC2X2_INT_SLO_NO_MOT_REG + +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Y_INT__POS 1 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Y_INT__LEN 1 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Y_INT__MSK 0x02 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Y_INT__REG SMI_ACC2X2_INT_SLO_NO_MOT_REG + +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Z_INT__POS 2 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Z_INT__LEN 1 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Z_INT__MSK 0x04 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_Z_INT__REG SMI_ACC2X2_INT_SLO_NO_MOT_REG + +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_SEL_INT__POS 3 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_SEL_INT__LEN 1 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_SEL_INT__MSK 0x08 +#define SMI_ACC2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG SMI_ACC2X2_INT_SLO_NO_MOT_REG + +#define SMI_ACC2X2_EN_INT1_PAD_LOWG__POS 0 +#define SMI_ACC2X2_EN_INT1_PAD_LOWG__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_LOWG__MSK 0x01 +#define SMI_ACC2X2_EN_INT1_PAD_LOWG__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_HIGHG__POS 1 +#define SMI_ACC2X2_EN_INT1_PAD_HIGHG__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_HIGHG__MSK 0x02 +#define SMI_ACC2X2_EN_INT1_PAD_HIGHG__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_SLOPE__POS 2 +#define SMI_ACC2X2_EN_INT1_PAD_SLOPE__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_SLOPE__MSK 0x04 +#define SMI_ACC2X2_EN_INT1_PAD_SLOPE__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_SLO_NO_MOT__POS 3 +#define SMI_ACC2X2_EN_INT1_PAD_SLO_NO_MOT__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_SLO_NO_MOT__MSK 0x08 +#define SMI_ACC2X2_EN_INT1_PAD_SLO_NO_MOT__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_DB_TAP__POS 4 +#define SMI_ACC2X2_EN_INT1_PAD_DB_TAP__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_DB_TAP__MSK 0x10 +#define SMI_ACC2X2_EN_INT1_PAD_DB_TAP__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_SNG_TAP__POS 5 +#define SMI_ACC2X2_EN_INT1_PAD_SNG_TAP__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_SNG_TAP__MSK 0x20 +#define SMI_ACC2X2_EN_INT1_PAD_SNG_TAP__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_ORIENT__POS 6 +#define SMI_ACC2X2_EN_INT1_PAD_ORIENT__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_ORIENT__MSK 0x40 +#define SMI_ACC2X2_EN_INT1_PAD_ORIENT__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_FLAT__POS 7 +#define SMI_ACC2X2_EN_INT1_PAD_FLAT__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_FLAT__MSK 0x80 +#define SMI_ACC2X2_EN_INT1_PAD_FLAT__REG SMI_ACC2X2_INT1_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_LOWG__POS 0 +#define SMI_ACC2X2_EN_INT2_PAD_LOWG__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_LOWG__MSK 0x01 +#define SMI_ACC2X2_EN_INT2_PAD_LOWG__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_HIGHG__POS 1 +#define SMI_ACC2X2_EN_INT2_PAD_HIGHG__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_HIGHG__MSK 0x02 +#define SMI_ACC2X2_EN_INT2_PAD_HIGHG__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_SLOPE__POS 2 +#define SMI_ACC2X2_EN_INT2_PAD_SLOPE__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_SLOPE__MSK 0x04 +#define SMI_ACC2X2_EN_INT2_PAD_SLOPE__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_SLO_NO_MOT__POS 3 +#define SMI_ACC2X2_EN_INT2_PAD_SLO_NO_MOT__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_SLO_NO_MOT__MSK 0x08 +#define SMI_ACC2X2_EN_INT2_PAD_SLO_NO_MOT__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_DB_TAP__POS 4 +#define SMI_ACC2X2_EN_INT2_PAD_DB_TAP__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_DB_TAP__MSK 0x10 +#define SMI_ACC2X2_EN_INT2_PAD_DB_TAP__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_SNG_TAP__POS 5 +#define SMI_ACC2X2_EN_INT2_PAD_SNG_TAP__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_SNG_TAP__MSK 0x20 +#define SMI_ACC2X2_EN_INT2_PAD_SNG_TAP__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_ORIENT__POS 6 +#define SMI_ACC2X2_EN_INT2_PAD_ORIENT__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_ORIENT__MSK 0x40 +#define SMI_ACC2X2_EN_INT2_PAD_ORIENT__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_FLAT__POS 7 +#define SMI_ACC2X2_EN_INT2_PAD_FLAT__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_FLAT__MSK 0x80 +#define SMI_ACC2X2_EN_INT2_PAD_FLAT__REG SMI_ACC2X2_INT2_PAD_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_NEWDATA__POS 0 +#define SMI_ACC2X2_EN_INT1_PAD_NEWDATA__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_NEWDATA__MSK 0x01 +#define SMI_ACC2X2_EN_INT1_PAD_NEWDATA__REG SMI_ACC2X2_INT_DATA_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_FWM__POS 1 +#define SMI_ACC2X2_EN_INT1_PAD_FWM__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_FWM__MSK 0x02 +#define SMI_ACC2X2_EN_INT1_PAD_FWM__REG SMI_ACC2X2_INT_DATA_SEL_REG + +#define SMI_ACC2X2_EN_INT1_PAD_FFULL__POS 2 +#define SMI_ACC2X2_EN_INT1_PAD_FFULL__LEN 1 +#define SMI_ACC2X2_EN_INT1_PAD_FFULL__MSK 0x04 +#define SMI_ACC2X2_EN_INT1_PAD_FFULL__REG SMI_ACC2X2_INT_DATA_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_FFULL__POS 5 +#define SMI_ACC2X2_EN_INT2_PAD_FFULL__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_FFULL__MSK 0x20 +#define SMI_ACC2X2_EN_INT2_PAD_FFULL__REG SMI_ACC2X2_INT_DATA_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_FWM__POS 6 +#define SMI_ACC2X2_EN_INT2_PAD_FWM__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_FWM__MSK 0x40 +#define SMI_ACC2X2_EN_INT2_PAD_FWM__REG SMI_ACC2X2_INT_DATA_SEL_REG + +#define SMI_ACC2X2_EN_INT2_PAD_NEWDATA__POS 7 +#define SMI_ACC2X2_EN_INT2_PAD_NEWDATA__LEN 1 +#define SMI_ACC2X2_EN_INT2_PAD_NEWDATA__MSK 0x80 +#define SMI_ACC2X2_EN_INT2_PAD_NEWDATA__REG SMI_ACC2X2_INT_DATA_SEL_REG + +#define SMI_ACC2X2_UNFILT_INT_SRC_LOWG__POS 0 +#define SMI_ACC2X2_UNFILT_INT_SRC_LOWG__LEN 1 +#define SMI_ACC2X2_UNFILT_INT_SRC_LOWG__MSK 0x01 +#define SMI_ACC2X2_UNFILT_INT_SRC_LOWG__REG SMI_ACC2X2_INT_SRC_REG + +#define SMI_ACC2X2_UNFILT_INT_SRC_HIGHG__POS 1 +#define SMI_ACC2X2_UNFILT_INT_SRC_HIGHG__LEN 1 +#define SMI_ACC2X2_UNFILT_INT_SRC_HIGHG__MSK 0x02 +#define SMI_ACC2X2_UNFILT_INT_SRC_HIGHG__REG SMI_ACC2X2_INT_SRC_REG + +#define SMI_ACC2X2_UNFILT_INT_SRC_SLOPE__POS 2 +#define SMI_ACC2X2_UNFILT_INT_SRC_SLOPE__LEN 1 +#define SMI_ACC2X2_UNFILT_INT_SRC_SLOPE__MSK 0x04 +#define SMI_ACC2X2_UNFILT_INT_SRC_SLOPE__REG SMI_ACC2X2_INT_SRC_REG + +#define SMI_ACC2X2_UNFILT_INT_SRC_SLO_NO_MOT__POS 3 +#define SMI_ACC2X2_UNFILT_INT_SRC_SLO_NO_MOT__LEN 1 +#define SMI_ACC2X2_UNFILT_INT_SRC_SLO_NO_MOT__MSK 0x08 +#define SMI_ACC2X2_UNFILT_INT_SRC_SLO_NO_MOT__REG SMI_ACC2X2_INT_SRC_REG + +#define SMI_ACC2X2_UNFILT_INT_SRC_TAP__POS 4 +#define SMI_ACC2X2_UNFILT_INT_SRC_TAP__LEN 1 +#define SMI_ACC2X2_UNFILT_INT_SRC_TAP__MSK 0x10 +#define SMI_ACC2X2_UNFILT_INT_SRC_TAP__REG SMI_ACC2X2_INT_SRC_REG + +#define SMI_ACC2X2_UNFILT_INT_SRC_DATA__POS 5 +#define SMI_ACC2X2_UNFILT_INT_SRC_DATA__LEN 1 +#define SMI_ACC2X2_UNFILT_INT_SRC_DATA__MSK 0x20 +#define SMI_ACC2X2_UNFILT_INT_SRC_DATA__REG SMI_ACC2X2_INT_SRC_REG + +#define SMI_ACC2X2_INT1_PAD_ACTIVE_LEVEL__POS 0 +#define SMI_ACC2X2_INT1_PAD_ACTIVE_LEVEL__LEN 1 +#define SMI_ACC2X2_INT1_PAD_ACTIVE_LEVEL__MSK 0x01 +#define SMI_ACC2X2_INT1_PAD_ACTIVE_LEVEL__REG SMI_ACC2X2_INT_SET_REG + +#define SMI_ACC2X2_INT2_PAD_ACTIVE_LEVEL__POS 2 +#define SMI_ACC2X2_INT2_PAD_ACTIVE_LEVEL__LEN 1 +#define SMI_ACC2X2_INT2_PAD_ACTIVE_LEVEL__MSK 0x04 +#define SMI_ACC2X2_INT2_PAD_ACTIVE_LEVEL__REG SMI_ACC2X2_INT_SET_REG + +#define SMI_ACC2X2_INT1_PAD_OUTPUT_TYPE__POS 1 +#define SMI_ACC2X2_INT1_PAD_OUTPUT_TYPE__LEN 1 +#define SMI_ACC2X2_INT1_PAD_OUTPUT_TYPE__MSK 0x02 +#define SMI_ACC2X2_INT1_PAD_OUTPUT_TYPE__REG SMI_ACC2X2_INT_SET_REG + +#define SMI_ACC2X2_INT2_PAD_OUTPUT_TYPE__POS 3 +#define SMI_ACC2X2_INT2_PAD_OUTPUT_TYPE__LEN 1 +#define SMI_ACC2X2_INT2_PAD_OUTPUT_TYPE__MSK 0x08 +#define SMI_ACC2X2_INT2_PAD_OUTPUT_TYPE__REG SMI_ACC2X2_INT_SET_REG + +#define SMI_ACC2X2_INT_MODE_SEL__POS 0 +#define SMI_ACC2X2_INT_MODE_SEL__LEN 4 +#define SMI_ACC2X2_INT_MODE_SEL__MSK 0x0F +#define SMI_ACC2X2_INT_MODE_SEL__REG SMI_ACC2X2_INT_CTRL_REG + +#define SMI_ACC2X2_RESET_INT__POS 7 +#define SMI_ACC2X2_RESET_INT__LEN 1 +#define SMI_ACC2X2_RESET_INT__MSK 0x80 +#define SMI_ACC2X2_RESET_INT__REG SMI_ACC2X2_INT_CTRL_REG + +#define SMI_ACC2X2_LOWG_DUR__POS 0 +#define SMI_ACC2X2_LOWG_DUR__LEN 8 +#define SMI_ACC2X2_LOWG_DUR__MSK 0xFF +#define SMI_ACC2X2_LOWG_DUR__REG SMI_ACC2X2_LOW_DURN_REG + +#define SMI_ACC2X2_LOWG_THRES__POS 0 +#define SMI_ACC2X2_LOWG_THRES__LEN 8 +#define SMI_ACC2X2_LOWG_THRES__MSK 0xFF +#define SMI_ACC2X2_LOWG_THRES__REG SMI_ACC2X2_LOW_THRES_REG + +#define SMI_ACC2X2_LOWG_HYST__POS 0 +#define SMI_ACC2X2_LOWG_HYST__LEN 2 +#define SMI_ACC2X2_LOWG_HYST__MSK 0x03 +#define SMI_ACC2X2_LOWG_HYST__REG SMI_ACC2X2_LOW_HIGH_HYST_REG + +#define SMI_ACC2X2_LOWG_INT_MODE__POS 2 +#define SMI_ACC2X2_LOWG_INT_MODE__LEN 1 +#define SMI_ACC2X2_LOWG_INT_MODE__MSK 0x04 +#define SMI_ACC2X2_LOWG_INT_MODE__REG SMI_ACC2X2_LOW_HIGH_HYST_REG + +#define SMI_ACC2X2_HIGHG_DUR__POS 0 +#define SMI_ACC2X2_HIGHG_DUR__LEN 8 +#define SMI_ACC2X2_HIGHG_DUR__MSK 0xFF +#define SMI_ACC2X2_HIGHG_DUR__REG SMI_ACC2X2_HIGH_DURN_REG + +#define SMI_ACC2X2_HIGHG_THRES__POS 0 +#define SMI_ACC2X2_HIGHG_THRES__LEN 8 +#define SMI_ACC2X2_HIGHG_THRES__MSK 0xFF +#define SMI_ACC2X2_HIGHG_THRES__REG SMI_ACC2X2_HIGH_THRES_REG + +#define SMI_ACC2X2_HIGHG_HYST__POS 6 +#define SMI_ACC2X2_HIGHG_HYST__LEN 2 +#define SMI_ACC2X2_HIGHG_HYST__MSK 0xC0 +#define SMI_ACC2X2_HIGHG_HYST__REG SMI_ACC2X2_LOW_HIGH_HYST_REG + +#define SMI_ACC2X2_SLOPE_DUR__POS 0 +#define SMI_ACC2X2_SLOPE_DUR__LEN 2 +#define SMI_ACC2X2_SLOPE_DUR__MSK 0x03 +#define SMI_ACC2X2_SLOPE_DUR__REG SMI_ACC2X2_SLOPE_DURN_REG + +#define SMI_ACC2X2_SLO_NO_MOT_DUR__POS 2 +#define SMI_ACC2X2_SLO_NO_MOT_DUR__LEN 6 +#define SMI_ACC2X2_SLO_NO_MOT_DUR__MSK 0xFC +#define SMI_ACC2X2_SLO_NO_MOT_DUR__REG SMI_ACC2X2_SLOPE_DURN_REG + +#define SMI_ACC2X2_SLOPE_THRES__POS 0 +#define SMI_ACC2X2_SLOPE_THRES__LEN 8 +#define SMI_ACC2X2_SLOPE_THRES__MSK 0xFF +#define SMI_ACC2X2_SLOPE_THRES__REG SMI_ACC2X2_SLOPE_THRES_REG + +#define SMI_ACC2X2_SLO_NO_MOT_THRES__POS 0 +#define SMI_ACC2X2_SLO_NO_MOT_THRES__LEN 8 +#define SMI_ACC2X2_SLO_NO_MOT_THRES__MSK 0xFF +#define SMI_ACC2X2_SLO_NO_MOT_THRES__REG SMI_ACC2X2_SLO_NO_MOT_THRES_REG + +#define SMI_ACC2X2_TAP_DUR__POS 0 +#define SMI_ACC2X2_TAP_DUR__LEN 3 +#define SMI_ACC2X2_TAP_DUR__MSK 0x07 +#define SMI_ACC2X2_TAP_DUR__REG SMI_ACC2X2_TAP_PARAM_REG + +#define SMI_ACC2X2_TAP_SHOCK_DURN__POS 6 +#define SMI_ACC2X2_TAP_SHOCK_DURN__LEN 1 +#define SMI_ACC2X2_TAP_SHOCK_DURN__MSK 0x40 +#define SMI_ACC2X2_TAP_SHOCK_DURN__REG SMI_ACC2X2_TAP_PARAM_REG + +#define SMI_ACC2X2_ADV_TAP_INT__POS 5 +#define SMI_ACC2X2_ADV_TAP_INT__LEN 1 +#define SMI_ACC2X2_ADV_TAP_INT__MSK 0x20 +#define SMI_ACC2X2_ADV_TAP_INT__REG SMI_ACC2X2_TAP_PARAM_REG + +#define SMI_ACC2X2_TAP_QUIET_DURN__POS 7 +#define SMI_ACC2X2_TAP_QUIET_DURN__LEN 1 +#define SMI_ACC2X2_TAP_QUIET_DURN__MSK 0x80 +#define SMI_ACC2X2_TAP_QUIET_DURN__REG SMI_ACC2X2_TAP_PARAM_REG + +#define SMI_ACC2X2_TAP_THRES__POS 0 +#define SMI_ACC2X2_TAP_THRES__LEN 5 +#define SMI_ACC2X2_TAP_THRES__MSK 0x1F +#define SMI_ACC2X2_TAP_THRES__REG SMI_ACC2X2_TAP_THRES_REG + +#define SMI_ACC2X2_TAP_SAMPLES__POS 6 +#define SMI_ACC2X2_TAP_SAMPLES__LEN 2 +#define SMI_ACC2X2_TAP_SAMPLES__MSK 0xC0 +#define SMI_ACC2X2_TAP_SAMPLES__REG SMI_ACC2X2_TAP_THRES_REG + +#define SMI_ACC2X2_ORIENT_MODE__POS 0 +#define SMI_ACC2X2_ORIENT_MODE__LEN 2 +#define SMI_ACC2X2_ORIENT_MODE__MSK 0x03 +#define SMI_ACC2X2_ORIENT_MODE__REG SMI_ACC2X2_ORIENT_PARAM_REG + +#define SMI_ACC2X2_ORIENT_BLOCK__POS 2 +#define SMI_ACC2X2_ORIENT_BLOCK__LEN 2 +#define SMI_ACC2X2_ORIENT_BLOCK__MSK 0x0C +#define SMI_ACC2X2_ORIENT_BLOCK__REG SMI_ACC2X2_ORIENT_PARAM_REG + +#define SMI_ACC2X2_ORIENT_HYST__POS 4 +#define SMI_ACC2X2_ORIENT_HYST__LEN 3 +#define SMI_ACC2X2_ORIENT_HYST__MSK 0x70 +#define SMI_ACC2X2_ORIENT_HYST__REG SMI_ACC2X2_ORIENT_PARAM_REG + +#define SMI_ACC2X2_ORIENT_AXIS__POS 7 +#define SMI_ACC2X2_ORIENT_AXIS__LEN 1 +#define SMI_ACC2X2_ORIENT_AXIS__MSK 0x80 +#define SMI_ACC2X2_ORIENT_AXIS__REG SMI_ACC2X2_THETA_BLOCK_REG + +#define SMI_ACC2X2_ORIENT_UD_EN__POS 6 +#define SMI_ACC2X2_ORIENT_UD_EN__LEN 1 +#define SMI_ACC2X2_ORIENT_UD_EN__MSK 0x40 +#define SMI_ACC2X2_ORIENT_UD_EN__REG SMI_ACC2X2_THETA_BLOCK_REG + +#define SMI_ACC2X2_THETA_BLOCK__POS 0 +#define SMI_ACC2X2_THETA_BLOCK__LEN 6 +#define SMI_ACC2X2_THETA_BLOCK__MSK 0x3F +#define SMI_ACC2X2_THETA_BLOCK__REG SMI_ACC2X2_THETA_BLOCK_REG + +#define SMI_ACC2X2_THETA_FLAT__POS 0 +#define SMI_ACC2X2_THETA_FLAT__LEN 6 +#define SMI_ACC2X2_THETA_FLAT__MSK 0x3F +#define SMI_ACC2X2_THETA_FLAT__REG SMI_ACC2X2_THETA_FLAT_REG + +#define SMI_ACC2X2_FLAT_HOLD_TIME__POS 4 +#define SMI_ACC2X2_FLAT_HOLD_TIME__LEN 2 +#define SMI_ACC2X2_FLAT_HOLD_TIME__MSK 0x30 +#define SMI_ACC2X2_FLAT_HOLD_TIME__REG SMI_ACC2X2_FLAT_HOLD_TIME_REG + +#define SMI_ACC2X2_FLAT_HYS__POS 0 +#define SMI_ACC2X2_FLAT_HYS__LEN 3 +#define SMI_ACC2X2_FLAT_HYS__MSK 0x07 +#define SMI_ACC2X2_FLAT_HYS__REG SMI_ACC2X2_FLAT_HOLD_TIME_REG + +#define SMI_ACC2X2_FIFO_WML_TRIG_RETAIN__POS 0 +#define SMI_ACC2X2_FIFO_WML_TRIG_RETAIN__LEN 6 +#define SMI_ACC2X2_FIFO_WML_TRIG_RETAIN__MSK 0x3F +#define SMI_ACC2X2_FIFO_WML_TRIG_RETAIN__REG SMI_ACC2X2_FIFO_WML_TRIG + +#define SMI_ACC2X2_EN_SELF_TEST__POS 0 +#define SMI_ACC2X2_EN_SELF_TEST__LEN 2 +#define SMI_ACC2X2_EN_SELF_TEST__MSK 0x03 +#define SMI_ACC2X2_EN_SELF_TEST__REG SMI_ACC2X2_SELF_TEST_REG + +#define SMI_ACC2X2_NEG_SELF_TEST__POS 2 +#define SMI_ACC2X2_NEG_SELF_TEST__LEN 1 +#define SMI_ACC2X2_NEG_SELF_TEST__MSK 0x04 +#define SMI_ACC2X2_NEG_SELF_TEST__REG SMI_ACC2X2_SELF_TEST_REG + +#define SMI_ACC2X2_SELF_TEST_AMP__POS 4 +#define SMI_ACC2X2_SELF_TEST_AMP__LEN 1 +#define SMI_ACC2X2_SELF_TEST_AMP__MSK 0x10 +#define SMI_ACC2X2_SELF_TEST_AMP__REG SMI_ACC2X2_SELF_TEST_REG + + +#define SMI_ACC2X2_UNLOCK_EE_PROG_MODE__POS 0 +#define SMI_ACC2X2_UNLOCK_EE_PROG_MODE__LEN 1 +#define SMI_ACC2X2_UNLOCK_EE_PROG_MODE__MSK 0x01 +#define SMI_ACC2X2_UNLOCK_EE_PROG_MODE__REG SMI_ACC2X2_EEPROM_CTRL_REG + +#define SMI_ACC2X2_START_EE_PROG_TRIG__POS 1 +#define SMI_ACC2X2_START_EE_PROG_TRIG__LEN 1 +#define SMI_ACC2X2_START_EE_PROG_TRIG__MSK 0x02 +#define SMI_ACC2X2_START_EE_PROG_TRIG__REG SMI_ACC2X2_EEPROM_CTRL_REG + +#define SMI_ACC2X2_EE_PROG_READY__POS 2 +#define SMI_ACC2X2_EE_PROG_READY__LEN 1 +#define SMI_ACC2X2_EE_PROG_READY__MSK 0x04 +#define SMI_ACC2X2_EE_PROG_READY__REG SMI_ACC2X2_EEPROM_CTRL_REG + +#define SMI_ACC2X2_UPDATE_IMAGE__POS 3 +#define SMI_ACC2X2_UPDATE_IMAGE__LEN 1 +#define SMI_ACC2X2_UPDATE_IMAGE__MSK 0x08 +#define SMI_ACC2X2_UPDATE_IMAGE__REG SMI_ACC2X2_EEPROM_CTRL_REG + +#define SMI_ACC2X2_EE_REMAIN__POS 4 +#define SMI_ACC2X2_EE_REMAIN__LEN 4 +#define SMI_ACC2X2_EE_REMAIN__MSK 0xF0 +#define SMI_ACC2X2_EE_REMAIN__REG SMI_ACC2X2_EEPROM_CTRL_REG + +#define SMI_ACC2X2_EN_SPI_MODE_3__POS 0 +#define SMI_ACC2X2_EN_SPI_MODE_3__LEN 1 +#define SMI_ACC2X2_EN_SPI_MODE_3__MSK 0x01 +#define SMI_ACC2X2_EN_SPI_MODE_3__REG SMI_ACC2X2_SERIAL_CTRL_REG + +#define SMI_ACC2X2_I2C_WATCHDOG_PERIOD__POS 1 +#define SMI_ACC2X2_I2C_WATCHDOG_PERIOD__LEN 1 +#define SMI_ACC2X2_I2C_WATCHDOG_PERIOD__MSK 0x02 +#define SMI_ACC2X2_I2C_WATCHDOG_PERIOD__REG SMI_ACC2X2_SERIAL_CTRL_REG + +#define SMI_ACC2X2_EN_I2C_WATCHDOG__POS 2 +#define SMI_ACC2X2_EN_I2C_WATCHDOG__LEN 1 +#define SMI_ACC2X2_EN_I2C_WATCHDOG__MSK 0x04 +#define SMI_ACC2X2_EN_I2C_WATCHDOG__REG SMI_ACC2X2_SERIAL_CTRL_REG + +#define SMI_ACC2X2_EXT_MODE__POS 7 +#define SMI_ACC2X2_EXT_MODE__LEN 1 +#define SMI_ACC2X2_EXT_MODE__MSK 0x80 +#define SMI_ACC2X2_EXT_MODE__REG SMI_ACC2X2_EXTMODE_CTRL_REG + +#define SMI_ACC2X2_ALLOW_UPPER__POS 6 +#define SMI_ACC2X2_ALLOW_UPPER__LEN 1 +#define SMI_ACC2X2_ALLOW_UPPER__MSK 0x40 +#define SMI_ACC2X2_ALLOW_UPPER__REG SMI_ACC2X2_EXTMODE_CTRL_REG + +#define SMI_ACC2X2_MAP_2_LOWER__POS 5 +#define SMI_ACC2X2_MAP_2_LOWER__LEN 1 +#define SMI_ACC2X2_MAP_2_LOWER__MSK 0x20 +#define SMI_ACC2X2_MAP_2_LOWER__REG SMI_ACC2X2_EXTMODE_CTRL_REG + +#define SMI_ACC2X2_MAGIC_NUMBER__POS 0 +#define SMI_ACC2X2_MAGIC_NUMBER__LEN 5 +#define SMI_ACC2X2_MAGIC_NUMBER__MSK 0x1F +#define SMI_ACC2X2_MAGIC_NUMBER__REG SMI_ACC2X2_EXTMODE_CTRL_REG + +#define SMI_ACC2X2_UNLOCK_EE_WRITE_TRIM__POS 4 +#define SMI_ACC2X2_UNLOCK_EE_WRITE_TRIM__LEN 4 +#define SMI_ACC2X2_UNLOCK_EE_WRITE_TRIM__MSK 0xF0 +#define SMI_ACC2X2_UNLOCK_EE_WRITE_TRIM__REG SMI_ACC2X2_CTRL_UNLOCK_REG + +#define SMI_ACC2X2_EN_SLOW_COMP_X__POS 0 +#define SMI_ACC2X2_EN_SLOW_COMP_X__LEN 1 +#define SMI_ACC2X2_EN_SLOW_COMP_X__MSK 0x01 +#define SMI_ACC2X2_EN_SLOW_COMP_X__REG SMI_ACC2X2_OFFSET_CTRL_REG + +#define SMI_ACC2X2_EN_SLOW_COMP_Y__POS 1 +#define SMI_ACC2X2_EN_SLOW_COMP_Y__LEN 1 +#define SMI_ACC2X2_EN_SLOW_COMP_Y__MSK 0x02 +#define SMI_ACC2X2_EN_SLOW_COMP_Y__REG SMI_ACC2X2_OFFSET_CTRL_REG + +#define SMI_ACC2X2_EN_SLOW_COMP_Z__POS 2 +#define SMI_ACC2X2_EN_SLOW_COMP_Z__LEN 1 +#define SMI_ACC2X2_EN_SLOW_COMP_Z__MSK 0x04 +#define SMI_ACC2X2_EN_SLOW_COMP_Z__REG SMI_ACC2X2_OFFSET_CTRL_REG + +#define SMI_ACC2X2_FAST_CAL_RDY_S__POS 4 +#define SMI_ACC2X2_FAST_CAL_RDY_S__LEN 1 +#define SMI_ACC2X2_FAST_CAL_RDY_S__MSK 0x10 +#define SMI_ACC2X2_FAST_CAL_RDY_S__REG SMI_ACC2X2_OFFSET_CTRL_REG + +#define SMI_ACC2X2_CAL_TRIGGER__POS 5 +#define SMI_ACC2X2_CAL_TRIGGER__LEN 2 +#define SMI_ACC2X2_CAL_TRIGGER__MSK 0x60 +#define SMI_ACC2X2_CAL_TRIGGER__REG SMI_ACC2X2_OFFSET_CTRL_REG + +#define SMI_ACC2X2_RESET_OFFSET_REGS__POS 7 +#define SMI_ACC2X2_RESET_OFFSET_REGS__LEN 1 +#define SMI_ACC2X2_RESET_OFFSET_REGS__MSK 0x80 +#define SMI_ACC2X2_RESET_OFFSET_REGS__REG SMI_ACC2X2_OFFSET_CTRL_REG + +#define SMI_ACC2X2_COMP_CUTOFF__POS 0 +#define SMI_ACC2X2_COMP_CUTOFF__LEN 1 +#define SMI_ACC2X2_COMP_CUTOFF__MSK 0x01 +#define SMI_ACC2X2_COMP_CUTOFF__REG SMI_ACC2X2_OFFSET_PARAMS_REG + +#define SMI_ACC2X2_COMP_TARGET_OFFSET_X__POS 1 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_X__LEN 2 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_X__MSK 0x06 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_X__REG SMI_ACC2X2_OFFSET_PARAMS_REG + +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Y__POS 3 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Y__LEN 2 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Y__MSK 0x18 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Y__REG SMI_ACC2X2_OFFSET_PARAMS_REG + +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Z__POS 5 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Z__LEN 2 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Z__MSK 0x60 +#define SMI_ACC2X2_COMP_TARGET_OFFSET_Z__REG SMI_ACC2X2_OFFSET_PARAMS_REG + +#define SMI_ACC2X2_FIFO_DATA_SELECT__POS 0 +#define SMI_ACC2X2_FIFO_DATA_SELECT__LEN 2 +#define SMI_ACC2X2_FIFO_DATA_SELECT__MSK 0x03 +#define SMI_ACC2X2_FIFO_DATA_SELECT__REG SMI_ACC2X2_FIFO_MODE_REG + +#define SMI_ACC2X2_FIFO_TRIGGER_SOURCE__POS 2 +#define SMI_ACC2X2_FIFO_TRIGGER_SOURCE__LEN 2 +#define SMI_ACC2X2_FIFO_TRIGGER_SOURCE__MSK 0x0C +#define SMI_ACC2X2_FIFO_TRIGGER_SOURCE__REG SMI_ACC2X2_FIFO_MODE_REG + +#define SMI_ACC2X2_FIFO_TRIGGER_ACTION__POS 4 +#define SMI_ACC2X2_FIFO_TRIGGER_ACTION__LEN 2 +#define SMI_ACC2X2_FIFO_TRIGGER_ACTION__MSK 0x30 +#define SMI_ACC2X2_FIFO_TRIGGER_ACTION__REG SMI_ACC2X2_FIFO_MODE_REG + +#define SMI_ACC2X2_FIFO_MODE__POS 6 +#define SMI_ACC2X2_FIFO_MODE__LEN 2 +#define SMI_ACC2X2_FIFO_MODE__MSK 0xC0 +#define SMI_ACC2X2_FIFO_MODE__REG SMI_ACC2X2_FIFO_MODE_REG + + +#define SMI_ACC2X2_STATUS1 0 +#define SMI_ACC2X2_STATUS2 1 +#define SMI_ACC2X2_STATUS3 2 +#define SMI_ACC2X2_STATUS4 3 +#define SMI_ACC2X2_STATUS5 4 + + +#define SMI_ACC2X2_RANGE_2G 3 +#define SMI_ACC2X2_RANGE_4G 5 +#define SMI_ACC2X2_RANGE_8G 8 +#define SMI_ACC2X2_RANGE_16G 12 + + +#define SMI_ACC2X2_BW_7_81HZ 0x08 +#define SMI_ACC2X2_BW_15_63HZ 0x09 +#define SMI_ACC2X2_BW_31_25HZ 0x0A +#define SMI_ACC2X2_BW_62_50HZ 0x0B +#define SMI_ACC2X2_BW_125HZ 0x0C +#define SMI_ACC2X2_BW_250HZ 0x0D +#define SMI_ACC2X2_BW_500HZ 0x0E +#define SMI_ACC2X2_BW_1000HZ 0x0F + +#define SMI_ACC2X2_SLEEP_DUR_0_5MS 0x05 +#define SMI_ACC2X2_SLEEP_DUR_1MS 0x06 +#define SMI_ACC2X2_SLEEP_DUR_2MS 0x07 +#define SMI_ACC2X2_SLEEP_DUR_4MS 0x08 +#define SMI_ACC2X2_SLEEP_DUR_6MS 0x09 +#define SMI_ACC2X2_SLEEP_DUR_10MS 0x0A +#define SMI_ACC2X2_SLEEP_DUR_25MS 0x0B +#define SMI_ACC2X2_SLEEP_DUR_50MS 0x0C +#define SMI_ACC2X2_SLEEP_DUR_100MS 0x0D +#define SMI_ACC2X2_SLEEP_DUR_500MS 0x0E +#define SMI_ACC2X2_SLEEP_DUR_1S 0x0F + +#define SMI_ACC2X2_LATCH_DUR_NON_LATCH 0x00 +#define SMI_ACC2X2_LATCH_DUR_250MS 0x01 +#define SMI_ACC2X2_LATCH_DUR_500MS 0x02 +#define SMI_ACC2X2_LATCH_DUR_1S 0x03 +#define SMI_ACC2X2_LATCH_DUR_2S 0x04 +#define SMI_ACC2X2_LATCH_DUR_4S 0x05 +#define SMI_ACC2X2_LATCH_DUR_8S 0x06 +#define SMI_ACC2X2_LATCH_DUR_LATCH 0x07 +#define SMI_ACC2X2_LATCH_DUR_NON_LATCH1 0x08 +#define SMI_ACC2X2_LATCH_DUR_250US 0x09 +#define SMI_ACC2X2_LATCH_DUR_500US 0x0A +#define SMI_ACC2X2_LATCH_DUR_1MS 0x0B +#define SMI_ACC2X2_LATCH_DUR_12_5MS 0x0C +#define SMI_ACC2X2_LATCH_DUR_25MS 0x0D +#define SMI_ACC2X2_LATCH_DUR_50MS 0x0E +#define SMI_ACC2X2_LATCH_DUR_LATCH1 0x0F + +#define SMI_ACC2X2_MODE_NORMAL 0 +#define SMI_ACC2X2_MODE_LOWPOWER1 1 +#define SMI_ACC2X2_MODE_SUSPEND 2 +#define SMI_ACC2X2_MODE_DEEP_SUSPEND 3 +#define SMI_ACC2X2_MODE_LOWPOWER2 4 +#define SMI_ACC2X2_MODE_STANDBY 5 + +#define SMI_ACC2X2_X_AXIS 0 +#define SMI_ACC2X2_Y_AXIS 1 +#define SMI_ACC2X2_Z_AXIS 2 + +#define SMI_ACC2X2_Low_G_Interrupt 0 +#define SMI_ACC2X2_High_G_X_Interrupt 1 +#define SMI_ACC2X2_High_G_Y_Interrupt 2 +#define SMI_ACC2X2_High_G_Z_Interrupt 3 +#define SMI_ACC2X2_DATA_EN 4 +#define SMI_ACC2X2_Slope_X_Interrupt 5 +#define SMI_ACC2X2_Slope_Y_Interrupt 6 +#define SMI_ACC2X2_Slope_Z_Interrupt 7 +#define SMI_ACC2X2_Single_Tap_Interrupt 8 +#define SMI_ACC2X2_Double_Tap_Interrupt 9 +#define SMI_ACC2X2_Orient_Interrupt 10 +#define SMI_ACC2X2_Flat_Interrupt 11 +#define SMI_ACC2X2_FFULL_INTERRUPT 12 +#define SMI_ACC2X2_FWM_INTERRUPT 13 + +#define SMI_ACC2X2_INT1_LOWG 0 +#define SMI_ACC2X2_INT2_LOWG 1 +#define SMI_ACC2X2_INT1_HIGHG 0 +#define SMI_ACC2X2_INT2_HIGHG 1 +#define SMI_ACC2X2_INT1_SLOPE 0 +#define SMI_ACC2X2_INT2_SLOPE 1 +#define SMI_ACC2X2_INT1_SLO_NO_MOT 0 +#define SMI_ACC2X2_INT2_SLO_NO_MOT 1 +#define SMI_ACC2X2_INT1_DTAP 0 +#define SMI_ACC2X2_INT2_DTAP 1 +#define SMI_ACC2X2_INT1_STAP 0 +#define SMI_ACC2X2_INT2_STAP 1 +#define SMI_ACC2X2_INT1_ORIENT 0 +#define SMI_ACC2X2_INT2_ORIENT 1 +#define SMI_ACC2X2_INT1_FLAT 0 +#define SMI_ACC2X2_INT2_FLAT 1 +#define SMI_ACC2X2_INT1_NDATA 0 +#define SMI_ACC2X2_INT2_NDATA 1 +#define SMI_ACC2X2_INT1_FWM 0 +#define SMI_ACC2X2_INT2_FWM 1 +#define SMI_ACC2X2_INT1_FFULL 0 +#define SMI_ACC2X2_INT2_FFULL 1 + +#define SMI_ACC2X2_SRC_LOWG 0 +#define SMI_ACC2X2_SRC_HIGHG 1 +#define SMI_ACC2X2_SRC_SLOPE 2 +#define SMI_ACC2X2_SRC_SLO_NO_MOT 3 +#define SMI_ACC2X2_SRC_TAP 4 +#define SMI_ACC2X2_SRC_DATA 5 + +#define SMI_ACC2X2_INT1_OUTPUT 0 +#define SMI_ACC2X2_INT2_OUTPUT 1 +#define SMI_ACC2X2_INT1_LEVEL 0 +#define SMI_ACC2X2_INT2_LEVEL 1 + +#define SMI_ACC2X2_LOW_DURATION 0 +#define SMI_ACC2X2_HIGH_DURATION 1 +#define SMI_ACC2X2_SLOPE_DURATION 2 +#define SMI_ACC2X2_SLO_NO_MOT_DURATION 3 + +#define SMI_ACC2X2_LOW_THRESHOLD 0 +#define SMI_ACC2X2_HIGH_THRESHOLD 1 +#define SMI_ACC2X2_SLOPE_THRESHOLD 2 +#define SMI_ACC2X2_SLO_NO_MOT_THRESHOLD 3 + + +#define SMI_ACC2X2_LOWG_HYST 0 +#define SMI_ACC2X2_HIGHG_HYST 1 + +#define SMI_ACC2X2_ORIENT_THETA 0 +#define SMI_ACC2X2_FLAT_THETA 1 + +#define SMI_ACC2X2_I2C_SELECT 0 +#define SMI_ACC2X2_I2C_EN 1 + +#define SMI_ACC2X2_SLOW_COMP_X 0 +#define SMI_ACC2X2_SLOW_COMP_Y 1 +#define SMI_ACC2X2_SLOW_COMP_Z 2 + +#define SMI_ACC2X2_CUT_OFF 0 +#define SMI_ACC2X2_OFFSET_TRIGGER_X 1 +#define SMI_ACC2X2_OFFSET_TRIGGER_Y 2 +#define SMI_ACC2X2_OFFSET_TRIGGER_Z 3 + +#define SMI_ACC2X2_GP0 0 +#define SMI_ACC2X2_GP1 1 + +#define SMI_ACC2X2_SLO_NO_MOT_EN_X 0 +#define SMI_ACC2X2_SLO_NO_MOT_EN_Y 1 +#define SMI_ACC2X2_SLO_NO_MOT_EN_Z 2 +#define SMI_ACC2X2_SLO_NO_MOT_EN_SEL 3 + +#define SMI_ACC2X2_WAKE_UP_DUR_20MS 0 +#define SMI_ACC2X2_WAKE_UP_DUR_80MS 1 +#define SMI_ACC2X2_WAKE_UP_DUR_320MS 2 +#define SMI_ACC2X2_WAKE_UP_DUR_2560MS 3 + +#define SMI_ACC2X2_SELF_TEST0_ON 1 +#define SMI_ACC2X2_SELF_TEST1_ON 2 + +#define SMI_ACC2X2_EE_W_OFF 0 +#define SMI_ACC2X2_EE_W_ON 1 + +#define SMI_ACC2X2_LOW_TH_IN_G(gthres, range) ((256 * gthres) / range) + + +#define SMI_ACC2X2_HIGH_TH_IN_G(gthres, range) ((256 * gthres) / range) + + +#define SMI_ACC2X2_LOW_HY_IN_G(ghyst, range) ((32 * ghyst) / range) + + +#define SMI_ACC2X2_HIGH_HY_IN_G(ghyst, range) ((32 * ghyst) / range) + + +#define SMI_ACC2X2_SLOPE_TH_IN_G(gthres, range) ((128 * gthres) / range) + + +#define SMI_ACC2X2_GET_BITSLICE(regvar, bitname)\ + ((regvar & bitname##__MSK) >> bitname##__POS) + + +#define SMI_ACC2X2_SET_BITSLICE(regvar, bitname, val)\ + ((regvar & ~bitname##__MSK) | ((val<smi130_hrtimer); + /*forward HRTIMER just before 1ms of irq arrival*/ + hrtimer_forward(&data->smi130_hrtimer, ktime_get(), + ns_to_ktime(data->time_odr - 1000000)); + hrtimer_restart(&data->smi130_hrtimer); +} +static void smi130_hrtimer_init(struct smi130_acc_data *data) +{ + hrtimer_init(&data->smi130_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->smi130_hrtimer.function = smi130_timer_function; +} +static void smi130_hrtimer_cleanup(struct smi130_acc_data *data) +{ + hrtimer_cancel(&data->smi130_hrtimer); +} +#else +static void smi130_set_cpu_idle_state(bool value) +{ +} +static void smi130_hrtimer_reset(struct smi130_acc_data *data) +{ + +} +static void smi130_hrtimer_init(struct smi130_acc_data *data) +{ + +} +static void smi130_hrtimer_remove(struct smi130_acc_data *data) +{ + +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void smi130_acc_early_suspend(struct early_suspend *h); +static void smi130_acc_late_resume(struct early_suspend *h); +#endif + +static int smi130_acc_set_mode(struct i2c_client *client, + u8 mode, u8 enabled_mode); +static int smi130_acc_get_mode(struct i2c_client *client, u8 *mode); +static int smi130_acc_get_fifo_mode(struct i2c_client *client, u8 *fifo_mode); +static int smi130_acc_set_fifo_mode(struct i2c_client *client, u8 fifo_mode); +static int smi130_acc_normal_to_suspend(struct smi130_acc_data *smi130_acc, + unsigned char data1, unsigned char data2); + +static void smi130_acc_delay(u32 msec) +{ + if (msec <= 20) + usleep_range(msec * 1000, msec * 1000); + else + msleep(msec); +} +/*Remapping for SMI_ACC2X2*/ +static const struct bosch_sensor_axis_remap +bosch_axis_remap_tab_dft[MAX_AXIS_REMAP_TAB_SZ] = { + /* src_x src_y src_z sign_x sign_y sign_z */ + { 0, 1, 2, 1, 1, 1 }, /* P0 */ + { 1, 0, 2, 1, -1, 1 }, /* P1 */ + { 0, 1, 2, -1, -1, 1 }, /* P2 */ + { 1, 0, 2, -1, 1, 1 }, /* P3 */ + + { 0, 1, 2, -1, 1, -1 }, /* P4 */ + { 1, 0, 2, -1, -1, -1 }, /* P5 */ + { 0, 1, 2, 1, -1, -1 }, /* P6 */ + { 1, 0, 2, 1, 1, -1 }, /* P7 */ +}; + + +static void bosch_remap_sensor_data(struct bosch_sensor_data *data, + const struct bosch_sensor_axis_remap *remap) +{ + struct bosch_sensor_data tmp; + + tmp.x = data->v[remap->src_x] * remap->sign_x; + tmp.y = data->v[remap->src_y] * remap->sign_y; + tmp.z = data->v[remap->src_z] * remap->sign_z; + + memcpy(data, &tmp, sizeof(*data)); +} + + +static void bosch_remap_sensor_data_dft_tab(struct bosch_sensor_data *data, + int place) +{ + /* sensor with place 0 needs not to be remapped */ + if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ)) + return; + + bosch_remap_sensor_data(data, &bosch_axis_remap_tab_dft[place]); +} + +static void smi130_acc_remap_sensor_data(struct smi130_accacc *val, + struct smi130_acc_data *client_data) +{ + struct bosch_sensor_data bsd; + int place; + + if ((NULL == client_data->bosch_pd) || (BOSCH_SENSOR_PLACE_UNKNOWN + == client_data->bosch_pd->place)) + place = BOSCH_SENSOR_PLACE_UNKNOWN; + else + place = client_data->bosch_pd->place; + +#ifdef CONFIG_SENSORS_BMI058 +/*x,y need to be invesed becase of HW Register for BMI058*/ + bsd.y = val->x; + bsd.x = val->y; + bsd.z = val->z; +#else + bsd.x = val->x; + bsd.y = val->y; + bsd.z = val->z; +#endif + + bosch_remap_sensor_data_dft_tab(&bsd, place); + + val->x = bsd.x; + val->y = bsd.y; + val->z = bsd.z; + +} + + +static int smi130_acc_smbus_read_byte(struct i2c_client *client, + unsigned char reg_addr, unsigned char *data) +{ +#if !defined SMI130_ACC_USE_BASIC_I2C_FUNC + s32 dummy; + int len = 1; + if (NULL == client) + return -ENODEV; + + while (0 != len--) { +#ifdef SMI130_ACC_SMBUS + dummy = i2c_smbus_read_byte_data(client, reg_addr); + if (dummy < 0) { + PERR("i2c bus read error"); + return -EIO; + } + *data = (u8)(dummy & 0xff); +#else + dummy = i2c_master_send(client, (char *)®_addr, 1); + if (dummy < 0) + return -EIO; + + dummy = i2c_master_recv(client, (char *)data, 1); + if (dummy < 0) + return -EIO; +#endif + reg_addr++; + data++; + } + return 0; +#else + int retry; + int len = 1; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < SMI_ACC_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + smi130_acc_delay(1); + } + + if (SMI_ACC_MAX_RETRY_I2C_XFER <= retry) { + PERR("I2C xfer error"); + return -EIO; + } + + return 0; +#endif +} + +static int smi130_acc_smbus_write_byte(struct i2c_client *client, + unsigned char reg_addr, unsigned char *data) +{ +#if !defined SMI130_ACC_USE_BASIC_I2C_FUNC + s32 dummy; + int len = 1; +#ifndef SMI130_ACC_SMBUS + u8 buffer[2]; +#endif + if (NULL == client) + return -ENODEV; + + while (0 != len--) { +#ifdef SMI130_ACC_SMBUS + dummy = i2c_smbus_write_byte_data(client, reg_addr, *data); +#else + buffer[0] = reg_addr; + buffer[1] = *data; + dummy = i2c_master_send(client, (char *)buffer, 2); +#endif + reg_addr++; + data++; + if (dummy < 0) { + PERR("error writing i2c bus"); + return -EIO; + } + + } + return 0; +#else + u8 buffer[2]; + int retry; + int len = 1; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buffer, + }, + }; + while (0 != len--) { + buffer[0] = reg_addr; + buffer[1] = *data; + for (retry = 0; retry < SMI_ACC_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, + ARRAY_SIZE(msg)) > 0) { + break; + } else { + smi130_acc_delay(1); + } + } + if (SMI_ACC_MAX_RETRY_I2C_XFER <= retry) { + PERR("I2C xfer error"); + return -EIO; + } + reg_addr++; + data++; + } + + return 0; +#endif +} + +static int smi130_acc_smbus_read_byte_block(struct i2c_client *client, + unsigned char reg_addr, unsigned char *data, unsigned char len) +{ + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < SMI_ACC_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + smi130_acc_delay(1); + } + + if (SMI_ACC_MAX_RETRY_I2C_XFER <= retry) { + PERR("I2C xfer error"); + return -EIO; + } + return 0; +} + +static int smi_acc_i2c_burst_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u16 len) +{ + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < SMI_ACC_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + smi130_acc_delay(1); + } + + if (SMI_ACC_MAX_RETRY_I2C_XFER <= retry) { + PINFO("I2C xfer error"); + return -EIO; + } + + return 0; +} + +static int smi130_acc_check_chip_id(struct i2c_client *client, + struct smi130_acc_data *data) +{ + int i = 0; + int err = 0; + unsigned char chip_id = 0; + unsigned char read_count = 0; + unsigned char smi130_acc_sensor_type_count = 0; + + smi130_acc_sensor_type_count = + sizeof(sensor_type_map) / sizeof(struct smi130_acc_type_map_t); + + while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { + if (smi130_acc_smbus_read_byte(client, SMI_ACC2X2_CHIP_ID_REG, + &chip_id) < 0) { + PERR("Bosch Sensortec Device not found\n\n" + "i2c bus read error, read chip_id:%d\n", chip_id); + continue; + } else { + for (i = 0; i < smi130_acc_sensor_type_count; i++) { + if (sensor_type_map[i].chip_id == chip_id) { + data->sensor_type = + sensor_type_map[i].sensor_type; + data->chip_id = chip_id; + PINFO("Bosch Sensortec Device detected,\n\n" + " HW IC name: %s\n", + sensor_type_map[i].sensor_name); + return err; + } + } + if (i < smi130_acc_sensor_type_count) + return err; + else { + if (read_count == CHECK_CHIP_ID_TIME_MAX) { + PERR("Failed! Bosch Sensortec Device\n\n" + " not found, mismatch chip_id:%d\n", + chip_id); + err = -ENODEV; + return err; + } + } + smi130_acc_delay(1); + } + } + return err; +} + +#ifdef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT +static int smi130_acc_set_newdata(struct i2c_client *client, + unsigned char channel, unsigned char int_newdata) +{ + + unsigned char data = 0; + int comres = 0; + + switch (channel) { + case SMI_ACC2X2_INT1_NDATA: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_NEWDATA__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, + SMI_ACC2X2_EN_INT1_PAD_NEWDATA, int_newdata); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_NEWDATA__REG, &data); + break; + case SMI_ACC2X2_INT2_NDATA: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_NEWDATA__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, + SMI_ACC2X2_EN_INT2_PAD_NEWDATA, int_newdata); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_NEWDATA__REG, &data); + break; + default: + comres = -1; + break; + } + + return comres; + +} +#endif /* CONFIG_SMI_ACC_ENABLE_NEWDATA_INT */ + +#ifdef SMI_ACC2X2_ENABLE_INT1 +static int smi130_acc_set_int1_pad_sel(struct i2c_client *client, unsigned char + int1sel) +{ + int comres = 0; + unsigned char data = 0; + unsigned char state; + state = 0x01; + + + switch (int1sel) { + case 0: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_LOWG__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_LOWG, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_LOWG__REG, &data); + break; + case 1: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_HIGHG__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_HIGHG, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_HIGHG__REG, &data); + break; + case 2: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_SLOPE__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_SLOPE, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_SLOPE__REG, &data); + break; + case 3: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_DB_TAP__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_DB_TAP, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_DB_TAP__REG, &data); + break; + case 4: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_SNG_TAP__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_SNG_TAP, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_SNG_TAP__REG, &data); + break; + case 5: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_ORIENT__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_ORIENT, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_ORIENT__REG, &data); + break; + case 6: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_FLAT__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_FLAT, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_FLAT__REG, &data); + break; + case 7: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT1_PAD_SLO_NO_MOT__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT1_PAD_SLO_NO_MOT, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT1_PAD_SLO_NO_MOT__REG, &data); + break; + + default: + break; + } + + return comres; +} +#endif /* SMI_ACC2X2_ENABLE_INT1 */ + +#ifdef SMI_ACC2X2_ENABLE_INT2 +static int smi130_acc_set_int2_pad_sel(struct i2c_client *client, unsigned char + int2sel) +{ + int comres = 0; + unsigned char data = 0; + unsigned char state; + state = 0x01; + + + switch (int2sel) { + case 0: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_LOWG__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_LOWG, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_LOWG__REG, &data); + break; + case 1: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_HIGHG__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_HIGHG, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_HIGHG__REG, &data); + break; + case 2: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_SLOPE__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_SLOPE, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_SLOPE__REG, &data); + break; + case 3: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_DB_TAP__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_DB_TAP, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_DB_TAP__REG, &data); + break; + case 4: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_SNG_TAP__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_SNG_TAP, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_SNG_TAP__REG, &data); + break; + case 5: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_ORIENT__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_ORIENT, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_ORIENT__REG, &data); + break; + case 6: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_FLAT__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_FLAT, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_FLAT__REG, &data); + break; + case 7: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_EN_INT2_PAD_SLO_NO_MOT__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_INT2_PAD_SLO_NO_MOT, + state); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_EN_INT2_PAD_SLO_NO_MOT__REG, &data); + break; + default: + break; + } + + return comres; +} +#endif /* SMI_ACC2X2_ENABLE_INT2 */ + +static int smi130_acc_set_Int_Enable(struct i2c_client *client, unsigned char + InterruptType , unsigned char value) +{ + int comres = 0; + unsigned char data1 = 0; + unsigned char data2 = 0; + + if ((11 < InterruptType) && (InterruptType < 16)) { + switch (InterruptType) { + case 12: + /* slow/no motion X Interrupt */ + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_X_INT__REG, &data1); + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_X_INT, value); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_X_INT__REG, &data1); + break; + case 13: + /* slow/no motion Y Interrupt */ + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_Y_INT__REG, &data1); + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_Y_INT, value); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_Y_INT__REG, &data1); + break; + case 14: + /* slow/no motion Z Interrupt */ + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_Z_INT__REG, &data1); + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_Z_INT, value); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_Z_INT__REG, &data1); + break; + case 15: + /* slow / no motion Interrupt select */ + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG, &data1); + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_SEL_INT, value); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG, &data1); + } + + return comres; + } + + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_INT_ENABLE1_REG, &data1); + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_INT_ENABLE2_REG, &data2); + + value = value & 1; + switch (InterruptType) { + case 0: + /* Low G Interrupt */ + data2 = SMI_ACC2X2_SET_BITSLICE(data2, SMI_ACC2X2_EN_LOWG_INT, value); + break; + + case 1: + /* High G X Interrupt */ + data2 = SMI_ACC2X2_SET_BITSLICE(data2, SMI_ACC2X2_EN_HIGHG_X_INT, + value); + break; + + case 2: + /* High G Y Interrupt */ + data2 = SMI_ACC2X2_SET_BITSLICE(data2, SMI_ACC2X2_EN_HIGHG_Y_INT, + value); + break; + + case 3: + /* High G Z Interrupt */ + data2 = SMI_ACC2X2_SET_BITSLICE(data2, SMI_ACC2X2_EN_HIGHG_Z_INT, + value); + break; + + case 4: + /* New Data Interrupt */ + data2 = SMI_ACC2X2_SET_BITSLICE(data2, SMI_ACC2X2_EN_NEW_DATA_INT, + value); + break; + + case 5: + /* Slope X Interrupt */ + data1 = SMI_ACC2X2_SET_BITSLICE(data1, SMI_ACC2X2_EN_SLOPE_X_INT, + value); + break; + + case 6: + /* Slope Y Interrupt */ + data1 = SMI_ACC2X2_SET_BITSLICE(data1, SMI_ACC2X2_EN_SLOPE_Y_INT, + value); + break; + + case 7: + /* Slope Z Interrupt */ + data1 = SMI_ACC2X2_SET_BITSLICE(data1, SMI_ACC2X2_EN_SLOPE_Z_INT, + value); + break; + + case 8: + /* Single Tap Interrupt */ + data1 = SMI_ACC2X2_SET_BITSLICE(data1, SMI_ACC2X2_EN_SINGLE_TAP_INT, + value); + break; + + case 9: + /* Double Tap Interrupt */ + data1 = SMI_ACC2X2_SET_BITSLICE(data1, SMI_ACC2X2_EN_DOUBLE_TAP_INT, + value); + break; + + case 10: + /* Orient Interrupt */ + data1 = SMI_ACC2X2_SET_BITSLICE(data1, SMI_ACC2X2_EN_ORIENT_INT, value); + break; + + case 11: + /* Flat Interrupt */ + data1 = SMI_ACC2X2_SET_BITSLICE(data1, SMI_ACC2X2_EN_FLAT_INT, value); + break; + + default: + break; + } + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_INT_ENABLE1_REG, + &data1); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_INT_ENABLE2_REG, + &data2); + + return comres; +} + + +#if defined(SMI_ACC2X2_ENABLE_INT1) || defined(SMI_ACC2X2_ENABLE_INT2) +static int smi130_acc_get_interruptstatus1(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_STATUS1_REG, &data); + *intstatus = data; + + return comres; +} + +#ifdef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT +/* +static int smi130_acc_get_interruptstatus2(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_STATUS2_REG, &data); + *intstatus = data; + + return comres; +} +*/ +#endif + +static int smi130_acc_get_HIGH_first(struct i2c_client *client, unsigned char + param, unsigned char *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + switch (param) { + case 0: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_STATUS_ORIENT_HIGH_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_HIGHG_FIRST_X); + *intstatus = data; + break; + case 1: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_STATUS_ORIENT_HIGH_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_HIGHG_FIRST_Y); + *intstatus = data; + break; + case 2: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_STATUS_ORIENT_HIGH_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_HIGHG_FIRST_Z); + *intstatus = data; + break; + default: + break; + } + + return comres; +} + +static int smi130_acc_get_HIGH_sign(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_STATUS_ORIENT_HIGH_REG, + &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_HIGHG_SIGN_S); + *intstatus = data; + + return comres; +} + +#ifndef CONFIG_SIG_MOTION +static int smi130_acc_get_slope_first(struct i2c_client *client, unsigned char + param, unsigned char *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + switch (param) { + case 0: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_STATUS_TAP_SLOPE_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_SLOPE_FIRST_X); + *intstatus = data; + break; + case 1: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_STATUS_TAP_SLOPE_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_SLOPE_FIRST_Y); + *intstatus = data; + break; + case 2: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_STATUS_TAP_SLOPE_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_SLOPE_FIRST_Z); + *intstatus = data; + break; + default: + break; + } + + return comres; +} + +static int smi130_acc_get_slope_sign(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_STATUS_TAP_SLOPE_REG, + &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_SLOPE_SIGN_S); + *intstatus = data; + + return comres; +} +#endif + +static int smi130_acc_get_orient_mbl_status(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_STATUS_ORIENT_HIGH_REG, + &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_ORIENT_S); + *intstatus = data; + + return comres; +} + +static int smi130_acc_get_orient_mbl_flat_status(struct i2c_client *client, unsigned + char *intstatus) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_STATUS_ORIENT_HIGH_REG, + &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FLAT_S); + *intstatus = data; + + return comres; +} +#endif /* defined(SMI_ACC2X2_ENABLE_INT1)||defined(SMI_ACC2X2_ENABLE_INT2) */ + +static int smi130_acc_set_Int_Mode(struct i2c_client *client, unsigned char Mode) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_INT_MODE_SEL__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_INT_MODE_SEL, Mode); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_INT_MODE_SEL__REG, &data); + + + return comres; +} + +static int smi130_acc_get_Int_Mode(struct i2c_client *client, unsigned char *Mode) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_INT_MODE_SEL__REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_INT_MODE_SEL); + *Mode = data; + + + return comres; +} +static int smi130_acc_set_slope_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_SLOPE_DUR__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_SLOPE_DUR, duration); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_SLOPE_DUR__REG, &data); + + return comres; +} + +static int smi130_acc_get_slope_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_SLOPE_DURN_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_SLOPE_DUR); + *status = data; + + + return comres; +} + +static int smi130_acc_set_slope_no_mot_duration(struct i2c_client *client, + unsigned char duration) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI130_ACC_SLO_NO_MOT_DUR__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI130_ACC_SLO_NO_MOT_DUR, duration); + comres = smi130_acc_smbus_write_byte(client, + SMI130_ACC_SLO_NO_MOT_DUR__REG, &data); + + + return comres; +} + +static int smi130_acc_get_slope_no_mot_duration(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI130_ACC_SLO_NO_MOT_DUR__REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI130_ACC_SLO_NO_MOT_DUR); + *status = data; + + + return comres; +} + +static int smi130_acc_set_slope_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data = 0; + + data = threshold; + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_SLOPE_THRES__REG, &data); + + return comres; +} + +static int smi130_acc_get_slope_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_SLOPE_THRES_REG, &data); + *status = data; + + return comres; +} + +static int smi130_acc_set_slope_no_mot_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data = 0; + + data = threshold; + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_SLO_NO_MOT_THRES_REG, &data); + + return comres; +} + +static int smi130_acc_get_slope_no_mot_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data = 0; + + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_SLO_NO_MOT_THRES_REG, &data); + *status = data; + + return comres; +} + + +static int smi130_acc_set_low_g_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_LOWG_DUR__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_LOWG_DUR, duration); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_LOWG_DUR__REG, &data); + + return comres; +} + +static int smi130_acc_get_low_g_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_LOW_DURN_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_LOWG_DUR); + *status = data; + + return comres; +} + +static int smi130_acc_set_low_g_threshold(struct i2c_client *client, unsigned char + threshold) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_LOWG_THRES__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_LOWG_THRES, threshold); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_LOWG_THRES__REG, &data); + + return comres; +} + +static int smi130_acc_get_low_g_threshold(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_LOW_THRES_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_LOWG_THRES); + *status = data; + + return comres; +} + +static int smi130_acc_set_high_g_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_HIGHG_DUR__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_HIGHG_DUR, duration); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_HIGHG_DUR__REG, &data); + + return comres; +} + +static int smi130_acc_get_high_g_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_HIGH_DURN_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_HIGHG_DUR); + *status = data; + + return comres; +} + +static int smi130_acc_set_high_g_threshold(struct i2c_client *client, unsigned char + threshold) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_HIGHG_THRES__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_HIGHG_THRES, threshold); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_HIGHG_THRES__REG, + &data); + + return comres; +} + +static int smi130_acc_get_high_g_threshold(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_HIGH_THRES_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_HIGHG_THRES); + *status = data; + + return comres; +} + + +static int smi130_acc_set_tap_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_DUR__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_TAP_DUR, duration); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_TAP_DUR__REG, &data); + + return comres; +} + +static int smi130_acc_get_tap_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_PARAM_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_TAP_DUR); + *status = data; + + return comres; +} + +static int smi130_acc_set_tap_shock(struct i2c_client *client, unsigned char setval) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_SHOCK_DURN__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_TAP_SHOCK_DURN, setval); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_TAP_SHOCK_DURN__REG, + &data); + + return comres; +} + +static int smi130_acc_get_tap_shock(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_PARAM_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_TAP_SHOCK_DURN); + *status = data; + + return comres; +} + +static int smi130_acc_set_tap_quiet(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_QUIET_DURN__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_TAP_QUIET_DURN, duration); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_TAP_QUIET_DURN__REG, + &data); + + return comres; +} + +static int smi130_acc_get_tap_quiet(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_PARAM_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_TAP_QUIET_DURN); + *status = data; + + return comres; +} + +static int smi130_acc_set_tap_threshold(struct i2c_client *client, unsigned char + threshold) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_THRES__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_TAP_THRES, threshold); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_TAP_THRES__REG, &data); + + return comres; +} + +static int smi130_acc_get_tap_threshold(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_THRES_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_TAP_THRES); + *status = data; + + return comres; +} + +static int smi130_acc_set_tap_samp(struct i2c_client *client, unsigned char samp) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_SAMPLES__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_TAP_SAMPLES, samp); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_TAP_SAMPLES__REG, + &data); + + return comres; +} + +static int smi130_acc_get_tap_samp(struct i2c_client *client, unsigned char *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TAP_THRES_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_TAP_SAMPLES); + *status = data; + + return comres; +} + +static int smi130_acc_set_orient_mbl_mode(struct i2c_client *client, unsigned char mode) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_ORIENT_MODE__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_ORIENT_MODE, mode); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_ORIENT_MODE__REG, + &data); + + return comres; +} + +static int smi130_acc_get_orient_mbl_mode(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_ORIENT_PARAM_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_ORIENT_MODE); + *status = data; + + return comres; +} + +static int smi130_acc_set_orient_mbl_blocking(struct i2c_client *client, unsigned char + samp) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_ORIENT_BLOCK__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_ORIENT_BLOCK, samp); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_ORIENT_BLOCK__REG, + &data); + + return comres; +} + +static int smi130_acc_get_orient_mbl_blocking(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_ORIENT_PARAM_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_ORIENT_BLOCK); + *status = data; + + return comres; +} + +static int smi130_acc_set_orient_mbl_hyst(struct i2c_client *client, unsigned char + orient_mblhyst) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_ORIENT_HYST__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_ORIENT_HYST, orient_mblhyst); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_ORIENT_HYST__REG, + &data); + + return comres; +} + +static int smi130_acc_get_orient_mbl_hyst(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_ORIENT_PARAM_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_ORIENT_HYST); + *status = data; + + return comres; +} +static int smi130_acc_set_theta_blocking(struct i2c_client *client, unsigned char + thetablk) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_THETA_BLOCK__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_THETA_BLOCK, thetablk); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_THETA_BLOCK__REG, + &data); + + return comres; +} + +static int smi130_acc_get_theta_blocking(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_THETA_BLOCK_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_THETA_BLOCK); + *status = data; + + return comres; +} + +static int smi130_acc_set_theta_flat(struct i2c_client *client, unsigned char + thetaflat) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_THETA_FLAT__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_THETA_FLAT, thetaflat); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_THETA_FLAT__REG, &data); + + return comres; +} + +static int smi130_acc_get_theta_flat(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_THETA_FLAT_REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_THETA_FLAT); + *status = data; + + return comres; +} + +static int smi130_acc_set_flat_hold_time(struct i2c_client *client, unsigned char + holdtime) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_FLAT_HOLD_TIME__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_FLAT_HOLD_TIME, holdtime); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_FLAT_HOLD_TIME__REG, + &data); + + return comres; +} + +static int smi130_acc_get_flat_hold_time(struct i2c_client *client, unsigned char + *holdtime) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_FLAT_HOLD_TIME_REG, + &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FLAT_HOLD_TIME); + *holdtime = data; + + return comres; +} + +/*! + * brief: smi130_acc switch from normal to suspend mode + * @param[i] smi130_acc + * @param[i] data1, write to PMU_LPW + * @param[i] data2, write to PMU_LOW_NOSIE + * + * @return zero success, none-zero failed + */ +static int smi130_acc_normal_to_suspend(struct smi130_acc_data *smi130_acc, + unsigned char data1, unsigned char data2) +{ + unsigned char current_fifo_mode; + unsigned char current_op_mode; + if (smi130_acc == NULL) + return -ENODEV; + /* get current op mode from mode register */ + if (smi130_acc_get_mode(smi130_acc->smi130_acc_client, ¤t_op_mode) < 0) + return -EIO; + /* only aimed at operatiom mode chang from normal/lpw1 mode + * to suspend state. + */ + if (current_op_mode == SMI_ACC2X2_MODE_NORMAL || + current_op_mode == SMI_ACC2X2_MODE_LOWPOWER1) { + /* get current fifo mode from fifo config register */ + if (smi130_acc_get_fifo_mode(smi130_acc->smi130_acc_client, + ¤t_fifo_mode) < 0) + return -EIO; + else { + smi130_acc_smbus_write_byte(smi130_acc->smi130_acc_client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, &data2); + smi130_acc_smbus_write_byte(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_CTRL_REG, &data1); + /*! Aim at fifo workarounds with FIFO_CONFIG_1 */ + current_fifo_mode |= FIFO_WORKAROUNDS_MSK; + smi130_acc_smbus_write_byte(smi130_acc->smi130_acc_client, + SMI_ACC2X2_FIFO_MODE__REG, ¤t_fifo_mode); + smi130_acc_delay(3); + return 0; + } + } else { + smi130_acc_smbus_write_byte(smi130_acc->smi130_acc_client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, &data2); + smi130_acc_smbus_write_byte(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_CTRL_REG, &data1); + smi130_acc_delay(3); + return 0; + } + +} + +static int smi130_acc_set_mode(struct i2c_client *client, unsigned char mode, + unsigned char enabled_mode) +{ + int comres = 0; + unsigned char data1 = 0; + unsigned char data2 = 0; + int ret = 0; + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + mutex_lock(&smi130_acc->mode_mutex); + if (SMI_ACC2X2_MODE_SUSPEND == mode) { + if (enabled_mode != SMI_ACC_ENABLED_ALL) { + if ((smi130_acc->smi_acc_mode_enabled & + (1<mode_mutex); + return 0; + } else { + smi130_acc->smi_acc_mode_enabled &= ~(1<smi_acc_mode_enabled = 0; + } + } else if (SMI_ACC2X2_MODE_NORMAL == mode) { + if ((smi130_acc->smi_acc_mode_enabled & (1<mode_mutex); + return 0; + } else { + smi130_acc->smi_acc_mode_enabled |= (1<smi_acc_mode_enabled = 0; + } + mutex_unlock(&smi130_acc->mode_mutex); + + if (mode < 6) { + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_MODE_CTRL_REG, + &data1); + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, + &data2); + switch (mode) { + case SMI_ACC2X2_MODE_NORMAL: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_MODE_CTRL, 0); + data2 = SMI_ACC2X2_SET_BITSLICE(data2, + SMI_ACC2X2_LOW_POWER_MODE, 0); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_MODE_CTRL_REG, &data1); + smi130_acc_delay(3); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case SMI_ACC2X2_MODE_LOWPOWER1: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_MODE_CTRL, 2); + data2 = SMI_ACC2X2_SET_BITSLICE(data2, + SMI_ACC2X2_LOW_POWER_MODE, 0); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_MODE_CTRL_REG, &data1); + smi130_acc_delay(3); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case SMI_ACC2X2_MODE_SUSPEND: + if (smi130_acc->smi_acc_mode_enabled != 0) { + PERR("smi_acc still working"); + return 0; + } + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_MODE_CTRL, 4); + data2 = SMI_ACC2X2_SET_BITSLICE(data2, + SMI_ACC2X2_LOW_POWER_MODE, 0); + /*aimed at anomaly resolution when switch to suspend*/ + ret = smi130_acc_normal_to_suspend(smi130_acc, data1, data2); + if (ret < 0) + PERR("Error switching to suspend"); + break; + case SMI_ACC2X2_MODE_DEEP_SUSPEND: + if (smi130_acc->smi_acc_mode_enabled != 0) { + PERR("smi_acc still working"); + return 0; + } + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_MODE_CTRL, 1); + data2 = SMI_ACC2X2_SET_BITSLICE(data2, + SMI_ACC2X2_LOW_POWER_MODE, 1); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_MODE_CTRL_REG, &data1); + smi130_acc_delay(3); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case SMI_ACC2X2_MODE_LOWPOWER2: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_MODE_CTRL, 2); + data2 = SMI_ACC2X2_SET_BITSLICE(data2, + SMI_ACC2X2_LOW_POWER_MODE, 1); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_MODE_CTRL_REG, &data1); + smi130_acc_delay(3); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case SMI_ACC2X2_MODE_STANDBY: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_MODE_CTRL, 4); + data2 = SMI_ACC2X2_SET_BITSLICE(data2, + SMI_ACC2X2_LOW_POWER_MODE, 1); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_LOW_NOISE_CTRL_REG, &data2); + smi130_acc_delay(3); + smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_MODE_CTRL_REG, &data1); + break; + } + } else { + comres = -1; + } + + return comres; +} + + +static int smi130_acc_get_mode(struct i2c_client *client, unsigned char *mode) +{ + int comres = 0; + unsigned char data1 = 0; + unsigned char data2 = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_MODE_CTRL_REG, &data1); + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_LOW_NOISE_CTRL_REG, + &data2); + + data1 = (data1 & 0xE0) >> 5; + data2 = (data2 & 0x40) >> 6; + + + if ((data1 == 0x00) && (data2 == 0x00)) { + *mode = SMI_ACC2X2_MODE_NORMAL; + } else { + if ((data1 == 0x02) && (data2 == 0x00)) { + *mode = SMI_ACC2X2_MODE_LOWPOWER1; + } else { + if ((data1 == 0x04 || data1 == 0x06) && + (data2 == 0x00)) { + *mode = SMI_ACC2X2_MODE_SUSPEND; + } else { + if (((data1 & 0x01) == 0x01)) { + *mode = SMI_ACC2X2_MODE_DEEP_SUSPEND; + } else { + if ((data1 == 0x02) && + (data2 == 0x01)) { + *mode = SMI_ACC2X2_MODE_LOWPOWER2; + } else { + if ((data1 == 0x04) && (data2 == + 0x01)) { + *mode = + SMI_ACC2X2_MODE_STANDBY; + } else { + *mode = + SMI_ACC2X2_MODE_DEEP_SUSPEND; + } + } + } + } + } + } + + return comres; +} + +static int smi130_acc_set_range(struct i2c_client *client, unsigned char Range) +{ + int comres = 0; + unsigned char data1 = 0; + + if ((Range == 3) || (Range == 5) || (Range == 8) || (Range == 12)) { + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_RANGE_SEL_REG, + &data1); + switch (Range) { + case SMI_ACC2X2_RANGE_2G: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_RANGE_SEL, 3); + break; + case SMI_ACC2X2_RANGE_4G: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_RANGE_SEL, 5); + break; + case SMI_ACC2X2_RANGE_8G: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_RANGE_SEL, 8); + break; + case SMI_ACC2X2_RANGE_16G: + data1 = SMI_ACC2X2_SET_BITSLICE(data1, + SMI_ACC2X2_RANGE_SEL, 12); + break; + default: + break; + } + comres += smi130_acc_smbus_write_byte(client, SMI_ACC2X2_RANGE_SEL_REG, + &data1); + } else { + comres = -1; + } + + return comres; +} + +static int smi130_acc_get_range(struct i2c_client *client, unsigned char *Range) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_RANGE_SEL__REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_RANGE_SEL); + *Range = data; + + return comres; +} + + +static int smi130_acc_set_bandwidth(struct i2c_client *client, unsigned char BW) +{ + int comres = 0; + unsigned char data = 0; + int Bandwidth = 0; + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (BW > 7 && BW < 16) { + switch (BW) { + case SMI_ACC2X2_BW_7_81HZ: + Bandwidth = SMI_ACC2X2_BW_7_81HZ; + smi130_acc->time_odr = 64000000; + + /* 7.81 Hz 64000 uS */ + break; + case SMI_ACC2X2_BW_15_63HZ: + Bandwidth = SMI_ACC2X2_BW_15_63HZ; + smi130_acc->time_odr = 32000000; + /* 15.63 Hz 32000 uS */ + break; + case SMI_ACC2X2_BW_31_25HZ: + Bandwidth = SMI_ACC2X2_BW_31_25HZ; + smi130_acc->time_odr = 16000000; + /* 31.25 Hz 16000 uS */ + break; + case SMI_ACC2X2_BW_62_50HZ: + Bandwidth = SMI_ACC2X2_BW_62_50HZ; + smi130_acc->time_odr = 8000000; + /* 62.50 Hz 8000 uS */ + break; + case SMI_ACC2X2_BW_125HZ: + Bandwidth = SMI_ACC2X2_BW_125HZ; + smi130_acc->time_odr = 4000000; + /* 125 Hz 4000 uS */ + break; + case SMI_ACC2X2_BW_250HZ: + Bandwidth = SMI_ACC2X2_BW_250HZ; + smi130_acc->time_odr = 2000000; + /* 250 Hz 2000 uS */ + break; + case SMI_ACC2X2_BW_500HZ: + Bandwidth = SMI_ACC2X2_BW_500HZ; + smi130_acc->time_odr = 1000000; + /* 500 Hz 1000 uS */ + break; + case SMI_ACC2X2_BW_1000HZ: + Bandwidth = SMI_ACC2X2_BW_1000HZ; + smi130_acc->time_odr = 500000; + /* 1000 Hz 500 uS */ + break; + default: + break; + } + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_BANDWIDTH__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_BANDWIDTH, Bandwidth); + comres += smi130_acc_smbus_write_byte(client, SMI_ACC2X2_BANDWIDTH__REG, + &data); + } else { + comres = -1; + } + + return comres; +} + +static int smi130_acc_get_bandwidth(struct i2c_client *client, unsigned char *BW) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_BANDWIDTH__REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_BANDWIDTH); + *BW = data; + + return comres; +} + +int smi130_acc_get_sleep_duration(struct i2c_client *client, unsigned char + *sleep_dur) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_SLEEP_DUR__REG, &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_SLEEP_DUR); + *sleep_dur = data; + + return comres; +} + +int smi130_acc_set_sleep_duration(struct i2c_client *client, unsigned char + sleep_dur) +{ + int comres = 0; + unsigned char data = 0; + int sleep_duration = 0; + + if (sleep_dur > 4 && sleep_dur < 16) { + switch (sleep_dur) { + case SMI_ACC2X2_SLEEP_DUR_0_5MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_0_5MS; + + /* 0.5 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_1MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_1MS; + + /* 1 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_2MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_2MS; + + /* 2 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_4MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_4MS; + + /* 4 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_6MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_6MS; + + /* 6 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_10MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_10MS; + + /* 10 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_25MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_25MS; + + /* 25 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_50MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_50MS; + + /* 50 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_100MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_100MS; + + /* 100 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_500MS: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_500MS; + + /* 500 MS */ + break; + case SMI_ACC2X2_SLEEP_DUR_1S: + sleep_duration = SMI_ACC2X2_SLEEP_DUR_1S; + + /* 1 SECS */ + break; + default: + break; + } + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_SLEEP_DUR__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_SLEEP_DUR, + sleep_duration); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_SLEEP_DUR__REG, + &data); + } else { + comres = -1; + } + + + return comres; +} + +static int smi130_acc_get_fifo_mode(struct i2c_client *client, unsigned char + *fifo_mode) +{ + int comres; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_FIFO_MODE__REG, &data); + *fifo_mode = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FIFO_MODE); + + return comres; +} + +static int smi130_acc_set_fifo_mode(struct i2c_client *client, unsigned char + fifo_mode) +{ + unsigned char data = 0; + int comres = 0; + + if (fifo_mode < 4) { + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_FIFO_MODE__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_FIFO_MODE, fifo_mode); + /*! Aim at fifo workarounds with FIFO_CONFIG_1 */ + data |= FIFO_WORKAROUNDS_MSK; + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_FIFO_MODE__REG, + &data); + } else { + comres = -1; + } + + return comres; +} + +static int smi130_acc_get_fifo_trig(struct i2c_client *client, unsigned char + *fifo_trig) +{ + int comres; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_FIFO_TRIGGER_ACTION__REG, &data); + *fifo_trig = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FIFO_TRIGGER_ACTION); + + return comres; +} + +static int smi130_acc_set_fifo_trig(struct i2c_client *client, unsigned char + fifo_trig) +{ + unsigned char data = 0; + int comres = 0; + + if (fifo_trig < 4) { + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_FIFO_TRIGGER_ACTION__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_FIFO_TRIGGER_ACTION, + fifo_trig); + /*! Aim at fifo workarounds with FIFO_CONFIG_1 */ + data |= FIFO_WORKAROUNDS_MSK; + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_FIFO_TRIGGER_ACTION__REG, &data); + } else { + comres = -1; + } + + return comres; +} + +static int smi130_acc_get_fifo_trig_src(struct i2c_client *client, unsigned char + *trig_src) +{ + int comres; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_FIFO_TRIGGER_SOURCE__REG, &data); + *trig_src = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FIFO_TRIGGER_SOURCE); + + return comres; +} + +static int smi130_acc_set_fifo_trig_src(struct i2c_client *client, unsigned char + trig_src) +{ + unsigned char data = 0; + int comres = 0; + + if (trig_src < 4) { + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_FIFO_TRIGGER_SOURCE__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_FIFO_TRIGGER_SOURCE, + trig_src); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_FIFO_TRIGGER_SOURCE__REG, &data); + } else { + comres = -1; + } + + return comres; +} + +static int smi130_acc_get_fifo_framecount(struct i2c_client *client, unsigned char + *framecount) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_FIFO_FRAME_COUNTER_S__REG, &data); + *framecount = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FIFO_FRAME_COUNTER_S); + + return comres; +} + +static int smi130_acc_get_fifo_data_sel(struct i2c_client *client, unsigned char + *data_sel) +{ + int comres; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_FIFO_DATA_SELECT__REG, &data); + *data_sel = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FIFO_DATA_SELECT); + + return comres; +} + +static int smi130_acc_set_fifo_data_sel(struct i2c_client *client, unsigned char + data_sel) +{ + unsigned char data = 0; + int comres = 0; + + if (data_sel < 4) { + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_FIFO_DATA_SELECT__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_FIFO_DATA_SELECT, + data_sel); + /*! Aim at fifo workarounds with FIFO_CONFIG_1 */ + data |= FIFO_WORKAROUNDS_MSK; + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_FIFO_DATA_SELECT__REG, + &data); + } else { + comres = -1; + } + + return comres; +} + + +static int smi130_acc_get_offset_target(struct i2c_client *client, unsigned char + channel, unsigned char *offset) +{ + unsigned char data = 0; + int comres = 0; + + switch (channel) { + case SMI_ACC2X2_CUT_OFF: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_CUTOFF__REG, &data); + *offset = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_COMP_CUTOFF); + break; + case SMI_ACC2X2_OFFSET_TRIGGER_X: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_X__REG, &data); + *offset = SMI_ACC2X2_GET_BITSLICE(data, + SMI_ACC2X2_COMP_TARGET_OFFSET_X); + break; + case SMI_ACC2X2_OFFSET_TRIGGER_Y: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_Y__REG, &data); + *offset = SMI_ACC2X2_GET_BITSLICE(data, + SMI_ACC2X2_COMP_TARGET_OFFSET_Y); + break; + case SMI_ACC2X2_OFFSET_TRIGGER_Z: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_Z__REG, &data); + *offset = SMI_ACC2X2_GET_BITSLICE(data, + SMI_ACC2X2_COMP_TARGET_OFFSET_Z); + break; + default: + comres = -1; + break; + } + + return comres; +} + +static int smi130_acc_set_offset_target(struct i2c_client *client, unsigned char + channel, unsigned char offset) +{ + unsigned char data = 0; + int comres = 0; + + switch (channel) { + case SMI_ACC2X2_CUT_OFF: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_CUTOFF__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_COMP_CUTOFF, + offset); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_COMP_CUTOFF__REG, &data); + break; + case SMI_ACC2X2_OFFSET_TRIGGER_X: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_X__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, + SMI_ACC2X2_COMP_TARGET_OFFSET_X, + offset); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_X__REG, + &data); + break; + case SMI_ACC2X2_OFFSET_TRIGGER_Y: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_Y__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, + SMI_ACC2X2_COMP_TARGET_OFFSET_Y, + offset); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_Y__REG, + &data); + break; + case SMI_ACC2X2_OFFSET_TRIGGER_Z: + comres = smi130_acc_smbus_read_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_Z__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, + SMI_ACC2X2_COMP_TARGET_OFFSET_Z, + offset); + comres = smi130_acc_smbus_write_byte(client, + SMI_ACC2X2_COMP_TARGET_OFFSET_Z__REG, + &data); + break; + default: + comres = -1; + break; + } + + return comres; +} + +static int smi130_acc_get_cal_ready(struct i2c_client *client, + unsigned char *calrdy) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_FAST_CAL_RDY_S__REG, + &data); + data = SMI_ACC2X2_GET_BITSLICE(data, SMI_ACC2X2_FAST_CAL_RDY_S); + *calrdy = data; + + return comres; +} + +static int smi130_acc_set_cal_trigger(struct i2c_client *client, unsigned char + caltrigger) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_CAL_TRIGGER__REG, &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_CAL_TRIGGER, caltrigger); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_CAL_TRIGGER__REG, + &data); + + return comres; +} + +static int smi130_acc_write_reg(struct i2c_client *client, unsigned char addr, + unsigned char *data) +{ + int comres = 0; + comres = smi130_acc_smbus_write_byte(client, addr, data); + + return comres; +} + + +static int smi130_acc_set_offset_x(struct i2c_client *client, unsigned char + offsetfilt) +{ + int comres = 0; + unsigned char data = 0; + + data = offsetfilt; + +#ifdef CONFIG_SENSORS_BMI058 + comres = smi130_acc_smbus_write_byte(client, BMI058_OFFSET_X_AXIS_REG, + &data); +#else + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_OFFSET_X_AXIS_REG, + &data); +#endif + + return comres; +} + + +static int smi130_acc_get_offset_x(struct i2c_client *client, unsigned char + *offsetfilt) +{ + int comres = 0; + unsigned char data = 0; + +#ifdef CONFIG_SENSORS_BMI058 + comres = smi130_acc_smbus_read_byte(client, BMI058_OFFSET_X_AXIS_REG, + &data); +#else + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_OFFSET_X_AXIS_REG, + &data); +#endif + *offsetfilt = data; + + return comres; +} + +static int smi130_acc_set_offset_y(struct i2c_client *client, unsigned char + offsetfilt) +{ + int comres = 0; + unsigned char data = 0; + + data = offsetfilt; + +#ifdef CONFIG_SENSORS_BMI058 + comres = smi130_acc_smbus_write_byte(client, BMI058_OFFSET_Y_AXIS_REG, + &data); +#else + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_OFFSET_Y_AXIS_REG, + &data); +#endif + return comres; +} + +static int smi130_acc_get_offset_y(struct i2c_client *client, unsigned char + *offsetfilt) +{ + int comres = 0; + unsigned char data = 0; + +#ifdef CONFIG_SENSORS_BMI058 + comres = smi130_acc_smbus_read_byte(client, BMI058_OFFSET_Y_AXIS_REG, + &data); +#else + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_OFFSET_Y_AXIS_REG, + &data); +#endif + *offsetfilt = data; + + return comres; +} + +static int smi130_acc_set_offset_z(struct i2c_client *client, unsigned char + offsetfilt) +{ + int comres = 0; + unsigned char data = 0; + + data = offsetfilt; + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_OFFSET_Z_AXIS_REG, + &data); + + return comres; +} + +static int smi130_acc_get_offset_z(struct i2c_client *client, unsigned char + *offsetfilt) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_OFFSET_Z_AXIS_REG, + &data); + *offsetfilt = data; + + return comres; +} + + +static int smi130_acc_set_selftest_st(struct i2c_client *client, unsigned char + selftest) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_EN_SELF_TEST__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_EN_SELF_TEST, selftest); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_EN_SELF_TEST__REG, + &data); + + return comres; +} + +static int smi130_acc_set_selftest_stn(struct i2c_client *client, unsigned char stn) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_NEG_SELF_TEST__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_NEG_SELF_TEST, stn); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_NEG_SELF_TEST__REG, + &data); + + return comres; +} + +static int smi130_acc_set_selftest_amp(struct i2c_client *client, unsigned char amp) +{ + int comres = 0; + unsigned char data = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_SELF_TEST_AMP__REG, + &data); + data = SMI_ACC2X2_SET_BITSLICE(data, SMI_ACC2X2_SELF_TEST_AMP, amp); + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_SELF_TEST_AMP__REG, + &data); + + return comres; +} + +static int smi130_acc_read_accel_x(struct i2c_client *client, + signed char sensor_type, short *a_x) +{ + int comres = 0; + unsigned char data[2] = {0}; + + switch (sensor_type) { + case 0: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_X12_LSB__REG, data, 2); + *a_x = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_X12_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_X_MSB)<<(SMI_ACC2X2_ACC_X12_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(SMI_ACC2X2_ACC_X12_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(SMI_ACC2X2_ACC_X12_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + break; + case 1: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_X10_LSB__REG, data, 2); + *a_x = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_X10_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_X_MSB)<<(SMI_ACC2X2_ACC_X10_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(SMI_ACC2X2_ACC_X10_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(SMI_ACC2X2_ACC_X10_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + break; + case 2: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_X8_LSB__REG, data, 2); + *a_x = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_X8_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_X_MSB)<<(SMI_ACC2X2_ACC_X8_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(SMI_ACC2X2_ACC_X8_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(SMI_ACC2X2_ACC_X8_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + break; + case 3: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_X14_LSB__REG, data, 2); + *a_x = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_X14_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_X_MSB)<<(SMI_ACC2X2_ACC_X14_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(SMI_ACC2X2_ACC_X14_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(SMI_ACC2X2_ACC_X14_LSB__LEN + + SMI_ACC2X2_ACC_X_MSB__LEN)); + break; + default: + break; + } + + return comres; +} + +static int smi130_acc_soft_reset(struct i2c_client *client) +{ + int comres = 0; + unsigned char data = SMI_ACC2X2_EN_SOFT_RESET_VALUE; + + comres = smi130_acc_smbus_write_byte(client, SMI_ACC2X2_EN_SOFT_RESET__REG, + &data); + + return comres; +} + +static int smi130_acc_read_accel_y(struct i2c_client *client, + signed char sensor_type, short *a_y) +{ + int comres = 0; + unsigned char data[2] = {0}; + + switch (sensor_type) { + case 0: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Y12_LSB__REG, data, 2); + *a_y = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Y12_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Y_MSB)<<(SMI_ACC2X2_ACC_Y12_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(SMI_ACC2X2_ACC_Y12_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Y12_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + break; + case 1: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Y10_LSB__REG, data, 2); + *a_y = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Y10_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Y_MSB)<<(SMI_ACC2X2_ACC_Y10_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(SMI_ACC2X2_ACC_Y10_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Y10_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + break; + case 2: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Y8_LSB__REG, data, 2); + *a_y = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Y8_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Y_MSB)<<(SMI_ACC2X2_ACC_Y8_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(SMI_ACC2X2_ACC_Y8_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Y8_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + break; + case 3: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Y14_LSB__REG, data, 2); + *a_y = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Y14_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Y_MSB)<<(SMI_ACC2X2_ACC_Y14_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(SMI_ACC2X2_ACC_Y14_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Y14_LSB__LEN + + SMI_ACC2X2_ACC_Y_MSB__LEN)); + break; + default: + break; + } + + return comres; +} + +static int smi130_acc_read_accel_z(struct i2c_client *client, + signed char sensor_type, short *a_z) +{ + int comres = 0; + unsigned char data[2] = {0}; + + switch (sensor_type) { + case 0: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Z12_LSB__REG, data, 2); + *a_z = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Z12_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Z_MSB)<<(SMI_ACC2X2_ACC_Z12_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(SMI_ACC2X2_ACC_Z12_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Z12_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + break; + case 1: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Z10_LSB__REG, data, 2); + *a_z = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Z10_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Z_MSB)<<(SMI_ACC2X2_ACC_Z10_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(SMI_ACC2X2_ACC_Z10_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Z10_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + break; + case 2: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Z8_LSB__REG, data, 2); + *a_z = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Z8_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Z_MSB)<<(SMI_ACC2X2_ACC_Z8_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(SMI_ACC2X2_ACC_Z8_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Z8_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + break; + case 3: + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_Z14_LSB__REG, data, 2); + *a_z = SMI_ACC2X2_GET_BITSLICE(data[0], SMI_ACC2X2_ACC_Z14_LSB)| + (SMI_ACC2X2_GET_BITSLICE(data[1], + SMI_ACC2X2_ACC_Z_MSB)<<(SMI_ACC2X2_ACC_Z14_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(SMI_ACC2X2_ACC_Z14_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(SMI_ACC2X2_ACC_Z14_LSB__LEN + + SMI_ACC2X2_ACC_Z_MSB__LEN)); + break; + default: + break; + } + + return comres; +} + + +static int smi130_acc_read_temperature(struct i2c_client *client, + signed char *temperature) +{ + unsigned char data = 0; + int comres = 0; + + comres = smi130_acc_smbus_read_byte(client, SMI_ACC2X2_TEMPERATURE_REG, &data); + *temperature = (signed char)data; + + return comres; +} + +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static inline int smi130_check_acc_early_buff_enable_flag( + struct smi130_acc_data *client_data) +{ + if (client_data->acc_buffer_smi130_samples == true) + return 1; + else + return 0; +} +#else +static inline int smi130_check_acc_early_buff_enable_flag( + struct smi130_acc_data *client_data) +{ + return 0; +} +#endif + +static ssize_t smi130_acc_enable_int_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int type, value; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); +#ifdef CONFIG_SENSORS_BMI058 + int i; +#endif + + sscanf(buf, "%3d %3d", &type, &value); + +#ifdef CONFIG_SENSORS_BMI058 + for (i = 0; i < sizeof(int_map) / sizeof(struct interrupt_map_t); i++) { + if (int_map[i].x == type) { + type = int_map[i].y; + break; + } + if (int_map[i].y == type) { + type = int_map[i].x; + break; + } + } +#endif + + if (smi130_acc_set_Int_Enable(smi130_acc->smi130_acc_client, type, value) < 0) + return -EINVAL; + + return count; +} + + +static ssize_t smi130_acc_int_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_Int_Mode(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_int_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_Int_Mode(smi130_acc->smi130_acc_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t smi130_acc_slope_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_slope_duration(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_slope_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_slope_duration(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_slope_no_mot_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_slope_no_mot_duration(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_slope_no_mot_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_slope_no_mot_duration(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + + +static ssize_t smi130_acc_slope_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_slope_threshold(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_slope_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_slope_threshold(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_slope_no_mot_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_slope_no_mot_threshold(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_slope_no_mot_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_slope_no_mot_threshold(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_high_g_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_high_g_duration(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_high_g_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_high_g_duration(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_high_g_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_high_g_threshold(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_high_g_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_high_g_threshold(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_low_g_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_low_g_duration(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_low_g_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_low_g_duration(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_low_g_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_low_g_threshold(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_low_g_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_low_g_threshold(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t smi130_acc_tap_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_tap_threshold(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_tap_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_tap_threshold(smi130_acc->smi130_acc_client, (unsigned char)data) + < 0) + return -EINVAL; + + return count; +} +static ssize_t smi130_acc_tap_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_tap_duration(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_tap_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_tap_duration(smi130_acc->smi130_acc_client, (unsigned char)data) + < 0) + return -EINVAL; + + return count; +} +static ssize_t smi130_acc_tap_quiet_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_tap_quiet(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_tap_quiet_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_tap_quiet(smi130_acc->smi130_acc_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_tap_shock_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_tap_shock(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_tap_shock_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_tap_shock(smi130_acc->smi130_acc_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_tap_samp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_tap_samp(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_tap_samp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_tap_samp(smi130_acc->smi130_acc_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_orient_mbl_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_orient_mbl_mode(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_orient_mbl_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_orient_mbl_mode(smi130_acc->smi130_acc_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_orient_mbl_blocking_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_orient_mbl_blocking(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_orient_mbl_blocking_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_orient_mbl_blocking(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t smi130_acc_orient_mbl_hyst_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_orient_mbl_hyst(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_orient_mbl_hyst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_orient_mbl_hyst(smi130_acc->smi130_acc_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_orient_mbl_theta_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_theta_blocking(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_orient_mbl_theta_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_theta_blocking(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_flat_theta_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_theta_flat(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_flat_theta_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_theta_flat(smi130_acc->smi130_acc_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} +static ssize_t smi130_acc_flat_hold_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_flat_hold_time(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} +static ssize_t smi130_acc_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%d\n", atomic_read(&smi130_acc->selftest_result)); + +} + +static ssize_t smi130_acc_softreset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_soft_reset(smi130_acc->smi130_acc_client) < 0) + return -EINVAL; + + return count; +} +static ssize_t smi130_acc_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + + unsigned long data; + unsigned char clear_value = 0; + int error; + short value1 = 0; + short value2 = 0; + short diff = 0; + unsigned long result = 0; + unsigned char test_result_branch = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + smi130_acc_soft_reset(smi130_acc->smi130_acc_client); + smi130_acc_delay(5); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (data != 1) + return -EINVAL; + + smi130_acc_write_reg(smi130_acc->smi130_acc_client, 0x32, &clear_value); + + if ((smi130_acc->sensor_type == SMI_ACC280_TYPE) || + (smi130_acc->sensor_type == SMI_ACC255_TYPE)) { +#ifdef CONFIG_SENSORS_BMI058 + /*set self test amp */ + if (smi130_acc_set_selftest_amp(smi130_acc->smi130_acc_client, 1) < 0) + return -EINVAL; + /* set to 8 G range */ + if (smi130_acc_set_range(smi130_acc->smi130_acc_client, + SMI_ACC2X2_RANGE_8G) < 0) + return -EINVAL; +#else + /* set to 4 G range */ + if (smi130_acc_set_range(smi130_acc->smi130_acc_client, + SMI_ACC2X2_RANGE_4G) < 0) + return -EINVAL; +#endif + } + + if ((smi130_acc->sensor_type == SMI_ACC250E_TYPE) || + (smi130_acc->sensor_type == SMI_ACC222E_TYPE)) { + /* set to 8 G range */ + if (smi130_acc_set_range(smi130_acc->smi130_acc_client, 8) < 0) + return -EINVAL; + if (smi130_acc_set_selftest_amp(smi130_acc->smi130_acc_client, 1) < 0) + return -EINVAL; + } + + /* 1 for x-axis(but BMI058 is 1 for y-axis )*/ + smi130_acc_set_selftest_st(smi130_acc->smi130_acc_client, 1); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 0); + smi130_acc_delay(10); + smi130_acc_read_accel_x(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value1); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 1); + smi130_acc_delay(10); + smi130_acc_read_accel_x(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value2); + diff = value1-value2; + +#ifdef CONFIG_SENSORS_BMI058 + PINFO("diff y is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + test_result_branch = 2; +#else + PINFO("diff x is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + test_result_branch = 1; +#endif + + if (smi130_acc->sensor_type == SMI_ACC280_TYPE) { +#ifdef CONFIG_SENSORS_BMI058 + if (abs(diff) < 819) + result |= test_result_branch; +#else + if (abs(diff) < 1638) + result |= test_result_branch; +#endif + } + if (smi130_acc->sensor_type == SMI_ACC255_TYPE) { + if (abs(diff) < 409) + result |= 1; + } + if (smi130_acc->sensor_type == SMI_ACC250E_TYPE) { + if (abs(diff) < 51) + result |= 1; + } + if (smi130_acc->sensor_type == SMI_ACC222E_TYPE) { + if (abs(diff) < 12) + result |= 1; + } + + /* 2 for y-axis but BMI058 is 1*/ + smi130_acc_set_selftest_st(smi130_acc->smi130_acc_client, 2); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 0); + smi130_acc_delay(10); + smi130_acc_read_accel_y(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value1); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 1); + smi130_acc_delay(10); + smi130_acc_read_accel_y(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value2); + diff = value1-value2; + +#ifdef CONFIG_SENSORS_BMI058 + PINFO("diff x is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + test_result_branch = 1; +#else + PINFO("diff y is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + test_result_branch = 2; +#endif + + if (smi130_acc->sensor_type == SMI_ACC280_TYPE) { +#ifdef CONFIG_SENSORS_BMI058 + if (abs(diff) < 819) + result |= test_result_branch; +#else + if (abs(diff) < 1638) + result |= test_result_branch; +#endif + } + if (smi130_acc->sensor_type == SMI_ACC255_TYPE) { + if (abs(diff) < 409) + result |= test_result_branch; + } + if (smi130_acc->sensor_type == SMI_ACC250E_TYPE) { + if (abs(diff) < 51) + result |= test_result_branch; + } + if (smi130_acc->sensor_type == SMI_ACC222E_TYPE) { + if (abs(diff) < 12) + result |= test_result_branch; + } + + + smi130_acc_set_selftest_st(smi130_acc->smi130_acc_client, 3); /* 3 for z-axis*/ + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 0); + smi130_acc_delay(10); + smi130_acc_read_accel_z(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value1); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 1); + smi130_acc_delay(10); + smi130_acc_read_accel_z(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value2); + diff = value1-value2; + + PINFO("diff z is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + + if (smi130_acc->sensor_type == SMI_ACC280_TYPE) { +#ifdef CONFIG_SENSORS_BMI058 + if (abs(diff) < 409) + result |= 4; +#else + if (abs(diff) < 819) + result |= 4; +#endif + } + if (smi130_acc->sensor_type == SMI_ACC255_TYPE) { + if (abs(diff) < 204) + result |= 4; + } + if (smi130_acc->sensor_type == SMI_ACC250E_TYPE) { + if (abs(diff) < 25) + result |= 4; + } + if (smi130_acc->sensor_type == SMI_ACC222E_TYPE) { + if (abs(diff) < 6) + result |= 4; + } + + /* self test for smi_acc254 */ + if ((smi130_acc->sensor_type == SMI_ACC255_TYPE) && (result > 0)) { + result = 0; + smi130_acc_soft_reset(smi130_acc->smi130_acc_client); + smi130_acc_delay(5); + smi130_acc_write_reg(smi130_acc->smi130_acc_client, 0x32, &clear_value); + /* set to 8 G range */ + if (smi130_acc_set_range(smi130_acc->smi130_acc_client, 8) < 0) + return -EINVAL; + if (smi130_acc_set_selftest_amp(smi130_acc->smi130_acc_client, 1) < 0) + return -EINVAL; + + smi130_acc_set_selftest_st(smi130_acc->smi130_acc_client, 1); /* 1 + for x-axis*/ + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 0); /* + positive direction*/ + smi130_acc_delay(10); + smi130_acc_read_accel_x(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value1); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 1); /* + negative direction*/ + smi130_acc_delay(10); + smi130_acc_read_accel_x(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value2); + diff = value1-value2; + + PINFO("diff x is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + if (abs(diff) < 204) + result |= 1; + + smi130_acc_set_selftest_st(smi130_acc->smi130_acc_client, 2); /* 2 + for y-axis*/ + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 0); /* + positive direction*/ + smi130_acc_delay(10); + smi130_acc_read_accel_y(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value1); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 1); /* + negative direction*/ + smi130_acc_delay(10); + smi130_acc_read_accel_y(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value2); + diff = value1-value2; + PINFO("diff y is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + + if (abs(diff) < 204) + result |= 2; + + smi130_acc_set_selftest_st(smi130_acc->smi130_acc_client, 3); /* 3 + for z-axis*/ + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 0); /* + positive direction*/ + smi130_acc_delay(10); + smi130_acc_read_accel_z(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value1); + smi130_acc_set_selftest_stn(smi130_acc->smi130_acc_client, 1); /* + negative direction*/ + smi130_acc_delay(10); + smi130_acc_read_accel_z(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &value2); + diff = value1-value2; + + PINFO("diff z is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + if (abs(diff) < 102) + result |= 4; + } + + atomic_set(&smi130_acc->selftest_result, (unsigned int)result); + + smi130_acc_soft_reset(smi130_acc->smi130_acc_client); + smi130_acc_delay(5); + PINFO("self test finished\n"); + + return count; +} + + + +static ssize_t smi130_acc_flat_hold_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_flat_hold_time(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +const int smi130_acc_sensor_bitwidth[] = { + 12, 10, 8, 14 +}; + +static int smi130_acc_read_accel_xyz(struct i2c_client *client, + signed char sensor_type, struct smi130_accacc *acc) +{ + int comres = 0; + unsigned char data[6] = {0}; + struct smi130_acc_data *client_data = i2c_get_clientdata(client); +#ifndef SMI_ACC2X2_SENSOR_IDENTIFICATION_ENABLE + int bitwidth; +#endif + comres = smi130_acc_smbus_read_byte_block(client, + SMI_ACC2X2_ACC_X12_LSB__REG, data, 6); + if (sensor_type >= 4) + return -EINVAL; + + acc->x = (data[1]<<8)|data[0]; + acc->y = (data[3]<<8)|data[2]; + acc->z = (data[5]<<8)|data[4]; + +#ifndef SMI_ACC2X2_SENSOR_IDENTIFICATION_ENABLE + bitwidth = smi130_acc_sensor_bitwidth[sensor_type]; + + acc->x = (acc->x >> (16 - bitwidth)); + acc->y = (acc->y >> (16 - bitwidth)); + acc->z = (acc->z >> (16 - bitwidth)); +#endif + + smi130_acc_remap_sensor_data(acc, client_data); + return comres; +} + +#ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT +static void smi130_acc_work_func(struct work_struct *work) +{ + struct smi130_acc_data *smi130_acc = container_of((struct delayed_work *)work, + struct smi130_acc_data, work); + static struct smi130_accacc acc; + unsigned long delay = msecs_to_jiffies(atomic_read(&smi130_acc->delay)); + + smi130_acc_read_accel_xyz(smi130_acc->smi130_acc_client, smi130_acc->sensor_type, &acc); + input_report_abs(smi130_acc->input, ABS_X, acc.x); + input_report_abs(smi130_acc->input, ABS_Y, acc.y); + input_report_abs(smi130_acc->input, ABS_Z, acc.z); + input_sync(smi130_acc->input); + mutex_lock(&smi130_acc->value_mutex); + smi130_acc->value = acc; + mutex_unlock(&smi130_acc->value_mutex); + schedule_delayed_work(&smi130_acc->work, delay); +} +#endif +static struct workqueue_struct *reportdata_wq; + +uint64_t smi130_acc_get_alarm_timestamp(void) +{ + uint64_t ts_ap; + struct timespec tmp_time; + get_monotonic_boottime(&tmp_time); + ts_ap = (uint64_t)tmp_time.tv_sec * 1000000000 + tmp_time.tv_nsec; + return ts_ap; +} + +#define ABS(x) ((x) > 0 ? (x) : -(x)) + +static void smi130_acc_timer_work_fun(struct work_struct *work) +{ + struct smi130_acc_data *smi130_acc = + container_of(work, + struct smi130_acc_data, report_data_work); + int i; + unsigned char count = 0; + unsigned char mode = 0; + signed char fifo_data_out[MAX_FIFO_F_LEVEL * MAX_FIFO_F_BYTES] = {0}; + unsigned char f_len = 0; + uint64_t del = 0; + uint64_t time_internal = 0; + int64_t drift_time = 0; + static uint64_t time_odr; + struct smi130_accacc acc_lsb; + struct timespec ts; + static uint32_t data_cnt; + static uint32_t pre_data_cnt; + static int64_t sample_drift_offset; + + if (smi130_acc->fifo_datasel) { + /*Select one axis data output for every fifo frame*/ + f_len = 2; + } else { + /*Select X Y Z axis data output for every fifo frame*/ + f_len = 6; + } + if (smi130_acc_get_fifo_framecount(smi130_acc->smi130_acc_client, &count) < 0) { + PERR("smi130_acc_get_fifo_framecount err\n"); + return; + } + if (count == 0) { + PERR("smi130_acc_get_fifo_framecount zero\n"); + return; + } + if (count > MAX_FIFO_F_LEVEL) { + if (smi130_acc_get_mode(smi130_acc->smi130_acc_client, &mode) < 0) { + PERR("smi130_acc_get_mode err\n"); + return; + } + if (SMI_ACC2X2_MODE_NORMAL == mode) { + PERR("smi130_acc fifo_count: %d abnormal, op_mode: %d\n", + count, mode); + count = MAX_FIFO_F_LEVEL; + } else { + /*chip already suspend or shutdown*/ + count = 0; + return; + } + } + if (smi_acc_i2c_burst_read(smi130_acc->smi130_acc_client, + SMI_ACC2X2_FIFO_DATA_OUTPUT_REG, fifo_data_out, + count * f_len) < 0) { + PERR("smi130_acc read fifo err\n"); + return; + } + smi130_acc->fifo_time = smi130_acc_get_alarm_timestamp(); + if (smi130_acc->acc_count == 0) + smi130_acc->base_time = smi130_acc->timestamp = + smi130_acc->fifo_time - (count-1) * smi130_acc->time_odr; + + smi130_acc->acc_count += count; + del = smi130_acc->fifo_time - smi130_acc->base_time; + time_internal = div64_u64(del, smi130_acc->acc_count); + + data_cnt++; + if (data_cnt == 1) + time_odr = smi130_acc->time_odr; + + if (time_internal > time_odr) { + if (time_internal - time_odr > div64_u64 (time_odr, 200)) + time_internal = time_odr + div64_u64(time_odr, 200); + } else { + if (time_odr - time_internal > div64_u64(time_odr, 200)) + time_internal = time_odr - div64_u64(time_odr, 200); + } +/* please give attation for the fifo output data format*/ + if (f_len == 6) { + /* Select X Y Z axis data output for every frame */ + for (i = 0; i < count; i++) { + if (smi130_acc->debug_level & 0x01) + printk(KERN_INFO "smi_acc time =%llu fifo_time =%llu smi_acc->count=%llu time_internal =%lld time_odr = %lld ", + smi130_acc->timestamp, smi130_acc->fifo_time, + smi130_acc->acc_count, time_internal, time_odr); + + ts = ns_to_timespec(smi130_acc->timestamp); + acc_lsb.x = + ((unsigned char)fifo_data_out[i * f_len + 1] << 8 | + (unsigned char)fifo_data_out[i * f_len + 0]); + acc_lsb.y = + ((unsigned char)fifo_data_out[i * f_len + 3] << 8 | + (unsigned char)fifo_data_out[i * f_len + 2]); + acc_lsb.z = + ((unsigned char)fifo_data_out[i * f_len + 5] << 8 | + (unsigned char)fifo_data_out[i * f_len + 4]); +#ifndef SMI_ACC2X2_SENSOR_IDENTIFICATION_ENABLE + acc_lsb.x >>= + (16 - smi130_acc_sensor_bitwidth[smi130_acc->sensor_type]); + acc_lsb.y >>= + (16 - smi130_acc_sensor_bitwidth[smi130_acc->sensor_type]); + acc_lsb.z >>= + (16 - smi130_acc_sensor_bitwidth[smi130_acc->sensor_type]); +#endif + smi130_acc_remap_sensor_data(&acc_lsb, smi130_acc); + input_event(smi130_acc->input, EV_MSC, MSC_TIME, + ts.tv_sec); + input_event(smi130_acc->input, EV_MSC, MSC_TIME, + ts.tv_nsec); + input_event(smi130_acc->input, EV_MSC, + MSC_GESTURE, acc_lsb.x); + input_event(smi130_acc->input, EV_MSC, + MSC_RAW, acc_lsb.y); + input_event(smi130_acc->input, EV_MSC, + MSC_SCAN, acc_lsb.z); + input_sync(smi130_acc->input); + smi130_acc->timestamp += + time_internal - sample_drift_offset; + } + } + drift_time = smi130_acc->timestamp - smi130_acc->fifo_time; + if (data_cnt % 20 == 0) { + if (ABS(drift_time) > div64_u64(time_odr, 5)) { + sample_drift_offset = + div64_s64(drift_time, smi130_acc->acc_count - pre_data_cnt); + pre_data_cnt = smi130_acc->acc_count; + time_odr = time_internal; + } + } + +} + +static enum hrtimer_restart reportdata_timer_fun( + struct hrtimer *hrtimer) +{ + struct smi130_acc_data *client_data = + container_of(hrtimer, struct smi130_acc_data, timer); + int32_t delay = 0; + delay = 8; + queue_work(reportdata_wq, &(client_data->report_data_work)); + /*set delay 8ms*/ + client_data->work_delay_kt = ns_to_ktime(delay*1000000); + hrtimer_forward(hrtimer, ktime_get(), client_data->work_delay_kt); + + return HRTIMER_RESTART; +} + +static ssize_t smi130_acc_enable_timer_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%d\n", smi130_acc->is_timer_running); +} + +static ssize_t smi130_acc_enable_timer_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (data) { + if (0 == smi130_acc->is_timer_running) { + hrtimer_start(&smi130_acc->timer, + ns_to_ktime(1000000), + HRTIMER_MODE_REL); + smi130_acc->base_time = 0; + smi130_acc->timestamp = 0; + smi130_acc->is_timer_running = 1; + } + } else { + if (1 == smi130_acc->is_timer_running) { + hrtimer_cancel(&smi130_acc->timer); + smi130_acc->is_timer_running = 0; + smi130_acc->base_time = 0; + smi130_acc->timestamp = 0; + smi130_acc->fifo_time = 0; + smi130_acc->acc_count = 0; + } + } + return count; +} + +static ssize_t smi130_acc_debug_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + err = snprintf(buf, 8, "%d\n", smi130_acc->debug_level); + return err; +} +static ssize_t smi130_acc_debug_level_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int32_t ret = 0; + unsigned long data; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + ret = kstrtoul(buf, 16, &data); + if (ret) + return ret; + smi130_acc->debug_level = (uint8_t)data; + return count; +} + +static ssize_t smi130_acc_register_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int address, value; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + sscanf(buf, "%3d %3d", &address, &value); + if (smi130_acc_write_reg(smi130_acc->smi130_acc_client, (unsigned char)address, + (unsigned char *)&value) < 0) + return -EINVAL; + return count; +} +static ssize_t smi130_acc_register_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + size_t count = 0; + u8 reg[0x40] = {0}; + int i; + + for (i = 0; i < 0x40; i++) { + smi130_acc_smbus_read_byte(smi130_acc->smi130_acc_client, i, reg+i); + + count += snprintf(&buf[count], 32, "0x%x: %d\n", i, reg[i]); + } + return count; + + +} + +static ssize_t smi130_acc_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_range(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = smi130_check_acc_early_buff_enable_flag(smi130_acc); + if (error) + return count; + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_range(smi130_acc->smi130_acc_client, (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_bandwidth_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_bandwidth(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_bandwidth_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = smi130_check_acc_early_buff_enable_flag(smi130_acc); + if (error) + return count; + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc->sensor_type == SMI_ACC280_TYPE) + if ((unsigned char) data > 14) + return -EINVAL; + + if (smi130_acc_set_bandwidth(smi130_acc->smi130_acc_client, + (unsigned char) data) < 0) + return -EINVAL; + smi130_acc->base_time = 0; + smi130_acc->acc_count = 0; + + return count; +} + +static ssize_t smi130_acc_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_mode(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 32, "%d %d\n", data, smi130_acc->smi_acc_mode_enabled); +} + +static ssize_t smi130_acc_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = smi130_check_acc_early_buff_enable_flag(smi130_acc); + if (error) + return count; + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_mode(smi130_acc->smi130_acc_client, + (unsigned char) data, SMI_ACC_ENABLED_BSX) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_value_cache_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi130_acc_data *smi130_acc = input_get_drvdata(input); + struct smi130_accacc acc_value; + + mutex_lock(&smi130_acc->value_mutex); + acc_value = smi130_acc->value; + mutex_unlock(&smi130_acc->value_mutex); + + return snprintf(buf, 96, "%d %d %d\n", acc_value.x, acc_value.y, + acc_value.z); +} + +static ssize_t smi130_acc_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi130_acc_data *smi130_acc = input_get_drvdata(input); + struct smi130_accacc acc_value; + + smi130_acc_read_accel_xyz(smi130_acc->smi130_acc_client, smi130_acc->sensor_type, + &acc_value); + + return snprintf(buf, 96, "%d %d %d\n", acc_value.x, acc_value.y, + acc_value.z); +} + +static ssize_t smi130_acc_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%d\n", atomic_read(&smi130_acc->delay)); + +} + +static ssize_t smi130_acc_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%u\n", smi130_acc->chip_id); + +} + + +static ssize_t smi130_acc_place_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + int place = BOSCH_SENSOR_PLACE_UNKNOWN; + + if (NULL != smi130_acc->bosch_pd) + place = smi130_acc->bosch_pd->place; + + return snprintf(buf, 16, "%d\n", place); +} + + +static ssize_t smi130_acc_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (data > SMI_ACC2X2_MAX_DELAY) + data = SMI_ACC2X2_MAX_DELAY; + atomic_set(&smi130_acc->delay, (unsigned int) data); + + return count; +} + + +static ssize_t smi130_acc_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%d\n", atomic_read(&smi130_acc->enable)); + +} + +static void smi130_acc_set_enable(struct device *dev, int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + int pre_enable = atomic_read(&smi130_acc->enable); + + mutex_lock(&smi130_acc->enable_mutex); + if (enable) { + if (pre_enable == 0) { + smi130_acc_set_mode(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_NORMAL, SMI_ACC_ENABLED_INPUT); + + #ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + schedule_delayed_work(&smi130_acc->work, + msecs_to_jiffies(atomic_read(&smi130_acc->delay))); +#endif + atomic_set(&smi130_acc->enable, 1); + } + + } else { + if (pre_enable == 1) { + smi130_acc_set_mode(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_SUSPEND, SMI_ACC_ENABLED_INPUT); + + #ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + cancel_delayed_work_sync(&smi130_acc->work); +#endif + atomic_set(&smi130_acc->enable, 0); + } + } + mutex_unlock(&smi130_acc->enable_mutex); + +} + +static ssize_t smi130_acc_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if ((data == 0) || (data == 1)) + smi130_acc_set_enable(dev, data); + + return count; +} +static ssize_t smi130_acc_fast_calibration_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + +#ifdef CONFIG_SENSORS_BMI058 + if (smi130_acc_get_offset_target(smi130_acc->smi130_acc_client, + BMI058_OFFSET_TRIGGER_X, &data) < 0) + return -EINVAL; +#else + if (smi130_acc_get_offset_target(smi130_acc->smi130_acc_client, + SMI_ACC2X2_OFFSET_TRIGGER_X, &data) < 0) + return -EINVAL; +#endif + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_fast_calibration_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + +#ifdef CONFIG_SENSORS_BMI058 + if (smi130_acc_set_offset_target(smi130_acc->smi130_acc_client, + BMI058_OFFSET_TRIGGER_X, (unsigned char)data) < 0) + return -EINVAL; +#else + if (smi130_acc_set_offset_target(smi130_acc->smi130_acc_client, + SMI_ACC2X2_OFFSET_TRIGGER_X, (unsigned char)data) < 0) + return -EINVAL; +#endif + + if (smi130_acc_set_cal_trigger(smi130_acc->smi130_acc_client, 1) < 0) + return -EINVAL; + + do { + smi130_acc_delay(2); + smi130_acc_get_cal_ready(smi130_acc->smi130_acc_client, &tmp); + + /*PINFO("wait 2ms cal ready flag is %d\n", tmp); */ + timeout++; + if (timeout == 50) { + PINFO("get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + PINFO("x axis fast calibration finished\n"); + return count; +} + +static ssize_t smi130_acc_fast_calibration_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + +#ifdef CONFIG_SENSORS_BMI058 + if (smi130_acc_get_offset_target(smi130_acc->smi130_acc_client, + BMI058_OFFSET_TRIGGER_Y, &data) < 0) + return -EINVAL; +#else + if (smi130_acc_get_offset_target(smi130_acc->smi130_acc_client, + SMI_ACC2X2_OFFSET_TRIGGER_Y, &data) < 0) + return -EINVAL; +#endif + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_fast_calibration_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + +#ifdef CONFIG_SENSORS_BMI058 + if (smi130_acc_set_offset_target(smi130_acc->smi130_acc_client, + BMI058_OFFSET_TRIGGER_Y, (unsigned char)data) < 0) + return -EINVAL; +#else + if (smi130_acc_set_offset_target(smi130_acc->smi130_acc_client, + SMI_ACC2X2_OFFSET_TRIGGER_Y, (unsigned char)data) < 0) + return -EINVAL; +#endif + + if (smi130_acc_set_cal_trigger(smi130_acc->smi130_acc_client, 2) < 0) + return -EINVAL; + + do { + smi130_acc_delay(2); + smi130_acc_get_cal_ready(smi130_acc->smi130_acc_client, &tmp); + + /*PINFO("wait 2ms cal ready flag is %d\n", tmp);*/ + timeout++; + if (timeout == 50) { + PINFO("get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + PINFO("y axis fast calibration finished\n"); + return count; +} + +static ssize_t smi130_acc_fast_calibration_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_offset_target(smi130_acc->smi130_acc_client, 3, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_fast_calibration_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_offset_target(smi130_acc->smi130_acc_client, 3, (unsigned + char)data) < 0) + return -EINVAL; + + if (smi130_acc_set_cal_trigger(smi130_acc->smi130_acc_client, 3) < 0) + return -EINVAL; + + do { + smi130_acc_delay(2); + smi130_acc_get_cal_ready(smi130_acc->smi130_acc_client, &tmp); + + /*PINFO("wait 2ms cal ready flag is %d\n", tmp);*/ + timeout++; + if (timeout == 50) { + PINFO("get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + PINFO("z axis fast calibration finished\n"); + return count; +} + + +static ssize_t smi130_acc_SleepDur_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_sleep_duration(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_SleepDur_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_sleep_duration(smi130_acc->smi130_acc_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_fifo_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_fifo_mode(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_fifo_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_fifo_mode(smi130_acc->smi130_acc_client, + (unsigned char) data) < 0) + return -EINVAL; + return count; +} + + + +static ssize_t smi130_acc_fifo_trig_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_fifo_trig(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_fifo_trig_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_fifo_trig(smi130_acc->smi130_acc_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + + + +static ssize_t smi130_acc_fifo_trig_src_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_fifo_trig_src(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_fifo_trig_src_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (smi130_acc_set_fifo_trig_src(smi130_acc->smi130_acc_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + + +/*! + * @brief show fifo_data_sel axis definition(Android definition, not sensor HW reg). + * 0--> x, y, z axis fifo data for every frame + * 1--> only x axis fifo data for every frame + * 2--> only y axis fifo data for every frame + * 3--> only z axis fifo data for every frame + */ +static ssize_t smi130_acc_fifo_data_sel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + signed char place = BOSCH_SENSOR_PLACE_UNKNOWN; + if (smi130_acc_get_fifo_data_sel(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + +#ifdef CONFIG_SENSORS_BMI058 +/*Update BMI058 fifo_data_sel to the SMI130_ACC common definition*/ + if (BMI058_FIFO_DAT_SEL_X == data) + data = SMI_ACC2X2_FIFO_DAT_SEL_X; + else if (BMI058_FIFO_DAT_SEL_Y == data) + data = SMI_ACC2X2_FIFO_DAT_SEL_Y; +#endif + + /*remaping fifo_dat_sel if define virtual place in BSP files*/ + if ((NULL != smi130_acc->bosch_pd) && + (BOSCH_SENSOR_PLACE_UNKNOWN != smi130_acc->bosch_pd->place)) { + place = smi130_acc->bosch_pd->place; + /* sensor with place 0 needs not to be remapped */ + if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { + /* SMI_ACC2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3; + * but bosch_axis_remap_tab_dft[i].src_x:0, y:1, z:2 + * so we need to +1*/ + if (SMI_ACC2X2_FIFO_DAT_SEL_X == data) + data = bosch_axis_remap_tab_dft[place].src_x + 1; + else if (SMI_ACC2X2_FIFO_DAT_SEL_Y == data) + data = bosch_axis_remap_tab_dft[place].src_y + 1; + } + } + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_fifo_framecount_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + unsigned char mode; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_fifo_framecount(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + if (data > MAX_FIFO_F_LEVEL) { + + if (smi130_acc_get_mode(smi130_acc->smi130_acc_client, &mode) < 0) + return -EINVAL; + + if (SMI_ACC2X2_MODE_NORMAL == mode) { + PERR("smi130_acc fifo_count: %d abnormal, op_mode: %d", + data, mode); + data = MAX_FIFO_F_LEVEL; + } else { + /*chip already suspend or shutdown*/ + data = 0; + } + } + + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_fifo_framecount_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + smi130_acc->fifo_count = (unsigned int) data; + + return count; +} + +static ssize_t smi130_acc_temperature_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_read_temperature(smi130_acc->smi130_acc_client, &data) < 0) + return -EINVAL; + + return snprintf(buf, 16, "%d\n", data); + +} + +/*! + * @brief store fifo_data_sel axis definition(Android definition, not sensor HW reg). + * 0--> x, y, z axis fifo data for every frame + * 1--> only x axis fifo data for every frame + * 2--> only y axis fifo data for every frame + * 3--> only z axis fifo data for every frame + */ +static ssize_t smi130_acc_fifo_data_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + signed char place; + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + /*save fifo_data_sel(android definition)*/ + smi130_acc->fifo_datasel = (unsigned char) data; + + /*remaping fifo_dat_sel if define virtual place*/ + if ((NULL != smi130_acc->bosch_pd) && + (BOSCH_SENSOR_PLACE_UNKNOWN != smi130_acc->bosch_pd->place)) { + place = smi130_acc->bosch_pd->place; + /* sensor with place 0 needs not to be remapped */ + if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { + /*Need X Y axis revesal sensor place: P1, P3, P5, P7 */ + /* SMI_ACC2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3; + * but bosch_axis_remap_tab_dft[i].src_x:0, y:1, z:2 + * so we need to +1*/ + if (SMI_ACC2X2_FIFO_DAT_SEL_X == data) + data = bosch_axis_remap_tab_dft[place].src_x + 1; + else if (SMI_ACC2X2_FIFO_DAT_SEL_Y == data) + data = bosch_axis_remap_tab_dft[place].src_y + 1; + } + } +#ifdef CONFIG_SENSORS_BMI058 + /*Update BMI058 fifo_data_sel to the SMI130_ACC common definition*/ + if (SMI_ACC2X2_FIFO_DAT_SEL_X == data) + data = BMI058_FIFO_DAT_SEL_X; + else if (SMI_ACC2X2_FIFO_DAT_SEL_Y == data) + data = BMI058_FIFO_DAT_SEL_Y; + +#endif + if (smi130_acc_set_fifo_data_sel(smi130_acc->smi130_acc_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_fifo_data_out_frame_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char f_len = 0; + unsigned char count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + if (smi130_acc->fifo_datasel) { + /*Select one axis data output for every fifo frame*/ + f_len = 2; + } else { + /*Select X Y Z axis data output for every fifo frame*/ + f_len = 6; + } + if (smi130_acc_get_fifo_framecount(smi130_acc->smi130_acc_client, &count) < 0) { + PERR("smi130_acc_get_fifo_framecount err\n"); + return -EINVAL; + } + if (count == 0) + return 0; + if (smi_acc_i2c_burst_read(smi130_acc->smi130_acc_client, + SMI_ACC2X2_FIFO_DATA_OUTPUT_REG, buf, + count * f_len) < 0) + return -EINVAL; + + return count * f_len; +} + +static ssize_t smi130_acc_offset_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_offset_x(smi130_acc->smi130_acc_client, &data) < 0) + return snprintf(buf, 48, "Read error\n"); + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_offset_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_offset_x(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_offset_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_offset_y(smi130_acc->smi130_acc_client, &data) < 0) + return snprintf(buf, 48, "Read error\n"); + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_offset_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_offset_y(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_offset_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + if (smi130_acc_get_offset_z(smi130_acc->smi130_acc_client, &data) < 0) + return snprintf(buf, 48, "Read error\n"); + + return snprintf(buf, 16, "%d\n", data); + +} + +static ssize_t smi130_acc_offset_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (smi130_acc_set_offset_z(smi130_acc->smi130_acc_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi130_acc_driver_version_show(struct device *dev + , struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + int ret; + + if (smi130_acc == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + + ret = snprintf(buf, 128, "Driver version: %s\n", + DRIVER_VERSION); + return ret; +} + +#ifdef CONFIG_SIG_MOTION +static int smi130_acc_set_en_slope_int(struct smi130_acc_data *smi130_acc, + int en) +{ + int err; + struct i2c_client *client = smi130_acc->smi130_acc_client; + + if (en) { + /* Set the related parameters which needs to be fine tuned by + * interfaces: slope_threshold and slope_duration + */ + /*dur: 192 samples ~= 3s*/ + err = smi130_acc_set_slope_duration(client, 0x0); + err += smi130_acc_set_slope_threshold(client, 0x16); + + /*Enable the interrupts*/ + err += smi130_acc_set_Int_Enable(client, 5, 1);/*Slope X*/ + err += smi130_acc_set_Int_Enable(client, 6, 1);/*Slope Y*/ + err += smi130_acc_set_Int_Enable(client, 7, 1);/*Slope Z*/ + #ifdef SMI_ACC2X2_ENABLE_INT1 + /* TODO: SLOPE can now only be routed to INT1 pin*/ + err += smi130_acc_set_int1_pad_sel(client, PAD_SLOP); + #else + /* err += smi130_acc_set_int2_pad_sel(client, PAD_SLOP); */ + #endif + } else { + err = smi130_acc_set_Int_Enable(client, 5, 0);/*Slope X*/ + err += smi130_acc_set_Int_Enable(client, 6, 0);/*Slope Y*/ + err += smi130_acc_set_Int_Enable(client, 7, 0);/*Slope Z*/ + } + return err; +} + +static ssize_t smi130_acc_en_sig_motion_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%d\n", atomic_read(&smi130_acc->en_sig_motion)); +} + +static int smi130_acc_set_en_sig_motion(struct smi130_acc_data *smi130_acc, + int en) +{ + int err = 0; + + en = (en >= 1) ? 1 : 0; /* set sig motion sensor status */ + + if (atomic_read(&smi130_acc->en_sig_motion) != en) { + if (en) { + err = smi130_acc_set_mode(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_NORMAL, SMI_ACC_ENABLED_SGM); + err = smi130_acc_set_en_slope_int(smi130_acc, en); + enable_irq_wake(smi130_acc->IRQ); + } else { + disable_irq_wake(smi130_acc->IRQ); + err = smi130_acc_set_en_slope_int(smi130_acc, en); + err = smi130_acc_set_mode(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_SUSPEND, SMI_ACC_ENABLED_SGM); + } + atomic_set(&smi130_acc->en_sig_motion, en); + } + return err; +} + +static ssize_t smi130_acc_en_sig_motion_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if ((data == 0) || (data == 1)) + smi130_acc_set_en_sig_motion(smi130_acc, data); + + return count; +} +#endif + +#ifdef CONFIG_DOUBLE_TAP +static int smi130_acc_set_en_single_tap_int(struct smi130_acc_data *smi130_acc, int en) +{ + int err; + struct i2c_client *client = smi130_acc->smi130_acc_client; + + if (en) { + /* set tap interruption parameter here if needed. + smi130_acc_set_tap_duration(client, 0xc0); + smi130_acc_set_tap_threshold(client, 0x16); + */ + + /*Enable the single tap interrupts*/ + err = smi130_acc_set_Int_Enable(client, 8, 1); + #ifdef SMI_ACC2X2_ENABLE_INT1 + err += smi130_acc_set_int1_pad_sel(client, PAD_SINGLE_TAP); + #else + err += smi130_acc_set_int2_pad_sel(client, PAD_SINGLE_TAP); + #endif + } else { + err = smi130_acc_set_Int_Enable(client, 8, 0); + } + return err; +} + +static ssize_t smi130_acc_tap_time_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%d\n", smi130_acc->tap_time_period); +} + +static ssize_t smi130_acc_tap_time_period_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + smi130_acc->tap_time_period = data; + + return count; +} + +static ssize_t smi130_acc_en_double_tap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%d\n", atomic_read(&smi130_acc->en_double_tap)); +} + +static int smi130_acc_set_en_double_tap(struct smi130_acc_data *smi130_acc, + int en) +{ + int err = 0; + + en = (en >= 1) ? 1 : 0; + + if (atomic_read(&smi130_acc->en_double_tap) != en) { + if (en) { + err = smi130_acc_set_mode(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_NORMAL, SMI_ACC_ENABLED_DTAP); + err = smi130_acc_set_en_single_tap_int(smi130_acc, en); + } else { + err = smi130_acc_set_en_single_tap_int(smi130_acc, en); + err = smi130_acc_set_mode(smi130_acc->smi130_acc_client, + SMI_ACC2X2_MODE_SUSPEND, SMI_ACC_ENABLED_DTAP); + } + atomic_set(&smi130_acc->en_double_tap, en); + } + return err; +} + +static ssize_t smi130_acc_en_double_tap_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if ((data == 0) || (data == 1)) + smi130_acc_set_en_double_tap(smi130_acc, data); + + return count; +} + +static void smi130_acc_tap_timeout_handle(unsigned long data) +{ + struct smi130_acc_data *smi130_acc = (struct smi130_acc_data *)data; + + PINFO("tap interrupt handle, timeout\n"); + mutex_lock(&smi130_acc->tap_mutex); + smi130_acc->tap_times = 0; + mutex_unlock(&smi130_acc->tap_mutex); + + /* if a single tap need to report, open the define */ +#ifdef REPORT_SINGLE_TAP_WHEN_DOUBLE_TAP_SENSOR_ENABLED + input_report_rel(smi130_acc->dev_interrupt, + SINGLE_TAP_INTERRUPT, + SINGLE_TAP_INTERRUPT_HAPPENED); + input_sync(smi130_acc->dev_interrupt); +#endif + +} +#endif + +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static int smi_acc_read_bootsampl(struct smi130_acc_data *client_data, + unsigned long enable_read) +{ + int i = 0; + + if (enable_read) { + client_data->acc_buffer_smi130_samples = false; + for (i = 0; i < client_data->acc_bufsample_cnt; i++) { + if (client_data->debug_level & 0x08) + PINFO("acc=%d,x=%d,y=%d,z=%d,sec=%d,ns=%lld\n", + i, client_data->smi130_acc_samplist[i]->xyz[0], + client_data->smi130_acc_samplist[i]->xyz[1], + client_data->smi130_acc_samplist[i]->xyz[2], + client_data->smi130_acc_samplist[i]->tsec, + client_data->smi130_acc_samplist[i]->tnsec); + input_report_abs(client_data->accbuf_dev, ABS_X, + client_data->smi130_acc_samplist[i]->xyz[0]); + input_report_abs(client_data->accbuf_dev, ABS_Y, + client_data->smi130_acc_samplist[i]->xyz[1]); + input_report_abs(client_data->accbuf_dev, ABS_Z, + client_data->smi130_acc_samplist[i]->xyz[2]); + input_report_abs(client_data->accbuf_dev, ABS_RX, + client_data->smi130_acc_samplist[i]->tsec); + input_report_abs(client_data->accbuf_dev, ABS_RY, + client_data->smi130_acc_samplist[i]->tnsec); + input_sync(client_data->accbuf_dev); + } + } else { + /* clean up */ + if (client_data->acc_bufsample_cnt != 0) { + for (i = 0; i < SMI_ACC_MAXSAMPLE; i++) + kmem_cache_free(client_data->smi_acc_cachepool, + client_data->smi130_acc_samplist[i]); + kmem_cache_destroy(client_data->smi_acc_cachepool); + client_data->acc_bufsample_cnt = 0; + } + + } + /*SYN_CONFIG indicates end of data*/ + input_event(client_data->accbuf_dev, EV_SYN, SYN_CONFIG, 0xFFFFFFFF); + input_sync(client_data->accbuf_dev); + if (client_data->debug_level & 0x08) + PINFO("End of acc samples bufsample_cnt=%d\n", + client_data->acc_bufsample_cnt); + return 0; +} +static ssize_t read_acc_boot_sample_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + + return snprintf(buf, 16, "%u\n", + smi130_acc->read_acc_boot_sample); +} + +static ssize_t read_acc_boot_sample_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + struct i2c_client *client = to_i2c_client(dev); + struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client); + unsigned long enable = 0; + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable > 1) { + PERR("Invalid value of input, input=%ld\n", enable); + return -EINVAL; + } + err = smi_acc_read_bootsampl(smi130_acc, enable); + if (err) + return err; + + smi130_acc->read_acc_boot_sample = enable; + return count; +} +#endif + +static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, + smi130_acc_range_show, smi130_acc_range_store); +static DEVICE_ATTR(bandwidth, S_IRUGO | S_IWUSR, + smi130_acc_bandwidth_show, smi130_acc_bandwidth_store); +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static DEVICE_ATTR(read_acc_boot_sample, S_IRUGO|S_IWUSR, + read_acc_boot_sample_show, read_acc_boot_sample_store); +#endif +static DEVICE_ATTR(op_mode, S_IRUGO | S_IWUSR, + smi130_acc_mode_show, smi130_acc_mode_store); +static DEVICE_ATTR(value, S_IRUSR, + smi130_acc_value_show, NULL); +static DEVICE_ATTR(value_cache, S_IRUSR, + smi130_acc_value_cache_show, NULL); +static DEVICE_ATTR(delay, S_IRUGO | S_IWUSR, + smi130_acc_delay_show, smi130_acc_delay_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, + smi130_acc_enable_show, smi130_acc_enable_store); +static DEVICE_ATTR(SleepDur, S_IRUGO | S_IWUSR, + smi130_acc_SleepDur_show, smi130_acc_SleepDur_store); +static DEVICE_ATTR(fast_calibration_x, S_IRUGO | S_IWUSR, + smi130_acc_fast_calibration_x_show, + smi130_acc_fast_calibration_x_store); +static DEVICE_ATTR(fast_calibration_y, S_IRUGO | S_IWUSR, + smi130_acc_fast_calibration_y_show, + smi130_acc_fast_calibration_y_store); +static DEVICE_ATTR(fast_calibration_z, S_IRUGO | S_IWUSR, + smi130_acc_fast_calibration_z_show, + smi130_acc_fast_calibration_z_store); +static DEVICE_ATTR(fifo_mode, S_IRUGO | S_IWUSR, + smi130_acc_fifo_mode_show, smi130_acc_fifo_mode_store); +static DEVICE_ATTR(fifo_framecount, S_IRUGO | S_IWUSR, + smi130_acc_fifo_framecount_show, smi130_acc_fifo_framecount_store); +static DEVICE_ATTR(fifo_trig, S_IRUGO | S_IWUSR, + smi130_acc_fifo_trig_show, smi130_acc_fifo_trig_store); +static DEVICE_ATTR(fifo_trig_src, S_IRUGO | S_IWUSR, + smi130_acc_fifo_trig_src_show, smi130_acc_fifo_trig_src_store); +static DEVICE_ATTR(fifo_data_sel, S_IRUGO | S_IWUSR, + smi130_acc_fifo_data_sel_show, smi130_acc_fifo_data_sel_store); +static DEVICE_ATTR(fifo_data_frame, S_IRUGO, + smi130_acc_fifo_data_out_frame_show, NULL); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, + smi130_acc_register_show, smi130_acc_register_store); +static DEVICE_ATTR(chip_id, S_IRUSR, + smi130_acc_chip_id_show, NULL); +static DEVICE_ATTR(offset_x, S_IRUGO | S_IWUSR, + smi130_acc_offset_x_show, + smi130_acc_offset_x_store); +static DEVICE_ATTR(offset_y, S_IRUGO | S_IWUSR, + smi130_acc_offset_y_show, + smi130_acc_offset_y_store); +static DEVICE_ATTR(offset_z, S_IRUGO | S_IWUSR, + smi130_acc_offset_z_show, + smi130_acc_offset_z_store); +static DEVICE_ATTR(enable_int, S_IWUSR, + NULL, smi130_acc_enable_int_store); +static DEVICE_ATTR(int_mode, S_IRUGO | S_IWUSR, + smi130_acc_int_mode_show, smi130_acc_int_mode_store); +static DEVICE_ATTR(slope_duration, S_IRUGO | S_IWUSR, + smi130_acc_slope_duration_show, smi130_acc_slope_duration_store); +static DEVICE_ATTR(slope_threshold, S_IRUGO | S_IWUSR, + smi130_acc_slope_threshold_show, smi130_acc_slope_threshold_store); +static DEVICE_ATTR(slope_no_mot_duration, S_IRUGO | S_IWUSR, + smi130_acc_slope_no_mot_duration_show, + smi130_acc_slope_no_mot_duration_store); +static DEVICE_ATTR(slope_no_mot_threshold, S_IRUGO | S_IWUSR, + smi130_acc_slope_no_mot_threshold_show, + smi130_acc_slope_no_mot_threshold_store); +static DEVICE_ATTR(high_g_duration, S_IRUGO | S_IWUSR, + smi130_acc_high_g_duration_show, smi130_acc_high_g_duration_store); +static DEVICE_ATTR(high_g_threshold, S_IRUGO | S_IWUSR, + smi130_acc_high_g_threshold_show, smi130_acc_high_g_threshold_store); +static DEVICE_ATTR(low_g_duration, S_IRUGO | S_IWUSR, + smi130_acc_low_g_duration_show, smi130_acc_low_g_duration_store); +static DEVICE_ATTR(low_g_threshold, S_IRUGO | S_IWUSR, + smi130_acc_low_g_threshold_show, smi130_acc_low_g_threshold_store); +static DEVICE_ATTR(tap_duration, S_IRUGO | S_IWUSR, + smi130_acc_tap_duration_show, smi130_acc_tap_duration_store); +static DEVICE_ATTR(tap_threshold, S_IRUGO | S_IWUSR, + smi130_acc_tap_threshold_show, smi130_acc_tap_threshold_store); +static DEVICE_ATTR(tap_quiet, S_IRUGO | S_IWUSR, + smi130_acc_tap_quiet_show, smi130_acc_tap_quiet_store); +static DEVICE_ATTR(tap_shock, S_IRUGO | S_IWUSR, + smi130_acc_tap_shock_show, smi130_acc_tap_shock_store); +static DEVICE_ATTR(tap_samp, S_IRUGO | S_IWUSR, + smi130_acc_tap_samp_show, smi130_acc_tap_samp_store); +static DEVICE_ATTR(orient_mbl_mode, S_IRUGO | S_IWUSR, + smi130_acc_orient_mbl_mode_show, smi130_acc_orient_mbl_mode_store); +static DEVICE_ATTR(orient_mbl_blocking, S_IRUGO | S_IWUSR, + smi130_acc_orient_mbl_blocking_show, smi130_acc_orient_mbl_blocking_store); +static DEVICE_ATTR(orient_mbl_hyst, S_IRUGO | S_IWUSR, + smi130_acc_orient_mbl_hyst_show, smi130_acc_orient_mbl_hyst_store); +static DEVICE_ATTR(orient_mbl_theta, S_IRUGO | S_IWUSR, + smi130_acc_orient_mbl_theta_show, smi130_acc_orient_mbl_theta_store); +static DEVICE_ATTR(flat_theta, S_IRUGO | S_IWUSR, + smi130_acc_flat_theta_show, smi130_acc_flat_theta_store); +static DEVICE_ATTR(flat_hold_time, S_IRUGO | S_IWUSR, + smi130_acc_flat_hold_time_show, smi130_acc_flat_hold_time_store); +static DEVICE_ATTR(selftest, S_IRUGO | S_IWUSR, + smi130_acc_selftest_show, smi130_acc_selftest_store); +static DEVICE_ATTR(softreset, S_IWUSR, + NULL, smi130_acc_softreset_store); +static DEVICE_ATTR(enable_timer, S_IRUGO | S_IWUSR, + smi130_acc_enable_timer_show, smi130_acc_enable_timer_store); +static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR, + smi130_acc_debug_level_show, smi130_acc_debug_level_store); +static DEVICE_ATTR(temperature, S_IRUSR, + smi130_acc_temperature_show, NULL); +static DEVICE_ATTR(place, S_IRUSR, + smi130_acc_place_show, NULL); +static DEVICE_ATTR(driver_version, S_IRUSR, + smi130_acc_driver_version_show, NULL); + +#ifdef CONFIG_SIG_MOTION +static DEVICE_ATTR(en_sig_motion, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + smi130_acc_en_sig_motion_show, smi130_acc_en_sig_motion_store); +#endif +#ifdef CONFIG_DOUBLE_TAP +static DEVICE_ATTR(tap_time_period, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + smi130_acc_tap_time_period_show, smi130_acc_tap_time_period_store); +static DEVICE_ATTR(en_double_tap, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + smi130_acc_en_double_tap_show, smi130_acc_en_double_tap_store); +#endif + +static struct attribute *smi130_acc_attributes[] = { + &dev_attr_range.attr, + &dev_attr_bandwidth.attr, +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING + &dev_attr_read_acc_boot_sample.attr, +#endif + &dev_attr_op_mode.attr, + &dev_attr_value.attr, + &dev_attr_value_cache.attr, + &dev_attr_delay.attr, + &dev_attr_enable.attr, + &dev_attr_SleepDur.attr, + &dev_attr_reg.attr, + &dev_attr_fast_calibration_x.attr, + &dev_attr_fast_calibration_y.attr, + &dev_attr_fast_calibration_z.attr, + &dev_attr_fifo_mode.attr, + &dev_attr_fifo_framecount.attr, + &dev_attr_fifo_trig.attr, + &dev_attr_fifo_trig_src.attr, + &dev_attr_fifo_data_sel.attr, + &dev_attr_fifo_data_frame.attr, + &dev_attr_chip_id.attr, + &dev_attr_offset_x.attr, + &dev_attr_offset_y.attr, + &dev_attr_offset_z.attr, + &dev_attr_enable_int.attr, + &dev_attr_enable_timer.attr, + &dev_attr_debug_level.attr, + &dev_attr_int_mode.attr, + &dev_attr_slope_duration.attr, + &dev_attr_slope_threshold.attr, + &dev_attr_slope_no_mot_duration.attr, + &dev_attr_slope_no_mot_threshold.attr, + &dev_attr_high_g_duration.attr, + &dev_attr_high_g_threshold.attr, + &dev_attr_low_g_duration.attr, + &dev_attr_low_g_threshold.attr, + &dev_attr_tap_threshold.attr, + &dev_attr_tap_duration.attr, + &dev_attr_tap_quiet.attr, + &dev_attr_tap_shock.attr, + &dev_attr_tap_samp.attr, + &dev_attr_orient_mbl_mode.attr, + &dev_attr_orient_mbl_blocking.attr, + &dev_attr_orient_mbl_hyst.attr, + &dev_attr_orient_mbl_theta.attr, + &dev_attr_flat_theta.attr, + &dev_attr_flat_hold_time.attr, + &dev_attr_selftest.attr, + &dev_attr_softreset.attr, + &dev_attr_temperature.attr, + &dev_attr_place.attr, + &dev_attr_driver_version.attr, +#ifdef CONFIG_SIG_MOTION + &dev_attr_en_sig_motion.attr, +#endif +#ifdef CONFIG_DOUBLE_TAP + &dev_attr_en_double_tap.attr, +#endif + + NULL +}; + +static struct attribute_group smi130_acc_attribute_group = { + .attrs = smi130_acc_attributes +}; + +#ifdef CONFIG_SIG_MOTION +static struct attribute *smi130_acc_sig_motion_attributes[] = { + &dev_attr_slope_duration.attr, + &dev_attr_slope_threshold.attr, + &dev_attr_en_sig_motion.attr, + NULL +}; +static struct attribute_group smi130_acc_sig_motion_attribute_group = { + .attrs = smi130_acc_sig_motion_attributes +}; +#endif + +#ifdef CONFIG_DOUBLE_TAP +static struct attribute *smi130_acc_double_tap_attributes[] = { + &dev_attr_tap_threshold.attr, + &dev_attr_tap_duration.attr, + &dev_attr_tap_quiet.attr, + &dev_attr_tap_shock.attr, + &dev_attr_tap_samp.attr, + &dev_attr_tap_time_period.attr, + &dev_attr_en_double_tap.attr, + NULL +}; +static struct attribute_group smi130_acc_double_tap_attribute_group = { + .attrs = smi130_acc_double_tap_attributes +}; +#endif + + +#if defined(SMI_ACC2X2_ENABLE_INT1) || defined(SMI_ACC2X2_ENABLE_INT2) +unsigned char *orient_mbl[] = {"upward looking portrait upright", + "upward looking portrait upside-down", + "upward looking landscape left", + "upward looking landscape right", + "downward looking portrait upright", + "downward looking portrait upside-down", + "downward looking landscape left", + "downward looking landscape right"}; + + +static void smi130_acc_high_g_interrupt_handle(struct smi130_acc_data *smi130_acc) +{ + unsigned char first_value = 0; + unsigned char sign_value = 0; + int i; + + for (i = 0; i < 3; i++) { + smi130_acc_get_HIGH_first(smi130_acc->smi130_acc_client, i, &first_value); + if (first_value == 1) { + smi130_acc_get_HIGH_sign(smi130_acc->smi130_acc_client, + &sign_value); + if (sign_value == 1) { + if (i == 0) + input_report_rel(smi130_acc->dev_interrupt, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_X_N); + if (i == 1) + input_report_rel(smi130_acc->dev_interrupt, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Y_N); + if (i == 2) + input_report_rel(smi130_acc->dev_interrupt, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Z_N); + } else { + if (i == 0) + input_report_rel(smi130_acc->dev_interrupt, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_X); + if (i == 1) + input_report_rel(smi130_acc->dev_interrupt, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Y); + if (i == 2) + input_report_rel(smi130_acc->dev_interrupt, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Z); + } + } + + PINFO("High G interrupt happened,exis is %d,\n\n" + "first is %d,sign is %d\n", i, + first_value, sign_value); + } + + +} + +#ifndef CONFIG_SIG_MOTION +static void smi130_acc_slope_interrupt_handle(struct smi130_acc_data *smi130_acc) +{ + unsigned char first_value = 0; + unsigned char sign_value = 0; + int i; + for (i = 0; i < 3; i++) { + smi130_acc_get_slope_first(smi130_acc->smi130_acc_client, i, &first_value); + if (first_value == 1) { + smi130_acc_get_slope_sign(smi130_acc->smi130_acc_client, + &sign_value); + if (sign_value == 1) { + if (i == 0) + input_report_rel(smi130_acc->dev_interrupt, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_X_N); + if (i == 1) + input_report_rel(smi130_acc->dev_interrupt, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Y_N); + if (i == 2) + input_report_rel(smi130_acc->dev_interrupt, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Z_N); + } else { + if (i == 0) + input_report_rel(smi130_acc->dev_interrupt, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_X); + if (i == 1) + input_report_rel(smi130_acc->dev_interrupt, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Y); + if (i == 2) + input_report_rel(smi130_acc->dev_interrupt, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Z); + + } + } + + PINFO("Slop interrupt happened,exis is %d,\n\n" + "first is %d,sign is %d\n", i, + first_value, sign_value); + } +} +#endif +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static void store_acc_boot_sample(struct smi130_acc_data *client_data, + int x, int y, int z, struct timespec ts) +{ + if (false == client_data->acc_buffer_smi130_samples) + return; + if (ts.tv_sec < client_data->max_buffer_time) { + if (client_data->acc_bufsample_cnt < SMI_ACC_MAXSAMPLE) { + client_data->smi130_acc_samplist[client_data-> + acc_bufsample_cnt]->xyz[0] = x; + client_data->smi130_acc_samplist[client_data-> + acc_bufsample_cnt]->xyz[1] = y; + client_data->smi130_acc_samplist[client_data-> + acc_bufsample_cnt]->xyz[2] = z; + client_data->smi130_acc_samplist[client_data-> + acc_bufsample_cnt]->tsec = ts.tv_sec; + client_data->smi130_acc_samplist[client_data-> + acc_bufsample_cnt]->tnsec = ts.tv_nsec; + client_data->acc_bufsample_cnt++; + } + } else { + PINFO("End of ACC buffering %d\n", + client_data->acc_bufsample_cnt); + client_data->acc_buffer_smi130_samples = false; + } +} +#else +static void store_acc_boot_sample(struct smi130_acc_data *client_data, + int x, int y, int z, struct timespec ts) +{ +} +#endif + +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static int smi130_acc_early_buff_init(struct i2c_client *client, + struct smi130_acc_data *client_data) +{ + int i = 0, err = 0; + + client_data->acc_bufsample_cnt = 0; + client_data->report_evt_cnt = 5; + client_data->max_buffer_time = 40; + + client_data->smi_acc_cachepool = kmem_cache_create("acc_sensor_sample", + sizeof(struct smi_acc_sample), + 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!client_data->smi_acc_cachepool) { + PERR("smi_acc_cachepool cache create failed\n"); + err = -ENOMEM; + return 0; + } + for (i = 0; i < SMI_ACC_MAXSAMPLE; i++) { + client_data->smi130_acc_samplist[i] = + kmem_cache_alloc(client_data->smi_acc_cachepool, + GFP_KERNEL); + if (!client_data->smi130_acc_samplist[i]) { + err = -ENOMEM; + goto clean_exit1; + } + } + + client_data->accbuf_dev = input_allocate_device(); + if (!client_data->accbuf_dev) { + err = -ENOMEM; + PERR("input device allocation failed\n"); + goto clean_exit1; + } + client_data->accbuf_dev->name = "smi130_accbuf"; + client_data->accbuf_dev->id.bustype = BUS_I2C; + input_set_events_per_packet(client_data->accbuf_dev, + client_data->report_evt_cnt * SMI_ACC_MAXSAMPLE); + set_bit(EV_ABS, client_data->accbuf_dev->evbit); + input_set_abs_params(client_data->accbuf_dev, ABS_X, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->accbuf_dev, ABS_Y, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->accbuf_dev, ABS_Z, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->accbuf_dev, ABS_RX, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->accbuf_dev, ABS_RY, + -G_MAX, G_MAX, 0, 0); + err = input_register_device(client_data->accbuf_dev); + if (err) { + PERR("unable to register input device %s\n", + client_data->accbuf_dev->name); + goto clean_exit2; + } + + client_data->acc_buffer_smi130_samples = true; + + smi130_set_cpu_idle_state(true); + + smi130_acc_set_mode(client, SMI_ACC2X2_MODE_NORMAL, 1); + smi130_acc_set_bandwidth(client, SMI_ACC2X2_BW_62_50HZ); + smi130_acc_set_range(client, SMI_ACC2X2_RANGE_2G); + + return 1; + +clean_exit2: + input_free_device(client_data->accbuf_dev); +clean_exit1: + for (i = 0; i < SMI_ACC_MAXSAMPLE; i++) + kmem_cache_free(client_data->smi_acc_cachepool, + client_data->smi130_acc_samplist[i]); + kmem_cache_destroy(client_data->smi_acc_cachepool); + + return 0; +} + +static void smi130_acc_input_cleanup(struct smi130_acc_data *client_data) +{ + int i = 0; + + input_unregister_device(client_data->accbuf_dev); + input_free_device(client_data->accbuf_dev); + for (i = 0; i < SMI_ACC_MAXSAMPLE; i++) + kmem_cache_free(client_data->smi_acc_cachepool, + client_data->smi130_acc_samplist[i]); + kmem_cache_destroy(client_data->smi_acc_cachepool); +} +#else +static int smi130_acc_early_buff_init(struct i2c_client *client, + struct smi130_acc_data *client_data) +{ + return 1; +} +static void smi130_acc_input_cleanup(struct smi130_acc_data *client_data) +{ +} +#endif + +static irqreturn_t smi130_acc_irq_work_func(int irq, void *handle) +{ + struct smi130_acc_data *smi130_acc = handle; +#ifdef CONFIG_DOUBLE_TAP + struct i2c_client *client = smi130_acc->smi130_acc_client; +#endif + + unsigned char status = 0; + unsigned char first_value = 0; + unsigned char sign_value = 0; + +#ifdef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + static struct smi130_accacc acc; + struct timespec ts; + /* + do not use this function judge new data interrupt + smi130_acc_get_interruptstatus2(smi130_acc->smi130_acc_client, &status); + use the + x-axis value bit new_data_x + y-axis value bit new_data_y + z-axis value bit new_data_z + judge if this is the new data + */ + /* PINFO("New data interrupt happened\n");*/ + smi130_acc_read_accel_xyz(smi130_acc->smi130_acc_client, + smi130_acc->sensor_type, &acc); + ts = ns_to_timespec(smi130_acc->timestamp); + //if ((acc.x & SMI_ACC2X2_NEW_DATA_X__MSK) && + // (acc.y & SMI_ACC2X2_NEW_DATA_Y__MSK) && + // (acc.x & SMI_ACC2X2_NEW_DATA_Z__MSK)) + { + input_event(smi130_acc->input, EV_MSC, MSC_TIME, + ts.tv_sec); + input_event(smi130_acc->input, EV_MSC, MSC_TIME, + ts.tv_nsec); + input_event(smi130_acc->input, EV_MSC, + MSC_GESTURE, acc.x); + input_event(smi130_acc->input, EV_MSC, + MSC_RAW, acc.y); + input_event(smi130_acc->input, EV_MSC, + MSC_SCAN, acc.z); + input_sync(smi130_acc->input); + mutex_lock(&smi130_acc->value_mutex); + smi130_acc->value = acc; + mutex_unlock(&smi130_acc->value_mutex); + } + store_acc_boot_sample(smi130_acc, acc.x, acc.y, acc.z, ts); + + smi130_set_cpu_idle_state(false); + return IRQ_HANDLED; +#endif + smi130_acc_get_interruptstatus1(smi130_acc->smi130_acc_client, &status); + PDEBUG("smi130_acc_irq_work_func, status = 0x%x\n", status); + +#ifdef CONFIG_SIG_MOTION + if (status & 0x04) { + if (atomic_read(&smi130_acc->en_sig_motion) == 1) { + PINFO("Significant motion interrupt happened\n"); + /* close sig sensor, + it will be open again if APP wants */ + smi130_acc_set_en_sig_motion(smi130_acc, 0); + + input_report_rel(smi130_acc->dev_interrupt, + SLOP_INTERRUPT, 1); + input_sync(smi130_acc->dev_interrupt); + } + } +#endif + +#ifdef CONFIG_DOUBLE_TAP + if (status & 0x20) { + if (atomic_read(&smi130_acc->en_double_tap) == 1) { + PINFO("single tap interrupt happened\n"); + smi130_acc_set_Int_Enable(client, 8, 0); + if (smi130_acc->tap_times == 0) { + mod_timer(&smi130_acc->tap_timer, jiffies + + msecs_to_jiffies(smi130_acc->tap_time_period)); + smi130_acc->tap_times = 1; + } else { + /* only double tap is judged */ + PINFO("double tap\n"); + mutex_lock(&smi130_acc->tap_mutex); + smi130_acc->tap_times = 0; + del_timer(&smi130_acc->tap_timer); + mutex_unlock(&smi130_acc->tap_mutex); + input_report_rel(smi130_acc->dev_interrupt, + DOUBLE_TAP_INTERRUPT, + DOUBLE_TAP_INTERRUPT_HAPPENED); + input_sync(smi130_acc->dev_interrupt); + } + smi130_acc_set_Int_Enable(client, 8, 1); + } + } +#endif + + switch (status) { + + case 0x01: + PINFO("Low G interrupt happened\n"); + input_report_rel(smi130_acc->dev_interrupt, LOW_G_INTERRUPT, + LOW_G_INTERRUPT_HAPPENED); + break; + + case 0x02: + smi130_acc_high_g_interrupt_handle(smi130_acc); + break; + +#ifndef CONFIG_SIG_MOTION + case 0x04: + smi130_acc_slope_interrupt_handle(smi130_acc); + break; +#endif + + case 0x08: + PINFO("slow/ no motion interrupt happened\n"); + input_report_rel(smi130_acc->dev_interrupt, + SLOW_NO_MOTION_INTERRUPT, + SLOW_NO_MOTION_INTERRUPT_HAPPENED); + break; + +#ifndef CONFIG_DOUBLE_TAP + case 0x10: + PINFO("double tap interrupt happened\n"); + input_report_rel(smi130_acc->dev_interrupt, + DOUBLE_TAP_INTERRUPT, + DOUBLE_TAP_INTERRUPT_HAPPENED); + break; + case 0x20: + PINFO("single tap interrupt happened\n"); + input_report_rel(smi130_acc->dev_interrupt, + SINGLE_TAP_INTERRUPT, + SINGLE_TAP_INTERRUPT_HAPPENED); + break; +#endif + + case 0x40: + smi130_acc_get_orient_mbl_status(smi130_acc->smi130_acc_client, + &first_value); + PINFO("orient_mbl interrupt happened,%s\n", + orient_mbl[first_value]); + if (first_value == 0) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED); + else if (first_value == 1) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED); + else if (first_value == 2) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED); + else if (first_value == 3) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED); + else if (first_value == 4) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED); + else if (first_value == 5) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED); + else if (first_value == 6) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED); + else if (first_value == 7) + input_report_abs(smi130_acc->dev_interrupt, + ORIENT_INTERRUPT, + DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED); + break; + case 0x80: + smi130_acc_get_orient_mbl_flat_status(smi130_acc->smi130_acc_client, + &sign_value); + PINFO("flat interrupt happened,flat status is %d\n", + sign_value); + if (sign_value == 1) { + input_report_abs(smi130_acc->dev_interrupt, + FLAT_INTERRUPT, + FLAT_INTERRUPT_TURE_HAPPENED); + } else { + input_report_abs(smi130_acc->dev_interrupt, + FLAT_INTERRUPT, + FLAT_INTERRUPT_FALSE_HAPPENED); + } + break; + + default: + break; + } +} + +static irqreturn_t smi130_acc_irq_handler(int irq, void *handle) +{ + struct smi130_acc_data *data = handle; + + if (data == NULL) + return IRQ_HANDLED; + if (data->smi130_acc_client == NULL) + return IRQ_HANDLED; + data->timestamp = smi130_acc_get_alarm_timestamp(); + smi130_hrtimer_reset(data); + + return IRQ_WAKE_THREAD; +} +#endif /* defined(SMI_ACC2X2_ENABLE_INT1)||defined(SMI_ACC2X2_ENABLE_INT2) */ + + +static int smi130_acc_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct smi130_acc_data *data; + struct input_dev *dev; + struct bosch_dev *dev_acc; +#if defined(SMI_ACC2X2_ENABLE_INT1) || defined(SMI_ACC2X2_ENABLE_INT2) + struct bosch_sensor_specific *pdata; +#endif + struct input_dev *dev_interrupt; + + PINFO("smi130_acc_probe start\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + PERR("i2c_check_functionality error\n"); + err = -EIO; + goto exit; + } + data = kzalloc(sizeof(struct smi130_acc_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + /* read and check chip id */ + if (smi130_acc_check_chip_id(client, data) < 0) { + err = -EINVAL; + goto kfree_exit; + } + + /* do soft reset */ + smi130_acc_delay(5); + if (smi130_acc_soft_reset(client) < 0) { + PERR("i2c bus write error, pls check HW connection\n"); + err = -EINVAL; + goto kfree_exit; + } + smi130_acc_delay(20); + + i2c_set_clientdata(client, data); + data->smi130_acc_client = client; + mutex_init(&data->value_mutex); + mutex_init(&data->mode_mutex); + mutex_init(&data->enable_mutex); + smi130_acc_set_bandwidth(client, SMI_ACC2X2_BW_SET); + smi130_acc_set_range(client, SMI_ACC2X2_RANGE_SET); + +#if defined(SMI_ACC2X2_ENABLE_INT1) || defined(SMI_ACC2X2_ENABLE_INT2) + + pdata = client->dev.platform_data; + if (pdata) { + if (pdata->irq_gpio_cfg && (pdata->irq_gpio_cfg() < 0)) { + PERR("IRQ GPIO conf. error %d\n", + client->irq); + } + } + +#ifdef SMI_ACC2X2_ENABLE_INT1 + /* maps interrupt to INT1 pin */ + smi130_acc_set_int1_pad_sel(client, PAD_LOWG); + smi130_acc_set_int1_pad_sel(client, PAD_HIGHG); + smi130_acc_set_int1_pad_sel(client, PAD_SLOP); + smi130_acc_set_int1_pad_sel(client, PAD_DOUBLE_TAP); + smi130_acc_set_int1_pad_sel(client, PAD_SINGLE_TAP); + smi130_acc_set_int1_pad_sel(client, PAD_ORIENT); + smi130_acc_set_int1_pad_sel(client, PAD_FLAT); + smi130_acc_set_int1_pad_sel(client, PAD_SLOW_NO_MOTION); +#ifdef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + smi130_acc_set_newdata(client, SMI_ACC2X2_INT1_NDATA, 1); + smi130_acc_set_newdata(client, SMI_ACC2X2_INT2_NDATA, 0); +#endif +#endif + +#ifdef SMI_ACC2X2_ENABLE_INT2 + /* maps interrupt to INT2 pin */ + smi130_acc_set_int2_pad_sel(client, PAD_LOWG); + smi130_acc_set_int2_pad_sel(client, PAD_HIGHG); + smi130_acc_set_int2_pad_sel(client, PAD_SLOP); + smi130_acc_set_int2_pad_sel(client, PAD_DOUBLE_TAP); + smi130_acc_set_int2_pad_sel(client, PAD_SINGLE_TAP); + smi130_acc_set_int2_pad_sel(client, PAD_ORIENT); + smi130_acc_set_int2_pad_sel(client, PAD_FLAT); + smi130_acc_set_int2_pad_sel(client, PAD_SLOW_NO_MOTION); +#ifdef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + smi130_acc_set_newdata(client, SMI_ACC2X2_INT1_NDATA, 0); + smi130_acc_set_newdata(client, SMI_ACC2X2_INT2_NDATA, 1); +#endif +#endif + + smi130_acc_set_Int_Mode(client, 1);/*latch interrupt 250ms*/ + + /* do not open any interrupt here */ + /*10,orient_mbl + 11,flat*/ + /* smi130_acc_set_Int_Enable(client, 10, 1); */ + /* smi130_acc_set_Int_Enable(client, 11, 1); */ + +#ifdef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + /* enable new data interrupt */ + smi130_acc_set_Int_Enable(client, 4, 1); +#endif + +#ifdef CONFIG_SIG_MOTION + enable_irq_wake(data->IRQ); +#endif + if (err) + PERR("could not request irq\n"); + +#endif + +#ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + INIT_DELAYED_WORK(&data->work, smi130_acc_work_func); +#endif + atomic_set(&data->delay, SMI_ACC2X2_MAX_DELAY); + atomic_set(&data->enable, 0); + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + + dev_interrupt = input_allocate_device(); + if (!dev_interrupt) { + kfree(data); + input_free_device(dev); /*free the successful dev and return*/ + return -ENOMEM; + } + + /* only value events reported */ + dev->name = SENSOR_NAME; + dev->id.bustype = BUS_I2C; + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Z, ABSMIN, ABSMAX, 0, 0); + input_set_capability(dev, EV_MSC, MSC_GESTURE); + input_set_capability(dev, EV_MSC, MSC_RAW); + input_set_capability(dev, EV_MSC, MSC_SCAN); + input_set_capability(dev, EV_MSC, MSC_TIME); + input_set_drvdata(dev, data); + err = input_register_device(dev); + if (err < 0) + goto err_register_input_device; + + /* all interrupt generated events are moved to interrupt input devices*/ + dev_interrupt->name = "smi_acc_interrupt"; + dev_interrupt->id.bustype = BUS_I2C; + input_set_capability(dev_interrupt, EV_REL, + SLOW_NO_MOTION_INTERRUPT); + input_set_capability(dev_interrupt, EV_REL, + LOW_G_INTERRUPT); + input_set_capability(dev_interrupt, EV_REL, + HIGH_G_INTERRUPT); + input_set_capability(dev_interrupt, EV_REL, + SLOP_INTERRUPT); + input_set_capability(dev_interrupt, EV_REL, + DOUBLE_TAP_INTERRUPT); + input_set_capability(dev_interrupt, EV_REL, + SINGLE_TAP_INTERRUPT); + input_set_capability(dev_interrupt, EV_ABS, + ORIENT_INTERRUPT); + input_set_capability(dev_interrupt, EV_ABS, + FLAT_INTERRUPT); + input_set_drvdata(dev_interrupt, data); + + err = input_register_device(dev_interrupt); + if (err < 0) + goto err_register_input_device_interrupt; + + data->dev_interrupt = dev_interrupt; + data->input = dev; + +#ifdef CONFIG_SIG_MOTION + data->g_sensor_class = class_create(THIS_MODULE, "sig_sensor"); + if (IS_ERR(data->g_sensor_class)) { + err = PTR_ERR(data->g_sensor_class); + data->g_sensor_class = NULL; + PERR("could not allocate g_sensor_class\n"); + goto err_create_class; + } + + data->g_sensor_dev = device_create(data->g_sensor_class, + NULL, 0, "%s", "g_sensor"); + if (unlikely(IS_ERR(data->g_sensor_dev))) { + err = PTR_ERR(data->g_sensor_dev); + data->g_sensor_dev = NULL; + + PERR("could not allocate g_sensor_dev\n"); + goto err_create_g_sensor_device; + } + + dev_set_drvdata(data->g_sensor_dev, data); + + err = sysfs_create_group(&data->g_sensor_dev->kobj, + &smi130_acc_sig_motion_attribute_group); + if (err < 0) + goto error_sysfs; +#endif + +#ifdef CONFIG_DOUBLE_TAP + data->g_sensor_class_doubletap = + class_create(THIS_MODULE, "dtap_sensor"); + if (IS_ERR(data->g_sensor_class_doubletap)) { + err = PTR_ERR(data->g_sensor_class_doubletap); + data->g_sensor_class_doubletap = NULL; + PERR("could not allocate g_sensor_class_doubletap\n"); + goto err_create_class; + } + + data->g_sensor_dev_doubletap = device_create( + data->g_sensor_class_doubletap, + NULL, 0, "%s", "g_sensor"); + if (unlikely(IS_ERR(data->g_sensor_dev_doubletap))) { + err = PTR_ERR(data->g_sensor_dev_doubletap); + data->g_sensor_dev_doubletap = NULL; + + PERR("could not allocate g_sensor_dev_doubletap\n"); + goto err_create_g_sensor_device_double_tap; + } + + dev_set_drvdata(data->g_sensor_dev_doubletap, data); + + err = sysfs_create_group(&data->g_sensor_dev_doubletap->kobj, + &smi130_acc_double_tap_attribute_group); + if (err < 0) + goto error_sysfs; +#endif + + err = sysfs_create_group(&data->input->dev.kobj, + &smi130_acc_attribute_group); + if (err < 0) + goto error_sysfs; + + dev_acc = bosch_allocate_device(); + if (!dev_acc) { + err = -ENOMEM; + goto error_sysfs; + } + dev_acc->name = ACC_NAME; + + bosch_set_drvdata(dev_acc, data); + + err = bosch_register_device(dev_acc); + if (err < 0) + goto bosch_free_acc_exit; + + data->bosch_acc = dev_acc; + err = sysfs_create_group(&data->bosch_acc->dev.kobj, + &smi130_acc_attribute_group); + + if (err < 0) + goto bosch_free_exit; + + if (NULL != client->dev.platform_data) { + data->bosch_pd = kzalloc(sizeof(*data->bosch_pd), + GFP_KERNEL); + + if (NULL != data->bosch_pd) { + memcpy(data->bosch_pd, client->dev.platform_data, + sizeof(*data->bosch_pd)); + PINFO("%s sensor driver set place: p%d", + data->bosch_pd->name, data->bosch_pd->place); + } + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + data->early_suspend.suspend = smi130_acc_early_suspend; + data->early_suspend.resume = smi130_acc_late_resume; + register_early_suspend(&data->early_suspend); +#endif + INIT_WORK(&data->report_data_work, + smi130_acc_timer_work_fun); + reportdata_wq = create_singlethread_workqueue("smi130_acc_wq"); + if (NULL == reportdata_wq) + PERR("fail to create the reportdta_wq"); + hrtimer_init(&data->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + data->timer.function = reportdata_timer_fun; + data->work_delay_kt = ns_to_ktime(4000000); + data->is_timer_running = 0; + data->timestamp = 0; + data->time_odr = 4000000;/*default bandwidth 125HZ*/ + data->smi_acc_mode_enabled = 0; + data->fifo_datasel = 0; + data->fifo_count = 0; + data->acc_count = 0; + +#ifdef CONFIG_SIG_MOTION + atomic_set(&data->en_sig_motion, 0); +#endif +#ifdef CONFIG_DOUBLE_TAP + atomic_set(&data->en_double_tap, 0); + data->tap_times = 0; + data->tap_time_period = DEFAULT_TAP_JUDGE_PERIOD; + mutex_init(&data->tap_mutex); + setup_timer(&data->tap_timer, smi130_acc_tap_timeout_handle, + (unsigned long)data); +#endif + if (smi130_acc_set_mode(client, SMI_ACC2X2_MODE_SUSPEND, SMI_ACC_ENABLED_ALL) < 0) + return -EINVAL; + data->IRQ = client->irq; + PDEBUG("data->IRQ = %d", data->IRQ); + err = request_threaded_irq(data->IRQ, smi130_acc_irq_handler, + smi130_acc_irq_work_func, IRQF_TRIGGER_RISING, + "smi130_acc", data); + + smi130_hrtimer_init(data); + err = smi130_acc_early_buff_init(client, data); + if (!err) + goto exit; + + PINFO("SMI130_ACC driver probe successfully"); + + return 0; + +bosch_free_exit: + bosch_unregister_device(dev_acc); + +bosch_free_acc_exit: + bosch_free_device(dev_acc); + +error_sysfs: + input_unregister_device(data->input); + +#ifdef CONFIG_DOUBLE_TAP +err_create_g_sensor_device_double_tap: + class_destroy(data->g_sensor_class_doubletap); +#endif + +#ifdef CONFIG_SIG_MOTION +err_create_g_sensor_device: + class_destroy(data->g_sensor_class); +#endif + +#if defined(CONFIG_SIG_MOTION) || defined(CONFIG_DOUBLE_TAP) +err_create_class: + input_unregister_device(data->dev_interrupt); +#endif + +err_register_input_device_interrupt: + input_free_device(dev_interrupt); + input_unregister_device(data->input); + +err_register_input_device: + input_free_device(dev); + +kfree_exit: + if ((NULL != data) && (NULL != data->bosch_pd)) { + kfree(data->bosch_pd); + data->bosch_pd = NULL; + } + kfree(data); +exit: + return err; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void smi130_acc_early_suspend(struct early_suspend *h) +{ + struct smi130_acc_data *data = + container_of(h, struct smi130_acc_data, early_suspend); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + smi130_acc_set_mode(data->smi130_acc_client, + SMI_ACC2X2_MODE_SUSPEND, SMI_ACC_ENABLED_INPUT); +#ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + cancel_delayed_work_sync(&data->work); +#endif + } + if (data->is_timer_running) { + /*diable fifo_mode when close timer*/ + if (smi130_acc_set_fifo_mode(data->smi130_acc_client, 0) < 0) + PERR("set fifo_mode falied"); + hrtimer_cancel(&data->timer); + data->base_time = 0; + data->timestamp = 0; + data->fifo_time = 0; + data->acc_count = 0; + } + mutex_unlock(&data->enable_mutex); +} + +static void smi130_acc_late_resume(struct early_suspend *h) +{ + struct smi130_acc_data *data = + container_of(h, struct smi130_acc_data, early_suspend); + if (NULL == data) + return; + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + smi130_acc_set_mode(data->smi130_acc_client, + SMI_ACC2X2_MODE_NORMAL, SMI_ACC_ENABLED_INPUT); +#ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + schedule_delayed_work(&data->work, + msecs_to_jiffies(atomic_read(&data->delay))); +#endif + } + if (data->is_timer_running) { + hrtimer_start(&data->timer, + ns_to_ktime(data->time_odr), + HRTIMER_MODE_REL); + /*enable fifo_mode when init*/ + if (smi130_acc_set_fifo_mode(data->smi130_acc_client, 2) < 0) + PERR("set fifo_mode falied"); + data->base_time = 0; + data->timestamp = 0; + data->is_timer_running = 1; + data->acc_count = 0; + } + mutex_unlock(&data->enable_mutex); +} +#endif + +static int smi130_acc_remove(struct i2c_client *client) +{ + struct smi130_acc_data *data = i2c_get_clientdata(client); + + if (NULL == data) + return 0; + + smi130_hrtimer_cleanup(data); + smi130_acc_input_cleanup(data); + smi130_acc_set_enable(&client->dev, 0); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif + sysfs_remove_group(&data->input->dev.kobj, &smi130_acc_attribute_group); + input_unregister_device(data->input); + + if (NULL != data->bosch_pd) { + kfree(data->bosch_pd); + data->bosch_pd = NULL; + } + + kfree(data); + return 0; +} + +void smi130_acc_shutdown(struct i2c_client *client) +{ + struct smi130_acc_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->enable_mutex); + smi130_acc_set_mode(data->smi130_acc_client, + SMI_ACC2X2_MODE_DEEP_SUSPEND, SMI_ACC_ENABLED_ALL); + mutex_unlock(&data->enable_mutex); +} + +#ifdef CONFIG_PM +static int smi130_acc_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct smi130_acc_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + smi130_acc_set_mode(data->smi130_acc_client, + SMI_ACC2X2_MODE_SUSPEND, SMI_ACC_ENABLED_INPUT); +#ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + cancel_delayed_work_sync(&data->work); +#endif + } + if (data->is_timer_running) { + hrtimer_cancel(&data->timer); + data->base_time = 0; + data->timestamp = 0; + data->fifo_time = 0; + data->acc_count = 0; + } + mutex_unlock(&data->enable_mutex); + + return 0; +} + +static int smi130_acc_resume(struct i2c_client *client) +{ + struct smi130_acc_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + smi130_acc_set_mode(data->smi130_acc_client, + SMI_ACC2X2_MODE_NORMAL, SMI_ACC_ENABLED_INPUT); +#ifndef CONFIG_SMI_ACC_ENABLE_NEWDATA_INT + schedule_delayed_work(&data->work, + msecs_to_jiffies(atomic_read(&data->delay))); +#endif + } + if (data->is_timer_running) { + hrtimer_start(&data->timer, + ns_to_ktime(data->time_odr), + HRTIMER_MODE_REL); + data->base_time = 0; + data->timestamp = 0; + data->is_timer_running = 1; + } + mutex_unlock(&data->enable_mutex); + + return 0; +} + +#else + +#define smi130_acc_suspend NULL +#define smi130_acc_resume NULL + +#endif /* CONFIG_PM */ + +static const struct i2c_device_id smi130_acc_id[] = { + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, smi130_acc_id); +static const struct of_device_id smi130_acc_of_match[] = { + { .compatible = "smi130_acc", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, smi130_acc_of_match); + +static struct i2c_driver smi130_acc_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = smi130_acc_of_match, + }, + .suspend = smi130_acc_suspend, + .resume = smi130_acc_resume, + .id_table = smi130_acc_id, + .probe = smi130_acc_probe, + .remove = smi130_acc_remove, + .shutdown = smi130_acc_shutdown, +}; + +static int __init SMI_ACC2X2_init(void) +{ + return i2c_add_driver(&smi130_acc_driver); +} + +static void __exit SMI_ACC2X2_exit(void) +{ + i2c_del_driver(&smi130_acc_driver); +} + +MODULE_AUTHOR("contact@bosch-sensortec.com"); +MODULE_DESCRIPTION("SMI_ACC2X2 ACCELEROMETER SENSOR DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(SMI_ACC2X2_init); +module_exit(SMI_ACC2X2_exit); + diff --git a/drivers/input/sensors/smi130/smi130_driver.c b/drivers/input/sensors/smi130/smi130_driver.c new file mode 100644 index 0000000000000000000000000000000000000000..bc5d949fad075dbbbf6eb722361448e55388c8f0 --- /dev/null +++ b/drivers/input/sensors/smi130/smi130_driver.c @@ -0,0 +1,4121 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename smi130_driver.c + * @date 2016/08/01 14:40 + * @Modification Date 2018/08/28 18:20 + * @id "b5ff23a" + * @version 1.3 + * + * @brief + * The core code of SMI130 device driver + * + * @detail + * This file implements the core code of SMI130 device driver, + * which includes hardware related functions, input device register, + * device attribute files, etc. +*/ + +#include "smi130.h" +#include "smi130_driver.h" +#include +#include +#include +#include + + +#define DRIVER_VERSION "0.0.53.0" +#define I2C_BURST_READ_MAX_LEN (256) +#define SMI130_STORE_COUNT (6000) +#define LMADA (1) +uint64_t g_current_apts_us_mbl; + + +enum SMI_SENSOR_INT_T { + /* Interrupt enable0*/ + SMI_ANYMO_X_INT = 0, + SMI_ANYMO_Y_INT, + SMI_ANYMO_Z_INT, + SMI_D_TAP_INT, + SMI_S_TAP_INT, + SMI_ORIENT_INT, + SMI_FLAT_INT, + /* Interrupt enable1*/ + SMI_HIGH_X_INT, + SMI_HIGH_Y_INT, + SMI_HIGH_Z_INT, + SMI_LOW_INT, + SMI_DRDY_INT, + SMI_FFULL_INT, + SMI_FWM_INT, + /* Interrupt enable2 */ + SMI_NOMOTION_X_INT, + SMI_NOMOTION_Y_INT, + SMI_NOMOTION_Z_INT, + SMI_STEP_DETECTOR_INT, + INT_TYPE_MAX +}; + +/*smi fifo sensor type combination*/ +enum SMI_SENSOR_FIFO_COMBINATION { + SMI_FIFO_A = 0, + SMI_FIFO_G, + SMI_FIFO_M, + SMI_FIFO_G_A, + SMI_FIFO_M_A, + SMI_FIFO_M_G, + SMI_FIFO_M_G_A, + SMI_FIFO_COM_MAX +}; + +/*smi fifo analyse return err status*/ +enum SMI_FIFO_ANALYSE_RETURN_T { + FIFO_OVER_READ_RETURN = -10, + FIFO_SENSORTIME_RETURN = -9, + FIFO_SKIP_OVER_LEN = -8, + FIFO_M_G_A_OVER_LEN = -7, + FIFO_M_G_OVER_LEN = -6, + FIFO_M_A_OVER_LEN = -5, + FIFO_G_A_OVER_LEN = -4, + FIFO_M_OVER_LEN = -3, + FIFO_G_OVER_LEN = -2, + FIFO_A_OVER_LEN = -1 +}; + +/*!smi sensor generic power mode enum */ +enum SMI_DEV_OP_MODE { + SENSOR_PM_NORMAL = 0, + SENSOR_PM_LP1, + SENSOR_PM_SUSPEND, + SENSOR_PM_LP2 +}; + +/*! smi acc sensor power mode enum */ +enum SMI_ACC_PM_TYPE { + SMI_ACC_PM_NORMAL = 0, + SMI_ACC_PM_LP1, + SMI_ACC_PM_SUSPEND, + SMI_ACC_PM_LP2, + SMI_ACC_PM_MAX +}; + +/*! smi gyro sensor power mode enum */ +enum SMI_GYRO_PM_TYPE { + SMI_GYRO_PM_NORMAL = 0, + SMI_GYRO_PM_FAST_START, + SMI_GYRO_PM_SUSPEND, + SMI_GYRO_PM_MAX +}; + +/*! smi mag sensor power mode enum */ +enum SMI_MAG_PM_TYPE { + SMI_MAG_PM_NORMAL = 0, + SMI_MAG_PM_LP1, + SMI_MAG_PM_SUSPEND, + SMI_MAG_PM_LP2, + SMI_MAG_PM_MAX +}; + + +/*! smi sensor support type*/ +enum SMI_SENSOR_TYPE { + SMI_ACC_SENSOR, + SMI_GYRO_SENSOR, + SMI_MAG_SENSOR, + SMI_SENSOR_TYPE_MAX +}; + +/*!smi sensor generic power mode enum */ +enum SMI_AXIS_TYPE { + X_AXIS = 0, + Y_AXIS, + Z_AXIS, + AXIS_MAX +}; + +/*!smi sensor generic intterrupt enum */ +enum SMI_INT_TYPE { + SMI130_INT0 = 0, + SMI130_INT1, + SMI130_INT_MAX +}; + +/*! smi sensor time resolution definition*/ +enum SMI_SENSOR_TIME_RS_TYPE { + TS_0_78_HZ = 1,/*0.78HZ*/ + TS_1_56_HZ,/*1.56HZ*/ + TS_3_125_HZ,/*3.125HZ*/ + TS_6_25_HZ,/*6.25HZ*/ + TS_12_5_HZ,/*12.5HZ*/ + TS_25_HZ,/*25HZ, odr=6*/ + TS_50_HZ,/*50HZ*/ + TS_100_HZ,/*100HZ*/ + TS_200_HZ,/*200HZ*/ + TS_400_HZ,/*400HZ*/ + TS_800_HZ,/*800HZ*/ + TS_1600_HZ,/*1600HZ*/ + TS_MAX_HZ +}; + +/*! smi sensor interface mode */ +enum SMI_SENSOR_IF_MODE_TYPE { + /*primary interface:autoconfig/secondary interface off*/ + P_AUTO_S_OFF = 0, + /*primary interface:I2C/secondary interface:OIS*/ + P_I2C_S_OIS, + /*primary interface:autoconfig/secondary interface:Magnetometer*/ + P_AUTO_S_MAG, + /*interface mode reseved*/ + IF_MODE_RESEVED + +}; + +/*! smi130 acc/gyro calibration status in H/W layer */ +enum SMI_CALIBRATION_STATUS_TYPE { + /*SMI FAST Calibration ready x/y/z status*/ + SMI_ACC_X_FAST_CALI_RDY = 0, + SMI_ACC_Y_FAST_CALI_RDY, + SMI_ACC_Z_FAST_CALI_RDY +}; + +unsigned int reg_op_addr_mbl; + +static const int smi_pmu_cmd_acc_arr[SMI_ACC_PM_MAX] = { + /*!smi pmu for acc normal, low power1, + * suspend, low power2 mode command */ + CMD_PMU_ACC_NORMAL, + CMD_PMU_ACC_LP1, + CMD_PMU_ACC_SUSPEND, + CMD_PMU_ACC_LP2 +}; + +static const int smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_MAX] = { + /*!smi pmu for gyro normal, fast startup, + * suspend mode command */ + CMD_PMU_GYRO_NORMAL, + CMD_PMU_GYRO_FASTSTART, + CMD_PMU_GYRO_SUSPEND +}; + +static const int smi_pmu_cmd_mag_arr[SMI_MAG_PM_MAX] = { + /*!smi pmu for mag normal, low power1, + * suspend, low power2 mode command */ + CMD_PMU_MAG_NORMAL, + CMD_PMU_MAG_LP1, + CMD_PMU_MAG_SUSPEND, + CMD_PMU_MAG_LP2 +}; + +static const char *smi_axis_name[AXIS_MAX] = {"x", "y", "z"}; + +static const int smi_interrupt_type[] = { + /*!smi interrupt type */ + /* Interrupt enable0 , index=0~6*/ + SMI130_ANY_MOTION_X_ENABLE, + SMI130_ANY_MOTION_Y_ENABLE, + SMI130_ANY_MOTION_Z_ENABLE, + SMI130_DOUBLE_TAP_ENABLE, + SMI130_SINGLE_TAP_ENABLE, + SMI130_ORIENT_ENABLE, + SMI130_FLAT_ENABLE, + /* Interrupt enable1, index=7~13*/ + SMI130_HIGH_G_X_ENABLE, + SMI130_HIGH_G_Y_ENABLE, + SMI130_HIGH_G_Z_ENABLE, + SMI130_LOW_G_ENABLE, + SMI130_DATA_RDY_ENABLE, + SMI130_FIFO_FULL_ENABLE, + SMI130_FIFO_WM_ENABLE, + /* Interrupt enable2, index = 14~17*/ + SMI130_NOMOTION_X_ENABLE, + SMI130_NOMOTION_Y_ENABLE, + SMI130_NOMOTION_Z_ENABLE, + SMI130_STEP_DETECTOR_EN +}; + +/*! smi sensor time depend on ODR*/ +struct smi_sensor_time_odr_tbl { + u32 ts_duration_lsb; + u32 ts_duration_us; + u32 ts_delat;/*sub current delat fifo_time*/ +}; + +struct smi130_axis_data_t { + s16 x; + s16 y; + s16 z; +}; + +struct smi130_type_mapping_type { + + /*! smi16x sensor chip id */ + uint16_t chip_id; + + /*! smi16x chip revision code */ + uint16_t revision_id; + + /*! smi130_acc sensor name */ + const char *sensor_name; +}; + +struct smi130_store_info_t { + uint8_t current_frm_cnt; + uint64_t current_apts_us[2]; + uint8_t fifo_ts_total_frmcnt; + uint64_t fifo_time; +}; + +uint64_t get_current_timestamp_mbl(void) +{ + uint64_t ts_ap; + struct timespec tmp_time; + get_monotonic_boottime(&tmp_time); + ts_ap = (uint64_t)tmp_time.tv_sec * 1000000000 + tmp_time.tv_nsec; + return ts_ap; + +} + +/*! sensor support type map */ +static const struct smi130_type_mapping_type sensor_type_map[] = { + + {SENSOR_CHIP_ID_SMI, SENSOR_CHIP_REV_ID_SMI, "SMI130/162AB"}, + {SENSOR_CHIP_ID_SMI_C2, SENSOR_CHIP_REV_ID_SMI, "SMI130C2"}, + {SENSOR_CHIP_ID_SMI_C3, SENSOR_CHIP_REV_ID_SMI, "SMI130C3"}, + +}; + +/*!smi130 sensor time depends on ODR */ +static const struct smi_sensor_time_odr_tbl + sensortime_duration_tbl[TS_MAX_HZ] = { + {0x010000, 2560000, 0x00ffff},/*2560ms, 0.39hz, odr=resver*/ + {0x008000, 1280000, 0x007fff},/*1280ms, 0.78hz, odr_acc=1*/ + {0x004000, 640000, 0x003fff},/*640ms, 1.56hz, odr_acc=2*/ + {0x002000, 320000, 0x001fff},/*320ms, 3.125hz, odr_acc=3*/ + {0x001000, 160000, 0x000fff},/*160ms, 6.25hz, odr_acc=4*/ + {0x000800, 80000, 0x0007ff},/*80ms, 12.5hz*/ + {0x000400, 40000, 0x0003ff},/*40ms, 25hz, odr_acc = odr_gyro =6*/ + {0x000200, 20000, 0x0001ff},/*20ms, 50hz, odr = 7*/ + {0x000100, 10000, 0x0000ff},/*10ms, 100hz, odr=8*/ + {0x000080, 5000, 0x00007f},/*5ms, 200hz, odr=9*/ + {0x000040, 2500, 0x00003f},/*2.5ms, 400hz, odr=10*/ + {0x000020, 1250, 0x00001f},/*1.25ms, 800hz, odr=11*/ + {0x000010, 625, 0x00000f},/*0.625ms, 1600hz, odr=12*/ + +}; + +#if defined(CONFIG_USE_QUALCOMM_HAL) +#define POLL_INTERVAL_MIN_MS 10 +#define POLL_INTERVAL_MAX_MS 4000 +#define POLL_DEFAULT_INTERVAL_MS 200 +#define SMI130_ACCEL_MIN_VALUE -32768 +#define SMI130_ACCEL_MAX_VALUE 32767 +#define SMI130_GYRO_MIN_VALUE -32768 +#define SMI130_GYRO_MAX_VALUE 32767 +#define SMI130_ACCEL_DEFAULT_POLL_INTERVAL_MS 200 +#define SMI130_GYRO_DEFAULT_POLL_INTERVAL_MS 200 +#define SMI130_ACCEL_MIN_POLL_INTERVAL_MS 10 +#define SMI130_ACCEL_MAX_POLL_INTERVAL_MS 5000 +#define SMI130_GYRO_MIN_POLL_INTERVAL_MS 10 +#define SMI130_GYRO_MAX_POLL_INTERVAL_MS 5000 +static struct sensors_classdev smi130_accel_cdev = { + .name = "smi130-accel", + .vendor = "bosch", + .version = 1, + .handle = SENSORS_ACCELERATION_HANDLE, + .type = SENSOR_TYPE_ACCELEROMETER, + .max_range = "156.8", /* 16g */ + .resolution = "0.153125", /* 15.6mg */ + .sensor_power = "0.13", /* typical value */ + .min_delay = POLL_INTERVAL_MIN_MS * 1000, /* in microseconds */ + .max_delay = POLL_INTERVAL_MAX_MS, + .delay_msec = POLL_DEFAULT_INTERVAL_MS, /* in millisecond */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .max_latency = 0, + .flags = 0, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_set_latency = NULL, + .sensors_flush = NULL, + .sensors_self_test = NULL, +}; +static struct sensors_classdev smi130_gyro_cdev = { + .name = "smi130-gyro", + .vendor = "bosch", + .version = 1, + .handle = SENSORS_GYROSCOPE_HANDLE, + .type = SENSOR_TYPE_GYROSCOPE, + .max_range = "34.906586", /* rad/s */ + .resolution = "0.0010681152", /* rad/s */ + .sensor_power = "3.6", /* 3.6 mA */ + .min_delay = SMI130_GYRO_MIN_POLL_INTERVAL_MS * 1000, + .max_delay = SMI130_GYRO_MAX_POLL_INTERVAL_MS, + .delay_msec = SMI130_GYRO_DEFAULT_POLL_INTERVAL_MS, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .max_latency = 0, + .flags = 0, /* SENSOR_FLAG_CONTINUOUS_MODE */ + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_enable_wakeup = NULL, + .sensors_set_latency = NULL, + .sensors_flush = NULL, +}; +#endif +static void smi_delay(u32 msec) +{ + if (msec <= 20) + usleep_range(msec * 1000, msec * 1000); + else + msleep(msec); +} + +static void smi_dump_reg(struct smi_client_data *client_data) +{ + #define REG_MAX0 0x24 + #define REG_MAX1 0x56 + int i; + u8 dbg_buf0[REG_MAX0]; + u8 dbg_buf1[REG_MAX1]; + u8 dbg_buf_str0[REG_MAX0 * 3 + 1] = ""; + u8 dbg_buf_str1[REG_MAX1 * 3 + 1] = ""; + + dev_notice(client_data->dev, "\nFrom 0x00:\n"); + + client_data->device.bus_read(client_data->device.dev_addr, + SMI_REG_NAME(USER_CHIP_ID), dbg_buf0, REG_MAX0); + for (i = 0; i < REG_MAX0; i++) { + snprintf(dbg_buf_str0 + i * 3, 16, "%02x%c", dbg_buf0[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + dev_notice(client_data->dev, "%s\n", dbg_buf_str0); + + client_data->device.bus_read(client_data->device.dev_addr, + SMI130_USER_ACCEL_CONFIG_ADDR, dbg_buf1, REG_MAX1); + dev_notice(client_data->dev, "\nFrom 0x40:\n"); + for (i = 0; i < REG_MAX1; i++) { + snprintf(dbg_buf_str1 + i * 3, 16, "%02x%c", dbg_buf1[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + dev_notice(client_data->dev, "\n%s\n", dbg_buf_str1); + } + + +void smi_fifo_frame_bytes_extend_calc( + struct smi_client_data *client_data, + unsigned int *fifo_frmbytes_extend) +{ + + switch (client_data->fifo_data_sel) { + case SMI_FIFO_A_SEL: + case SMI_FIFO_G_SEL: + *fifo_frmbytes_extend = 7; + break; + case SMI_FIFO_G_A_SEL: + *fifo_frmbytes_extend = 13; + break; + case SMI_FIFO_M_SEL: + *fifo_frmbytes_extend = 9; + break; + case SMI_FIFO_M_A_SEL: + case SMI_FIFO_M_G_SEL: + /*8(mag) + 6(gyro or acc) +1(head) = 15*/ + *fifo_frmbytes_extend = 15; + break; + case SMI_FIFO_M_G_A_SEL: + /*8(mag) + 6(gyro or acc) + 6 + 1 = 21*/ + *fifo_frmbytes_extend = 21; + break; + default: + *fifo_frmbytes_extend = 0; + break; + + }; + +} + +static int smi_input_init(struct smi_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = input_allocate_device(); + if (NULL == dev) + return -ENOMEM; +#if defined(CONFIG_USE_QUALCOMM_HAL) + dev->name = "smi130-accel"; +#else + dev->name = SENSOR_NAME; +#endif + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_MSC, MSC_GESTURE); + input_set_capability(dev, EV_MSC, INPUT_EVENT_SGM); + + input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_GYRO_CALIB_DONE); + input_set_capability(dev, EV_MSC, INPUT_EVENT_STEP_DETECTOR); + input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_ACC_CALIB_DONE); + + + input_set_capability(dev, EV_REL, REL_X); + input_set_capability(dev, EV_REL, REL_Y); + input_set_capability(dev, EV_REL, REL_Z); + #if defined(CONFIG_USE_QUALCOMM_HAL) + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_X, + SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE, + 0, 0); + input_set_abs_params(dev, ABS_Y, + SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE, + 0, 0); + input_set_abs_params(dev, ABS_Z, + SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE, + 0, 0); + #endif + input_set_drvdata(dev, client_data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + dev_notice(client_data->dev, "smi130 input free!\n"); + return err; + } + client_data->input = dev; + dev_notice(client_data->dev, + "smi130 input register successfully, %s!\n", + client_data->input->name); + return err; +} + +//#if defined(CONFIG_USE_QUALCOMM_HAL) +static int smi_gyro_input_init(struct smi_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = input_allocate_device(); + if (NULL == dev) + return -ENOMEM; + dev->name = "smi130-gyro"; + dev->id.bustype = BUS_I2C; + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_capability(dev, EV_MSC, MSC_GESTURE); + input_set_capability(dev, EV_MSC, INPUT_EVENT_SGM); + + input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_GYRO_CALIB_DONE); + input_set_capability(dev, EV_MSC, INPUT_EVENT_STEP_DETECTOR); + input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_ACC_CALIB_DONE); + #if defined(CONFIG_USE_QUALCOMM_HAL) + input_set_abs_params(dev, ABS_RX, + SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE, + 0, 0); + input_set_abs_params(dev, ABS_RY, + SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE, + 0, 0); + input_set_abs_params(dev, ABS_RZ, + SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE, + 0, 0); + #endif + input_set_drvdata(dev, client_data); + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + dev_notice(client_data->dev, "smi130 input free!\n"); + return err; + } + client_data->gyro_input = dev; + dev_notice(client_data->dev, + "smi130 input register successfully, %s!\n", + client_data->gyro_input->name); + return err; +} +//#endif +static void smi_input_destroy(struct smi_client_data *client_data) +{ + struct input_dev *dev = client_data->input; + + input_unregister_device(dev); + input_free_device(dev); +} + +static int smi_check_chip_id(struct smi_client_data *client_data) +{ + int8_t err = 0; + int8_t i = 0; + uint8_t chip_id = 0; + uint8_t read_count = 0; + u8 smi_sensor_cnt = sizeof(sensor_type_map) + / sizeof(struct smi130_type_mapping_type); + /* read and check chip id */ + while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { + if (client_data->device.bus_read(client_data->device.dev_addr, + SMI_REG_NAME(USER_CHIP_ID), &chip_id, 1) < 0) { + + dev_err(client_data->dev, + "Bosch Sensortec Device not found" + "read chip_id:%d\n", chip_id); + continue; + } else { + for (i = 0; i < smi_sensor_cnt; i++) { + if (sensor_type_map[i].chip_id == chip_id) { + client_data->chip_id = chip_id; + dev_notice(client_data->dev, + "Bosch Sensortec Device detected, " + "HW IC name: %s\n", sensor_type_map[i].sensor_name); + break; + } + } + if (i < smi_sensor_cnt) + break; + else { + if (read_count == CHECK_CHIP_ID_TIME_MAX) { + dev_err(client_data->dev, + "Failed!Bosch Sensortec Device not found" + " mismatch chip_id:%d\n", chip_id); + err = -ENODEV; + return err; + } + } + smi_delay(1); + } + } + return err; + +} + +static int smi_pmu_set_suspend(struct smi_client_data *client_data) +{ + int err = 0; + if (client_data == NULL) + return -EINVAL; + else { + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SENSOR_PM_SUSPEND]); + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SENSOR_PM_SUSPEND]); + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_mag_arr[SENSOR_PM_SUSPEND]); + client_data->pw.acc_pm = SMI_ACC_PM_SUSPEND; + client_data->pw.gyro_pm = SMI_GYRO_PM_SUSPEND; + client_data->pw.mag_pm = SMI_MAG_PM_SUSPEND; + } + + return err; +} + +static int smi_get_err_status(struct smi_client_data *client_data) +{ + int err = 0; + + err = SMI_CALL_API(get_error_status)(&client_data->err_st.fatal_err, + &client_data->err_st.err_code, &client_data->err_st.i2c_fail, + &client_data->err_st.drop_cmd, &client_data->err_st.mag_drdy_err); + return err; +} + +static void smi_work_func(struct work_struct *work) +{ + struct smi_client_data *client_data = + container_of((struct delayed_work *)work, + struct smi_client_data, work); + unsigned long delay = + msecs_to_jiffies(atomic_read(&client_data->delay)); + struct smi130_accel_t data; + int err; + + err = SMI_CALL_API(read_accel_xyz)(&data); + if (err < 0) + return; + + /*report current frame via input event*/ + input_event(client_data->input, EV_REL, REL_X, data.x); + input_event(client_data->input, EV_REL, REL_Y, data.y); + input_event(client_data->input, EV_REL, REL_Z, data.z); + input_sync(client_data->input); + + schedule_delayed_work(&client_data->work, delay); +} + +static ssize_t smi130_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 16, "0x%x\n", client_data->chip_id); +} + +static ssize_t smi130_err_st_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err = 0; + err = smi_get_err_status(client_data); + if (err) + return err; + else { + return snprintf(buf, 128, "fatal_err:0x%x, err_code:%d,\n\n" + "i2c_fail_err:%d, drop_cmd_err:%d, mag_drdy_err:%d\n", + client_data->err_st.fatal_err, + client_data->err_st.err_code, + client_data->err_st.i2c_fail, + client_data->err_st.drop_cmd, + client_data->err_st.mag_drdy_err); + + } +} + +static ssize_t smi130_sensor_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + u32 sensor_time; + err = SMI_CALL_API(get_sensor_time)(&sensor_time); + if (err) + return err; + else + return snprintf(buf, 16, "0x%x\n", (unsigned int)sensor_time); +} + +static ssize_t smi130_fifo_flush_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long enable; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable) + err = SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA); + + if (err) + dev_err(client_data->dev, "fifo flush failed!\n"); + + return count; + +} + + +static ssize_t smi130_fifo_bytecount_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned int fifo_bytecount = 0; + + SMI_CALL_API(fifo_length)(&fifo_bytecount); + err = snprintf(buf, 16, "%u\n", fifo_bytecount); + return err; +} + +static ssize_t smi130_fifo_bytecount_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err; + unsigned long data; + err = kstrtoul(buf, 10, &data); + if (err) + return err; + client_data->fifo_bytecount = (unsigned int) data; + + return count; +} + +int smi130_fifo_data_sel_get(struct smi_client_data *client_data) +{ + int err = 0; + unsigned char fifo_acc_en, fifo_gyro_en, fifo_mag_en; + unsigned char fifo_datasel; + + err += SMI_CALL_API(get_fifo_accel_enable)(&fifo_acc_en); + err += SMI_CALL_API(get_fifo_gyro_enable)(&fifo_gyro_en); + err += SMI_CALL_API(get_fifo_mag_enable)(&fifo_mag_en); + + if (err) + return err; + + fifo_datasel = (fifo_acc_en << SMI_ACC_SENSOR) | + (fifo_gyro_en << SMI_GYRO_SENSOR) | + (fifo_mag_en << SMI_MAG_SENSOR); + + client_data->fifo_data_sel = fifo_datasel; + + return err; + + +} + +static ssize_t smi130_fifo_data_sel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + err = smi130_fifo_data_sel_get(client_data); + if (err) { + dev_err(client_data->dev, "get fifo_sel failed!\n"); + return -EINVAL; + } + return snprintf(buf, 16, "%d\n", client_data->fifo_data_sel); +} + +/* write any value to clear all the fifo data. */ +static ssize_t smi130_fifo_data_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err; + unsigned long data; + unsigned char fifo_datasel; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* data format: aimed 0b0000 0x(m)x(g)x(a), x:1 enable, 0:disable*/ + if (data > 7) + return -EINVAL; + + + fifo_datasel = (unsigned char)data; + + + err += SMI_CALL_API(set_fifo_accel_enable) + ((fifo_datasel & (1 << SMI_ACC_SENSOR)) ? 1 : 0); + err += SMI_CALL_API(set_fifo_gyro_enable) + (fifo_datasel & (1 << SMI_GYRO_SENSOR) ? 1 : 0); + err += SMI_CALL_API(set_fifo_mag_enable) + ((fifo_datasel & (1 << SMI_MAG_SENSOR)) ? 1 : 0); + + err += SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA); + if (err) + return -EIO; + else { + dev_notice(client_data->dev, "FIFO A_en:%d, G_en:%d, M_en:%d\n", + (fifo_datasel & (1 << SMI_ACC_SENSOR)) ? 1 : 0, + (fifo_datasel & (1 << SMI_GYRO_SENSOR) ? 1 : 0), + ((fifo_datasel & (1 << SMI_MAG_SENSOR)) ? 1 : 0)); + client_data->fifo_data_sel = fifo_datasel; + } + return count; +} + +static ssize_t smi130_fifo_data_out_frame_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + int err = 0; + uint32_t fifo_bytecount = 0; + + err = SMI_CALL_API(fifo_length)(&fifo_bytecount); + if (err < 0) { + dev_err(client_data->dev, "read fifo_length err"); + return -EINVAL; + } + if (fifo_bytecount == 0) + return 0; + err = smi_burst_read_wrapper(client_data->device.dev_addr, + SMI130_USER_FIFO_DATA__REG, buf, + fifo_bytecount); + if (err) { + dev_err(client_data->dev, "read fifo err"); + SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA); + return -EINVAL; + } + return fifo_bytecount; + +} + +static ssize_t smi130_fifo_watermark_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data = 0xff; + + err = SMI_CALL_API(get_fifo_wm)(&data); + + if (err) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_fifo_watermark_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long data; + unsigned char fifo_watermark; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + fifo_watermark = (unsigned char)data; + err = SMI_CALL_API(set_fifo_wm)(fifo_watermark); + if (err) + return -EIO; + + return count; +} + + +static ssize_t smi130_fifo_header_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data = 0xff; + + err = SMI_CALL_API(get_fifo_header_enable)(&data); + + if (err) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_fifo_header_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err; + unsigned long data; + unsigned char fifo_header_en; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + if (data > 1) + return -ENOENT; + + fifo_header_en = (unsigned char)data; + err = SMI_CALL_API(set_fifo_header_enable)(fifo_header_en); + if (err) + return -EIO; + + client_data->fifo_head_en = fifo_header_en; + + return count; +} + +static ssize_t smi130_fifo_time_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data = 0; + + err = SMI_CALL_API(get_fifo_time_enable)(&data); + + if (!err) + err = snprintf(buf, 16, "%d\n", data); + + return err; +} + +static ssize_t smi130_fifo_time_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long data; + unsigned char fifo_ts_en; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + fifo_ts_en = (unsigned char)data; + + err = SMI_CALL_API(set_fifo_time_enable)(fifo_ts_en); + if (err) + return -EIO; + + return count; +} + +static ssize_t smi130_fifo_int_tag_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + unsigned char fifo_tag_int1 = 0; + unsigned char fifo_tag_int2 = 0; + unsigned char fifo_tag_int; + + err += SMI_CALL_API(get_fifo_tag_intr1_enable)(&fifo_tag_int1); + err += SMI_CALL_API(get_fifo_tag_intr2_enable)(&fifo_tag_int2); + + fifo_tag_int = (fifo_tag_int1 << SMI130_INT0) | + (fifo_tag_int2 << SMI130_INT1); + + if (!err) + err = snprintf(buf, 16, "%d\n", fifo_tag_int); + + return err; +} + +static ssize_t smi130_fifo_int_tag_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err; + unsigned long data; + unsigned char fifo_tag_int_en; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + if (data > 3) + return -EINVAL; + + fifo_tag_int_en = (unsigned char)data; + + err += SMI_CALL_API(set_fifo_tag_intr1_enable) + ((fifo_tag_int_en & (1 << SMI130_INT0)) ? 1 : 0); + err += SMI_CALL_API(set_fifo_tag_intr2_enable) + ((fifo_tag_int_en & (1 << SMI130_INT1)) ? 1 : 0); + + if (err) { + dev_err(client_data->dev, "fifo int tag en err:%d\n", err); + return -EIO; + } + client_data->fifo_int_tag_en = fifo_tag_int_en; + + return count; +} + +static int smi130_set_acc_op_mode(struct smi_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + unsigned char stc_enable; + unsigned char std_enable; + mutex_lock(&client_data->mutex_op_mode); + + if (op_mode < SMI_ACC_PM_MAX) { + switch (op_mode) { + case SMI_ACC_PM_NORMAL: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]); + client_data->pw.acc_pm = SMI_ACC_PM_NORMAL; + smi_delay(10); + break; + case SMI_ACC_PM_LP1: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_LP1]); + client_data->pw.acc_pm = SMI_ACC_PM_LP1; + smi_delay(3); + break; + case SMI_ACC_PM_SUSPEND: + SMI_CALL_API(get_step_counter_enable)(&stc_enable); + SMI_CALL_API(get_step_detector_enable)(&std_enable); + if ((stc_enable == 0) && (std_enable == 0) && + (client_data->sig_flag == 0)) { + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_SUSPEND]); + client_data->pw.acc_pm = SMI_ACC_PM_SUSPEND; + smi_delay(10); + } + break; + case SMI_ACC_PM_LP2: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_LP2]); + client_data->pw.acc_pm = SMI_ACC_PM_LP2; + smi_delay(3); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + + return err; + + +} + +static ssize_t smi130_temperature_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + s16 temp = 0xff; + + err = SMI_CALL_API(get_temp)(&temp); + + if (!err) + err = snprintf(buf, 16, "0x%x\n", temp); + + return err; +} + +static ssize_t smi130_place_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int place = BOSCH_SENSOR_PLACE_UNKNOWN; + + if (NULL != client_data->bosch_pd) + place = client_data->bosch_pd->place; + + return snprintf(buf, 16, "%d\n", place); +} + +static ssize_t smi130_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 16, "%d\n", atomic_read(&client_data->delay)); + +} + +static ssize_t smi130_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err; + unsigned long data; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + if (data == 0) { + err = -EINVAL; + return err; + } + + if (data < SMI_DELAY_MIN) + data = SMI_DELAY_MIN; + + atomic_set(&client_data->delay, (unsigned int)data); + + return count; +} + +static ssize_t smi130_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 16, "%d\n", atomic_read(&client_data->wkqueue_en)); + +} + +static ssize_t smi130_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err; + unsigned long enable; + int pre_enable = atomic_read(&client_data->wkqueue_en); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + + enable = enable ? 1 : 0; + mutex_lock(&client_data->mutex_enable); + if (enable) { + if (pre_enable == 0) { + smi130_set_acc_op_mode(client_data, + SMI_ACC_PM_NORMAL); + schedule_delayed_work(&client_data->work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + atomic_set(&client_data->wkqueue_en, 1); + } + + } else { + if (pre_enable == 1) { + smi130_set_acc_op_mode(client_data, + SMI_ACC_PM_SUSPEND); + + cancel_delayed_work_sync(&client_data->work); + atomic_set(&client_data->wkqueue_en, 0); + } + } + + mutex_unlock(&client_data->mutex_enable); + + return count; +} + +#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2) +/* accel sensor part */ +static ssize_t smi130_anymot_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data; + + err = SMI_CALL_API(get_intr_any_motion_durn)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_anymot_duration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_intr_any_motion_durn)((unsigned char)data); + if (err < 0) + return -EIO; + + return count; +} + +static ssize_t smi130_anymot_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_intr_any_motion_thres)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_anymot_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_intr_any_motion_thres)((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_step_detector_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data = 0; + u8 step_det; + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + err = SMI_CALL_API(get_step_detector_enable)(&step_det); + /*smi130_get_status0_step_int*/ + if (err < 0) + return err; +/*client_data->std will be updated in smi_stepdetector_interrupt_handle */ + if ((step_det == 1) && (client_data->std == 1)) { + data = 1; + client_data->std = 0; + } + else { + data = 0; + } + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_step_detector_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_step_detector_enable)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_step_detector_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_step_detector_enable)((unsigned char)data); + if (err < 0) + return -EIO; + if (data == 0) + client_data->pedo_data.wkar_step_detector_status = 0; + return count; +} + +static ssize_t smi130_signification_motion_enable_store( + struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel*/ + err = SMI_CALL_API(set_intr_significant_motion_select)( + (unsigned char)data); + if (err < 0) + return -EIO; + if (data == 1) { + err = SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_X_ENABLE, 1); + err += SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_Y_ENABLE, 1); + err += SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_Z_ENABLE, 1); + if (err < 0) + return -EIO; + enable_irq_wake(client_data->IRQ); + client_data->sig_flag = 1; + } else { + err = SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_X_ENABLE, 0); + err += SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_Y_ENABLE, 0); + err += SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_Z_ENABLE, 0); + if (err < 0) + return -EIO; + disable_irq_wake(client_data->IRQ); + client_data->sig_flag = 0; + } + return count; +} + +static ssize_t smi130_signification_motion_enable_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + /*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel*/ + err = SMI_CALL_API(get_intr_significant_motion_select)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static int sigmotion_init_interrupts(u8 sig_map_int_pin) +{ + int ret = 0; +/*0x60 */ + ret += smi130_set_intr_any_motion_thres(0x1e); +/* 0x62(bit 3~2) 0=1.5s */ + ret += smi130_set_intr_significant_motion_skip(0); +/*0x62(bit 5~4) 1=0.5s*/ + ret += smi130_set_intr_significant_motion_proof(1); +/*0x50 (bit 0, 1, 2) INT_EN_0 anymo x y z*/ + ret += smi130_map_significant_motion_intr(sig_map_int_pin); +/*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel +close the signification_motion*/ + ret += smi130_set_intr_significant_motion_select(0); +/*close the anymotion interrupt*/ + ret += SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_X_ENABLE, 0); + ret += SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_Y_ENABLE, 0); + ret += SMI_CALL_API(set_intr_enable_0) + (SMI130_ANY_MOTION_Z_ENABLE, 0); + if (ret) + printk(KERN_ERR "smi130 sig motion failed setting,%d!\n", ret); + return ret; + +} +#endif + +static ssize_t smi130_acc_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char range; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = SMI_CALL_API(get_accel_range)(&range); + if (err) + return err; + + client_data->range.acc_range = range; + return snprintf(buf, 16, "%d\n", range); +} + +static ssize_t smi130_acc_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long range; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + + err = kstrtoul(buf, 10, &range); + if (err) + return err; + + err = SMI_CALL_API(set_accel_range)(range); + if (err) + return -EIO; + + client_data->range.acc_range = range; + return count; +} + +static ssize_t smi130_acc_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char acc_odr; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = SMI_CALL_API(get_accel_output_data_rate)(&acc_odr); + if (err) + return err; + + client_data->odr.acc_odr = acc_odr; + return snprintf(buf, 16, "%d\n", acc_odr); +} + +static ssize_t smi130_acc_odr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long acc_odr; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &acc_odr); + if (err) + return err; + + if (acc_odr < 1 || acc_odr > 12) + return -EIO; + + if (acc_odr < 5) + err = SMI_CALL_API(set_accel_under_sampling_parameter)(1); + else + err = SMI_CALL_API(set_accel_under_sampling_parameter)(0); + + if (err) + return err; + + err = SMI_CALL_API(set_accel_output_data_rate)(acc_odr); + if (err) + return -EIO; + client_data->odr.acc_odr = acc_odr; + return count; +} + +static ssize_t smi130_acc_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err = 0; + u8 accel_pmu_status = 0; + err = SMI_CALL_API(get_accel_power_mode_stat)( + &accel_pmu_status); + + if (err) + return err; + else + return snprintf(buf, 32, "reg:%d, val:%d\n", accel_pmu_status, + client_data->pw.acc_pm); +} + +static ssize_t smi130_acc_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err; + unsigned long op_mode; + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + + err = smi130_set_acc_op_mode(client_data, op_mode); + if (err) + return err; + else + return count; + +} + +static ssize_t smi130_acc_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct smi130_accel_t data; + + int err; + + err = SMI_CALL_API(read_accel_xyz)(&data); + if (err < 0) + return err; + + return snprintf(buf, 48, "%hd %hd %hd\n", + data.x, data.y, data.z); +} + +static ssize_t smi130_acc_fast_calibration_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_foc_accel_x)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_fast_calibration_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + s8 accel_offset_x = 0; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* 0: disable, 1: +1g, 2: -1g, 3: 0g */ + if (data > 3) + return -EINVAL; + + err = SMI_CALL_API(set_accel_foc_trigger)(X_AXIS, + data, &accel_offset_x); + if (err) + return -EIO; + else + client_data->calib_status |= + SMI_FAST_CALI_TRUE << SMI_ACC_X_FAST_CALI_RDY; + return count; +} + +static ssize_t smi130_acc_fast_calibration_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_foc_accel_y)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_fast_calibration_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + s8 accel_offset_y = 0; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* 0: disable, 1: +1g, 2: -1g, 3: 0g */ + if (data > 3) + return -EINVAL; + + err = SMI_CALL_API(set_accel_foc_trigger)(Y_AXIS, + data, &accel_offset_y); + if (err) + return -EIO; + else + client_data->calib_status |= + SMI_FAST_CALI_TRUE << SMI_ACC_Y_FAST_CALI_RDY; + return count; +} + +static ssize_t smi130_acc_fast_calibration_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_foc_accel_z)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_fast_calibration_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + s8 accel_offset_z = 0; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + unsigned char data1[3] = {0}; + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* 0: disable, 1: +1g, 2: -1g, 3: 0g */ + if (data > 3) + return -EINVAL; + + err = SMI_CALL_API(set_accel_foc_trigger)(Z_AXIS, + data, &accel_offset_z); + if (err) + return -EIO; + else + client_data->calib_status |= + SMI_FAST_CALI_TRUE << SMI_ACC_Z_FAST_CALI_RDY; + + if (client_data->calib_status == SMI_FAST_CALI_ALL_RDY) { + err = SMI_CALL_API(get_accel_offset_compensation_xaxis)( + &data1[0]); + err += SMI_CALL_API(get_accel_offset_compensation_yaxis)( + &data1[1]); + err += SMI_CALL_API(get_accel_offset_compensation_zaxis)( + &data1[2]); + dev_info(client_data->dev, "accx %d, accy %d, accz %d\n", + data1[0], data1[1], data1[2]); + if (err) + return -EIO; + input_event(client_data->input, EV_MSC, + INPUT_EVENT_FAST_ACC_CALIB_DONE, + (data1[0] | (data1[1] << 8) | (data1[2] << 16))); + input_sync(client_data->input); + client_data->calib_status = 0; + } + + return count; +} + +static ssize_t smi130_acc_offset_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_accel_offset_compensation_xaxis)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + + +static ssize_t smi130_acc_offset_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_accel_offset_compensation_xaxis) + ((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_acc_offset_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_accel_offset_compensation_yaxis)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_offset_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_accel_offset_compensation_yaxis) + ((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_acc_offset_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_accel_offset_compensation_zaxis)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_acc_offset_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_accel_offset_compensation_zaxis) + ((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + u8 raw_data[15] = {0}; + unsigned int sensor_time = 0; + + int err; + memset(raw_data, 0, sizeof(raw_data)); + + err = client_data->device.bus_read(client_data->device.dev_addr, + SMI130_USER_DATA_8_GYRO_X_LSB__REG, raw_data, 15); + if (err) + return err; + + udelay(10); + sensor_time = (u32)(raw_data[14] << 16 | raw_data[13] << 8 + | raw_data[12]); + + return snprintf(buf, 128, "%d %d %d %d %d %d %u", + (s16)(raw_data[1] << 8 | raw_data[0]), + (s16)(raw_data[3] << 8 | raw_data[2]), + (s16)(raw_data[5] << 8 | raw_data[4]), + (s16)(raw_data[7] << 8 | raw_data[6]), + (s16)(raw_data[9] << 8 | raw_data[8]), + (s16)(raw_data[11] << 8 | raw_data[10]), + sensor_time); + +} + +static ssize_t smi130_step_counter_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = SMI_CALL_API(get_step_counter_enable)(&data); + + client_data->stc_enable = data; + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_step_counter_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_step_counter_enable)((unsigned char)data); + + client_data->stc_enable = data; + + if (err < 0) + return -EIO; + return count; +} + + +static ssize_t smi130_step_counter_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_step_mode)((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_step_counter_clc_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = smi130_clear_step_counter(); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_step_counter_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u16 data; + int err; + static u16 last_stc_value; + + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = SMI_CALL_API(read_step_count)(&data); + + if (err < 0) + return err; + if (data >= last_stc_value) { + client_data->pedo_data.last_step_counter_value += ( + data - last_stc_value); + last_stc_value = data; + } else + last_stc_value = data; + return snprintf(buf, 16, "%d\n", + client_data->pedo_data.last_step_counter_value); +} + +static ssize_t smi130_smi_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + u8 raw_data[12] = {0}; + + int err; + memset(raw_data, 0, sizeof(raw_data)); + + err = client_data->device.bus_read(client_data->device.dev_addr, + SMI130_USER_DATA_8_GYRO_X_LSB__REG, raw_data, 12); + if (err) + return err; + /*output:gyro x y z acc x y z*/ + return snprintf(buf, 96, "%hd %d %hd %hd %hd %hd\n", + (s16)(raw_data[1] << 8 | raw_data[0]), + (s16)(raw_data[3] << 8 | raw_data[2]), + (s16)(raw_data[5] << 8 | raw_data[4]), + (s16)(raw_data[7] << 8 | raw_data[6]), + (s16)(raw_data[9] << 8 | raw_data[8]), + (s16)(raw_data[11] << 8 | raw_data[10])); + +} + + +static ssize_t smi130_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 16, "0x%x\n", + atomic_read(&client_data->selftest_result)); +} + +static int smi_restore_hw_cfg(struct smi_client_data *client); + +/*! + * @brief store selftest result which make up of acc and gyro + * format: 0b 0000 xxxx x:1 failed, 0 success + * bit3: gyro_self + * bit2..0: acc_self z y x + */ +static ssize_t smi130_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err = 0; + int i = 0; + + u8 acc_selftest = 0; + u8 gyro_selftest = 0; + u8 smi_selftest = 0; + s16 axis_p_value, axis_n_value; + u16 diff_axis[3] = {0xff, 0xff, 0xff}; + u8 acc_odr, range, acc_selftest_amp, acc_selftest_sign; + + dev_notice(client_data->dev, "Selftest for SMI16x starting.\n"); + + client_data->selftest = 1; + + /*soft reset*/ + err = SMI_CALL_API(set_command_register)(CMD_RESET_USER_REG); + msleep(70); + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]); + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]); + err += SMI_CALL_API(set_accel_under_sampling_parameter)(0); + err += SMI_CALL_API(set_accel_output_data_rate)( + SMI130_ACCEL_OUTPUT_DATA_RATE_1600HZ); + + /* set to 8G range*/ + err += SMI_CALL_API(set_accel_range)(SMI130_ACCEL_RANGE_8G); + /* set to self amp high */ + err += SMI_CALL_API(set_accel_selftest_amp)(SMI_SELFTEST_AMP_HIGH); + + + err += SMI_CALL_API(get_accel_output_data_rate)(&acc_odr); + err += SMI_CALL_API(get_accel_range)(&range); + err += SMI_CALL_API(get_accel_selftest_amp)(&acc_selftest_amp); + err += SMI_CALL_API(read_accel_x)(&axis_n_value); + + dev_info(client_data->dev, + "acc_odr:%d, acc_range:%d, acc_selftest_amp:%d, acc_x:%d\n", + acc_odr, range, acc_selftest_amp, axis_n_value); + + for (i = X_AXIS; i < AXIS_MAX; i++) { + axis_n_value = 0; + axis_p_value = 0; + /* set every selftest axis */ + /*set_acc_selftest_axis(param),param x:1, y:2, z:3 + * but X_AXIS:0, Y_AXIS:1, Z_AXIS:2 + * so we need to +1*/ + err += SMI_CALL_API(set_accel_selftest_axis)(i + 1); + msleep(50); + switch (i) { + case X_AXIS: + /* set negative sign */ + err += SMI_CALL_API(set_accel_selftest_sign)(0); + err += SMI_CALL_API(get_accel_selftest_sign)( + &acc_selftest_sign); + + msleep(60); + err += SMI_CALL_API(read_accel_x)(&axis_n_value); + dev_info(client_data->dev, + "acc_x_selftest_sign:%d, axis_n_value:%d\n", + acc_selftest_sign, axis_n_value); + + /* set postive sign */ + err += SMI_CALL_API(set_accel_selftest_sign)(1); + err += SMI_CALL_API(get_accel_selftest_sign)( + &acc_selftest_sign); + + msleep(60); + err += SMI_CALL_API(read_accel_x)(&axis_p_value); + dev_info(client_data->dev, + "acc_x_selftest_sign:%d, axis_p_value:%d\n", + acc_selftest_sign, axis_p_value); + diff_axis[i] = abs(axis_p_value - axis_n_value); + break; + + case Y_AXIS: + /* set negative sign */ + err += SMI_CALL_API(set_accel_selftest_sign)(0); + msleep(60); + err += SMI_CALL_API(read_accel_y)(&axis_n_value); + /* set postive sign */ + err += SMI_CALL_API(set_accel_selftest_sign)(1); + msleep(60); + err += SMI_CALL_API(read_accel_y)(&axis_p_value); + diff_axis[i] = abs(axis_p_value - axis_n_value); + break; + + case Z_AXIS: + /* set negative sign */ + err += SMI_CALL_API(set_accel_selftest_sign)(0); + msleep(60); + err += SMI_CALL_API(read_accel_z)(&axis_n_value); + /* set postive sign */ + err += SMI_CALL_API(set_accel_selftest_sign)(1); + msleep(60); + err += SMI_CALL_API(read_accel_z)(&axis_p_value); + /* also start gyro self test */ + err += SMI_CALL_API(set_gyro_selftest_start)(1); + msleep(60); + err += SMI_CALL_API(get_gyro_selftest)(&gyro_selftest); + + diff_axis[i] = abs(axis_p_value - axis_n_value); + break; + default: + err += -EINVAL; + break; + } + if (err) { + dev_err(client_data->dev, + "Failed selftest axis:%s, p_val=%d, n_val=%d\n", + smi_axis_name[i], axis_p_value, axis_n_value); + client_data->selftest = 0; + return -EINVAL; + } + + /*400mg for acc z axis*/ + if (Z_AXIS == i) { + if (diff_axis[i] < 1639) { + acc_selftest |= 1 << i; + dev_err(client_data->dev, + "Over selftest minimum for " + "axis:%s,diff=%d,p_val=%d, n_val=%d\n", + smi_axis_name[i], diff_axis[i], + axis_p_value, axis_n_value); + } + } else { + /*800mg for x or y axis*/ + if (diff_axis[i] < 3277) { + acc_selftest |= 1 << i; + + if (smi_get_err_status(client_data) < 0) + return err; + dev_err(client_data->dev, + "Over selftest minimum for " + "axis:%s,diff=%d, p_val=%d, n_val=%d\n", + smi_axis_name[i], diff_axis[i], + axis_p_value, axis_n_value); + dev_err(client_data->dev, "err_st:0x%x\n", + client_data->err_st.err_st_all); + + } + } + + } + /* gyro_selftest==1,gyro selftest successfully, + * but smi_result bit4 0 is successful, 1 is failed*/ + smi_selftest = (acc_selftest & 0x0f) | ((!gyro_selftest) << AXIS_MAX); + atomic_set(&client_data->selftest_result, smi_selftest); + /*soft reset*/ + err = SMI_CALL_API(set_command_register)(CMD_RESET_USER_REG); + if (err) { + client_data->selftest = 0; + return err; + } + msleep(50); + + smi_restore_hw_cfg(client_data); + + client_data->selftest = 0; + dev_notice(client_data->dev, "Selftest for SMI16x finished\n"); + + return count; +} + +/* gyro sensor part */ +static ssize_t smi130_gyro_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int err = 0; + u8 gyro_pmu_status = 0; + + err = SMI_CALL_API(get_gyro_power_mode_stat)( + &gyro_pmu_status); + + if (err) + return err; + else + return snprintf(buf, 32, "reg:%d, val:%d\n", gyro_pmu_status, + client_data->pw.gyro_pm); +} + +static ssize_t smi130_gyro_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + unsigned long op_mode; + int err; + + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + + mutex_lock(&client_data->mutex_op_mode); + + if (op_mode < SMI_GYRO_PM_MAX) { + switch (op_mode) { + case SMI_GYRO_PM_NORMAL: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]); + client_data->pw.gyro_pm = SMI_GYRO_PM_NORMAL; + smi_delay(60); + break; + case SMI_GYRO_PM_FAST_START: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_FAST_START]); + client_data->pw.gyro_pm = SMI_GYRO_PM_FAST_START; + smi_delay(60); + break; + case SMI_GYRO_PM_SUSPEND: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_SUSPEND]); + client_data->pw.gyro_pm = SMI_GYRO_PM_SUSPEND; + smi_delay(60); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + + if (err) + return err; + else + return count; + +} + +static ssize_t smi130_gyro_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct smi130_gyro_t data; + int err; + + err = SMI_CALL_API(read_gyro_xyz)(&data); + if (err < 0) + return err; + + + return snprintf(buf, 48, "%hd %hd %hd\n", data.x, + data.y, data.z); +} + +static ssize_t smi130_gyro_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char range; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = SMI_CALL_API(get_gyro_range)(&range); + if (err) + return err; + + client_data->range.gyro_range = range; + return snprintf(buf, 16, "%d\n", range); +} + +static ssize_t smi130_gyro_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long range; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &range); + if (err) + return err; + + err = SMI_CALL_API(set_gyro_range)(range); + if (err) + return -EIO; + + client_data->range.gyro_range = range; + return count; +} + +static ssize_t smi130_gyro_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char gyro_odr; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = SMI_CALL_API(get_gyro_output_data_rate)(&gyro_odr); + if (err) + return err; + + client_data->odr.gyro_odr = gyro_odr; + return snprintf(buf, 16, "%d\n", gyro_odr); +} + +static ssize_t smi130_gyro_odr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long gyro_odr; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &gyro_odr); + if (err) + return err; + + if (gyro_odr < 6 || gyro_odr > 13) + return -EIO; + + err = SMI_CALL_API(set_gyro_output_data_rate)(gyro_odr); + if (err) + return -EIO; + + client_data->odr.gyro_odr = gyro_odr; + return count; +} + +static ssize_t smi130_gyro_fast_calibration_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = SMI_CALL_API(get_foc_gyro_enable)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_gyro_fast_calibration_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long enable; + s8 err; + s16 gyr_off_x; + s16 gyr_off_y; + s16 gyr_off_z; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + + err = SMI_CALL_API(set_foc_gyro_enable)((u8)enable, + &gyr_off_x, &gyr_off_y, &gyr_off_z); + + if (err < 0) + return -EIO; + else { + input_event(client_data->input, EV_MSC, + INPUT_EVENT_FAST_GYRO_CALIB_DONE, 1); + input_sync(client_data->input); + } + return count; +} + +static ssize_t smi130_gyro_offset_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 data = 0; + s8 err = 0; + + err = SMI_CALL_API(get_gyro_offset_compensation_xaxis)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_gyro_offset_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + s8 err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_gyro_offset_compensation_xaxis)((s16)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_gyro_offset_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 data = 0; + s8 err = 0; + + err = SMI_CALL_API(get_gyro_offset_compensation_yaxis)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_gyro_offset_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + s8 err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_gyro_offset_compensation_yaxis)((s16)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_gyro_offset_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 data = 0; + int err = 0; + + err = SMI_CALL_API(get_gyro_offset_compensation_zaxis)(&data); + + if (err < 0) + return err; + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t smi130_gyro_offset_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = SMI_CALL_API(set_gyro_offset_compensation_zaxis)((s16)data); + + if (err < 0) + return -EIO; + return count; +} + + +/* mag sensor part */ +#ifdef SMI130_MAG_INTERFACE_SUPPORT +static ssize_t smi130_mag_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + u8 mag_op_mode; + s8 err; + err = smi130_get_mag_power_mode_stat(&mag_op_mode); + if (err) { + dev_err(client_data->dev, + "Failed to get SMI130 mag power mode:%d\n", err); + return err; + } else + return snprintf(buf, 32, "%d, reg:%d\n", + client_data->pw.mag_pm, mag_op_mode); +} + +static ssize_t smi130_mag_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + unsigned long op_mode; + int err; + + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + + if (op_mode == client_data->pw.mag_pm) + return count; + + mutex_lock(&client_data->mutex_op_mode); + + + if (op_mode < SMI_MAG_PM_MAX) { + switch (op_mode) { + case SMI_MAG_PM_NORMAL: + /* need to modify as mag sensor connected, + * set write address to 0x4c and triggers + * write operation + * 0x4c(op mode control reg) + * enables normal mode in magnetometer */ +#if defined(SMI130_AKM09912_SUPPORT) + err = smi130_set_bosch_akm_and_secondary_if_powermode( + SMI130_MAG_FORCE_MODE); +#else + err = smi130_set_bmm150_mag_and_secondary_if_power_mode( + SMI130_MAG_FORCE_MODE); +#endif + client_data->pw.mag_pm = SMI_MAG_PM_NORMAL; + smi_delay(5); + break; + case SMI_MAG_PM_LP1: + /* need to modify as mag sensor connected, + * set write address to 0x4 band triggers + * write operation + * 0x4b(bmm150, power control reg, bit0) + * enables power in magnetometer*/ +#if defined(SMI130_AKM09912_SUPPORT) + err = smi130_set_bosch_akm_and_secondary_if_powermode( + SMI130_MAG_FORCE_MODE); +#else + err = smi130_set_bmm150_mag_and_secondary_if_power_mode( + SMI130_MAG_FORCE_MODE); +#endif + client_data->pw.mag_pm = SMI_MAG_PM_LP1; + smi_delay(5); + break; + case SMI_MAG_PM_SUSPEND: + case SMI_MAG_PM_LP2: +#if defined(SMI130_AKM09912_SUPPORT) + err = smi130_set_bosch_akm_and_secondary_if_powermode( + SMI130_MAG_SUSPEND_MODE); +#else + err = smi130_set_bmm150_mag_and_secondary_if_power_mode( + SMI130_MAG_SUSPEND_MODE); +#endif + client_data->pw.mag_pm = op_mode; + smi_delay(5); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + + if (err) { + dev_err(client_data->dev, + "Failed to switch SMI130 mag power mode:%d\n", + client_data->pw.mag_pm); + return err; + } else + return count; + +} + +static ssize_t smi130_mag_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + unsigned char mag_odr = 0; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = SMI_CALL_API(get_mag_output_data_rate)(&mag_odr); + if (err) + return err; + + client_data->odr.mag_odr = mag_odr; + return snprintf(buf, 16, "%d\n", mag_odr); +} + +static ssize_t smi130_mag_odr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long mag_odr; + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &mag_odr); + if (err) + return err; + /*1~25/32hz,..6(25hz),7(50hz),... */ + err = SMI_CALL_API(set_mag_output_data_rate)(mag_odr); + if (err) + return -EIO; + + client_data->odr.mag_odr = mag_odr; + return count; +} + +static ssize_t smi130_mag_i2c_address_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + s8 err; + + err = SMI_CALL_API(set_mag_manual_enable)(1); + err += SMI_CALL_API(get_i2c_device_addr)(&data); + err += SMI_CALL_API(set_mag_manual_enable)(0); + + if (err < 0) + return err; + return snprintf(buf, 16, "0x%x\n", data); +} + +static ssize_t smi130_mag_i2c_address_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err += SMI_CALL_API(set_mag_manual_enable)(1); + if (!err) + err += SMI_CALL_API(set_i2c_device_addr)((unsigned char)data); + err += SMI_CALL_API(set_mag_manual_enable)(0); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_mag_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + struct smi130_mag_xyz_s32_t data; + int err; + /* raw data with compensation */ +#if defined(SMI130_AKM09912_SUPPORT) + err = smi130_bosch_akm09912_compensate_xyz(&data); +#else + err = smi130_bmm150_mag_compensate_xyz(&data); +#endif + + if (err < 0) { + memset(&data, 0, sizeof(data)); + dev_err(client_data->dev, "mag not ready!\n"); + } + return snprintf(buf, 48, "%hd %hd %hd\n", data.x, + data.y, data.z); +} +static ssize_t smi130_mag_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + unsigned char mag_offset; + err = SMI_CALL_API(get_mag_offset)(&mag_offset); + if (err) + return err; + + return snprintf(buf, 16, "%d\n", mag_offset); + +} + +static ssize_t smi130_mag_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err += SMI_CALL_API(set_mag_manual_enable)(1); + if (err == 0) + err += SMI_CALL_API(set_mag_offset)((unsigned char)data); + err += SMI_CALL_API(set_mag_manual_enable)(0); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t smi130_mag_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s8 err = 0; + u8 mag_chipid; + + err = smi130_set_mag_manual_enable(0x01); + /* read mag chip_id value */ +#if defined(SMI130_AKM09912_SUPPORT) + err += smi130_set_mag_read_addr(AKM09912_CHIP_ID_REG); + /* 0x04 is mag_x lsb register */ + err += smi130_read_reg(SMI130_USER_DATA_0_MAG_X_LSB__REG, + &mag_chipid, 1); + + /* Must add this commands to re-set data register addr of mag sensor */ + err += smi130_set_mag_read_addr(AKM_DATA_REGISTER); +#else + err += smi130_set_mag_read_addr(SMI130_BMM150_CHIP_ID); + /* 0x04 is mag_x lsb register */ + err += smi130_read_reg(SMI130_USER_DATA_0_MAG_X_LSB__REG, + &mag_chipid, 1); + + /* Must add this commands to re-set data register addr of mag sensor */ + /* 0x42 is bmm150 data register address */ + err += smi130_set_mag_read_addr(SMI130_BMM150_DATA_REG); +#endif + + err += smi130_set_mag_manual_enable(0x00); + + if (err) + return err; + + return snprintf(buf, 16, "%x\n", mag_chipid); + +} + +static ssize_t smi130_mag_chip_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 mag_chipid = 0; +#if defined(SMI130_AKM09912_SUPPORT) + mag_chipid = 15; +#else + mag_chipid = 150; +#endif + return snprintf(buf, 16, "%d\n", mag_chipid); +} + +struct smi130_mag_xyz_s32_t mag_compensate; +static ssize_t smi130_mag_compensate_xyz_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + memcpy(buf, &mag_compensate, sizeof(mag_compensate)); + return sizeof(mag_compensate); +} +static ssize_t smi130_mag_compensate_xyz_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct smi130_mag_xyzr_t mag_raw; + memset(&mag_compensate, 0, sizeof(mag_compensate)); + memset(&mag_raw, 0, sizeof(mag_raw)); + mag_raw.x = (buf[1] << 8 | buf[0]); + mag_raw.y = (buf[3] << 8 | buf[2]); + mag_raw.z = (buf[5] << 8 | buf[4]); + mag_raw.r = (buf[7] << 8 | buf[6]); + mag_raw.x = mag_raw.x >> 3; + mag_raw.y = mag_raw.y >> 3; + mag_raw.z = mag_raw.z >> 1; + mag_raw.r = mag_raw.r >> 2; + smi130_bmm150_mag_compensate_xyz_raw( + &mag_compensate, mag_raw); + return count; +} + +#endif + +#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2) +static ssize_t smi_enable_int_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int interrupt_type, value; + + sscanf(buf, "%3d %3d", &interrupt_type, &value); + + if (interrupt_type < 0 || interrupt_type > 16) + return -EINVAL; + + if (interrupt_type <= SMI_FLAT_INT) { + if (SMI_CALL_API(set_intr_enable_0) + (smi_interrupt_type[interrupt_type], value) < 0) + return -EINVAL; + } else if (interrupt_type <= SMI_FWM_INT) { + if (SMI_CALL_API(set_intr_enable_1) + (smi_interrupt_type[interrupt_type], value) < 0) + return -EINVAL; + } else { + if (SMI_CALL_API(set_intr_enable_2) + (smi_interrupt_type[interrupt_type], value) < 0) + return -EINVAL; + } + + return count; +} + +#endif + +static ssize_t smi130_show_reg_sel(struct device *dev + , struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + + return snprintf(buf, 64, "reg=0X%02X, len=%d\n", + client_data->reg_sel, client_data->reg_len); +} + +static ssize_t smi130_store_reg_sel(struct device *dev + , struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + ssize_t ret; + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + ret = sscanf(buf, "%11X %11d", + &client_data->reg_sel, &client_data->reg_len); + if (ret != 2) { + dev_err(client_data->dev, "Invalid argument"); + return -EINVAL; + } + + return count; +} + +static ssize_t smi130_show_reg_val(struct device *dev + , struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + + ssize_t ret; + u8 reg_data[128] = {0}, i; + int pos; + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + + ret = smi_burst_read_wrapper(client_data->device.dev_addr, + client_data->reg_sel, + reg_data, client_data->reg_len); + if (ret < 0) { + dev_err(client_data->dev, "Reg op failed"); + return ret; + } + + pos = 0; + for (i = 0; i < client_data->reg_len; ++i) { + pos += snprintf(buf + pos, 16, "%02X", reg_data[i]); + buf[pos++] = (i + 1) % 16 == 0 ? '\n' : ' '; + } + if (buf[pos - 1] == ' ') + buf[pos - 1] = '\n'; + + return pos; +} + +static ssize_t smi130_store_reg_val(struct device *dev + , struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + ssize_t ret; + u8 reg_data[32] = {0}; + int i, j, status, digit; + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + status = 0; + for (i = j = 0; i < count && j < client_data->reg_len; ++i) { + if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t' || + buf[i] == '\r') { + status = 0; + ++j; + continue; + } + digit = buf[i] & 0x10 ? (buf[i] & 0xF) : ((buf[i] & 0xF) + 9); + printk(KERN_INFO "digit is %d", digit); + switch (status) { + case 2: + ++j; /* Fall thru */ + case 0: + reg_data[j] = digit; + status = 1; + break; + case 1: + reg_data[j] = reg_data[j] * 16 + digit; + status = 2; + break; + } + } + if (status > 0) + ++j; + if (j > client_data->reg_len) + j = client_data->reg_len; + else if (j < client_data->reg_len) { + dev_err(client_data->dev, "Invalid argument"); + return -EINVAL; + } + printk(KERN_INFO "Reg data read as"); + for (i = 0; i < j; ++i) + printk(KERN_INFO "%d", reg_data[i]); + + ret = SMI_CALL_API(write_reg)( + client_data->reg_sel, + reg_data, client_data->reg_len); + if (ret < 0) { + dev_err(client_data->dev, "Reg op failed"); + return ret; + } + + return count; +} + +static ssize_t smi130_driver_version_show(struct device *dev + , struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_client_data *client_data = input_get_drvdata(input); + int ret; + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + + ret = snprintf(buf, 128, "Driver version: %s\n", + DRIVER_VERSION); + + return ret; +} +static DEVICE_ATTR(chip_id, S_IRUGO, + smi130_chip_id_show, NULL); +static DEVICE_ATTR(err_st, S_IRUGO, + smi130_err_st_show, NULL); +static DEVICE_ATTR(sensor_time, S_IRUGO, + smi130_sensor_time_show, NULL); + +static DEVICE_ATTR(selftest, S_IRUGO | S_IWUSR, + smi130_selftest_show, smi130_selftest_store); +static DEVICE_ATTR(fifo_flush, S_IRUGO | S_IWUSR, + NULL, smi130_fifo_flush_store); +static DEVICE_ATTR(fifo_bytecount, S_IRUGO | S_IWUSR, + smi130_fifo_bytecount_show, smi130_fifo_bytecount_store); +static DEVICE_ATTR(fifo_data_sel, S_IRUGO | S_IWUSR, + smi130_fifo_data_sel_show, smi130_fifo_data_sel_store); +static DEVICE_ATTR(fifo_data_frame, S_IRUGO, + smi130_fifo_data_out_frame_show, NULL); + +static DEVICE_ATTR(fifo_watermark, S_IRUGO | S_IWUSR, + smi130_fifo_watermark_show, smi130_fifo_watermark_store); + +static DEVICE_ATTR(fifo_header_en, S_IRUGO | S_IWUSR, + smi130_fifo_header_en_show, smi130_fifo_header_en_store); +static DEVICE_ATTR(fifo_time_en, S_IRUGO | S_IWUSR, + smi130_fifo_time_en_show, smi130_fifo_time_en_store); +static DEVICE_ATTR(fifo_int_tag_en, S_IRUGO | S_IWUSR, + smi130_fifo_int_tag_en_show, smi130_fifo_int_tag_en_store); + +static DEVICE_ATTR(temperature, S_IRUGO, + smi130_temperature_show, NULL); +static DEVICE_ATTR(place, S_IRUGO, + smi130_place_show, NULL); +static DEVICE_ATTR(delay, S_IRUGO | S_IWUSR, + smi130_delay_show, smi130_delay_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, + smi130_enable_show, smi130_enable_store); +static DEVICE_ATTR(acc_range, S_IRUGO | S_IWUSR, + smi130_acc_range_show, smi130_acc_range_store); +static DEVICE_ATTR(acc_odr, S_IRUGO | S_IWUSR, + smi130_acc_odr_show, smi130_acc_odr_store); +static DEVICE_ATTR(acc_op_mode, S_IRUGO | S_IWUSR, + smi130_acc_op_mode_show, smi130_acc_op_mode_store); +static DEVICE_ATTR(acc_value, S_IRUGO, + smi130_acc_value_show, NULL); +static DEVICE_ATTR(acc_fast_calibration_x, S_IRUGO | S_IWUSR, + smi130_acc_fast_calibration_x_show, + smi130_acc_fast_calibration_x_store); +static DEVICE_ATTR(acc_fast_calibration_y, S_IRUGO | S_IWUSR, + smi130_acc_fast_calibration_y_show, + smi130_acc_fast_calibration_y_store); +static DEVICE_ATTR(acc_fast_calibration_z, S_IRUGO | S_IWUSR, + smi130_acc_fast_calibration_z_show, + smi130_acc_fast_calibration_z_store); +static DEVICE_ATTR(acc_offset_x, S_IRUGO | S_IWUSR, + smi130_acc_offset_x_show, + smi130_acc_offset_x_store); +static DEVICE_ATTR(acc_offset_y, S_IRUGO | S_IWUSR, + smi130_acc_offset_y_show, + smi130_acc_offset_y_store); +static DEVICE_ATTR(acc_offset_z, S_IRUGO | S_IWUSR, + smi130_acc_offset_z_show, + smi130_acc_offset_z_store); +static DEVICE_ATTR(test, S_IRUGO, + smi130_test_show, NULL); +static DEVICE_ATTR(stc_enable, S_IRUGO | S_IWUSR, + smi130_step_counter_enable_show, + smi130_step_counter_enable_store); +static DEVICE_ATTR(stc_mode, S_IRUGO | S_IWUSR, + NULL, smi130_step_counter_mode_store); +static DEVICE_ATTR(stc_clc, S_IRUGO | S_IWUSR, + NULL, smi130_step_counter_clc_store); +static DEVICE_ATTR(stc_value, S_IRUGO, + smi130_step_counter_value_show, NULL); +static DEVICE_ATTR(reg_sel, S_IRUGO | S_IWUSR, + smi130_show_reg_sel, smi130_store_reg_sel); +static DEVICE_ATTR(reg_val, S_IRUGO | S_IWUSR, + smi130_show_reg_val, smi130_store_reg_val); +static DEVICE_ATTR(driver_version, S_IRUGO, + smi130_driver_version_show, NULL); +/* gyro part */ +static DEVICE_ATTR(gyro_op_mode, S_IRUGO | S_IWUSR, + smi130_gyro_op_mode_show, smi130_gyro_op_mode_store); +static DEVICE_ATTR(gyro_value, S_IRUGO, + smi130_gyro_value_show, NULL); +static DEVICE_ATTR(gyro_range, S_IRUGO | S_IWUSR, + smi130_gyro_range_show, smi130_gyro_range_store); +static DEVICE_ATTR(gyro_odr, S_IRUGO | S_IWUSR, + smi130_gyro_odr_show, smi130_gyro_odr_store); +static DEVICE_ATTR(gyro_fast_calibration_en, S_IRUGO | S_IWUSR, +smi130_gyro_fast_calibration_en_show, smi130_gyro_fast_calibration_en_store); +static DEVICE_ATTR(gyro_offset_x, S_IRUGO | S_IWUSR, +smi130_gyro_offset_x_show, smi130_gyro_offset_x_store); +static DEVICE_ATTR(gyro_offset_y, S_IRUGO | S_IWUSR, +smi130_gyro_offset_y_show, smi130_gyro_offset_y_store); +static DEVICE_ATTR(gyro_offset_z, S_IRUGO | S_IWUSR, +smi130_gyro_offset_z_show, smi130_gyro_offset_z_store); + +#ifdef SMI130_MAG_INTERFACE_SUPPORT +static DEVICE_ATTR(mag_op_mode, S_IRUGO | S_IWUSR, + smi130_mag_op_mode_show, smi130_mag_op_mode_store); +static DEVICE_ATTR(mag_odr, S_IRUGO | S_IWUSR, + smi130_mag_odr_show, smi130_mag_odr_store); +static DEVICE_ATTR(mag_i2c_addr, S_IRUGO | S_IWUSR, + smi130_mag_i2c_address_show, smi130_mag_i2c_address_store); +static DEVICE_ATTR(mag_value, S_IRUGO, + smi130_mag_value_show, NULL); +static DEVICE_ATTR(mag_offset, S_IRUGO | S_IWUSR, + smi130_mag_offset_show, smi130_mag_offset_store); +static DEVICE_ATTR(mag_chip_id, S_IRUGO, + smi130_mag_chip_id_show, NULL); +static DEVICE_ATTR(mag_chip_name, S_IRUGO, + smi130_mag_chip_name_show, NULL); +static DEVICE_ATTR(mag_compensate, S_IRUGO | S_IWUSR, + smi130_mag_compensate_xyz_show, + smi130_mag_compensate_xyz_store); +#endif + + +#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2) +static DEVICE_ATTR(enable_int, S_IRUGO | S_IWUSR, + NULL, smi_enable_int_store); +static DEVICE_ATTR(anymot_duration, S_IRUGO | S_IWUSR, + smi130_anymot_duration_show, smi130_anymot_duration_store); +static DEVICE_ATTR(anymot_threshold, S_IRUGO | S_IWUSR, + smi130_anymot_threshold_show, smi130_anymot_threshold_store); +static DEVICE_ATTR(std_stu, S_IRUGO, + smi130_step_detector_status_show, NULL); +static DEVICE_ATTR(std_en, S_IRUGO | S_IWUSR, + smi130_step_detector_enable_show, + smi130_step_detector_enable_store); +static DEVICE_ATTR(sig_en, S_IRUGO | S_IWUSR, + smi130_signification_motion_enable_show, + smi130_signification_motion_enable_store); + +#endif + + + +static DEVICE_ATTR(smi_value, S_IRUGO, + smi130_smi_value_show, NULL); + + +static struct attribute *smi130_attributes[] = { + &dev_attr_chip_id.attr, + &dev_attr_err_st.attr, + &dev_attr_sensor_time.attr, + &dev_attr_selftest.attr, + &dev_attr_driver_version.attr, + &dev_attr_test.attr, + &dev_attr_fifo_flush.attr, + &dev_attr_fifo_header_en.attr, + &dev_attr_fifo_time_en.attr, + &dev_attr_fifo_int_tag_en.attr, + &dev_attr_fifo_bytecount.attr, + &dev_attr_fifo_data_sel.attr, + &dev_attr_fifo_data_frame.attr, + + &dev_attr_fifo_watermark.attr, + + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_temperature.attr, + &dev_attr_place.attr, + + &dev_attr_acc_range.attr, + &dev_attr_acc_odr.attr, + &dev_attr_acc_op_mode.attr, + &dev_attr_acc_value.attr, + + &dev_attr_acc_fast_calibration_x.attr, + &dev_attr_acc_fast_calibration_y.attr, + &dev_attr_acc_fast_calibration_z.attr, + &dev_attr_acc_offset_x.attr, + &dev_attr_acc_offset_y.attr, + &dev_attr_acc_offset_z.attr, + + &dev_attr_stc_enable.attr, + &dev_attr_stc_mode.attr, + &dev_attr_stc_clc.attr, + &dev_attr_stc_value.attr, + + &dev_attr_gyro_op_mode.attr, + &dev_attr_gyro_value.attr, + &dev_attr_gyro_range.attr, + &dev_attr_gyro_odr.attr, + &dev_attr_gyro_fast_calibration_en.attr, + &dev_attr_gyro_offset_x.attr, + &dev_attr_gyro_offset_y.attr, + &dev_attr_gyro_offset_z.attr, + +#ifdef SMI130_MAG_INTERFACE_SUPPORT + &dev_attr_mag_chip_id.attr, + &dev_attr_mag_op_mode.attr, + &dev_attr_mag_odr.attr, + &dev_attr_mag_i2c_addr.attr, + &dev_attr_mag_chip_name.attr, + &dev_attr_mag_value.attr, + &dev_attr_mag_offset.attr, + &dev_attr_mag_compensate.attr, +#endif + +#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2) + &dev_attr_enable_int.attr, + + &dev_attr_anymot_duration.attr, + &dev_attr_anymot_threshold.attr, + &dev_attr_std_stu.attr, + &dev_attr_std_en.attr, + &dev_attr_sig_en.attr, + +#endif + &dev_attr_reg_sel.attr, + &dev_attr_reg_val.attr, + &dev_attr_smi_value.attr, + NULL +}; + +static struct attribute_group smi130_attribute_group = { + .attrs = smi130_attributes +}; + +#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2) +static void smi_slope_interrupt_handle(struct smi_client_data *client_data) +{ + /* anym_first[0..2]: x, y, z */ + u8 anym_first[3] = {0}; + u8 status2; + u8 anym_sign; + u8 i = 0; + + client_data->device.bus_read(client_data->device.dev_addr, + SMI130_USER_INTR_STAT_2_ADDR, &status2, 1); + anym_first[0] = SMI130_GET_BITSLICE(status2, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X); + anym_first[1] = SMI130_GET_BITSLICE(status2, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y); + anym_first[2] = SMI130_GET_BITSLICE(status2, + SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z); + anym_sign = SMI130_GET_BITSLICE(status2, + SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN); + + for (i = 0; i < 3; i++) { + if (anym_first[i]) { + /*1: negative*/ + if (anym_sign) + dev_notice(client_data->dev, + "Anymotion interrupt happend!" + "%s axis, negative sign\n", smi_axis_name[i]); + else + dev_notice(client_data->dev, + "Anymotion interrupt happend!" + "%s axis, postive sign\n", smi_axis_name[i]); + } + } + + +} + +static void smi_fifo_watermark_interrupt_handle + (struct smi_client_data *client_data) +{ + int err = 0; + unsigned int fifo_len0 = 0; + unsigned int fifo_frmbytes_ext = 0; + unsigned char *fifo_data = NULL; + fifo_data = kzalloc(FIFO_DATA_BUFSIZE, GFP_KERNEL); + /*TO DO*/ + if (NULL == fifo_data) { + dev_err(client_data->dev, "no memory available"); + err = -ENOMEM; + } + smi_fifo_frame_bytes_extend_calc(client_data, &fifo_frmbytes_ext); + + if (client_data->pw.acc_pm == 2 && client_data->pw.gyro_pm == 2 + && client_data->pw.mag_pm == 2) + printk(KERN_INFO "pw_acc: %d, pw_gyro: %d\n", + client_data->pw.acc_pm, client_data->pw.gyro_pm); + if (!client_data->fifo_data_sel) + printk(KERN_INFO "no selsect sensor fifo, fifo_data_sel:%d\n", + client_data->fifo_data_sel); + + err = SMI_CALL_API(fifo_length)(&fifo_len0); + client_data->fifo_bytecount = fifo_len0; + + if (client_data->fifo_bytecount == 0 || err) + return; + + if (client_data->fifo_bytecount + fifo_frmbytes_ext > FIFO_DATA_BUFSIZE) + client_data->fifo_bytecount = FIFO_DATA_BUFSIZE; + /* need give attention for the time of burst read*/ + if (!err) { + err = smi_burst_read_wrapper(client_data->device.dev_addr, + SMI130_USER_FIFO_DATA__REG, fifo_data, + client_data->fifo_bytecount + fifo_frmbytes_ext); + } else + dev_err(client_data->dev, "read fifo leght err"); + + if (err) + dev_err(client_data->dev, "brust read fifo err\n"); + /*err = smi_fifo_analysis_handle(client_data, fifo_data, + client_data->fifo_bytecount + 20, fifo_out_data);*/ + if (fifo_data != NULL) { + kfree(fifo_data); + fifo_data = NULL; + } + +} +static void smi_data_ready_interrupt_handle( + struct smi_client_data *client_data, uint8_t status) +{ + uint8_t data12[12] = {0}; + struct smi130_accel_t accel; + struct smi130_gyro_t gyro; + struct timespec ts; + client_data->device.bus_read(client_data->device.dev_addr, + SMI130_USER_DATA_8_ADDR, data12, 12); + if (status & 0x80) + { + /*report acc data*/ + /* Data X */ + accel.x = (s16)((((s32)((s8)data12[7])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[6])); + /* Data Y */ + accel.y = (s16)((((s32)((s8)data12[9])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[8])); + /* Data Z */ + accel.z = (s16)((((s32)((s8)data12[11]))<< SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[10])); + ts = ns_to_timespec(client_data->timestamp); + input_event(client_data->input, EV_MSC, 6, ts.tv_sec); + input_event(client_data->input, EV_MSC, 6, ts.tv_nsec); + input_event(client_data->input, EV_MSC, MSC_GESTURE, accel.x); + input_event(client_data->input, EV_MSC, MSC_RAW, accel.y); + input_event(client_data->input, EV_MSC, MSC_SCAN, accel.z); + input_sync(client_data->input); + } + if (status & 0x40) + { + /*report gyro data*/ + /* Data X */ + gyro.x = (s16)((((s32)((s8)data12[1])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[0])); + /* Data Y */ + gyro.y = (s16)((((s32)((s8)data12[3])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[2])); + /* Data Z */ + gyro.z = (s16)((((s32)((s8)data12[5]))<< SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[4])); + ts = ns_to_timespec(client_data->timestamp); + input_event(client_data->gyro_input, EV_MSC, 6, ts.tv_sec); + input_event(client_data->gyro_input, EV_MSC, 6, ts.tv_nsec); + input_event(client_data->gyro_input, EV_MSC, MSC_GESTURE, gyro.x); + input_event(client_data->gyro_input, EV_MSC, MSC_RAW, gyro.y); + input_event(client_data->gyro_input, EV_MSC, MSC_SCAN, gyro.z); + input_sync(client_data->gyro_input); + } +} + +static void smi_signification_motion_interrupt_handle( + struct smi_client_data *client_data) +{ + printk(KERN_INFO "smi_signification_motion_interrupt_handle\n"); + input_event(client_data->input, EV_MSC, INPUT_EVENT_SGM, 1); +/*input_report_rel(client_data->input,INPUT_EVENT_SGM,1);*/ + input_sync(client_data->input); + smi130_set_command_register(CMD_RESET_INT_ENGINE); + +} +static void smi_stepdetector_interrupt_handle( + struct smi_client_data *client_data) +{ + u8 current_step_dector_st = 0; + client_data->pedo_data.wkar_step_detector_status++; + current_step_dector_st = + client_data->pedo_data.wkar_step_detector_status; + client_data->std = ((current_step_dector_st == 1) ? 0 : 1); + + input_event(client_data->input, EV_MSC, INPUT_EVENT_STEP_DETECTOR, 1); + input_sync(client_data->input); +} + +static void smi_irq_work_func(struct work_struct *work) +{ + struct smi_client_data *client_data = + container_of((struct work_struct *)work, + struct smi_client_data, irq_work); + + unsigned char int_status[4] = {0, 0, 0, 0}; + uint8_t status = 0; + + //client_data->device.bus_read(client_data->device.dev_addr, + // SMI130_USER_INTR_STAT_0_ADDR, int_status, 4); + client_data->device.bus_read(client_data->device.dev_addr, + SMI130_USER_STAT_ADDR, &status, 1); + printk("status = 0x%x", status); + if (SMI130_GET_BITSLICE(int_status[0], + SMI130_USER_INTR_STAT_0_ANY_MOTION)) + smi_slope_interrupt_handle(client_data); + + if (SMI130_GET_BITSLICE(int_status[0], + SMI130_USER_INTR_STAT_0_STEP_INTR)) + smi_stepdetector_interrupt_handle(client_data); + if (SMI130_GET_BITSLICE(int_status[1], + SMI130_USER_INTR_STAT_1_FIFO_WM_INTR)) + smi_fifo_watermark_interrupt_handle(client_data); + if ((status & 0x80) || (status & 0x40)) + smi_data_ready_interrupt_handle(client_data, status); + /* Clear ALL inputerrupt status after handler sig mition*/ + /* Put this commads intot the last one*/ + if (SMI130_GET_BITSLICE(int_status[0], + SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR)) + smi_signification_motion_interrupt_handle(client_data); + +} + +static void smi130_delay_sigmo_work_func(struct work_struct *work) +{ + struct smi_client_data *client_data = + container_of(work, struct smi_client_data, + delay_work_sig.work); + unsigned char int_status[4] = {0, 0, 0, 0}; + + client_data->device.bus_read(client_data->device.dev_addr, + SMI130_USER_INTR_STAT_0_ADDR, int_status, 4); + if (SMI130_GET_BITSLICE(int_status[0], + SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR)) + smi_signification_motion_interrupt_handle(client_data); +} + +static irqreturn_t smi_irq_handler(int irq, void *handle) +{ + struct smi_client_data *client_data = handle; + int in_suspend_copy; + in_suspend_copy = atomic_read(&client_data->in_suspend); + + if (client_data == NULL) + return IRQ_HANDLED; + if (client_data->dev == NULL) + return IRQ_HANDLED; + /*this only deal with SIG_motion CTS test*/ + if ((in_suspend_copy == 1) && + (client_data->sig_flag == 1)) { + /*wake_lock_timeout(&client_data->wakelock, HZ);*/ + schedule_delayed_work(&client_data->delay_work_sig, + msecs_to_jiffies(50)); + } + schedule_work(&client_data->irq_work); + + return IRQ_HANDLED; +} +#endif /* defined(SMI_ENABLE_INT1)||defined(SMI_ENABLE_INT2) */ + +static int smi_restore_hw_cfg(struct smi_client_data *client) +{ + int err = 0; + + if ((client->fifo_data_sel) & (1 << SMI_ACC_SENSOR)) { + err += SMI_CALL_API(set_accel_range)(client->range.acc_range); + err += SMI_CALL_API(set_accel_output_data_rate) + (client->odr.acc_odr); + err += SMI_CALL_API(set_fifo_accel_enable)(1); + } + if ((client->fifo_data_sel) & (1 << SMI_GYRO_SENSOR)) { + err += SMI_CALL_API(set_gyro_range)(client->range.gyro_range); + err += SMI_CALL_API(set_gyro_output_data_rate) + (client->odr.gyro_odr); + err += SMI_CALL_API(set_fifo_gyro_enable)(1); + } + if ((client->fifo_data_sel) & (1 << SMI_MAG_SENSOR)) { + err += SMI_CALL_API(set_mag_output_data_rate) + (client->odr.mag_odr); + err += SMI_CALL_API(set_fifo_mag_enable)(1); + } + err += SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA); + + mutex_lock(&client->mutex_op_mode); + if (client->pw.acc_pm != SMI_ACC_PM_SUSPEND) { + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]); + smi_delay(3); + } + mutex_unlock(&client->mutex_op_mode); + + mutex_lock(&client->mutex_op_mode); + if (client->pw.gyro_pm != SMI_GYRO_PM_SUSPEND) { + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]); + smi_delay(3); + } + mutex_unlock(&client->mutex_op_mode); + + mutex_lock(&client->mutex_op_mode); + + if (client->pw.mag_pm != SMI_MAG_PM_SUSPEND) { +#ifdef SMI130_AKM09912_SUPPORT + err += smi130_set_bosch_akm_and_secondary_if_powermode + (SMI130_MAG_FORCE_MODE); +#else + err += smi130_set_bmm150_mag_and_secondary_if_power_mode + (SMI130_MAG_FORCE_MODE); +#endif + smi_delay(3); + } + mutex_unlock(&client->mutex_op_mode); + + return err; +} + +#if defined(CONFIG_USE_QUALCOMM_HAL) +static void smi130_accel_work_fn(struct work_struct *work) +{ + struct smi_client_data *sensor; + ktime_t timestamp; + struct smi130_accel_t data; + int err; + sensor = container_of((struct delayed_work *)work, + struct smi_client_data, accel_poll_work); + timestamp = ktime_get(); + err = SMI_CALL_API(read_accel_xyz)(&data); + if (err) + dev_err(sensor->dev, "read data err"); + input_report_abs(sensor->input, ABS_X, + (data.x)); + input_report_abs(sensor->input, ABS_Y, + (data.y)); + input_report_abs(sensor->input, ABS_Z, + (data.z)); + input_event(sensor->input, + EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(sensor->input, EV_SYN, + SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); + input_sync(sensor->input); + if (atomic_read(&sensor->accel_en)) + queue_delayed_work(sensor->data_wq, + &sensor->accel_poll_work, + msecs_to_jiffies(sensor->accel_poll_ms)); +} +static void smi130_gyro_work_fn(struct work_struct *work) +{ + struct smi_client_data *sensor; + ktime_t timestamp; + struct smi130_gyro_t data; + int err; + sensor = container_of((struct delayed_work *)work, + struct smi_client_data, gyro_poll_work); + timestamp = ktime_get(); + err = SMI_CALL_API(read_gyro_xyz)(&data); + if (err) + dev_err(sensor->dev, "read data err"); + input_report_abs(sensor->gyro_input, ABS_RX, + (data.x)); + input_report_abs(sensor->gyro_input, ABS_RY, + (data.y)); + input_report_abs(sensor->gyro_input, ABS_RZ, + (data.z)); + input_event(sensor->gyro_input, + EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(sensor->gyro_input, EV_SYN, + SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); + input_sync(sensor->gyro_input); + if (atomic_read(&sensor->gyro_en)) + queue_delayed_work(sensor->data_wq, + &sensor->gyro_poll_work, + msecs_to_jiffies(sensor->gyro_poll_ms)); +} +static int smi130_set_gyro_op_mode(struct smi_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + mutex_lock(&client_data->mutex_op_mode); + if (op_mode < SMI_GYRO_PM_MAX) { + switch (op_mode) { + case SMI_GYRO_PM_NORMAL: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]); + client_data->pw.gyro_pm = SMI_GYRO_PM_NORMAL; + smi_delay(60); + break; + case SMI_GYRO_PM_FAST_START: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_FAST_START]); + client_data->pw.gyro_pm = SMI_GYRO_PM_FAST_START; + smi_delay(60); + break; + case SMI_GYRO_PM_SUSPEND: + err = SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_SUSPEND]); + client_data->pw.gyro_pm = SMI_GYRO_PM_SUSPEND; + smi_delay(60); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + mutex_unlock(&client_data->mutex_op_mode); + return err; +} +static int smi130_accel_set_enable( + struct smi_client_data *client_data, bool enable) +{ + int ret = 0; + dev_notice(client_data->dev, + "smi130_accel_set_enable enable=%d\n", enable); + if (enable) { + ret = smi130_set_acc_op_mode(client_data, 0); + if (ret) { + dev_err(client_data->dev, + "Fail to enable accel engine ret=%d\n", ret); + ret = -EBUSY; + goto exit; + } + queue_delayed_work(client_data->data_wq, + &client_data->accel_poll_work, + msecs_to_jiffies(client_data->accel_poll_ms)); + atomic_set(&client_data->accel_en, 1); + } else { + atomic_set(&client_data->accel_en, 0); + cancel_delayed_work_sync(&client_data->accel_poll_work); + ret = smi130_set_acc_op_mode(client_data, 2); + if (ret) { + dev_err(client_data->dev, + "Fail to disable accel engine ret=%d\n", ret); + ret = -EBUSY; + goto exit; + } + } +exit: + return ret; +} +static int smi130_accel_set_poll_delay(struct smi_client_data *client_data, + unsigned long delay) +{ + dev_info(client_data->dev, + "smi130_accel_set_poll_delay delay_ms=%ld\n", delay); + if (delay < SMI130_ACCEL_MIN_POLL_INTERVAL_MS) + delay = SMI130_ACCEL_MIN_POLL_INTERVAL_MS; + if (delay > SMI130_ACCEL_MAX_POLL_INTERVAL_MS) + delay = SMI130_ACCEL_MAX_POLL_INTERVAL_MS; + client_data->accel_poll_ms = delay; + if (!atomic_read(&client_data->accel_en)) + goto exit; + cancel_delayed_work_sync(&client_data->accel_poll_work); + queue_delayed_work(client_data->data_wq, + &client_data->accel_poll_work, + msecs_to_jiffies(client_data->accel_poll_ms)); +exit: + return 0; +} +static int smi130_gyro_set_enable( + struct smi_client_data *client_data, bool enable) +{ + int ret = 0; + dev_notice(client_data->dev, + "smi130_gyro_set_enable enable=%d\n", enable); + if (enable) { + ret = smi130_set_gyro_op_mode(client_data, 0); + if (ret) { + dev_err(client_data->dev, + "Fail to enable gyro engine ret=%d\n", ret); + ret = -EBUSY; + goto exit; + } + queue_delayed_work(client_data->data_wq, + &client_data->gyro_poll_work, + msecs_to_jiffies(client_data->gyro_poll_ms)); + atomic_set(&client_data->gyro_en, 1); + } else { + atomic_set(&client_data->gyro_en, 0); + cancel_delayed_work_sync(&client_data->gyro_poll_work); + ret = smi130_set_gyro_op_mode(client_data, 2); + if (ret) { + dev_err(client_data->dev, + "Fail to disable accel engine ret=%d\n", ret); + ret = -EBUSY; + goto exit; + } + } +exit: + return ret; +} +static int smi130_gyro_set_poll_delay(struct smi_client_data *client_data, + unsigned long delay) +{ + dev_info(client_data->dev, + "smi130_accel_set_poll_delay delay_ms=%ld\n", delay); + if (delay < SMI130_GYRO_MIN_POLL_INTERVAL_MS) + delay = SMI130_GYRO_MIN_POLL_INTERVAL_MS; + if (delay > SMI130_GYRO_MAX_POLL_INTERVAL_MS) + delay = SMI130_GYRO_MAX_POLL_INTERVAL_MS; + client_data->gyro_poll_ms = delay; + if (!atomic_read(&client_data->gyro_en)) + goto exit; + cancel_delayed_work_sync(&client_data->gyro_poll_work); + queue_delayed_work(client_data->data_wq, + &client_data->gyro_poll_work, + msecs_to_jiffies(client_data->gyro_poll_ms)); +exit: + return 0; +} +static int smi130_accel_cdev_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct smi_client_data *sensor = container_of(sensors_cdev, + struct smi_client_data, accel_cdev); + return smi130_accel_set_enable(sensor, enable); +} +static int smi130_accel_cdev_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct smi_client_data *sensor = container_of(sensors_cdev, + struct smi_client_data, accel_cdev); + + return smi130_accel_set_poll_delay(sensor, delay_ms); +} + +static int smi130_gyro_cdev_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct smi_client_data *sensor = container_of(sensors_cdev, + struct smi_client_data, gyro_cdev); + + return smi130_gyro_set_enable(sensor, enable); +} + +static int smi130_gyro_cdev_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct smi_client_data *sensor = container_of(sensors_cdev, + struct smi_client_data, gyro_cdev); + + return smi130_gyro_set_poll_delay(sensor, delay_ms); +} +#endif + +int smi_probe(struct smi_client_data *client_data, struct device *dev) +{ + int err = 0; +#ifdef SMI130_MAG_INTERFACE_SUPPORT + u8 mag_dev_addr; + u8 mag_urst_len; + u8 mag_op_mode; +#endif + /* check chip id */ + err = smi_check_chip_id(client_data); + if (err) + goto exit_err_clean; + + dev_set_drvdata(dev, client_data); + client_data->dev = dev; + + mutex_init(&client_data->mutex_enable); + mutex_init(&client_data->mutex_op_mode); + + /* input device init */ + err = smi_input_init(client_data); + if (err < 0) + goto exit_err_clean; + + /* sysfs node creation */ + err = sysfs_create_group(&client_data->input->dev.kobj, + &smi130_attribute_group); + + if (err < 0) + goto exit_err_sysfs; + + if (NULL != dev->platform_data) { + client_data->bosch_pd = kzalloc(sizeof(*client_data->bosch_pd), + GFP_KERNEL); + + if (NULL != client_data->bosch_pd) { + memcpy(client_data->bosch_pd, dev->platform_data, + sizeof(*client_data->bosch_pd)); + dev_notice(dev, "%s sensor driver set place: p%d\n", + client_data->bosch_pd->name, + client_data->bosch_pd->place); + } + } + + if (NULL != client_data->bosch_pd) { + memcpy(client_data->bosch_pd, dev->platform_data, + sizeof(*client_data->bosch_pd)); + dev_notice(dev, "%s sensor driver set place: p%d\n", + client_data->bosch_pd->name, + client_data->bosch_pd->place); + } + + + /* workqueue init */ + INIT_DELAYED_WORK(&client_data->work, smi_work_func); + atomic_set(&client_data->delay, SMI_DELAY_DEFAULT); + atomic_set(&client_data->wkqueue_en, 0); + + /* h/w init */ + client_data->device.delay_msec = smi_delay; + err = SMI_CALL_API(init)(&client_data->device); + + smi_dump_reg(client_data); + + /*power on detected*/ + /*or softrest(cmd 0xB6) */ + /*fatal err check*/ + /*soft reset*/ + err += SMI_CALL_API(set_command_register)(CMD_RESET_USER_REG); + smi_delay(3); + if (err) + dev_err(dev, "Failed soft reset, er=%d", err); + /*usr data config page*/ + err += SMI_CALL_API(set_target_page)(USER_DAT_CFG_PAGE); + if (err) + dev_err(dev, "Failed cffg page, er=%d", err); + err += smi_get_err_status(client_data); + if (err) { + dev_err(dev, "Failed to smi16x init!err_st=0x%x\n", + client_data->err_st.err_st_all); + goto exit_err_sysfs; + } + +#ifdef SMI130_MAG_INTERFACE_SUPPORT + err += smi130_set_command_register(MAG_MODE_NORMAL); + smi_delay(2); + err += smi130_get_mag_power_mode_stat(&mag_op_mode); + smi_delay(2); + err += SMI_CALL_API(get_i2c_device_addr)(&mag_dev_addr); + smi_delay(2); +#if defined(SMI130_AKM09912_SUPPORT) + err += SMI_CALL_API(set_i2c_device_addr)(SMI130_AKM09912_I2C_ADDRESS); + smi130_bosch_akm_mag_interface_init(SMI130_AKM09912_I2C_ADDRESS); +#else + err += SMI_CALL_API(set_i2c_device_addr)( + SMI130_AUX_BMM150_I2C_ADDRESS); + smi130_bmm150_mag_interface_init(); +#endif + + err += smi130_set_mag_burst(3); + err += smi130_get_mag_burst(&mag_urst_len); + if (err) + dev_err(client_data->dev, "Failed cffg mag, er=%d", err); + dev_info(client_data->dev, + "SMI130 mag_urst_len:%d, mag_add:0x%x, mag_op_mode:%d\n", + mag_urst_len, mag_dev_addr, mag_op_mode); +#endif + if (err < 0) + goto exit_err_sysfs; + + +#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2) + /*wake_lock_init(&client_data->wakelock, + WAKE_LOCK_SUSPEND, "smi130");*/ + client_data->gpio_pin = of_get_named_gpio_flags(dev->of_node, + "smi,gpio_irq", 0, NULL); + dev_info(client_data->dev, "SMI130 qpio number:%d\n", + client_data->gpio_pin); + err += gpio_request_one(client_data->gpio_pin, + GPIOF_IN, "smi130_int"); + err += gpio_direction_input(client_data->gpio_pin); + client_data->IRQ = gpio_to_irq(client_data->gpio_pin); + if (err) { + dev_err(client_data->dev, + "can not request gpio to irq number\n"); + client_data->gpio_pin = 0; + } + INIT_DELAYED_WORK(&client_data->delay_work_sig, + smi130_delay_sigmo_work_func); +#ifdef SMI130_ENABLE_INT1 + /* maps interrupt to INT1/InT2 pin */ + SMI_CALL_API(set_intr_any_motion)(SMI_INT0, ENABLE); + SMI_CALL_API(set_intr_fifo_wm)(SMI_INT0, ENABLE); + SMI_CALL_API(set_intr_data_rdy)(SMI_INT0, ENABLE); + + /*Set interrupt trige level way */ + SMI_CALL_API(set_intr_edge_ctrl)(SMI_INT0, SMI_INT_LEVEL); + smi130_set_intr_level(SMI_INT0, 1); + /*set interrupt latch temporary, 5 ms*/ + /*smi130_set_latch_int(5);*/ + + SMI_CALL_API(set_output_enable)( + SMI130_INTR1_OUTPUT_ENABLE, ENABLE); + sigmotion_init_interrupts(SMI130_MAP_INTR1); + SMI_CALL_API(map_step_detector_intr)(SMI130_MAP_INTR1); + /*close step_detector in init function*/ + SMI_CALL_API(set_step_detector_enable)(0); +#endif + +#ifdef SMI130_ENABLE_INT2 + /* maps interrupt to INT1/InT2 pin */ + SMI_CALL_API(set_intr_any_motion)(SMI_INT1, ENABLE); + SMI_CALL_API(set_intr_fifo_wm)(SMI_INT1, ENABLE); + SMI_CALL_API(set_intr_data_rdy)(SMI_INT1, ENABLE); + + /*Set interrupt trige level way */ + SMI_CALL_API(set_intr_edge_ctrl)(SMI_INT1, SMI_INT_LEVEL); + smi130_set_intr_level(SMI_INT1, 1); + /*set interrupt latch temporary, 5 ms*/ + /*smi130_set_latch_int(5);*/ + + SMI_CALL_API(set_output_enable)( + SMI130_INTR2_OUTPUT_ENABLE, ENABLE); + sigmotion_init_interrupts(SMI130_MAP_INTR2); + SMI_CALL_API(map_step_detector_intr)(SMI130_MAP_INTR2); + /*close step_detector in init function*/ + SMI_CALL_API(set_step_detector_enable)(0); +#endif + err = request_irq(client_data->IRQ, smi_irq_handler, + IRQF_TRIGGER_RISING, "smi130", client_data); + if (err) + dev_err(client_data->dev, "could not request irq\n"); + + INIT_WORK(&client_data->irq_work, smi_irq_work_func); +#endif + + client_data->selftest = 0; + + client_data->fifo_data_sel = 0; + #if defined(CONFIG_USE_QUALCOMM_HAL) + SMI_CALL_API(set_accel_output_data_rate)(9);/*defalut odr 200HZ*/ + SMI_CALL_API(set_gyro_output_data_rate)(9);/*defalut odr 200HZ*/ + #endif + SMI_CALL_API(get_accel_output_data_rate)(&client_data->odr.acc_odr); + SMI_CALL_API(get_gyro_output_data_rate)(&client_data->odr.gyro_odr); + SMI_CALL_API(get_mag_output_data_rate)(&client_data->odr.mag_odr); + SMI_CALL_API(set_fifo_time_enable)(1); + SMI_CALL_API(get_accel_range)(&client_data->range.acc_range); + SMI_CALL_API(get_gyro_range)(&client_data->range.gyro_range); + /* now it's power on which is considered as resuming from suspend */ + + /* gyro input device init */ + err = smi_gyro_input_init(client_data); + #if defined(CONFIG_USE_QUALCOMM_HAL) + /* gyro input device init */ + err = smi_gyro_input_init(client_data); + if (err < 0) + goto exit_err_clean; + client_data->accel_poll_ms = SMI130_ACCEL_DEFAULT_POLL_INTERVAL_MS; + client_data->gyro_poll_ms = SMI130_GYRO_DEFAULT_POLL_INTERVAL_MS; + client_data->data_wq = create_freezable_workqueue("smi130_data_work"); + if (!client_data->data_wq) { + dev_err(dev, "Cannot create workqueue!\n"); + goto exit_err_clean; + } + INIT_DELAYED_WORK(&client_data->accel_poll_work, + smi130_accel_work_fn); + client_data->accel_cdev = smi130_accel_cdev; + client_data->accel_cdev.delay_msec = client_data->accel_poll_ms; + client_data->accel_cdev.sensors_enable = smi130_accel_cdev_enable; + client_data->accel_cdev.sensors_poll_delay = + smi130_accel_cdev_poll_delay; + err = sensors_classdev_register(dev, &client_data->accel_cdev); + if (err) { + dev_err(dev, + "create accel class device file failed!\n"); + goto exit_err_clean; + } + INIT_DELAYED_WORK(&client_data->gyro_poll_work, smi130_gyro_work_fn); + client_data->gyro_cdev = smi130_gyro_cdev; + client_data->gyro_cdev.delay_msec = client_data->gyro_poll_ms; + client_data->gyro_cdev.sensors_enable = smi130_gyro_cdev_enable; + client_data->gyro_cdev.sensors_poll_delay = smi130_gyro_cdev_poll_delay; + err = sensors_classdev_register(dev, &client_data->gyro_cdev); + if (err) { + dev_err(dev, + "create accel class device file failed!\n"); + goto exit_err_clean; + } + #endif + /* set sensor PMU into suspend power mode for all */ + if (smi_pmu_set_suspend(client_data) < 0) { + dev_err(dev, "Failed to set SMI130 to suspend power mode\n"); + goto exit_err_sysfs; + } + /*enable the data ready interrupt*/ + SMI_CALL_API(set_intr_enable_1)(SMI130_DATA_RDY_ENABLE, 1); + dev_notice(dev, "sensor_time:%d, %d, %d", + sensortime_duration_tbl[0].ts_delat, + sensortime_duration_tbl[0].ts_duration_lsb, + sensortime_duration_tbl[0].ts_duration_us); + dev_notice(dev, "sensor %s probed successfully", SENSOR_NAME); + + return 0; + +exit_err_sysfs: + if (err) + smi_input_destroy(client_data); + +exit_err_clean: + if (err) { + if (client_data != NULL) { + if (NULL != client_data->bosch_pd) { + kfree(client_data->bosch_pd); + client_data->bosch_pd = NULL; + } + } + } + return err; +} +EXPORT_SYMBOL(smi_probe); + +/*! + * @brief remove smi client + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int smi_remove(struct device *dev) +{ + int err = 0; + struct smi_client_data *client_data = dev_get_drvdata(dev); + + if (NULL != client_data) { +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&client_data->early_suspend_handler); +#endif + mutex_lock(&client_data->mutex_enable); + if (SMI_ACC_PM_NORMAL == client_data->pw.acc_pm || + SMI_GYRO_PM_NORMAL == client_data->pw.gyro_pm || + SMI_MAG_PM_NORMAL == client_data->pw.mag_pm) { + cancel_delayed_work_sync(&client_data->work); + } + mutex_unlock(&client_data->mutex_enable); + + err = smi_pmu_set_suspend(client_data); + + smi_delay(5); + + sysfs_remove_group(&client_data->input->dev.kobj, + &smi130_attribute_group); + smi_input_destroy(client_data); + + if (NULL != client_data->bosch_pd) { + kfree(client_data->bosch_pd); + client_data->bosch_pd = NULL; + } + kfree(client_data); + } + + return err; +} +EXPORT_SYMBOL(smi_remove); + +static int smi_post_resume(struct smi_client_data *client_data) +{ + int err = 0; + + mutex_lock(&client_data->mutex_enable); + + if (atomic_read(&client_data->wkqueue_en) == 1) { + smi130_set_acc_op_mode(client_data, SMI_ACC_PM_NORMAL); + schedule_delayed_work(&client_data->work, + msecs_to_jiffies( + atomic_read(&client_data->delay))); + } + mutex_unlock(&client_data->mutex_enable); + + return err; +} + + +int smi_suspend(struct device *dev) +{ + int err = 0; + struct smi_client_data *client_data = dev_get_drvdata(dev); + unsigned char stc_enable; + unsigned char std_enable; + dev_err(client_data->dev, "smi suspend function entrance"); + + atomic_set(&client_data->in_suspend, 1); + if (atomic_read(&client_data->wkqueue_en) == 1) { + smi130_set_acc_op_mode(client_data, SMI_ACC_PM_SUSPEND); + cancel_delayed_work_sync(&client_data->work); + } + SMI_CALL_API(get_step_counter_enable)(&stc_enable); + SMI_CALL_API(get_step_detector_enable)(&std_enable); + if (client_data->pw.acc_pm != SMI_ACC_PM_SUSPEND && + (stc_enable != 1) && (std_enable != 1) && + (client_data->sig_flag != 1)) { + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_SUSPEND]); + smi_delay(3); + } + if (client_data->pw.gyro_pm != SMI_GYRO_PM_SUSPEND) { + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_SUSPEND]); + smi_delay(3); + } + + if (client_data->pw.mag_pm != SMI_MAG_PM_SUSPEND) { +#if defined(SMI130_AKM09912_SUPPORT) + err += smi130_set_bosch_akm_and_secondary_if_powermode( + SMI130_MAG_SUSPEND_MODE); +#else + err += smi130_set_bmm150_mag_and_secondary_if_power_mode( + SMI130_MAG_SUSPEND_MODE); +#endif + smi_delay(3); + } + + return err; +} +EXPORT_SYMBOL(smi_suspend); + +int smi_resume(struct device *dev) +{ + int err = 0; + struct smi_client_data *client_data = dev_get_drvdata(dev); + atomic_set(&client_data->in_suspend, 0); + if (client_data->pw.acc_pm != SMI_ACC_PM_SUSPEND) { + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]); + smi_delay(3); + } + if (client_data->pw.gyro_pm != SMI_GYRO_PM_SUSPEND) { + err += SMI_CALL_API(set_command_register) + (smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]); + smi_delay(3); + } + + if (client_data->pw.mag_pm != SMI_MAG_PM_SUSPEND) { +#if defined(SMI130_AKM09912_SUPPORT) + err += smi130_set_bosch_akm_and_secondary_if_powermode + (SMI130_MAG_FORCE_MODE); +#else + err += smi130_set_bmm150_mag_and_secondary_if_power_mode + (SMI130_MAG_FORCE_MODE); +#endif + smi_delay(3); + } + /* post resume operation */ + err += smi_post_resume(client_data); + + return err; +} +EXPORT_SYMBOL(smi_resume); + diff --git a/drivers/input/sensors/smi130/smi130_driver.h b/drivers/input/sensors/smi130/smi130_driver.h new file mode 100644 index 0000000000000000000000000000000000000000..4307ae55fd694173d0fff59ebcf04fcb33782527 --- /dev/null +++ b/drivers/input/sensors/smi130/smi130_driver.h @@ -0,0 +1,512 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename smi130_driver.h + * @date 2015/08/17 14:40 + * @Modification Date 2018/08/28 18:20 + * @id "e90a329" + * @version 1.3 + * + * @brief + * The head file of SMI130 device driver core code +*/ +#ifndef _SMI130_DRIVER_H +#define _SMI130_DRIVER_H + +#ifdef __KERNEL__ +#include +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include "smi130.h" + +#if defined(CONFIG_USE_QUALCOMM_HAL) +#include +#endif +/* sensor specific */ +#define SENSOR_NAME "smi130" +#define SMI130_ENABLE_INT1 1 +#define SMI130_ENABLE_INT2 1 +/*#define SMI130_MAG_INTERFACE_SUPPORT 1*/ + +/*#define SMI130_AKM09912_SUPPORT 1*/ +#define SMI_USE_BASIC_I2C_FUNC 1 +#define SENSOR_CHIP_ID_SMI (0xD0) +#define SENSOR_CHIP_ID_SMI_C2 (0xD1) +#define SENSOR_CHIP_ID_SMI_C3 (0xD3) + +#define SENSOR_CHIP_REV_ID_SMI (0x00) + +#define CHECK_CHIP_ID_TIME_MAX 5 + +#define SMI_REG_NAME(name) SMI130_##name##__REG +#define SMI_VAL_NAME(name) SMI130_##name +#define SMI_CALL_API(name) smi130_##name + +#define SMI_I2C_WRITE_DELAY_TIME (1) + +/* generic */ +#define SMI_MAX_RETRY_I2C_XFER (10) +#define SMI_MAX_RETRY_WAKEUP (5) +#define SMI_MAX_RETRY_WAIT_DRDY (100) + +#define SMI_DELAY_MIN (1) +#define SMI_DELAY_DEFAULT (200) + +#define SMI_VALUE_MAX (32767) +#define SMI_VALUE_MIN (-32768) + +#define BYTES_PER_LINE (16) + +#define BUF_SIZE_PRINT (16) + +#define SMI_FAST_CALI_TRUE (1) +#define SMI_FAST_CALI_ALL_RDY (7) + +/*! FIFO 1024 byte, max fifo frame count not over 150 */ +#define FIFO_FRAME_CNT 170 +#define FIFO_DATA_BUFSIZE 1024 + + +#define FRAME_LEN_ACC 6 +#define FRAME_LEN_GYRO 6 +#define FRAME_LEN_MAG 8 + +/*! SMI Self test */ +#define SMI_SELFTEST_AMP_HIGH 1 + +/* CMD */ +#define CMD_FOC_START 0x03 +#define CMD_PMU_ACC_SUSPEND 0x10 +#define CMD_PMU_ACC_NORMAL 0x11 +#define CMD_PMU_ACC_LP1 0x12 +#define CMD_PMU_ACC_LP2 0x13 +#define CMD_PMU_GYRO_SUSPEND 0x14 +#define CMD_PMU_GYRO_NORMAL 0x15 +#define CMD_PMU_GYRO_FASTSTART 0x17 +#define CMD_PMU_MAG_SUSPEND 0x18 +#define CMD_PMU_MAG_NORMAL 0x19 +#define CMD_PMU_MAG_LP1 0x1A +#define CMD_PMU_MAG_LP2 0x1B +#define CMD_CLR_FIFO_DATA 0xB0 +#define CMD_RESET_INT_ENGINE 0xB1 +#define CMD_RESET_USER_REG 0xB6 + +#define USER_DAT_CFG_PAGE 0x00 + +/*! FIFO Head definition*/ +#define FIFO_HEAD_A 0x84 +#define FIFO_HEAD_G 0x88 +#define FIFO_HEAD_M 0x90 + +#define FIFO_HEAD_G_A (FIFO_HEAD_G | FIFO_HEAD_A) +#define FIFO_HEAD_M_A (FIFO_HEAD_M | FIFO_HEAD_A) +#define FIFO_HEAD_M_G (FIFO_HEAD_M | FIFO_HEAD_G) + +#define FIFO_HEAD_M_G_A (FIFO_HEAD_M | FIFO_HEAD_G | FIFO_HEAD_A) + +#define FIFO_HEAD_SENSOR_TIME 0x44 +#define FIFO_HEAD_SKIP_FRAME 0x40 +#define FIFO_HEAD_OVER_READ_LSB 0x80 +#define FIFO_HEAD_OVER_READ_MSB 0x00 + +/*! FIFO head mode Frame bytes number definition */ +#define A_BYTES_FRM 6 +#define G_BYTES_FRM 6 +#define M_BYTES_FRM 8 +#define GA_BYTES_FRM 12 +#define MG_BYTES_FRM 14 +#define MA_BYTES_FRM 14 +#define MGA_BYTES_FRM 20 + +#define ACC_FIFO_HEAD "acc" +#define GYRO_FIFO_HEAD "gyro" +#define MAG_FIFO_HEAD "mag" + +/*! Bosch sensor unknown place*/ +#define BOSCH_SENSOR_PLACE_UNKNOWN (-1) +/*! Bosch sensor remapping table size P0~P7*/ +#define MAX_AXIS_REMAP_TAB_SZ 8 + +#define ENABLE 1 +#define DISABLE 0 + +/* smi sensor HW interrupt pin number */ +#define SMI_INT0 0 +#define SMI_INT1 1 + +#define SMI_INT_LEVEL 0 +#define SMI_INT_EDGE 1 + +/*! SMI mag interface */ + + +/* compensated output value returned if sensor had overflow */ +#define BMM050_OVERFLOW_OUTPUT -32768 +#define BMM050_OVERFLOW_OUTPUT_S32 ((s32)(-2147483647-1)) + +/* Trim Extended Registers */ +#define BMM050_DIG_X1 0x5D +#define BMM050_DIG_Y1 0x5E +#define BMM050_DIG_Z4_LSB 0x62 +#define BMM050_DIG_Z4_MSB 0x63 +#define BMM050_DIG_X2 0x64 +#define BMM050_DIG_Y2 0x65 +#define BMM050_DIG_Z2_LSB 0x68 +#define BMM050_DIG_Z2_MSB 0x69 +#define BMM050_DIG_Z1_LSB 0x6A +#define BMM050_DIG_Z1_MSB 0x6B +#define BMM050_DIG_XYZ1_LSB 0x6C +#define BMM050_DIG_XYZ1_MSB 0x6D +#define BMM050_DIG_Z3_LSB 0x6E +#define BMM050_DIG_Z3_MSB 0x6F +#define BMM050_DIG_XY2 0x70 +#define BMM050_DIG_XY1 0x71 + +struct smi130mag_compensate_t { + signed char dig_x1; + signed char dig_y1; + + signed char dig_x2; + signed char dig_y2; + + u16 dig_z1; + s16 dig_z2; + s16 dig_z3; + s16 dig_z4; + + unsigned char dig_xy1; + signed char dig_xy2; + + u16 dig_xyz1; +}; + +/*smi fifo sensor type combination*/ +enum SMI_FIFO_DATA_SELECT_T { + SMI_FIFO_A_SEL = 1, + SMI_FIFO_G_SEL, + SMI_FIFO_G_A_SEL, + SMI_FIFO_M_SEL, + SMI_FIFO_M_A_SEL, + SMI_FIFO_M_G_SEL, + SMI_FIFO_M_G_A_SEL, + SMI_FIFO_DATA_SEL_MAX +}; + +/*smi interrupt about step_detector and sgm*/ +#define INPUT_EVENT_STEP_DETECTOR 5 +#define INPUT_EVENT_SGM 3/*7*/ +#define INPUT_EVENT_FAST_ACC_CALIB_DONE 6 +#define INPUT_EVENT_FAST_GYRO_CALIB_DONE 4 + + +/*! +* Bst sensor common definition, +* please give parameters in BSP file. +*/ +struct bosch_sensor_specific { + char *name; + /* 0 to 7 */ + unsigned int place:3; + int irq; + int (*irq_gpio_cfg)(void); +}; + +/*! smi130 sensor spec of power mode */ +struct pw_mode { + u8 acc_pm; + u8 gyro_pm; + u8 mag_pm; +}; + +/*! smi130 sensor spec of odr */ +struct odr_t { + u8 acc_odr; + u8 gyro_odr; + u8 mag_odr; +}; + +/*! smi130 sensor spec of range */ +struct range_t { + u8 acc_range; + u8 gyro_range; +}; + +/*! smi130 sensor error status */ +struct err_status { + u8 fatal_err; + u8 err_code; + u8 i2c_fail; + u8 drop_cmd; + u8 mag_drdy_err; + u8 err_st_all; +}; + +/*! smi130 fifo frame for all sensors */ +struct fifo_frame_t { + struct smi130_accel_t *acc_farr; + struct smi130_gyro_t *gyro_farr; + struct smi130_mag_xyz_s32_t *mag_farr; + + unsigned char acc_frame_cnt; + unsigned char gyro_frame_cnt; + unsigned char mag_frame_cnt; + + u32 acc_lastf_ts; + u32 gyro_lastf_ts; + u32 mag_lastf_ts; +}; + +/*! smi130 fifo sensor time */ +struct fifo_sensor_time_t { + u32 acc_ts; + u32 gyro_ts; + u32 mag_ts; +}; + +struct pedometer_data_t { + /*! Fix step detector misinformation for the first time*/ + u8 wkar_step_detector_status; + u_int32_t last_step_counter_value; +}; + +struct smi_client_data { + struct smi130_t device; + struct device *dev; + struct input_dev *input;/*acc_device*/ + struct input_dev *gyro_input; + #if defined(CONFIG_USE_QUALCOMM_HAL) + struct input_dev *gyro_input; + struct sensors_classdev accel_cdev; + struct sensors_classdev gyro_cdev; + struct delayed_work accel_poll_work; + struct delayed_work gyro_poll_work; + u32 accel_poll_ms; + u32 gyro_poll_ms; + u32 accel_latency_ms; + u32 gyro_latency_ms; + atomic_t accel_en; + atomic_t gyro_en; + struct workqueue_struct *data_wq; + #endif + struct delayed_work work; + struct work_struct irq_work; + + u8 chip_id; + + struct pw_mode pw; + struct odr_t odr; + struct range_t range; /*TO DO*/ + struct err_status err_st; + struct pedometer_data_t pedo_data; + s8 place; + u8 selftest; + /*struct wake_lock wakelock;*/ + struct delayed_work delay_work_sig; + atomic_t in_suspend; + + atomic_t wkqueue_en; /*TO DO acc gyro mag*/ + atomic_t delay; + atomic_t selftest_result; + + u8 fifo_data_sel; + u16 fifo_bytecount; + u8 fifo_head_en; + unsigned char fifo_int_tag_en; + struct fifo_frame_t fifo_frame; + + unsigned char *fifo_data; + u64 fifo_time; + u8 stc_enable; + uint16_t gpio_pin; + u8 std; + u8 sig_flag; + unsigned char calib_status; + struct mutex mutex_op_mode; + struct mutex mutex_enable; + struct bosch_sensor_specific *bosch_pd; + int IRQ; + int reg_sel; + int reg_len; + uint64_t timestamp; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend_handler; +#endif +}; + + +/*! + * we use a typedef to hide the detail, + * because this type might be changed + */ +struct bosch_sensor_axis_remap { + /* src means which source will be mapped to target x, y, z axis */ + /* if an target OS axis is remapped from (-)x, + * src is 0, sign_* is (-)1 */ + /* if an target OS axis is remapped from (-)y, + * src is 1, sign_* is (-)1 */ + /* if an target OS axis is remapped from (-)z, + * src is 2, sign_* is (-)1 */ + int src_x:3; + int src_y:3; + int src_z:3; + + int sign_x:2; + int sign_y:2; + int sign_z:2; +}; + + +struct bosch_sensor_data { + union { + int16_t v[3]; + struct { + int16_t x; + int16_t y; + int16_t z; + }; + }; +}; + +s8 smi_burst_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u16 len); +int smi_probe(struct smi_client_data *client_data, struct device *dev); +int smi_remove(struct device *dev); +int smi_suspend(struct device *dev); +int smi_resume(struct device *dev); + + + + +#endif/*_SMI130_DRIVER_H*/ +/*@}*/ + diff --git a/drivers/input/sensors/smi130/smi130_gyro.c b/drivers/input/sensors/smi130/smi130_gyro.c new file mode 100644 index 0000000000000000000000000000000000000000..ef3fc38fb68b8dacc5ae008087957626e82c1d54 --- /dev/null +++ b/drivers/input/sensors/smi130/smi130_gyro.c @@ -0,0 +1,7422 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * @filename smi130_gyro.c + * @date 2013/11/25 + * @Modification Date 2018/08/28 18:20 + * @id "8fcde22" + * @version 1.5 + * + * @brief SMI130_GYROAPI +*/ + +#include "smi130_gyro.h" +static struct smi130_gyro_t *p_smi130_gyro; + + +/***************************************************************************** + * Description: *//**brief API Initialization routine + * + * + * + * +* \param smi130_gyro_t *smi130_gyro + * Pointer to a structure. + * + * structure members are + * + * unsigned char chip_id; + * unsigned char dev_addr; + * SMI130_GYRO_BRD_FUNC_PTR; + * SMI130_GYRO_WR_FUNC_PTR; + * SMI130_GYRO_RD_FUNC_PTR; + * void(*delay_msec)( SMI130_GYRO_MDELAY_DATA_TYPE ); + * + * + * + * + * + * \return result of communication routines + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_init(struct smi130_gyro_t *smi130_gyro) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char a_data_u8r = C_SMI130_GYRO_Zero_U8X; + p_smi130_gyro = smi130_gyro; + + p_smi130_gyro->dev_addr = SMI130_GYRO_I2C_ADDR; + + /*Read CHIP_ID */ + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_CHIP_ID_ADDR, &a_data_u8r, 1); + p_smi130_gyro->chip_id = a_data_u8r; + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads Rate dataX from location 02h and 03h + * registers + * + * + * + * + * \param + * SMI130_GYRO_S16 *data_x : Address of data_x + * + * + * \return + * result of communication routines + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_dataX(SMI130_GYRO_S16 *data_x) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char a_data_u8r[2] = {0, 0}; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RATE_X_LSB_VALUEX__REG, a_data_u8r, 2); + a_data_u8r[0] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[0], + SMI130_GYRO_RATE_X_LSB_VALUEX); + *data_x = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[1])) << + SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[0])); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads rate dataY from location 04h and 05h + * registers + * + * + * + * + * \param + * SMI130_GYRO_S16 *data_y : Address of data_y + * + * + * \return + * result of communication routines + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_dataY(SMI130_GYRO_S16 *data_y) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char a_data_u8r[2] = {0, 0}; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RATE_Y_LSB_VALUEY__REG, a_data_u8r, 2); + a_data_u8r[0] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[0], + SMI130_GYRO_RATE_Y_LSB_VALUEY); + *data_y = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[1])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[0])); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads rate dataZ from location 06h and 07h + * registers + * + * + * + * + * \param + * SMI130_GYRO_S16 *data_z : Address of data_z + * + * + * \return + * result of communication routines + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_dataZ(SMI130_GYRO_S16 *data_z) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char a_data_u8r[2] = {0, 0}; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RATE_Z_LSB_VALUEZ__REG, a_data_u8r, 2); + a_data_u8r[0] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[0], + SMI130_GYRO_RATE_Z_LSB_VALUEZ); + *data_z = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[1])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[0])); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads data X,Y and Z from location 02h to 07h + * + * + * + * + * \param + * smi130_gyro_data_t *data : Address of smi130_gyro_data_t + * + * + * \return + * result of communication routines + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_dataXYZ(struct smi130_gyro_data_t *data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char a_data_u8r[6] = {0, 0, 0, 0, 0, 0}; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RATE_X_LSB_VALUEX__REG, a_data_u8r, 6); + /* Data X */ + a_data_u8r[0] = + SMI130_GYRO_GET_BITSLICE(a_data_u8r[0], SMI130_GYRO_RATE_X_LSB_VALUEX); + data->datax = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[1])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[0])); + /* Data Y */ + a_data_u8r[2] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[2], + SMI130_GYRO_RATE_Y_LSB_VALUEY); + data->datay = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[3])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[2])); + /* Data Z */ + a_data_u8r[4] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[4], + SMI130_GYRO_RATE_Z_LSB_VALUEZ); + data->dataz = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[5])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[4])); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads data X,Y,Z and Interrupts + * from location 02h to 07h + * + * + * + * + * \param + * smi130_gyro_data_t *data : Address of smi130_gyro_data_t + * + * + * \return + * result of communication routines + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_dataXYZI(struct smi130_gyro_data_t *data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char a_data_u8r[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RATE_X_LSB_VALUEX__REG, a_data_u8r, 12); + /* Data X */ + a_data_u8r[0] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[0], + SMI130_GYRO_RATE_X_LSB_VALUEX); + data->datax = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[1])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[0])); + /* Data Y */ + a_data_u8r[2] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[2], + SMI130_GYRO_RATE_Y_LSB_VALUEY); + data->datay = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[3])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[2])); + /* Data Z */ + a_data_u8r[4] = SMI130_GYRO_GET_BITSLICE(a_data_u8r[4], + SMI130_GYRO_RATE_Z_LSB_VALUEZ); + data->dataz = (SMI130_GYRO_S16) + ((((SMI130_GYRO_S16)((signed char)a_data_u8r[5])) + << SMI130_GYRO_SHIFT_8_POSITION) | (a_data_u8r[4])); + data->intstatus[0] = a_data_u8r[7]; + data->intstatus[1] = a_data_u8r[8]; + data->intstatus[2] = a_data_u8r[9]; + data->intstatus[3] = a_data_u8r[10]; + data->intstatus[4] = a_data_u8r[11]; + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads Temperature from location 08h + * + * + * + * + * \param + * unsigned char *temp : Address of temperature + * + * + * \return + * result of communication routines + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_Temperature(unsigned char *temperature) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TEMP_ADDR, &v_data_u8r, 1); + *temperature = v_data_u8r; + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API reads the data from the given register + * + * + * + * + *\param unsigned char addr, unsigned char *data unsigned char len + * addr -> Address of the register + * data -> address of the variable, read value will be + * kept + * len -> No of byte to be read. + * \return results of bus communication function + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_read_register(unsigned char addr, +unsigned char *data, unsigned char len) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, addr, data, len); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API reads the data from the given register + * + * + * + * + *\param unsigned char addr, unsigned char *data SMI130_GYRO_S32 len + * addr -> Address of the register + * data -> address of the variable, read value will be + * kept + * len -> No of byte to be read. + * \return results of bus communication function + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_burst_read(unsigned char addr, +unsigned char *data, SMI130_GYRO_S32 len) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BURST_READ_FUNC(p_smi130_gyro->dev_addr, + addr, data, len); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API given data to the given register + * + * + * + * + *\param unsigned char addr, unsigned char data,unsigned char len + * addr -> Address of the register + * data -> Data to be written to the register + * len -> No of byte to be read. + * + * \return Results of bus communication function + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_write_register(unsigned char addr, +unsigned char *data, unsigned char len) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, addr, data, len); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads interrupt status 0 register byte from 09h + * + * + * + * + * \param + * unsigned char *status0_data : Address of status 0 register + * + * + * \return + * Result of bus communication function + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ + +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_interrupt_status_reg_0( +unsigned char *status0_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_STATUSZERO__REG, &v_data_u8r, 1); + *status0_data = + SMI130_GYRO_GET_BITSLICE(v_data_u8r, SMI130_GYRO_INT_STATUSZERO); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads interrupt status 1 register byte from 0Ah + * + * + * + * + * \param + * unsigned char *status1_data : Address of status register + * + * + * \return + * Result of bus communication function + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ + +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_interrupt_status_reg_1( +unsigned char *status1_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, SMI130_GYRO_INT_STATUSONE__REG, + &v_data_u8r, 1); + *status1_data = + SMI130_GYRO_GET_BITSLICE(v_data_u8r, SMI130_GYRO_INT_STATUSONE); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads interrupt status register byte from 0Bh + * + * + * + * + * \param + * unsigned char *status2_data : Address of status 2 register + * + * + * \return + * Result of bus communication function + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ + +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_interrupt_status_reg_2( +unsigned char *status2_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_STATUSTWO__REG, &v_data_u8r, 1); + *status2_data = + SMI130_GYRO_GET_BITSLICE(v_data_u8r, SMI130_GYRO_INT_STATUSTWO); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads interrupt status 3 register byte from 0Ch + * + * + * + * + * \param + * unsigned char *status3_data : Address of status 3 register + * + * + * \return + * Result of bus communication function + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ + +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_interrupt_status_reg_3( +unsigned char *status3_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_STATUSTHREE__REG, &v_data_u8r, 1); + *status3_data = + SMI130_GYRO_GET_BITSLICE(v_data_u8r, SMI130_GYRO_INT_STATUSTHREE); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API reads the range from register 0x0Fh of + * (0 to 2) bits + * + * + * + * + *\param unsigned char *range + * Range[0....7] + * 0 2000/s + * 1 1000/s + * 2 500/s + * 3 250/s + * 4 125/s + * + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_range_reg(unsigned char *range) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_RANGE_ADDR_RANGE__REG, &v_data_u8r, 1); + *range = + SMI130_GYRO_GET_BITSLICE(v_data_u8r, SMI130_GYRO_RANGE_ADDR_RANGE); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API sets the range register 0x0Fh + * (0 to 2 bits) + * + * + * + * + *\param unsigned char range + * + * Range[0....7] + * 0 2000/s + * 1 1000/s + * 2 500/s + * 3 250/s + * 4 125/s + * + * + * + * + * \return Communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_range_reg(unsigned char range) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (range < C_SMI130_GYRO_Five_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_RANGE_ADDR_RANGE__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_RANGE_ADDR_RANGE, + range); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_RANGE_ADDR_RANGE__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API reads the high resolution bit of 0x10h + * Register 7th bit + * + * + * + * + *\param unsigned char *high_res + * Pointer to a variable passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_high_res(unsigned char *high_res) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BW_ADDR_HIGH_RES__REG, &v_data_u8r, 1); + *high_res = + SMI130_GYRO_GET_BITSLICE(v_data_u8r, SMI130_GYRO_BW_ADDR_HIGH_RES); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API reads the bandwidth register of 0x10h 0 to + * 3 bits + * + * + * + * +* \param unsigned char *bandwidth + * pointer to a variable passed as a parameter + * + * 0 no filter(523 Hz) + * 1 230Hz + * 2 116Hz + * 3 47Hz + * 4 23Hz + * 5 12Hz + * 6 64Hz + * 7 32Hz + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_bw(unsigned char *bandwidth) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, SMI130_GYRO_BW_ADDR__REG, &v_data_u8r, 1); + *bandwidth = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_BW_ADDR); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API writes the Bandwidth register (0x10h of 0 + * to 3 bits) + * + * + * + * + *\param unsigned char bandwidth, + * The bandwidth to be set passed as a parameter + * + * 0 no filter(523 Hz) + * 1 230Hz + * 2 116Hz + * 3 47Hz + * 4 23Hz + * 5 12Hz + * 6 64Hz + * 7 32Hz + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_bw(unsigned char bandwidth) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + unsigned char v_mode_u8r = C_SMI130_GYRO_Zero_U8X; + unsigned char v_autosleepduration = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (bandwidth < C_SMI130_GYRO_Eight_U8X) { + smi130_gyro_get_mode(&v_mode_u8r); + if (v_mode_u8r == SMI130_GYRO_MODE_ADVANCEDPOWERSAVING) { + smi130_gyro_get_autosleepdur(&v_autosleepduration); + smi130_gyro_set_autosleepdur(v_autosleepduration, + bandwidth); + } + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BW_ADDR__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_BW_ADDR, bandwidth); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BW_ADDR__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API reads the status of External Trigger + * selection bits (4 and 5) of 0x12h registers + * + * + * + * + *\param unsigned char *pwu_ext_tri_sel + * Pointer to a variable passed as a parameter + * + * + * + * \return Communication Results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_pmu_ext_tri_sel( +unsigned char *pwu_ext_tri_sel) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR_EXT_TRI_SEL__REG, &v_data_u8r, 1); + *pwu_ext_tri_sel = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MODE_LPM2_ADDR_EXT_TRI_SEL); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API writes the External Trigger selection + * bits (4 and 5) of 0x12h registers + * + * + * + * + *\param unsigned char pwu_ext_tri_sel + * Value to be written passed as a parameter + * + * + * + * \return Communication Results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_pmu_ext_tri_sel( +unsigned char pwu_ext_tri_sel) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR_EXT_TRI_SEL__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MODE_LPM2_ADDR_EXT_TRI_SEL, pwu_ext_tri_sel); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR_EXT_TRI_SEL__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get data high bandwidth + * + * + * + * + *\param unsigned char *high_bw : Address of high_bw + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_high_bw(unsigned char *high_bw) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RATED_HBW_ADDR_DATA_HIGHBW__REG, &v_data_u8r, 1); + *high_bw = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_RATED_HBW_ADDR_DATA_HIGHBW); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set data high bandwidth + * + * + * + * + *\param unsigned char high_bw: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_high_bw(unsigned char high_bw) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (high_bw < C_SMI130_GYRO_Two_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_RATED_HBW_ADDR_DATA_HIGHBW__REG, + &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_RATED_HBW_ADDR_DATA_HIGHBW, high_bw); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_RATED_HBW_ADDR_DATA_HIGHBW__REG, + &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get shadow dis + * + * + * + * + *\param unsigned char *shadow_dis : Address of shadow_dis + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_shadow_dis(unsigned char *shadow_dis) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RATED_HBW_ADDR_SHADOW_DIS__REG, &v_data_u8r, 1); + *shadow_dis = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_RATED_HBW_ADDR_SHADOW_DIS); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set shadow dis + * + * + * + * + *\param unsigned char shadow_dis + * Value to be written passed as a parameter + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_shadow_dis(unsigned char shadow_dis) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (shadow_dis < C_SMI130_GYRO_Two_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_RATED_HBW_ADDR_SHADOW_DIS__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_RATED_HBW_ADDR_SHADOW_DIS, shadow_dis); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_RATED_HBW_ADDR_SHADOW_DIS__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief + * This function is used for the soft reset + * The soft reset register will be written with 0xB6. + * + * + * +* \param None + * + * + * + * \return Communication results. + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_soft_reset() +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_SoftReset_u8r = C_SMI130_GYRO_Zero_U8X; + v_SoftReset_u8r = 0xB6; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SOFTRESET_ADDR, &v_SoftReset_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get data enable data + * + * + * + * + *\param unsigned char *data_en : Address of data_en + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_data_enable(unsigned char *data_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_DATAEN__REG, &v_data_u8r, 1); + *data_en = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE0_DATAEN); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set data enable data + * + * + * + * + * \param unsigned char data_en: + * Value to be written passed as a \parameter + * 0 --> Disable + * 1 --> Enable + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_data_en(unsigned char data_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_DATAEN__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE0_DATAEN, data_en); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_DATAEN__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get fifo enable bit + * + * + * + * + * \param unsigned char *fifo_en : Address of fifo_en + * Pointer to a variable passed as a parameter + + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_enable(unsigned char *fifo_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_FIFOEN__REG, &v_data_u8r, 1); + *fifo_en = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE0_FIFOEN); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set fifo enable bit + * + * + * + * + * \param unsigned char fifo_en: + * Value to be written passed as a parameter + * 0 --> Disable + * 1 --> Enable + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_fifo_enable(unsigned char fifo_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (fifo_en < C_SMI130_GYRO_Two_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_FIFOEN__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE0_FIFOEN, fifo_en); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_FIFOEN__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API reads the status of the Auto offset + * Enable bit + * (0x15 Reg 3rd Bit) + * + * + * + * + * \param unsigned char *offset_en + * address of a variable, + * + * + * + * \return Communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_auto_offset_en( +unsigned char *offset_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_AUTO_OFFSETEN__REG, &v_data_u8r, 1); + *offset_en = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE0_AUTO_OFFSETEN); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API sets the Auto offset enable bit + * (Reg 0x15 3rd Bit) + * + * + * + * + * \param unsigned char offset_en + * 0 --> Disable + * 1 --> Enable + * + * \return Communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_auto_offset_en(unsigned char offset_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_AUTO_OFFSETEN__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE0_AUTO_OFFSETEN, offset_en); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE0_AUTO_OFFSETEN__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the output type status + * + * + * + * + * \param unsigned char channel,unsigned char *int_od + * SMI130_GYRO_INT1 -> 0 + * SMI130_GYRO_INT2 -> 1 + * int_od : open drain -> 1 + * push pull -> 0 + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int_od(unsigned char param, +unsigned char *int_od) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_INT1: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT1_OD__REG, &v_data_u8r, 1); + *int_od = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT1_OD); + break; + case SMI130_GYRO_INT2: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT2_OD__REG, &v_data_u8r, 1); + *int_od = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT2_OD); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the output type status + * + * + * + * + * \param unsigned char channel,unsigned char *int_od + * SMI130_GYRO_INT1 -> 0 + * SMI130_GYRO_INT2 -> 1 + * int_od : open drain -> 1 + * push pull -> 0 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int_od(unsigned char param, +unsigned char int_od) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_INT1: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT1_OD__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT1_OD, int_od); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT1_OD__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_INT2: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT2_OD__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT2_OD, int_od); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT2_OD__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Active Level status + * + * + * + * + * \param unsigned char channel,unsigned char *int_lvl + * SMI130_GYRO_INT1 -> 0 + * SMI130_GYRO_INT2 -> 1 + * int_lvl : Active HI -> 1 + * Active LO -> 0 + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int_lvl(unsigned char param, +unsigned char *int_lvl) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_INT1: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT1_LVL__REG, &v_data_u8r, 1); + *int_lvl = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT1_LVL); + break; + case SMI130_GYRO_INT2: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT2_LVL__REG, &v_data_u8r, 1); + *int_lvl = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT2_LVL); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Active Level status + * + * + * + * + * \param unsigned char channel,unsigned char *int_lvl + * SMI130_GYRO_INT1 -> 0 + * SMI130_GYRO_INT2 -> 1 + * int_lvl : Active HI -> 1 + * Active LO -> 0 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int_lvl(unsigned char param, +unsigned char int_lvl) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_INT1: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT1_LVL__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT1_LVL, int_lvl); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT1_LVL__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_INT2: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT2_LVL__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_ENABLE1_IT2_LVL, int_lvl); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_ENABLE1_IT2_LVL__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get High Interrupt1 + * + * + * + * + * \param unsigned char *int1_high : Address of high_bw + * Pointer to a variable passed as a parameter + + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int1_high(unsigned char *int1_high) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_0_INT1_HIGH__REG, &v_data_u8r, 1); + *int1_high = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_0_INT1_HIGH); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set High Interrupt1 + * + * + * + * + * \param unsigned char int1_high + * 0 -> Disable + * 1 -> Enable + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int1_high(unsigned char int1_high) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_0_INT1_HIGH__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_0_INT1_HIGH, int1_high); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_0_INT1_HIGH__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Any Interrupt1 + * + * + * + * + * \param unsigned char *int1_any : Address of high_bw + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int1_any(unsigned char *int1_any) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_0_INT1_ANY__REG, &v_data_u8r, 1); + *int1_any = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_0_INT1_ANY); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Any Interrupt1 + * + * + * + * + *\param unsigned char int1_any + * 0 -> Disable + * 1 -> Enable + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int1_any(unsigned char int1_any) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_0_INT1_ANY__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_0_INT1_ANY, int1_any); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_0_INT1_ANY__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get data Interrupt1 and data + * Interrupt2 + * + * + * + * + * \param unsigned char axis,unsigned char *int_data + * axis : + * SMI130_GYRO_INT1_DATA -> 0 + * SMI130_GYRO_INT2_DATA -> 1 + * int_data : + * Disable -> 0 + * Enable -> 1 + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int_data(unsigned char axis, +unsigned char *int_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_INT1_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_DATA__REG, &v_data_u8r, 1); + *int_data = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_DATA); + break; + case SMI130_GYRO_INT2_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_DATA__REG, &v_data_u8r, 1); + *int_data = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_DATA); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set data Interrupt1 and data + * Interrupt2 + * + * + * + * + * \param unsigned char axis,unsigned char *int_data + * axis : + * SMI130_GYRO_INT1_DATA -> 0 + * SMI130_GYRO_INT2_DATA -> 1 + * int_data : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int_data(unsigned char axis, +unsigned char int_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_INT1_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_DATA__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_DATA, int_data); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_DATA__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_INT2_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_DATA__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_DATA, int_data); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_DATA__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; + } + +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get fast offset and auto + * offset Interrupt2 + * + * + * + * + *\param unsigned char axis,unsigned char *int2_offset + * axis : + * SMI130_GYRO_AUTO_OFFSET -> 1 + * SMI130_GYRO_FAST_OFFSET -> 2 + * int2_offset : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int2_offset(unsigned char axis, +unsigned char *int2_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_FAST_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FAST_OFFSET__REG, &v_data_u8r, 1); + *int2_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_FAST_OFFSET); + break; + case SMI130_GYRO_AUTO_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_AUTO_OFFSET__REG, &v_data_u8r, 1); + *int2_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_AUTO_OFFSET); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set fast offset and auto + * offset Interrupt2 + * + * + * + * + *\param unsigned char axis,unsigned char *int2_offset + * axis : + * SMI130_GYRO_AUTO_OFFSET -> 1 + * SMI130_GYRO_FAST_OFFSET -> 2 + * int2_offset : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int2_offset(unsigned char axis, +unsigned char int2_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_FAST_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FAST_OFFSET__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_FAST_OFFSET, int2_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FAST_OFFSET__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_AUTO_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_AUTO_OFFSET__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_AUTO_OFFSET, int2_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_AUTO_OFFSET__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get fast offset and auto + * offset Interrupt1 + * + * + * + * + *\param unsigned char axis,unsigned char *int1_offset + * axis : + * SMI130_GYRO_AUTO_OFFSET -> 1 + * SMI130_GYRO_FAST_OFFSET -> 2 + * int2_offset : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int1_offset(unsigned char axis, +unsigned char *int1_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_FAST_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FAST_OFFSET__REG, &v_data_u8r, 1); + *int1_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_FAST_OFFSET); + break; + case SMI130_GYRO_AUTO_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_AUTO_OFFSET__REG, &v_data_u8r, 1); + *int1_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_AUTO_OFFSET); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set fast offset and auto + * offset Interrupt1 + * + * + * + * + *\param unsigned char axis,unsigned char *int1_offset + * axis : + * SMI130_GYRO_AUTO_OFFSET -> 1 + * SMI130_GYRO_FAST_OFFSET -> 2 + * int2_offset : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int1_offset(unsigned char axis, +unsigned char int1_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_FAST_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FAST_OFFSET__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_FAST_OFFSET, int1_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FAST_OFFSET__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_AUTO_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_AUTO_OFFSET__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_AUTO_OFFSET, int1_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_AUTO_OFFSET__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get status of FIFO Interrupt + * + * + * + * + *\param unsigned char *int_fifo : Address of int_fifo + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int_fifo(unsigned char *int_fifo) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_STATUS1_FIFO_INT__REG, &v_data_u8r, 1); + *int_fifo = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_STATUS1_FIFO_INT); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get FIFO Interrupt2 + * + * + * + * + *\param unsigned char *int_fifo + * int_fifo : + * Disable -> 0 + * Enable -> 1 + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int2_fifo(unsigned char *int_fifo) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FIFO__REG, &v_data_u8r, 1); + *int_fifo = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_FIFO); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get FIFO Interrupt1 + * + * + * + * + *\param unsigned char *int_fifo + * int_fifo : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int1_fifo(unsigned char *int_fifo) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FIFO__REG, &v_data_u8r, 1); + *int_fifo = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_FIFO); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief + * + * + * + * + * \param + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int_fifo(unsigned char axis, +unsigned char int_fifo) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_INT1: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FIFO__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_FIFO, int_fifo); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FIFO__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_INT2: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FIFO__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_FIFO, int_fifo); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FIFO__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set FIFO Interrupt1 + * + * + * + * + *\param unsigned char *fifo_int1 + * fifo_int1 : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int1_fifo(unsigned char fifo_int1) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (fifo_int1 < C_SMI130_GYRO_Two_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FIFO__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT1_FIFO, fifo_int1); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT1_FIFO__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set FIFO Interrupt2 + * + * + * + * + *\param unsigned char *fifo_int2 + * fifo_int2 : + * Disable -> 0 + * Enable -> 1 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int2_fifo(unsigned char fifo_int2) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (fifo_int2 < C_SMI130_GYRO_Two_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FIFO__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MAP_1_INT2_FIFO, fifo_int2); + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MAP_1_INT2_FIFO__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get High Interrupt2 + * + * + * + * + *\param unsigned char *int2_high : Address of int2_high + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int2_high(unsigned char *int2_high) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_2_INT2_HIGH__REG, &v_data_u8r, 1); + *int2_high = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_2_INT2_HIGH); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get High Interrupt2 + * + * + * + * + *\param unsigned char int2_high + * 0 -> Disable + * 1 -> Enable + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int2_high(unsigned char int2_high) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_2_INT2_HIGH__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_2_INT2_HIGH, int2_high); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_2_INT2_HIGH__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Any Interrupt2 + * + * + * + * + *\param unsigned char *int2_any : Address of int2_any + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_int2_any(unsigned char *int2_any) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_2_INT2_ANY__REG, &v_data_u8r, 1); + *int2_any = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_2_INT2_ANY); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Any Interrupt2 + * + * + * + * + *\param unsigned char int2_any + * 0 -> Disable + * 1 -> Enable + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_int2_any(unsigned char int2_any) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_2_INT2_ANY__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_MAP_2_INT2_ANY, int2_any); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_MAP_2_INT2_ANY__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get slow offset and fast + * offset unfilt data + * + * + * + *\param unsigned char param,unsigned char *offset_unfilt + * param : + * SMI130_GYRO_SLOW_OFFSET -> 0 + * SMI130_GYRO_FAST_OFFSET -> 2 + * offset_unfilt: Enable -> 1 + * Disable -> 0 + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_offset_unfilt(unsigned char param, +unsigned char *offset_unfilt) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_SLOW_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_SLOW_OFFSET_UNFILT__REG, + &v_data_u8r, 1); + *offset_unfilt = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_0_ADDR_SLOW_OFFSET_UNFILT); + break; + case SMI130_GYRO_FAST_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_1_ADDR_FAST_OFFSET_UNFILT__REG, + &v_data_u8r, 1); + *offset_unfilt = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_1_ADDR_FAST_OFFSET_UNFILT); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set slow offset and fast + * offset unfilt data + * + * + * + * + *\param unsigned char param,unsigned char *offset_unfilt + * param : + * SMI130_GYRO_SLOW_OFFSET -> 0 + * SMI130_GYRO_FAST_OFFSET -> 2 + * offset_unfilt: Enable -> 1 + * Disable -> 0 + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_offset_unfilt(unsigned char param, +unsigned char offset_unfilt) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_SLOW_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_SLOW_OFFSET_UNFILT__REG, + &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_0_ADDR_SLOW_OFFSET_UNFILT, offset_unfilt); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_SLOW_OFFSET_UNFILT__REG, + &v_data_u8r, 1); + break; + case SMI130_GYRO_FAST_OFFSET: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_1_ADDR_FAST_OFFSET_UNFILT__REG, + &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_1_ADDR_FAST_OFFSET_UNFILT, offset_unfilt); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_1_ADDR_FAST_OFFSET_UNFILT__REG, + &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Tap, High, Constant, Any, + * Shake unfilt data + * + * + * + * + *\param unsigned char param,unsigned char *unfilt_data + * param : + * + * SMI130_GYRO_HIGH_UNFILT_DATA -> 1 + * SMI130_GYRO_ANY_UNFILT_DATA -> 3 + * + * unfilt_data: Enable -> 1 + * Disable -> 0 + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_unfilt_data(unsigned char param, +unsigned char *unfilt_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_HIGH_UNFILT_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_HIGH_UNFILT_DATA__REG, + &v_data_u8r, 1); + *unfilt_data = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_0_ADDR_HIGH_UNFILT_DATA); + break; + case SMI130_GYRO_ANY_UNFILT_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_ANY_UNFILT_DATA__REG, &v_data_u8r, 1); + *unfilt_data = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_0_ADDR_ANY_UNFILT_DATA); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Tap, High, Constant, Any, + * Shake unfilt data + * + * + * + * + *\param unsigned char param,unsigned char *unfilt_data + * param : + * + * SMI130_GYRO_HIGH_UNFILT_DATA -> 1 + * SMI130_GYRO_ANY_UNFILT_DATA -> 3 + * + * unfilt_data: Enable -> 1 + * Disable -> 0 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_unfilt_data(unsigned char param, +unsigned char unfilt_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_HIGH_UNFILT_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_HIGH_UNFILT_DATA__REG, + &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_0_ADDR_HIGH_UNFILT_DATA, unfilt_data); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_HIGH_UNFILT_DATA__REG, + &v_data_u8r, 1); + break; + case SMI130_GYRO_ANY_UNFILT_DATA: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_ANY_UNFILT_DATA__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_0_ADDR_ANY_UNFILT_DATA, unfilt_data); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_0_ADDR_ANY_UNFILT_DATA__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Any Threshold + * + * + * + * + *\param unsigned char *any_th : Address of any_th + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_any_th(unsigned char *any_th) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_1_ADDR_ANY_TH__REG, &v_data_u8r, 1); + *any_th = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_1_ADDR_ANY_TH); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Any Threshold + * + * + * + * + *\param unsigned char any_th: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_any_th(unsigned char any_th) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_1_ADDR_ANY_TH__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_1_ADDR_ANY_TH, any_th); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_1_ADDR_ANY_TH__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Awake Duration + * + * + * + * + *\param unsigned char *awake_dur : Address of awake_dur + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_awake_dur(unsigned char *awake_dur) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_AWAKE_DUR__REG, &v_data_u8r, 1); + *awake_dur = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_AWAKE_DUR); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Awake Duration + * + * + * + * + *\param unsigned char awake_dur: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + ***************************************************************************** + * Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_awake_dur(unsigned char awake_dur) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_AWAKE_DUR__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_AWAKE_DUR, awake_dur); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_AWAKE_DUR__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Any Duration Sample + * + * + * + * + *\param unsigned char *dursample : Address of dursample + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_any_dursample(unsigned char *dursample) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_DURSAMPLE__REG, &v_data_u8r, 1); + *dursample = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_DURSAMPLE); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Any Duration Sample + * + * + * + * + *\param unsigned char dursample: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_any_dursample(unsigned char dursample) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_DURSAMPLE__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_DURSAMPLE, dursample); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_DURSAMPLE__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of Any Enable + * Channel X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *data + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * data : + * Enable -> 1 + * disable -> 0 + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_any_en_ch(unsigned char channel, +unsigned char *data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_X__REG, &v_data_u8r, 1); + *data = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_EN_X); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Y__REG, &v_data_u8r, 1); + *data = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Y); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Z__REG, &v_data_u8r, 1); + *data = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Z); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of Any Enable + * Channel X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *data + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * data : + * Enable -> 1 + * disable -> 0 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_any_en_ch(unsigned char channel, +unsigned char data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_X__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_EN_X, data); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_X__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Y__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Y, data); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Y__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Z__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Z, data); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_2_ADDR_ANY_EN_Z__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of FIFO WM + * Enable + * + * + * + * + *\param unsigned char *fifo_wn_en + * Enable -> 1 + * Disable -> 0 + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_watermark_enable( +unsigned char *fifo_wn_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_4_FIFO_WM_EN__REG, &v_data_u8r, 1); + *fifo_wn_en = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_4_FIFO_WM_EN); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set FIFO WM Enable + * + * + * + * + *\param unsigned char *fifo_wn_en + * Enable -> 1 + * Disable -> 0 + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_fifo_watermark_enable( +unsigned char fifo_wn_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (fifo_wn_en < C_SMI130_GYRO_Two_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_4_FIFO_WM_EN__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_INT_4_FIFO_WM_EN, fifo_wn_en); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_INT_4_FIFO_WM_EN__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the Interrupt Reset + * + * + * + * + *\param unsigned char reset_int + * 1 -> Reset All Interrupts + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_reset_int(unsigned char reset_int) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_RESET_INT__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_RST_LATCH_ADDR_RESET_INT, reset_int); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_RESET_INT__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the Offset Reset + * + * + * + * + *\param unsigned char offset_reset + * 1 -> Resets All the Offsets + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_offset_reset( +unsigned char offset_reset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_OFFSET_RESET__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_RST_LATCH_ADDR_OFFSET_RESET, offset_reset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_OFFSET_RESET__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the Latch Status + * + * + * + * + *\param unsigned char *latch_status : Address of latch_status + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_latch_status( +unsigned char *latch_status) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_STATUS__REG, &v_data_u8r, 1); + *latch_status = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_STATUS); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the Latch Status + * + * + * + * + *\param unsigned char latch_status: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_latch_status( +unsigned char latch_status) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_STATUS__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_STATUS, latch_status); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_STATUS__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the Latch Interrupt + * + * + * + * + *\param unsigned char *latch_int : Address of latch_int + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_latch_int(unsigned char *latch_int) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_INT__REG, &v_data_u8r, 1); + *latch_int = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_INT); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the Latch Interrupt + * + * + * + * + *\param unsigned char latch_int: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_latch_int(unsigned char latch_int) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_INT__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_INT, latch_int); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_RST_LATCH_ADDR_LATCH_INT__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of High + * Hysteresis X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *high_hy + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * high_hy : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_high_hy(unsigned char channel, +unsigned char *high_hy) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_X__REG, &v_data_u8r, 1); + *high_hy = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_HY_X); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_Y__REG, &v_data_u8r, 1); + *high_hy = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_HY_Y); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_Z__REG, &v_data_u8r, 1); + *high_hy = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_HY_Z); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of High + * Hysteresis X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *high_hy + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * high_hy : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_high_hy(unsigned char channel, +unsigned char high_hy) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_X__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_HY_X, high_hy); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_X__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_Y__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_HY_Y, high_hy); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_Y__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_Z__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_HY_Z, high_hy); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_HY_Z__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of High + * Threshold X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *high_th + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * high_th : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_high_th(unsigned char channel, +unsigned char *high_th) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_X__REG, &v_data_u8r, 1); + *high_th = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_TH_X); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_Y__REG, &v_data_u8r, 1); + *high_th = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_TH_Y); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_Z__REG, &v_data_u8r, 1); + *high_th = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_TH_Z); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of High + * Threshold X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *high_th + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * high_th : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_high_th(unsigned char channel, +unsigned char high_th) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_X__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_TH_X, high_th); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_X__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_Y__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_TH_Y, high_th); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_Y__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_Z__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_TH_Z, high_th); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_TH_Z__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of High Enable + * Channel X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *high_en + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * high_en : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_high_en_ch(unsigned char channel, +unsigned char *high_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_X__REG, &v_data_u8r, 1); + *high_en = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_EN_X); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_Y__REG, &v_data_u8r, 1); + *high_en = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_EN_Y); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_Z__REG, &v_data_u8r, 1); + *high_en = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_EN_Z); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of High Enable + * Channel X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *high_en + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * high_en : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_high_en_ch(unsigned char channel, +unsigned char high_en) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_X__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_EN_X, high_en); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_X__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_Y__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_EN_Y, high_en); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_Y__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_Z__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_HIGH_EN_Z, high_en); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_EN_Z__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get High Duration + * + * + * + * + *\param unsigned char channel,unsigned char *high_dur + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * *high_dur : Address of high_bw + * Pointer to a variable passed as a + * parameter + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_high_dur_ch(unsigned char channel, +unsigned char *high_dur) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_DUR_X_ADDR, &v_data_u8r, 1); + *high_dur = v_data_u8r; + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_DUR_Y_ADDR, &v_data_u8r, 1); + *high_dur = v_data_u8r; + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_DUR_Z_ADDR, &v_data_u8r, 1); + *high_dur = v_data_u8r; + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set High Duration + * + * + * + * + *\param unsigned char channel,unsigned char *high_dur + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * high_dur : Value to be written passed as a parameter + * + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_high_dur_ch(unsigned char channel, +unsigned char high_dur) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + v_data_u8r = high_dur; + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_DUR_X_ADDR, &v_data_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + v_data_u8r = high_dur; + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_DUR_Y_ADDR, &v_data_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + v_data_u8r = high_dur; + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_HIGH_DUR_Z_ADDR, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Slow Offset Threshold + * + * + * + * + *\param unsigned char *offset_th : Address of offset_th + * Pointer to a variable passed as a parameter + + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_slow_offset_th( +unsigned char *offset_th) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_TH__REG, &v_data_u8r, 1); + *offset_th = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_TH); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Slow Offset Threshold + * + * + * + * + *\param unsigned char offset_th: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_slow_offset_th(unsigned char offset_th) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_TH__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_TH, offset_th); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_TH__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Slow Offset Duration + * + * + * + * + *\param unsigned char *offset_dur : Address of offset_dur + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_slow_offset_dur( +unsigned char *offset_dur) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_DUR__REG, &v_data_u8r, 1); + *offset_dur = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_DUR); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Slow Offset Duration + * + * + * + * + *\param unsigned char offset_dur: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_slow_offset_dur( +unsigned char offset_dur) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_DUR__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_DUR, offset_dur); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_DUR__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Slow Offset Enable channel + * X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *slow_offset + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * slow_offset : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_slow_offset_en_ch( +unsigned char channel, unsigned char *slow_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_X__REG, &v_data_u8r, 1); + *slow_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_EN_X); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_Y__REG, &v_data_u8r, 1); + *slow_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_EN_Y); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_Z__REG, &v_data_u8r, 1); + *slow_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_EN_Z); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Slow Offset Enable channel + * X,Y,Z + * + * + * + * + *\param unsigned char channel,unsigned char *slow_offset + * channel : + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * slow_offset : + * Enable -> 1 + * disable -> 0 + * + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_slow_offset_en_ch( +unsigned char channel, unsigned char slow_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_X__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_EN_X, slow_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_X__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_Y__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_EN_Y, slow_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_Y__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_Z__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_SLOW_OFFSET_EN_Z, + slow_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_SLOW_OFFSET_EN_Z__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Fast Offset WordLength and + * Auto Offset WordLength + * + * + * + * + *\param unsigned char channel,unsigned char *offset_wl + * channel : + * SMI130_GYRO_AUTO_OFFSET_WL -> 0 + * SMI130_GYRO_FAST_OFFSET_WL -> 1 + * *offset_wl : Address of high_bw + * Pointer to a variable passed as a + * parameter + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_offset_wl(unsigned char channel, +unsigned char *offset_wl) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_AUTO_OFFSET_WL: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_AUTO_OFFSET_WL__REG, &v_data_u8r, 1); + *offset_wl = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_AUTO_OFFSET_WL); + break; + case SMI130_GYRO_FAST_OFFSET_WL: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_WL__REG, &v_data_u8r, 1); + *offset_wl = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FAST_OFFSET_WL); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Fast Offset WordLength and + * Auto Offset WordLength + * + * + * + * + *\param unsigned char channel,unsigned char *offset_wl + * channel : + * SMI130_GYRO_AUTO_OFFSET_WL -> 0 + * SMI130_GYRO_FAST_OFFSET_WL -> 1 + * offset_wl : Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_offset_wl( +unsigned char channel, unsigned char offset_wl) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_AUTO_OFFSET_WL: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_AUTO_OFFSET_WL__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_AUTO_OFFSET_WL, offset_wl); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_AUTO_OFFSET_WL__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_FAST_OFFSET_WL: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_WL__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FAST_OFFSET_WL, offset_wl); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_WL__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to enable fast offset + * + * + * + * +* \param smi130_gyro_enable_fast_offset + * Enable -> 1 + * Disable -> 0 + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_enable_fast_offset() +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FAST_OFFSET_EN, 1); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API read the Fast offset en status from the + * 0x32h of 0 to 2 bits. + * + * + * + * + *\param unsigned char *fast_offset + * Pointer to a variable passed as a parameter + * + * + * + * \return Communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fast_offset_en_ch( +unsigned char *fast_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN_XYZ__REG, &v_data_u8r, 1); + *fast_offset = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FAST_OFFSET_EN_XYZ); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API writes the Fast offset enable bit based + * on the Channel selection 0x32h of (0 to 2 bits) + * + * + * + * +* \param unsigned char channel,unsigned char fast_offset + * + * channel --> SMI130_GYRO_X_AXIS,SMI130_GYRO_Y_AXIS,SMI130_GYRO_Z_AXIS + * fast_offset --> 0 - Disable + * 1 - Enable + * + * + * + * \return Communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_fast_offset_en_ch( +unsigned char channel, unsigned char fast_offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (channel) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN_X__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FAST_OFFSET_EN_X, fast_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN_X__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN_Y__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FAST_OFFSET_EN_Y, fast_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN_Y__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN_Z__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FAST_OFFSET_EN_Z, fast_offset); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FAST_OFFSET_EN_Z__REG, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of nvm program + * remain + * + * + * + * + *\param unsigned char *nvm_remain + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_nvm_remain(unsigned char *nvm_remain) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_REMAIN__REG, &v_data_u8r, 1); + *nvm_remain = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_REMAIN); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of nvm load + * + * + * + * + *\param unsigned char nvm_load + * 1 -> load offset value from NVM + * 0 -> no action + * + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_nvm_load(unsigned char nvm_load) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_LOAD__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_LOAD, nvm_load); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_LOAD__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of nvmprogram + * ready + * + * + * + * + *\param unsigned char *nvm_rdy + * 1 -> program seq finished + * 0 -> program seq in progress + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_nvm_rdy(unsigned char *nvm_rdy) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_RDY__REG, &v_data_u8r, 1); + *nvm_rdy = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_RDY); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of nvm program + * trigger + * + * + * + * + *\param unsigned char trig + * 1 -> trig program seq (wo) + * 0 -> No Action + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_nvm_prog_trig(unsigned char prog_trig) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_TRIG__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_TRIG, prog_trig); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_TRIG__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of nvm program + * mode + * + * + * + * +* \param unsigned char *prog_mode : Address of *prog_mode + * 1 -> Enable program mode + * 0 -> Disable program mode + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_nvm_prog_mode(unsigned char *prog_mode) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_MODE__REG, &v_data_u8r, 1); + *prog_mode = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_MODE); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/****************************************************************************** + * Description: *//**brief This API is used to set the status of nvmprogram + * mode + * + * + * + * +* \param(unsigned char prog_mode) + * 1 -> Enable program mode + * 0 -> Disable program mode + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_nvm_prog_mode(unsigned char prog_mode) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_MODE__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_MODE, prog_mode); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_NVM_CTRL_ADDR_NVM_PROG_MODE__REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of i2c wdt + * + * + * + * + *\param unsigned char channel,unsigned char *prog_mode + * SMI130_GYRO_I2C_WDT_SEL 1 + * SMI130_GYRO_I2C_WDT_EN 0 + * *prog_mode : Address of prog_mode + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_i2c_wdt(unsigned char i2c_wdt, +unsigned char *prog_mode) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (i2c_wdt) { + case SMI130_GYRO_I2C_WDT_EN: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_EN__REG, + &v_data_u8r, 1); + *prog_mode = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_EN); + break; + case SMI130_GYRO_I2C_WDT_SEL: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_SEL__REG, + &v_data_u8r, 1); + *prog_mode = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_SEL); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of i2c wdt + * + * + * + * + *\param unsigned char channel,unsigned char prog_mode + * SMI130_GYRO_I2C_WDT_SEL 1 + * SMI130_GYRO_I2C_WDT_EN 0 + * prog_mode : Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_i2c_wdt(unsigned char i2c_wdt, +unsigned char prog_mode) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (i2c_wdt) { + case SMI130_GYRO_I2C_WDT_EN: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_EN__REG, + &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_EN, prog_mode); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_EN__REG, + &v_data_u8r, 1); + break; + case SMI130_GYRO_I2C_WDT_SEL: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_SEL__REG, + &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_SEL, prog_mode); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_I2C_WDT_SEL__REG, + &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of spi3 + * + * + * + * +* \param unsigned char *spi3 : Address of spi3 + * Pointer to a variable passed as a parameter + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_spi3(unsigned char *spi3) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_SPI3__REG, &v_data_u8r, 1); + *spi3 = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_SPI3); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of spi3 + * + * + * + * + *\param unsigned char spi3 + * + * + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_spi3(unsigned char spi3) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_SPI3__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_SPI3, spi3); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_BGW_SPI3_WDT_ADDR_SPI3__REG, &v_data_u8r, 1); + } + return comres; +} +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_tag(unsigned char *tag) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF1_ADDR_TAG__REG, &v_data_u8r, 1); + *tag = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF1_ADDR_TAG); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of Tag + * + * + * + * + *\param unsigned char tag + * Enable -> 1 + * Disable -> 0 + * + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_fifo_tag(unsigned char tag) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (tag < C_SMI130_GYRO_Two_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF1_ADDR_TAG__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF1_ADDR_TAG, tag); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF1_ADDR_TAG__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get Water Mark Level + * + * + * + * + *\param unsigned char *water_mark_level : Address of water_mark_level + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_watermarklevel( +unsigned char *water_mark_level) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF1_ADDR_WML__REG, &v_data_u8r, 1); + *water_mark_level = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF1_ADDR_WML); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set Water Mark Level + * + * + * + * + *\param unsigned char water_mark_level: + * Value to be written passed as a parameter + + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_fifo_watermarklevel( +unsigned char water_mark_level) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (water_mark_level < C_SMI130_GYRO_OneTwentyEight_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF1_ADDR_WML__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF1_ADDR_WML, water_mark_level); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF1_ADDR_WML__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of offset + * + * + * + * + *\param unsigned char axis,unsigned char *offset + * axis -> + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * offset -> Any valid value + * + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_offset(unsigned char axis, +SMI130_GYRO_S16 *offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data1_u8r = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data2_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_X_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_X__REG, &v_data1_u8r, 1); + v_data1_u8r = SMI130_GYRO_GET_BITSLICE(v_data1_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_X); + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC1_ADDR_OFFSET_X__REG, &v_data2_u8r, 1); + v_data2_u8r = SMI130_GYRO_GET_BITSLICE(v_data2_u8r, + SMI130_GYRO_OFC1_ADDR_OFFSET_X); + v_data2_u8r = ((v_data2_u8r << + SMI130_GYRO_SHIFT_2_POSITION) | v_data1_u8r); + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, SMI130_GYRO_OFC2_ADDR, &v_data1_u8r, 1); + *offset = (SMI130_GYRO_S16)((((SMI130_GYRO_S16) + ((signed char)v_data1_u8r)) + << SMI130_GYRO_SHIFT_4_POSITION) | (v_data2_u8r)); + break; + case SMI130_GYRO_Y_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Y__REG, &v_data1_u8r, 1); + v_data1_u8r = SMI130_GYRO_GET_BITSLICE(v_data1_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Y); + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC1_ADDR_OFFSET_Y__REG, &v_data2_u8r, 1); + v_data2_u8r = SMI130_GYRO_GET_BITSLICE(v_data2_u8r, + SMI130_GYRO_OFC1_ADDR_OFFSET_Y); + v_data2_u8r = ((v_data2_u8r << + SMI130_GYRO_SHIFT_1_POSITION) | v_data1_u8r); + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC3_ADDR, &v_data1_u8r, 1); + *offset = (SMI130_GYRO_S16)((((SMI130_GYRO_S16) + ((signed char)v_data1_u8r)) + << SMI130_GYRO_SHIFT_4_POSITION) | (v_data2_u8r)); + break; + case SMI130_GYRO_Z_AXIS: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Z__REG, &v_data1_u8r, 1); + v_data1_u8r = SMI130_GYRO_GET_BITSLICE(v_data1_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Z); + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC1_ADDR_OFFSET_Z__REG, &v_data2_u8r, 1); + v_data2_u8r = SMI130_GYRO_GET_BITSLICE(v_data2_u8r, + SMI130_GYRO_OFC1_ADDR_OFFSET_Z); + v_data2_u8r = ((v_data2_u8r << SMI130_GYRO_SHIFT_1_POSITION) + | v_data1_u8r); + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC4_ADDR, &v_data1_u8r, 1); + *offset = (SMI130_GYRO_S16)((((SMI130_GYRO_S16) + ((signed char)v_data1_u8r)) + << SMI130_GYRO_SHIFT_4_POSITION) | (v_data2_u8r)); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of offset + * + * + * + * + *\param unsigned char axis,unsigned char offset + * axis -> + * SMI130_GYRO_X_AXIS -> 0 + * SMI130_GYRO_Y_AXIS -> 1 + * SMI130_GYRO_Z_AXIS -> 2 + * offset -> Any valid value + * + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_offset( +unsigned char axis, SMI130_GYRO_S16 offset) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data1_u8r = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data2_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (axis) { + case SMI130_GYRO_X_AXIS: + v_data1_u8r = ((signed char) (offset & 0x0FF0)) + >> SMI130_GYRO_SHIFT_4_POSITION; + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC2_ADDR, &v_data1_u8r, 1); + + v_data1_u8r = (unsigned char) (offset & 0x000C); + v_data2_u8r = SMI130_GYRO_SET_BITSLICE(v_data2_u8r, + SMI130_GYRO_OFC1_ADDR_OFFSET_X, v_data1_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC1_ADDR_OFFSET_X__REG, &v_data2_u8r, 1); + + v_data1_u8r = (unsigned char) (offset & 0x0003); + v_data2_u8r = SMI130_GYRO_SET_BITSLICE(v_data2_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_X, v_data1_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_X__REG, &v_data2_u8r, 1); + break; + case SMI130_GYRO_Y_AXIS: + v_data1_u8r = ((signed char) (offset & 0x0FF0)) >> + SMI130_GYRO_SHIFT_4_POSITION; + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC3_ADDR, &v_data1_u8r, 1); + + v_data1_u8r = (unsigned char) (offset & 0x000E); + v_data2_u8r = SMI130_GYRO_SET_BITSLICE(v_data2_u8r, + SMI130_GYRO_OFC1_ADDR_OFFSET_Y, v_data1_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC1_ADDR_OFFSET_Y__REG, &v_data2_u8r, 1); + + v_data1_u8r = (unsigned char) (offset & 0x0001); + v_data2_u8r = SMI130_GYRO_SET_BITSLICE(v_data2_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Y, v_data1_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Y__REG, &v_data2_u8r, 1); + break; + case SMI130_GYRO_Z_AXIS: + v_data1_u8r = ((signed char) (offset & 0x0FF0)) >> + SMI130_GYRO_SHIFT_4_POSITION; + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC4_ADDR, &v_data1_u8r, 1); + + v_data1_u8r = (unsigned char) (offset & 0x000E); + v_data2_u8r = SMI130_GYRO_SET_BITSLICE(v_data2_u8r, + SMI130_GYRO_OFC1_ADDR_OFFSET_Z, v_data1_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_OFC1_ADDR_OFFSET_Z__REG, &v_data2_u8r, 1); + + v_data1_u8r = (unsigned char) (offset & 0x0001); + v_data2_u8r = SMI130_GYRO_SET_BITSLICE(v_data2_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Z, v_data1_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_OFFSET_Z__REG, &v_data2_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of general + * purpose register + * + * + * + * + *\param unsigned char param,unsigned char *value + * param -> + * SMI130_GYRO_GP0 0 + * SMI130_GYRO_GP0 1 + * *value -> Address of high_bw + * Pointer to a variable passed as a parameter + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_gp(unsigned char param, +unsigned char *value) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_GP0: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_GP0__REG, &v_data_u8r, 1); + *value = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_GP0); + break; + case SMI130_GYRO_GP1: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP1_ADDR, &v_data_u8r, 1); + *value = v_data_u8r; + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of general + * purpose register + * + * + * + * + *\param unsigned char param,unsigned char value + * param -> + * SMI130_GYRO_GP0 0 + * SMI130_GYRO_GP0 1 + * value -> Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_gp(unsigned char param, +unsigned char value) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + switch (param) { + case SMI130_GYRO_GP0: + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_GP0__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_TRIM_GP0_ADDR_GP0, value); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP0_ADDR_GP0__REG, &v_data_u8r, 1); + break; + case SMI130_GYRO_GP1: + v_data_u8r = value; + comres = p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_TRIM_GP1_ADDR, &v_data_u8r, 1); + break; + default: + comres = E_SMI130_GYRO_OUT_OF_RANGE; + break; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads FIFI data from location 3Fh + * + * + * + * + * \param + * unsigned char *fifo_data : Address of FIFO data bits + * + * + * + * + * \return result of communication routines + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_FIFO_data_reg(unsigned char *fifo_data) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_DATA_ADDR, &v_data_u8r, 1); + *fifo_data = v_data_u8r; + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads interrupt fifo status register byte from 0Eh + * + * + * + * + * \param + * unsigned char *fifo_status : Address of Fifo status register + * + * + * \return + * Result of bus communication function + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ + +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifostatus_reg( +unsigned char *fifo_status) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_STATUS_ADDR, fifo_status, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads interrupt fifo status register byte from 0Eh + * + * + * + * + * \param + * unsigned char *fifo_framecount: Address of FIFO status register + * + * + * \return + * Result of bus communication function + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ + +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_framecount( +unsigned char *fifo_framecount) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_STATUS_FRAME_COUNTER__REG, &v_data_u8r, 1); + *fifo_framecount = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_STATUS_FRAME_COUNTER); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief Reads interrupt fifo status register byte from 0Eh + * + * + * + * + * \param + * unsigned char *fifo_overrun: Address of FIFO status register + * + * + * \return + * Result of bus communication function + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ + +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_overrun( +unsigned char *fifo_overrun) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_STATUS_OVERRUN__REG, &v_data_u8r, 1); + *fifo_overrun = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_STATUS_OVERRUN); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of fifo mode + * + * + * + * + *\param unsigned char *mode : Address of mode + * fifo_mode 0 --> Bypass + * 1 --> FIFO + * 2 --> Stream + * 3 --> Reserved + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_mode(unsigned char *mode) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF0_ADDR_MODE__REG, &v_data_u8r, 1); + *mode = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF0_ADDR_MODE); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used set to FIFO mode + * + * + * + * +* \param 0 --> BYPASS + * 1 --> FIFO + * 2 --> STREAM + * + * + * \return Communication Results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_fifo_mode(unsigned char mode) +{ + int comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (mode < C_SMI130_GYRO_Four_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF0_ADDR_MODE__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF0_ADDR_MODE, mode); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF0_ADDR_MODE__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the status of fifo data + * sel + * + * + * + * + *\param unsigned char *data_sel : Address of data_sel + * data_sel --> [0:3] + * 0 --> X,Y and Z (DEFAULT) + * 1 --> X only + * 2 --> Y only + * 3 --> Z only + * + * + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_fifo_data_sel(unsigned char *data_sel) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF0_ADDR_DATA_SEL__REG, &v_data_u8r, 1); + *data_sel = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF0_ADDR_DATA_SEL); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the status of fifo data + * sel + * + * + * + * + *\param unsigned char data_sel + * data_sel --> [0:3] + * 0 --> X,Y and Z (DEFAULT) + * 1 --> X only + * 2 --> Y only + * 3 --> Z only + * + * + * + * \return communication results + * + * + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_fifo_data_sel(unsigned char data_sel) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (data_sel < C_SMI130_GYRO_Four_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF0_ADDR_DATA_SEL__REG, &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_FIFO_CGF0_ADDR_DATA_SEL, data_sel); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_FIFO_CGF0_ADDR_DATA_SEL__REG, &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get the operating modes of the + * sensor + * + * + * + * + *\param unsigned char * mode : Address of mode + * 0 -> NORMAL + * 1 -> SUSPEND + * 2 -> DEEP SUSPEND + * 3 -> FAST POWERUP + * 4 -> ADVANCED POWERSAVING + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_mode(unsigned char *mode) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char data1 = C_SMI130_GYRO_Zero_U8X; + unsigned char data2 = C_SMI130_GYRO_Zero_U8X; + unsigned char data3 = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == C_SMI130_GYRO_Zero_U8X) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM1_ADDR, &data1, C_SMI130_GYRO_One_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data2, C_SMI130_GYRO_One_U8X); + data1 = (data1 & 0xA0) >> 5; + data3 = (data2 & 0x40) >> 6; + data2 = (data2 & 0x80) >> 7; + if (data3 == 0x01) { + *mode = SMI130_GYRO_MODE_ADVANCEDPOWERSAVING; + } else { + if ((data1 == 0x00) && (data2 == 0x00)) { + *mode = SMI130_GYRO_MODE_NORMAL; + } else { + if ((data1 == 0x01) || (data1 == 0x05)) { + *mode = SMI130_GYRO_MODE_DEEPSUSPEND; + } else { + if ((data1 == 0x04) && + (data2 == 0x00)) { + *mode = SMI130_GYRO_MODE_SUSPEND; + } else { + if ((data1 == 0x04) && + (data2 == 0x01)) + *mode = + SMI130_GYRO_MODE_FASTPOWERUP; + } + } + } + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set the operating Modes of the + * sensor + * + * + * + * + *\param unsigned char Mode + * 0 -> NORMAL + * 1 -> DEEPSUSPEND + * 2 -> SUSPEND + * 3 -> Fast Powerup + * 4 -> Advance Powerup + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_mode(unsigned char mode) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char data1 = C_SMI130_GYRO_Zero_U8X; + unsigned char data2 = C_SMI130_GYRO_Zero_U8X; + unsigned char data3 = C_SMI130_GYRO_Zero_U8X; + unsigned char v_autosleepduration = C_SMI130_GYRO_Zero_U8X; + unsigned char v_bw_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == C_SMI130_GYRO_Zero_U8X) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (mode < C_SMI130_GYRO_Five_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM1_ADDR, &data1, C_SMI130_GYRO_One_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data2, C_SMI130_GYRO_One_U8X); + switch (mode) { + case SMI130_GYRO_MODE_NORMAL: + data1 = SMI130_GYRO_SET_BITSLICE(data1, + SMI130_GYRO_MODE_LPM1, C_SMI130_GYRO_Zero_U8X); + data2 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_FAST_POWERUP, + C_SMI130_GYRO_Zero_U8X); + data3 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_ADV_POWERSAVING, + C_SMI130_GYRO_Zero_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM1_ADDR, &data1, C_SMI130_GYRO_One_U8X); + p_smi130_gyro->delay_msec(1);/*A minimum delay of atleast + 450us is required for Multiple write.*/ + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data3, C_SMI130_GYRO_One_U8X); + break; + case SMI130_GYRO_MODE_DEEPSUSPEND: + data1 = SMI130_GYRO_SET_BITSLICE(data1, + SMI130_GYRO_MODE_LPM1, C_SMI130_GYRO_One_U8X); + data2 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_FAST_POWERUP, + C_SMI130_GYRO_Zero_U8X); + data3 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_ADV_POWERSAVING, + C_SMI130_GYRO_Zero_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM1_ADDR, &data1, C_SMI130_GYRO_One_U8X); + p_smi130_gyro->delay_msec(1);/*A minimum delay of atleast + 450us is required for Multiple write.*/ + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data3, C_SMI130_GYRO_One_U8X); + break; + case SMI130_GYRO_MODE_SUSPEND: + data1 = SMI130_GYRO_SET_BITSLICE(data1, + SMI130_GYRO_MODE_LPM1, C_SMI130_GYRO_Four_U8X); + data2 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_FAST_POWERUP, + C_SMI130_GYRO_Zero_U8X); + data3 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_ADV_POWERSAVING, + C_SMI130_GYRO_Zero_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM1_ADDR, &data1, C_SMI130_GYRO_One_U8X); + p_smi130_gyro->delay_msec(1);/*A minimum delay of atleast + 450us is required for Multiple write.*/ + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data3, C_SMI130_GYRO_One_U8X); + break; + case SMI130_GYRO_MODE_FASTPOWERUP: + data1 = SMI130_GYRO_SET_BITSLICE(data1, + SMI130_GYRO_MODE_LPM1, C_SMI130_GYRO_Four_U8X); + data2 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_FAST_POWERUP, + C_SMI130_GYRO_One_U8X); + data3 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_ADV_POWERSAVING, + C_SMI130_GYRO_Zero_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM1_ADDR, &data1, C_SMI130_GYRO_One_U8X); + p_smi130_gyro->delay_msec(1);/*A minimum delay of atleast + 450us is required for Multiple write.*/ + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data3, C_SMI130_GYRO_One_U8X); + break; + case SMI130_GYRO_MODE_ADVANCEDPOWERSAVING: + /* Configuring the proper settings for auto + sleep duration */ + smi130_gyro_get_bw(&v_bw_u8r); + smi130_gyro_get_autosleepdur(&v_autosleepduration); + smi130_gyro_set_autosleepdur(v_autosleepduration, + v_bw_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data2, + C_SMI130_GYRO_One_U8X); + /* Configuring the advanced power saving mode*/ + data1 = SMI130_GYRO_SET_BITSLICE(data1, + SMI130_GYRO_MODE_LPM1, C_SMI130_GYRO_Zero_U8X); + data2 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_FAST_POWERUP, + C_SMI130_GYRO_Zero_U8X); + data3 = SMI130_GYRO_SET_BITSLICE(data2, + SMI130_GYRO_MODE_LPM2_ADDR_ADV_POWERSAVING, + C_SMI130_GYRO_One_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM1_ADDR, &data1, C_SMI130_GYRO_One_U8X); + p_smi130_gyro->delay_msec(1);/*A minimum delay of atleast + 450us is required for Multiple write.*/ + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR, &data3, C_SMI130_GYRO_One_U8X); + break; + } + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to to do selftest to sensor + * sensor + * + * + * + * + *\param unsigned char *result + * + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_selftest(unsigned char *result) + { + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char data1 = C_SMI130_GYRO_Zero_U8X; + unsigned char data2 = C_SMI130_GYRO_Zero_U8X; + + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SELF_TEST_ADDR, &data1, C_SMI130_GYRO_One_U8X); + data2 = SMI130_GYRO_GET_BITSLICE(data1, SMI130_GYRO_SELF_TEST_ADDR_RATEOK); + data1 = SMI130_GYRO_SET_BITSLICE(data1, SMI130_GYRO_SELF_TEST_ADDR_TRIGBIST, + C_SMI130_GYRO_One_U8X); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SELF_TEST_ADDR_TRIGBIST__REG, &data1, C_SMI130_GYRO_One_U8X); + + /* Waiting time to complete the selftest process */ + p_smi130_gyro->delay_msec(10); + + /* Reading Selftest result bir bist_failure */ + comres += p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_SELF_TEST_ADDR_BISTFAIL__REG, &data1, C_SMI130_GYRO_One_U8X); + data1 = SMI130_GYRO_GET_BITSLICE(data1, SMI130_GYRO_SELF_TEST_ADDR_BISTFAIL); + if ((data1 == 0x00) && (data2 == 0x01)) + *result = C_SMI130_GYRO_SUCCESS; + else + *result = C_SMI130_GYRO_FAILURE; + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get data auto sleep duration + * + * + * + * + *\param unsigned char *duration : Address of auto sleep duration + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_autosleepdur(unsigned char *duration) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR_AUTOSLEEPDUR__REG, &v_data_u8r, 1); + *duration = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MODE_LPM2_ADDR_AUTOSLEEPDUR); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set duration + * + * + * + * + *\param unsigned char duration: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_autosleepdur(unsigned char duration, +unsigned char bandwith) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + unsigned char v_autosleepduration_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR_AUTOSLEEPDUR__REG, + &v_data_u8r, 1); + if (duration < C_SMI130_GYRO_Eight_U8X) { + switch (bandwith) { + case C_SMI130_GYRO_No_Filter_U8X: + if (duration > + C_SMI130_GYRO_4ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_4ms_AutoSleepDur_U8X; + break; + case C_SMI130_GYRO_BW_230Hz_U8X: + if (duration > + C_SMI130_GYRO_4ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_4ms_AutoSleepDur_U8X; + break; + case C_SMI130_GYRO_BW_116Hz_U8X: + if (duration > + C_SMI130_GYRO_4ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_4ms_AutoSleepDur_U8X; + break; + case C_SMI130_GYRO_BW_47Hz_U8X: + if (duration > + C_SMI130_GYRO_5ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_5ms_AutoSleepDur_U8X; + break; + case C_SMI130_GYRO_BW_23Hz_U8X: + if (duration > + C_SMI130_GYRO_10ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_10ms_AutoSleepDur_U8X; + break; + case C_SMI130_GYRO_BW_12Hz_U8X: + if (duration > + C_SMI130_GYRO_20ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_20ms_AutoSleepDur_U8X; + break; + case C_SMI130_GYRO_BW_64Hz_U8X: + if (duration > + C_SMI130_GYRO_10ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_10ms_AutoSleepDur_U8X; + break; + case C_SMI130_GYRO_BW_32Hz_U8X: + if (duration > + C_SMI130_GYRO_20ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_20ms_AutoSleepDur_U8X; + break; + default: + if (duration > + C_SMI130_GYRO_4ms_AutoSleepDur_U8X) + v_autosleepduration_u8r = + duration; + else + v_autosleepduration_u8r = + C_SMI130_GYRO_4ms_AutoSleepDur_U8X; + break; + } + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MODE_LPM2_ADDR_AUTOSLEEPDUR, + v_autosleepduration_u8r); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODE_LPM2_ADDR_AUTOSLEEPDUR__REG, + &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to get data sleep duration + * + * + * + * + *\param unsigned char *duration : Address of sleep duration + * Pointer to a variable passed as a parameter + * + * + * + * \return + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_get_sleepdur(unsigned char *duration) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC(p_smi130_gyro->dev_addr, + SMI130_GYRO_MODELPM1_ADDR_SLEEPDUR__REG, &v_data_u8r, 1); + *duration = SMI130_GYRO_GET_BITSLICE(v_data_u8r, + SMI130_GYRO_MODELPM1_ADDR_SLEEPDUR); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/***************************************************************************** + * Description: *//**brief This API is used to set duration + * + * + * + * + *\param unsigned char duration: + * Value to be written passed as a parameter + * + * + * + * \return communication results + * + * + *****************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + *****************************************************************************/ +SMI130_GYRO_RETURN_FUNCTION_TYPE smi130_gyro_set_sleepdur(unsigned char duration) +{ + SMI130_GYRO_RETURN_FUNCTION_TYPE comres = C_SMI130_GYRO_Zero_U8X; + unsigned char v_data_u8r = C_SMI130_GYRO_Zero_U8X; + if (p_smi130_gyro == SMI130_GYRO_NULL) { + return E_SMI130_GYRO_NULL_PTR; + } else { + if (duration < C_SMI130_GYRO_Eight_U8X) { + comres = p_smi130_gyro->SMI130_GYRO_BUS_READ_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODELPM1_ADDR_SLEEPDUR__REG, + &v_data_u8r, 1); + v_data_u8r = SMI130_GYRO_SET_BITSLICE(v_data_u8r, + SMI130_GYRO_MODELPM1_ADDR_SLEEPDUR, duration); + comres += p_smi130_gyro->SMI130_GYRO_BUS_WRITE_FUNC + (p_smi130_gyro->dev_addr, + SMI130_GYRO_MODELPM1_ADDR_SLEEPDUR__REG, + &v_data_u8r, 1); + } else { + comres = E_SMI130_GYRO_OUT_OF_RANGE; + } + } + return comres; +} + diff --git a/drivers/input/sensors/smi130/smi130_gyro.h b/drivers/input/sensors/smi130/smi130_gyro.h new file mode 100644 index 0000000000000000000000000000000000000000..38e52acc304fc91fd5de947311951cd707a225a4 --- /dev/null +++ b/drivers/input/sensors/smi130/smi130_gyro.h @@ -0,0 +1,4705 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename smi130_gyro.h + * @date 2013/11/25 + * @Modification Date 2018/08/28 18:20 + * @id "8fcde22" + * @version 1.5 + * + * @brief Header of SMI130_GYRO API +*/ + +/* user defined code to be added here ... */ +#ifndef __SMI130_GYRO_H__ +#define __SMI130_GYRO_H__ + +#ifdef __KERNEL__ +#define SMI130_GYRO_U16 unsigned short /* 16 bit achieved with short */ +#define SMI130_GYRO_S16 signed short +#define SMI130_GYRO_S32 signed int /* 32 bit achieved with int */ +#else +#include /*needed to test integer limits */ + + +/* find correct data type for signed/unsigned 16 bit variables \ +by checking max of unsigned variant */ +#if USHRT_MAX == 0xFFFF + /* 16 bit achieved with short */ + #define SMI130_GYRO_U16 unsigned short + #define SMI130_GYRO_S16 signed short +#elif UINT_MAX == 0xFFFF + /* 16 bit achieved with int */ + #define SMI130_GYRO_U16 unsigned int + #define SMI130_GYRO_S16 signed int +#else + #error SMI130_GYRO_U16 and SMI130_GYRO_S16 could not be + #error defined automatically, please do so manually +#endif + +/* find correct data type for signed 32 bit variables */ +#if INT_MAX == 0x7FFFFFFF + /* 32 bit achieved with int */ + #define SMI130_GYRO_S32 signed int +#elif LONG_MAX == 0x7FFFFFFF + /* 32 bit achieved with long int */ + #define SMI130_GYRO_S32 signed long int +#else + #error SMI130_GYRO_S32 could not be + #error defined automatically, please do so manually +#endif +#endif + +/**\brief defines the calling parameter types of the SMI130_GYRO_WR_FUNCTION */ +#define SMI130_GYRO_BUS_WR_RETURN_TYPE char + +/**\brief links the order of parameters defined in +SMI130_GYRO_BUS_WR_PARAM_TYPE to function calls used inside the API*/ +#define SMI130_GYRO_BUS_WR_PARAM_TYPES unsigned char, unsigned char,\ +unsigned char *, unsigned char + +/**\brief links the order of parameters defined in +SMI130_GYRO_BUS_WR_PARAM_TYPE to function calls used inside the API*/ +#define SMI130_GYRO_BUS_WR_PARAM_ORDER(device_addr, register_addr,\ +register_data, wr_len) + +/* never change this line */ +#define SMI130_GYRO_BUS_WRITE_FUNC(device_addr, register_addr,\ +register_data, wr_len) bus_write(device_addr, register_addr,\ +register_data, wr_len) +/**\brief defines the return parameter type of the SMI130_GYRO_RD_FUNCTION +*/ +#define SMI130_GYRO_BUS_RD_RETURN_TYPE char +/**\brief defines the calling parameter types of the SMI130_GYRO_RD_FUNCTION +*/ +#define SMI130_GYRO_BUS_RD_PARAM_TYPES unsigned char, unsigned char,\ +unsigned char *, unsigned char +/**\brief links the order of parameters defined in \ +SMI130_GYRO_BUS_RD_PARAM_TYPE to function calls used inside the API +*/ +#define SMI130_GYRO_BUS_RD_PARAM_ORDER (device_addr, register_addr,\ +register_data) +/* never change this line */ +#define SMI130_GYRO_BUS_READ_FUNC(device_addr, register_addr,\ +register_data, rd_len)bus_read(device_addr, register_addr,\ +register_data, rd_len) +/**\brief defines the return parameter type of the SMI130_GYRO_RD_FUNCTION +*/ +#define SMI130_GYRO_BURST_RD_RETURN_TYPE char +/**\brief defines the calling parameter types of the SMI130_GYRO_RD_FUNCTION +*/ +#define SMI130_GYRO_BURST_RD_PARAM_TYPES unsigned char,\ +unsigned char, unsigned char *, signed int +/**\brief links the order of parameters defined in \ +SMI130_GYRO_BURST_RD_PARAM_TYPE to function calls used inside the API +*/ +#define SMI130_GYRO_BURST_RD_PARAM_ORDER (device_addr, register_addr,\ +register_data) +/* never change this line */ +#define SMI130_GYRO_BURST_READ_FUNC(device_addr, register_addr,\ +register_data, rd_len)burst_read(device_addr, \ +register_addr, register_data, rd_len) +/**\brief defines the return parameter type of the SMI130_GYRO_DELAY_FUNCTION +*/ +#define SMI130_GYRO_DELAY_RETURN_TYPE void +/* never change this line */ +#define SMI130_GYRO_DELAY_FUNC(delay_in_msec)\ + delay_func(delay_in_msec) +#define SMI130_GYRO_RETURN_FUNCTION_TYPE int +/**< This refers SMI130_GYRO return type as char */ + +#define SMI130_GYRO_I2C_ADDR1 0x68 +#define SMI130_GYRO_I2C_ADDR SMI130_GYRO_I2C_ADDR1 +#define SMI130_GYRO_I2C_ADDR2 0x69 + + + +/*Define of registers*/ + +/* Hard Wired */ +#define SMI130_GYRO_CHIP_ID_ADDR 0x00 +/**
> bitname##__POS) + +/* Set bit slice */ +#define SMI130_GYRO_SET_BITSLICE(regvar, bitname, val)\ +((regvar&~bitname##__MSK)|((val< +#include +#include +#include +#else +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include "smi130_gyro.h" +#include "bs_log.h" + +/* sensor specific */ +#define SENSOR_NAME "smi130_gyro" +#define SMI130_GYRO_ENABLE_INT1 1 +#define SENSOR_CHIP_ID_SMI_GYRO (0x0f) +#define CHECK_CHIP_ID_TIME_MAX 5 +#define DRIVER_VERSION "0.0.53.0" +#define SMI_GYRO_USE_FIFO 1 +#define SMI_GYRO_USE_BASIC_I2C_FUNC 1 +#define SMI_GYRO_REG_NAME(name) SMI130_GYRO_##name +#define SMI_GYRO_VAL_NAME(name) SMI130_GYRO_##name +#define SMI_GYRO_CALL_API(name) smi130_gyro_##name +#define MSC_TIME 6 + +#define SMI_GYRO_I2C_WRITE_DELAY_TIME 1 + +/* generic */ +#define SMI_GYRO_MAX_RETRY_I2C_XFER (100) +#define SMI_GYRO_MAX_RETRY_WAKEUP (5) +#define SMI_GYRO_MAX_RETRY_WAIT_DRDY (100) + +#define SMI_GYRO_DELAY_MIN (1) +#define SMI_GYRO_DELAY_DEFAULT (200) + +#define SMI_GYRO_VALUE_MAX (32767) +#define SMI_GYRO_VALUE_MIN (-32768) + +#define BYTES_PER_LINE (16) + +#define SMI_GYRO_SELF_TEST 0 + +#define SMI_GYRO_SOFT_RESET_VALUE 0xB6 + +#ifdef SMI_GYRO_USE_FIFO +#define MAX_FIFO_F_LEVEL 100 +#define MAX_FIFO_F_BYTES 8 +#define SMI130_GYRO_FIFO_DAT_SEL_X 1 +#define SMI130_GYRO_FIFO_DAT_SEL_Y 2 +#define SMI130_GYRO_FIFO_DAT_SEL_Z 3 +#endif + +/*! + * @brief:BMI058 feature + * macro definition +*/ +#ifdef CONFIG_SENSORS_BMI058 +/*! BMI058 X AXIS definition*/ +#define BMI058_X_AXIS SMI130_GYRO_Y_AXIS +/*! BMI058 Y AXIS definition*/ +#define BMI058_Y_AXIS SMI130_GYRO_X_AXIS + +#define C_BMI058_One_U8X 1 +#define C_BMI058_Two_U8X 2 +#endif + +/*! Bosch sensor unknown place*/ +#define BOSCH_SENSOR_PLACE_UNKNOWN (-1) +/*! Bosch sensor remapping table size P0~P7*/ +#define MAX_AXIS_REMAP_TAB_SZ 8 + + +struct bosch_sensor_specific { + char *name; + /* 0 to 7 */ + int place; + int irq; + int (*irq_gpio_cfg)(void); +}; + + +/*! + * we use a typedef to hide the detail, + * because this type might be changed + */ +struct bosch_sensor_axis_remap { + /* src means which source will be mapped to target x, y, z axis */ + /* if an target OS axis is remapped from (-)x, + * src is 0, sign_* is (-)1 */ + /* if an target OS axis is remapped from (-)y, + * src is 1, sign_* is (-)1 */ + /* if an target OS axis is remapped from (-)z, + * src is 2, sign_* is (-)1 */ + int src_x:3; + int src_y:3; + int src_z:3; + + int sign_x:2; + int sign_y:2; + int sign_z:2; +}; + + +struct bosch_sensor_data { + union { + int16_t v[3]; + struct { + int16_t x; + int16_t y; + int16_t z; + }; + }; +}; + +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +#define SMI_GYRO_MAXSAMPLE 4000 +#define G_MAX 23920640 +struct smi_gyro_sample { + int xyz[3]; + unsigned int tsec; + unsigned long long tnsec; +}; +#endif + +struct smi_gyro_client_data { + struct smi130_gyro_t device; + struct i2c_client *client; + struct input_dev *input; + struct delayed_work work; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend_handler; +#endif + + atomic_t delay; + uint8_t debug_level; + struct smi130_gyro_data_t value; + u8 enable:1; + unsigned int fifo_count; + unsigned char fifo_datasel; + uint64_t timestamp; + uint64_t base_time; + uint64_t fifo_time; + uint64_t gyro_count; + uint64_t time_odr; + /* controls not only reg, but also workqueue */ + struct mutex mutex_op_mode; + struct mutex mutex_enable; + struct bosch_sensor_specific *bosch_pd; + struct work_struct report_data_work; + int is_timer_running; + struct hrtimer timer; + ktime_t work_delay_kt; + uint8_t gpio_pin; + int16_t IRQ; +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING + bool read_gyro_boot_sample; + int gyro_bufsample_cnt; + bool gyro_buffer_smi130_samples; + struct kmem_cache *smi_gyro_cachepool; + struct smi_gyro_sample *smi130_gyro_samplist[SMI_GYRO_MAXSAMPLE]; + int max_buffer_time; + struct input_dev *gyrobuf_dev; + int report_evt_cnt; +#endif +}; + +static struct i2c_client *smi_gyro_client; +/* i2c operation for API */ +static int smi_gyro_i2c_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len); +static int smi_gyro_i2c_write(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len); + +static void smi_gyro_dump_reg(struct i2c_client *client); +static int smi_gyro_check_chip_id(struct i2c_client *client); + +static int smi_gyro_pre_suspend(struct i2c_client *client); +static int smi_gyro_post_resume(struct i2c_client *client); + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void smi_gyro_early_suspend(struct early_suspend *handler); +static void smi_gyro_late_resume(struct early_suspend *handler); +#endif + +static void smi130_gyro_delay(SMI130_GYRO_U16 msec) +{ + if (msec <= 20) + usleep_range(msec * 1000, msec * 1000); + else + msleep(msec); +} + +/*! +* SMI130_GYRO sensor remapping function +* need to give some parameter in BSP files first. +*/ +static const struct bosch_sensor_axis_remap + bosch_axis_remap_tab_dft[MAX_AXIS_REMAP_TAB_SZ] = { + /* src_x src_y src_z sign_x sign_y sign_z */ + { 0, 1, 2, 1, 1, 1 }, /* P0 */ + { 1, 0, 2, 1, -1, 1 }, /* P1 */ + { 0, 1, 2, -1, -1, 1 }, /* P2 */ + { 1, 0, 2, -1, 1, 1 }, /* P3 */ + + { 0, 1, 2, -1, 1, -1 }, /* P4 */ + { 1, 0, 2, -1, -1, -1 }, /* P5 */ + { 0, 1, 2, 1, -1, -1 }, /* P6 */ + { 1, 0, 2, 1, 1, -1 }, /* P7 */ +}; + +static void bosch_remap_sensor_data(struct bosch_sensor_data *data, + const struct bosch_sensor_axis_remap *remap) +{ + struct bosch_sensor_data tmp; + + tmp.x = data->v[remap->src_x] * remap->sign_x; + tmp.y = data->v[remap->src_y] * remap->sign_y; + tmp.z = data->v[remap->src_z] * remap->sign_z; + + memcpy(data, &tmp, sizeof(*data)); +} + +static void bosch_remap_sensor_data_dft_tab(struct bosch_sensor_data *data, + int place) +{ +/* sensor with place 0 needs not to be remapped */ + if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ)) + return; + bosch_remap_sensor_data(data, &bosch_axis_remap_tab_dft[place]); +} + +static void smi130_gyro_remap_sensor_data(struct smi130_gyro_data_t *val, + struct smi_gyro_client_data *client_data) +{ + struct bosch_sensor_data bsd; + int place; + + if ((NULL == client_data->bosch_pd) || (BOSCH_SENSOR_PLACE_UNKNOWN + == client_data->bosch_pd->place)) + place = BOSCH_SENSOR_PLACE_UNKNOWN; + else + place = client_data->bosch_pd->place; + +#ifdef CONFIG_SENSORS_BMI058 +/*x,y need to be invesed becase of HW Register for BMI058*/ + bsd.y = val->datax; + bsd.x = val->datay; + bsd.z = val->dataz; +#else + bsd.x = val->datax; + bsd.y = val->datay; + bsd.z = val->dataz; +#endif + + bosch_remap_sensor_data_dft_tab(&bsd, place); + + val->datax = bsd.x; + val->datay = bsd.y; + val->dataz = bsd.z; + +} + +static int smi_gyro_check_chip_id(struct i2c_client *client) +{ + int err = -1; + u8 chip_id = 0; + u8 read_count = 0; + + while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { + smi_gyro_i2c_read(client, SMI_GYRO_REG_NAME(CHIP_ID_ADDR), &chip_id, 1); + PINFO("read chip id result: %#x", chip_id); + + if ((chip_id & 0xff) != SENSOR_CHIP_ID_SMI_GYRO) { + smi130_gyro_delay(1); + } else { + err = 0; + break; + } + } + return err; +} + +static void smi_gyro_dump_reg(struct i2c_client *client) +{ + int i; + u8 dbg_buf[64] = {0}; + u8 dbg_buf_str[64 * 3 + 1] = ""; + + for (i = 0; i < BYTES_PER_LINE; i++) { + dbg_buf[i] = i; + snprintf(dbg_buf_str + i * 3, 16, "%02x%c", + dbg_buf[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + dev_dbg(&client->dev, "%s\n", dbg_buf_str); + + smi_gyro_i2c_read(client, SMI_GYRO_REG_NAME(CHIP_ID_ADDR), dbg_buf, 64); + for (i = 0; i < 64; i++) { + snprintf(dbg_buf_str + i * 3, 16, "%02x%c", + dbg_buf[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + dev_dbg(&client->dev, "%s\n", dbg_buf_str); +} + +/*i2c read routine for API*/ +static int smi_gyro_i2c_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ +#if !defined SMI_GYRO_USE_BASIC_I2C_FUNC + s32 dummy; + if (NULL == client) + return -ENODEV; + + while (0 != len--) { +#ifdef SMI_GYRO_SMBUS + dummy = i2c_smbus_read_byte_data(client, reg_addr); + if (dummy < 0) { + dev_err(&client->dev, "i2c bus read error"); + return -EIO; + } + *data = (u8)(dummy & 0xff); +#else + dummy = i2c_master_send(client, (char *)®_addr, 1); + if (dummy < 0) + return -EIO; + + dummy = i2c_master_recv(client, (char *)data, 1); + if (dummy < 0) + return -EIO; +#endif + reg_addr++; + data++; + } + return 0; +#else + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < SMI_GYRO_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + smi130_gyro_delay(SMI_GYRO_I2C_WRITE_DELAY_TIME); + } + + if (SMI_GYRO_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + + return 0; +#endif +} + +#ifdef SMI_GYRO_USE_FIFO +static int smi_gyro_i2c_burst_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u16 len) +{ + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < SMI_GYRO_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + smi130_gyro_delay(SMI_GYRO_I2C_WRITE_DELAY_TIME); + } + + if (SMI_GYRO_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + + return 0; +} +#endif + +/*i2c write routine for */ +static int smi_gyro_i2c_write(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ +#if !defined SMI_GYRO_USE_BASIC_I2C_FUNC + s32 dummy; + +#ifndef SMI_GYRO_SMBUS + u8 buffer[2]; +#endif + + if (NULL == client) + return -ENODEV; + + while (0 != len--) { +#ifdef SMI_GYRO_SMBUS + dummy = i2c_smbus_write_byte_data(client, reg_addr, *data); +#else + buffer[0] = reg_addr; + buffer[1] = *data; + dummy = i2c_master_send(client, (char *)buffer, 2); +#endif + reg_addr++; + data++; + if (dummy < 0) { + dev_err(&client->dev, "error writing i2c bus"); + return -EIO; + } + + } + return 0; +#else + u8 buffer[2]; + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buffer, + }, + }; + + while (0 != len--) { + buffer[0] = reg_addr; + buffer[1] = *data; + for (retry = 0; retry < SMI_GYRO_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, + ARRAY_SIZE(msg)) > 0) { + break; + } else { + smi130_gyro_delay(SMI_GYRO_I2C_WRITE_DELAY_TIME); + } + } + if (SMI_GYRO_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + reg_addr++; + data++; + } + + return 0; +#endif +} + +static int smi_gyro_i2c_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + int err; + err = smi_gyro_i2c_read(smi_gyro_client, reg_addr, data, len); + return err; +} + +static int smi_gyro_i2c_write_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + int err; + err = smi_gyro_i2c_write(smi_gyro_client, reg_addr, data, len); + return err; +} + + +static void smi_gyro_work_func(struct work_struct *work) +{ + struct smi_gyro_client_data *client_data = + container_of((struct delayed_work *)work, + struct smi_gyro_client_data, work); + + unsigned long delay = + msecs_to_jiffies(atomic_read(&client_data->delay)); + struct smi130_gyro_data_t gyro_data; + + SMI_GYRO_CALL_API(get_dataXYZ)(&gyro_data); + /*remapping for SMI130_GYRO sensor*/ + smi130_gyro_remap_sensor_data(&gyro_data, client_data); + + input_report_abs(client_data->input, ABS_X, gyro_data.datax); + input_report_abs(client_data->input, ABS_Y, gyro_data.datay); + input_report_abs(client_data->input, ABS_Z, gyro_data.dataz); + input_sync(client_data->input); + + schedule_delayed_work(&client_data->work, delay); +} + +static struct workqueue_struct *reportdata_wq; + +uint64_t smi130_gyro_get_alarm_timestamp(void) +{ + uint64_t ts_ap; + struct timespec tmp_time; + get_monotonic_boottime(&tmp_time); + ts_ap = (uint64_t)tmp_time.tv_sec * 1000000000 + tmp_time.tv_nsec; + return ts_ap; +} +#define ABS(x) ((x) > 0 ? (x) : -(x)) + +static void smi130_gyro_work_func(struct work_struct *work) +{ + struct smi_gyro_client_data *smi130_gyro = + container_of(work, + struct smi_gyro_client_data, report_data_work); + int i; + struct smi130_gyro_data_t gyro_lsb; + unsigned char fifo_framecount; + signed char fifo_data_out[MAX_FIFO_F_LEVEL * MAX_FIFO_F_BYTES] = {0}; + unsigned char f_len = 0; + uint64_t del; + uint64_t time_internal; + struct timespec ts; + int64_t drift_time = 0; + static uint64_t time_odr; + static uint32_t data_cnt; + static uint32_t pre_data_cnt; + static int64_t sample_drift_offset; + if (smi130_gyro->fifo_datasel) + /*Select one axis data output for every fifo frame*/ + f_len = 2; + else + /*Select X Y Z axis data output for every fifo frame*/ + f_len = 6; + if (SMI_GYRO_CALL_API(get_fifo_framecount)(&fifo_framecount) < 0) { + PERR("bm160_get_fifo_framecount err\n"); + return; + } + if (fifo_framecount == 0) + return; + if (fifo_framecount > MAX_FIFO_F_LEVEL) + fifo_framecount = MAX_FIFO_F_LEVEL; + if (smi_gyro_i2c_burst_read(smi130_gyro->client, SMI130_GYRO_FIFO_DATA_ADDR, + fifo_data_out, fifo_framecount * f_len) < 0) { + PERR("smi130_gyro read fifo err\n"); + return; + } + smi130_gyro->fifo_time = smi130_gyro_get_alarm_timestamp(); + if (smi130_gyro->gyro_count == 0) + smi130_gyro->base_time = smi130_gyro->timestamp = + smi130_gyro->fifo_time - (fifo_framecount-1) * smi130_gyro->time_odr; + + smi130_gyro->gyro_count += fifo_framecount; + del = smi130_gyro->fifo_time - smi130_gyro->base_time; + time_internal = div64_u64(del, smi130_gyro->gyro_count); + data_cnt++; + if (data_cnt == 1) + time_odr = smi130_gyro->time_odr; + if (time_internal > time_odr) { + if (time_internal - time_odr > div64_u64 (time_odr, 200)) + time_internal = time_odr + div64_u64(time_odr, 200); + } else { + if (time_odr - time_internal > div64_u64(time_odr, 200)) + time_internal = time_odr - div64_u64(time_odr, 200); + } + + /* Select X Y Z axis data output for every frame */ + for (i = 0; i < fifo_framecount; i++) { + if (smi130_gyro->debug_level & 0x01) + printk(KERN_INFO "smi_gyro time =%llu fifo_time = %llu time_internal = %llu smi_gyro->count= %llu count = %d", + smi130_gyro->timestamp, smi130_gyro->fifo_time, + time_internal, smi130_gyro->gyro_count, fifo_framecount); + ts = ns_to_timespec(smi130_gyro->timestamp); + gyro_lsb.datax = + ((unsigned char)fifo_data_out[i * f_len + 1] << 8 + | (unsigned char)fifo_data_out[i * f_len + 0]); + gyro_lsb.datay = + ((unsigned char)fifo_data_out[i * f_len + 3] << 8 + | (unsigned char)fifo_data_out[i * f_len + 2]); + gyro_lsb.dataz = + ((unsigned char)fifo_data_out[i * f_len + 5] << 8 + | (unsigned char)fifo_data_out[i * f_len + 4]); + smi130_gyro_remap_sensor_data(&gyro_lsb, smi130_gyro); + input_event(smi130_gyro->input, EV_MSC, MSC_TIME, + ts.tv_sec); + input_event(smi130_gyro->input, EV_MSC, MSC_TIME, + ts.tv_nsec); + input_event(smi130_gyro->input, EV_MSC, + MSC_GESTURE, gyro_lsb.datax); + input_event(smi130_gyro->input, EV_MSC, + MSC_RAW, gyro_lsb.datay); + input_event(smi130_gyro->input, EV_MSC, + MSC_SCAN, gyro_lsb.dataz); + input_sync(smi130_gyro->input); + smi130_gyro->timestamp += time_internal - sample_drift_offset; + } + drift_time = smi130_gyro->timestamp - smi130_gyro->fifo_time; + if (data_cnt % 20 == 0) { + if (ABS(drift_time) > div64_u64(time_odr, 5)) { + sample_drift_offset = + div64_s64(drift_time, smi130_gyro->gyro_count - pre_data_cnt); + pre_data_cnt = smi130_gyro->gyro_count; + time_odr = time_internal; + } + } +} + + +static enum hrtimer_restart reportdata_timer_fun( + struct hrtimer *hrtimer) +{ + struct smi_gyro_client_data *client_data = + container_of(hrtimer, struct smi_gyro_client_data, timer); + int32_t delay = 0; + delay = 10; + queue_work(reportdata_wq, &(client_data->report_data_work)); + client_data->work_delay_kt = ns_to_ktime(delay*1000000); + hrtimer_forward(hrtimer, ktime_get(), client_data->work_delay_kt); + + return HRTIMER_RESTART; +} + +static ssize_t smi_gyro_show_enable_timer(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 16, "%d\n", client_data->is_timer_running); +} + +static ssize_t smi_gyro_store_enable_timer(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (data) { + if (0 == client_data->is_timer_running) { + hrtimer_start(&client_data->timer, + ns_to_ktime(10000000), + HRTIMER_MODE_REL); + client_data->is_timer_running = 1; + client_data->base_time = 0; + client_data->timestamp = 0; + client_data->gyro_count = 0; + } + } else { + if (1 == client_data->is_timer_running) { + hrtimer_cancel(&client_data->timer); + client_data->is_timer_running = 0; + client_data->base_time = 0; + client_data->timestamp = 0; + client_data->gyro_count = 0; + } + } + return count; +} + +static ssize_t smi130_gyro_show_debug_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + err = snprintf(buf, 8, "%d\n", client_data->debug_level); + return err; +} +static ssize_t smi130_gyro_store_debug_level(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int32_t ret = 0; + unsigned long data; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + ret = kstrtoul(buf, 16, &data); + if (ret) + return ret; + client_data->debug_level = (uint8_t)data; + return count; +} + +static int smi_gyro_set_soft_reset(struct i2c_client *client) +{ + int err = 0; + unsigned char data = SMI_GYRO_SOFT_RESET_VALUE; + err = smi_gyro_i2c_write(client, SMI130_GYRO_BGW_SOFTRESET_ADDR, &data, 1); + return err; +} + +static ssize_t smi_gyro_show_chip_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 16, "%d\n", SENSOR_CHIP_ID_SMI_GYRO); +} + +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static inline int smi130_check_gyro_early_buff_enable_flag( + struct smi_gyro_client_data *client_data) +{ + if (client_data->gyro_buffer_smi130_samples == true) + return 1; + else + return 0; +} +#else +static inline int smi130_check_gyro_early_buff_enable_flag( + struct smi_gyro_client_data *client_data) +{ + return 0; +} +#endif + +static ssize_t smi_gyro_show_op_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + u8 op_mode = 0xff; + + mutex_lock(&client_data->mutex_op_mode); + SMI_GYRO_CALL_API(get_mode)(&op_mode); + mutex_unlock(&client_data->mutex_op_mode); + + ret = snprintf(buf, 16, "%d\n", op_mode); + + return ret; +} + +static ssize_t smi_gyro_store_op_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + long op_mode; + + err = smi130_check_gyro_early_buff_enable_flag(client_data); + if (err) + return count; + + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + mutex_lock(&client_data->mutex_op_mode); + + err = SMI_GYRO_CALL_API(set_mode)(op_mode); + + mutex_unlock(&client_data->mutex_op_mode); + + if (err) + return err; + else + return count; +} + + + +static ssize_t smi_gyro_show_value(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + int count; + + struct smi130_gyro_data_t value_data; + SMI_GYRO_CALL_API(get_dataXYZ)(&value_data); + /*SMI130_GYRO sensor raw data remapping*/ + smi130_gyro_remap_sensor_data(&value_data, client_data); + + count = snprintf(buf, 96, "%hd %hd %hd\n", + value_data.datax, + value_data.datay, + value_data.dataz); + + return count; +} + +static ssize_t smi_gyro_show_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char range = 0; + SMI_GYRO_CALL_API(get_range_reg)(&range); + err = snprintf(buf, 16, "%d\n", range); + return err; +} + +static ssize_t smi_gyro_store_range(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long range; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + err = smi130_check_gyro_early_buff_enable_flag(client_data); + if (err) + return count; + + err = kstrtoul(buf, 10, &range); + if (err) + return err; + SMI_GYRO_CALL_API(set_range_reg)(range); + return count; +} + +/* +decimation odr filter bandwidth bits +20 100HZ 32HZ 7 +10 200Hz 64HZ 6 +20 100HZ 12HZ 5 +10 200hz 23HZ 4 +5 400HZ 47HZ 3 +2 1000HZ 116HZ 2 +0 2000HZ 230HZ 1 +0 2000HZ Unfiltered(523HZ) 0 +*/ + +static const uint64_t odr_map[8] = { +500000, 500000, 1000000, 2500000, 5000000, 10000000, 5000000, 10000000}; + +static ssize_t smi_gyro_show_bandwidth(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char bandwidth = 0; + SMI_GYRO_CALL_API(get_bw)(&bandwidth); + err = snprintf(buf, 16, "%d\n", bandwidth); + return err; +} + +static ssize_t smi_gyro_store_bandwidth(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + unsigned long bandwidth; + u8 op_mode = 0xff; + + err = smi130_check_gyro_early_buff_enable_flag(client_data); + if (err) + return count; + + err = kstrtoul(buf, 10, &bandwidth); + if (err) + return err; + /* + set bandwidth only in the op_mode=0 + */ + err = SMI_GYRO_CALL_API(get_mode)(&op_mode); + if (op_mode == 0) { + err += SMI_GYRO_CALL_API(set_bw)(bandwidth); + } else { + err += SMI_GYRO_CALL_API(set_mode)(0); + err += SMI_GYRO_CALL_API(set_bw)(bandwidth); + smi130_gyro_delay(1); + err += SMI_GYRO_CALL_API(set_mode)(2); + smi130_gyro_delay(3); + } + + if (err) + PERR("set failed"); + client_data->time_odr = odr_map[bandwidth]; + client_data->base_time = 0; + client_data->gyro_count = 0; + return count; +} + + +static ssize_t smi_gyro_show_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + int err; + + mutex_lock(&client_data->mutex_enable); + err = snprintf(buf, 16, "%d\n", client_data->enable); + mutex_unlock(&client_data->mutex_enable); + return err; +} + +static ssize_t smi_gyro_store_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + data = data ? 1 : 0; + mutex_lock(&client_data->mutex_enable); + if (data != client_data->enable) { + if (data) { + schedule_delayed_work( + &client_data->work, + msecs_to_jiffies(atomic_read( + &client_data->delay))); + } else { + cancel_delayed_work_sync(&client_data->work); + } + + client_data->enable = data; + } + mutex_unlock(&client_data->mutex_enable); + + return count; +} + +static ssize_t smi_gyro_show_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 16, "%d\n", atomic_read(&client_data->delay)); + +} + +static ssize_t smi_gyro_store_delay(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + if (data == 0) { + err = -EINVAL; + return err; + } + + if (data < SMI_GYRO_DELAY_MIN) + data = SMI_GYRO_DELAY_MIN; + + atomic_set(&client_data->delay, data); + + return count; +} + + +static ssize_t smi_gyro_store_fastoffset_en(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long fastoffset_en; + err = kstrtoul(buf, 10, &fastoffset_en); + if (err) + return err; + if (fastoffset_en) { + +#ifdef CONFIG_SENSORS_BMI058 + SMI_GYRO_CALL_API(set_fast_offset_en_ch)(BMI058_X_AXIS, 1); + SMI_GYRO_CALL_API(set_fast_offset_en_ch)(BMI058_Y_AXIS, 1); +#else + SMI_GYRO_CALL_API(set_fast_offset_en_ch)(SMI130_GYRO_X_AXIS, 1); + SMI_GYRO_CALL_API(set_fast_offset_en_ch)(SMI130_GYRO_Y_AXIS, 1); +#endif + + SMI_GYRO_CALL_API(set_fast_offset_en_ch)(SMI130_GYRO_Z_AXIS, 1); + SMI_GYRO_CALL_API(enable_fast_offset)(); + } + return count; +} + +static ssize_t smi_gyro_store_slowoffset_en(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long slowoffset_en; + err = kstrtoul(buf, 10, &slowoffset_en); + if (err) + return err; + if (slowoffset_en) { + SMI_GYRO_CALL_API(set_slow_offset_th)(3); + SMI_GYRO_CALL_API(set_slow_offset_dur)(0); +#ifdef CONFIG_SENSORS_BMI058 + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(BMI058_X_AXIS, 1); + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(BMI058_Y_AXIS, 1); +#else + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(SMI130_GYRO_X_AXIS, 1); + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(SMI130_GYRO_Y_AXIS, 1); +#endif + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(SMI130_GYRO_Z_AXIS, 1); + } else { +#ifdef CONFIG_SENSORS_BMI058 + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(BMI058_X_AXIS, 0); + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(BMI058_Y_AXIS, 0); +#else + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(SMI130_GYRO_X_AXIS, 0); + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(SMI130_GYRO_Y_AXIS, 0); +#endif + SMI_GYRO_CALL_API(set_slow_offset_en_ch)(SMI130_GYRO_Z_AXIS, 0); + } + + return count; +} + +static ssize_t smi_gyro_show_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char selftest; + SMI_GYRO_CALL_API(selftest)(&selftest); + err = snprintf(buf, 16, "%d\n", selftest); + return err; +} + +static ssize_t smi_gyro_show_sleepdur(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char sleepdur; + SMI_GYRO_CALL_API(get_sleepdur)(&sleepdur); + err = snprintf(buf, 16, "%d\n", sleepdur); + return err; +} + +static ssize_t smi_gyro_store_sleepdur(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long sleepdur; + err = kstrtoul(buf, 10, &sleepdur); + if (err) + return err; + SMI_GYRO_CALL_API(set_sleepdur)(sleepdur); + return count; +} + +static ssize_t smi_gyro_show_autosleepdur(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char autosleepdur; + SMI_GYRO_CALL_API(get_autosleepdur)(&autosleepdur); + err = snprintf(buf, 16, "%d\n", autosleepdur); + return err; +} + +static ssize_t smi_gyro_store_autosleepdur(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long autosleepdur; + unsigned char bandwidth; + err = kstrtoul(buf, 10, &autosleepdur); + if (err) + return err; + SMI_GYRO_CALL_API(get_bw)(&bandwidth); + SMI_GYRO_CALL_API(set_autosleepdur)(autosleepdur, bandwidth); + return count; +} + +static ssize_t smi_gyro_show_place(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + int place = BOSCH_SENSOR_PLACE_UNKNOWN; + + if (NULL != client_data->bosch_pd) + place = client_data->bosch_pd->place; + + return snprintf(buf, 16, "%d\n", place); +} + + +#ifdef SMI_GYRO_DEBUG +static ssize_t smi_gyro_store_softreset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long softreset; + err = kstrtoul(buf, 10, &softreset); + if (err) + return err; + SMI_GYRO_CALL_API(set_soft_reset)(); + return count; +} + +static ssize_t smi_gyro_show_dumpreg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count = 0; + u8 reg[0x40]; + int i; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + for (i = 0; i < 0x40; i++) { + smi_gyro_i2c_read(client_data->client, i, reg+i, 1); + + count += snprintf(&buf[count], 48, "0x%x: 0x%x\n", i, reg[i]); + } + return count; +} +#endif + +#ifdef SMI_GYRO_USE_FIFO +static ssize_t smi_gyro_show_fifo_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char fifo_mode; + SMI_GYRO_CALL_API(get_fifo_mode)(&fifo_mode); + err = snprintf(buf, 16, "%d\n", fifo_mode); + return err; +} + +static ssize_t smi_gyro_store_fifo_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long fifo_mode; + err = kstrtoul(buf, 10, &fifo_mode); + if (err) + return err; + SMI_GYRO_CALL_API(set_fifo_mode)(fifo_mode); + return count; +} + +static ssize_t smi_gyro_show_fifo_framecount(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char fifo_framecount; + SMI_GYRO_CALL_API(get_fifo_framecount)(&fifo_framecount); + err = snprintf(buf, 32, "%d\n", fifo_framecount); + return err; +} + +static ssize_t smi_gyro_store_fifo_framecount(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + error = kstrtoul(buf, 10, &data); + if (error) + return error; + client_data->fifo_count = (unsigned int) data; + + return count; +} + +static ssize_t smi_gyro_show_fifo_overrun(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char fifo_overrun; + SMI_GYRO_CALL_API(get_fifo_overrun)(&fifo_overrun); + err = snprintf(buf, 16, "%d\n", fifo_overrun); + return err; +} + +static ssize_t smi_gyro_show_fifo_data_frame(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char f_len = 0; + unsigned char fifo_framecount; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + if (client_data->fifo_datasel) + /*Select one axis data output for every fifo frame*/ + f_len = 2; + else + /*Select X Y Z axis data output for every fifo frame*/ + f_len = 6; + + if (SMI_GYRO_CALL_API(get_fifo_framecount)(&fifo_framecount) < 0) { + PERR("bm160_get_fifo_framecount err\n"); + return -EINVAL; + } + if (fifo_framecount == 0) + return 0; + + smi_gyro_i2c_burst_read(client_data->client, SMI130_GYRO_FIFO_DATA_ADDR, + buf, fifo_framecount * f_len); + return fifo_framecount * f_len; +} + +/*! + * @brief show fifo_data_sel axis definition(Android definition, not sensor HW reg). + * 0--> x, y, z axis fifo data for every frame + * 1--> only x axis fifo data for every frame + * 2--> only y axis fifo data for every frame + * 3--> only z axis fifo data for every frame + */ +static ssize_t smi_gyro_show_fifo_data_sel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char fifo_data_sel; + struct i2c_client *client = to_i2c_client(dev); + struct smi_gyro_client_data *client_data = i2c_get_clientdata(client); + signed char place = BOSCH_SENSOR_PLACE_UNKNOWN; + + SMI_GYRO_CALL_API(get_fifo_data_sel)(&fifo_data_sel); + + /*remapping fifo_dat_sel if define virtual place in BSP files*/ + if ((NULL != client_data->bosch_pd) && + (BOSCH_SENSOR_PLACE_UNKNOWN != client_data->bosch_pd->place)) { + place = client_data->bosch_pd->place; + /* sensor with place 0 needs not to be remapped */ + if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { + if (SMI130_GYRO_FIFO_DAT_SEL_X == fifo_data_sel) + /* SMI130_GYRO_FIFO_DAT_SEL_X: 1, Y:2, Z:3; + *bosch_axis_remap_tab_dft[i].src_x:0, y:1, z:2 + *so we need to +1*/ + fifo_data_sel = + bosch_axis_remap_tab_dft[place].src_x + 1; + + else if (SMI130_GYRO_FIFO_DAT_SEL_Y == fifo_data_sel) + fifo_data_sel = + bosch_axis_remap_tab_dft[place].src_y + 1; + } + + } + + err = snprintf(buf, 16, "%d\n", fifo_data_sel); + return err; +} + +/*! + * @brief store fifo_data_sel axis definition(Android definition, not sensor HW reg). + * 0--> x, y, z axis fifo data for every frame + * 1--> only x axis fifo data for every frame + * 2--> only y axis fifo data for every frame + * 3--> only z axis fifo data for every frame + */ +static ssize_t smi_gyro_store_fifo_data_sel(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + +{ + int err; + unsigned long fifo_data_sel; + + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + signed char place; + + err = kstrtoul(buf, 10, &fifo_data_sel); + if (err) + return err; + + /*save fifo_data_sel(android axis definition)*/ + client_data->fifo_datasel = (unsigned char) fifo_data_sel; + + /*remaping fifo_dat_sel if define virtual place*/ + if ((NULL != client_data->bosch_pd) && + (BOSCH_SENSOR_PLACE_UNKNOWN != client_data->bosch_pd->place)) { + place = client_data->bosch_pd->place; + /* sensor with place 0 needs not to be remapped */ + if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { + /*Need X Y axis revesal sensor place: P1, P3, P5, P7 */ + /* SMI130_GYRO_FIFO_DAT_SEL_X: 1, Y:2, Z:3; + * but bosch_axis_remap_tab_dft[i].src_x:0, y:1, z:2 + * so we need to +1*/ + if (SMI130_GYRO_FIFO_DAT_SEL_X == fifo_data_sel) + fifo_data_sel = + bosch_axis_remap_tab_dft[place].src_x + 1; + + else if (SMI130_GYRO_FIFO_DAT_SEL_Y == fifo_data_sel) + fifo_data_sel = + bosch_axis_remap_tab_dft[place].src_y + 1; + } + } + + if (SMI_GYRO_CALL_API(set_fifo_data_sel)(fifo_data_sel) < 0) + return -EINVAL; + + return count; +} + +static ssize_t smi_gyro_show_fifo_tag(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char fifo_tag; + SMI_GYRO_CALL_API(get_fifo_tag)(&fifo_tag); + err = snprintf(buf, 16, "%d\n", fifo_tag); + return err; +} + +static ssize_t smi_gyro_store_fifo_tag(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + +{ + int err; + unsigned long fifo_tag; + err = kstrtoul(buf, 10, &fifo_tag); + if (err) + return err; + SMI_GYRO_CALL_API(set_fifo_tag)(fifo_tag); + return count; +} +#endif + +static ssize_t smi130_gyro_driver_version_show(struct device *dev + , struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + int ret; + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + + ret = snprintf(buf, 128, "Driver version: %s\n", + DRIVER_VERSION); + return ret; +} + +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static int smi_gyro_read_bootsampl(struct smi_gyro_client_data *client_data, + unsigned long enable_read) +{ + int i = 0; + + if (enable_read) { + client_data->gyro_buffer_smi130_samples = false; + for (i = 0; i < client_data->gyro_bufsample_cnt; i++) { + if (client_data->debug_level & 0x08) + PINFO("gyro=%d,x=%d,y=%d,z=%d,sec=%d,ns=%lld\n", + i, client_data->smi130_gyro_samplist[i]->xyz[0], + client_data->smi130_gyro_samplist[i]->xyz[1], + client_data->smi130_gyro_samplist[i]->xyz[2], + client_data->smi130_gyro_samplist[i]->tsec, + client_data->smi130_gyro_samplist[i]->tnsec); + input_report_abs(client_data->gyrobuf_dev, ABS_X, + client_data->smi130_gyro_samplist[i]->xyz[0]); + input_report_abs(client_data->gyrobuf_dev, ABS_Y, + client_data->smi130_gyro_samplist[i]->xyz[1]); + input_report_abs(client_data->gyrobuf_dev, ABS_Z, + client_data->smi130_gyro_samplist[i]->xyz[2]); + input_report_abs(client_data->gyrobuf_dev, ABS_RX, + client_data->smi130_gyro_samplist[i]->tsec); + input_report_abs(client_data->gyrobuf_dev, ABS_RY, + client_data->smi130_gyro_samplist[i]->tnsec); + input_sync(client_data->gyrobuf_dev); + } + } else { + /* clean up */ + if (client_data->gyro_bufsample_cnt != 0) { + for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++) + kmem_cache_free(client_data->smi_gyro_cachepool, + client_data->smi130_gyro_samplist[i]); + kmem_cache_destroy(client_data->smi_gyro_cachepool); + client_data->gyro_bufsample_cnt = 0; + } + + } + /*SYN_CONFIG indicates end of data*/ + input_event(client_data->gyrobuf_dev, EV_SYN, SYN_CONFIG, 0xFFFFFFFF); + input_sync(client_data->gyrobuf_dev); + if (client_data->debug_level & 0x08) + PINFO("End of gyro samples bufsample_cnt=%d\n", + client_data->gyro_bufsample_cnt); + return 0; +} +static ssize_t read_gyro_boot_sample_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 16, "%u\n", + client_data->read_gyro_boot_sample); +} +static ssize_t read_gyro_boot_sample_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct smi_gyro_client_data *client_data = input_get_drvdata(input); + unsigned long enable = 0; + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable > 1) { + PERR("Invalid value of input, input=%ld\n", enable); + return -EINVAL; + } + err = smi_gyro_read_bootsampl(client_data, enable); + if (err) + return err; + client_data->read_gyro_boot_sample = enable; + + return count; +} +#endif + + +static DEVICE_ATTR(chip_id, S_IRUSR, + smi_gyro_show_chip_id, NULL); +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static DEVICE_ATTR(read_gyro_boot_sample, S_IRUGO | S_IWUSR, + read_gyro_boot_sample_show, read_gyro_boot_sample_store); +#endif +static DEVICE_ATTR(op_mode, S_IRUGO | S_IWUSR, + smi_gyro_show_op_mode, smi_gyro_store_op_mode); +static DEVICE_ATTR(value, S_IRUSR, + smi_gyro_show_value, NULL); +static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, + smi_gyro_show_range, smi_gyro_store_range); +static DEVICE_ATTR(bandwidth, S_IRUGO | S_IWUSR, + smi_gyro_show_bandwidth, smi_gyro_store_bandwidth); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, + smi_gyro_show_enable, smi_gyro_store_enable); +static DEVICE_ATTR(delay, S_IRUGO | S_IWUSR, + smi_gyro_show_delay, smi_gyro_store_delay); +static DEVICE_ATTR(fastoffset_en, S_IWUSR, + NULL, smi_gyro_store_fastoffset_en); +static DEVICE_ATTR(slowoffset_en, S_IWUSR, + NULL, smi_gyro_store_slowoffset_en); +static DEVICE_ATTR(selftest, S_IRUGO, + smi_gyro_show_selftest, NULL); +static DEVICE_ATTR(sleepdur, S_IRUGO | S_IWUSR, + smi_gyro_show_sleepdur, smi_gyro_store_sleepdur); +static DEVICE_ATTR(autosleepdur, S_IRUGO | S_IWUSR, + smi_gyro_show_autosleepdur, smi_gyro_store_autosleepdur); +static DEVICE_ATTR(place, S_IRUSR, + smi_gyro_show_place, NULL); +static DEVICE_ATTR(enable_timer, S_IRUGO | S_IWUSR, + smi_gyro_show_enable_timer, smi_gyro_store_enable_timer); +static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR, + smi130_gyro_show_debug_level, smi130_gyro_store_debug_level); +static DEVICE_ATTR(driver_version, S_IRUSR, + smi130_gyro_driver_version_show, NULL); +#ifdef SMI_GYRO_DEBUG +static DEVICE_ATTR(softreset, S_IWUSR, + NULL, smi_gyro_store_softreset); +static DEVICE_ATTR(regdump, S_IRUSR, + smi_gyro_show_dumpreg, NULL); +#endif +#ifdef SMI_GYRO_USE_FIFO +static DEVICE_ATTR(fifo_mode, S_IRUGO | S_IWUSR, + smi_gyro_show_fifo_mode, smi_gyro_store_fifo_mode); +static DEVICE_ATTR(fifo_framecount, S_IRUGO | S_IWUSR, + smi_gyro_show_fifo_framecount, smi_gyro_store_fifo_framecount); +static DEVICE_ATTR(fifo_overrun, S_IRUGO, + smi_gyro_show_fifo_overrun, NULL); +static DEVICE_ATTR(fifo_data_frame, S_IRUSR, + smi_gyro_show_fifo_data_frame, NULL); +static DEVICE_ATTR(fifo_data_sel, S_IRUGO | S_IWUSR, + smi_gyro_show_fifo_data_sel, smi_gyro_store_fifo_data_sel); +static DEVICE_ATTR(fifo_tag, S_IRUGO | S_IWUSR, + smi_gyro_show_fifo_tag, smi_gyro_store_fifo_tag); +#endif + +static struct attribute *smi_gyro_attributes[] = { + &dev_attr_chip_id.attr, +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING + &dev_attr_read_gyro_boot_sample.attr, +#endif + &dev_attr_op_mode.attr, + &dev_attr_value.attr, + &dev_attr_range.attr, + &dev_attr_bandwidth.attr, + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_fastoffset_en.attr, + &dev_attr_slowoffset_en.attr, + &dev_attr_selftest.attr, + &dev_attr_sleepdur.attr, + &dev_attr_autosleepdur.attr, + &dev_attr_place.attr, + &dev_attr_enable_timer.attr, + &dev_attr_debug_level.attr, + &dev_attr_driver_version.attr, +#ifdef SMI_GYRO_DEBUG + &dev_attr_softreset.attr, + &dev_attr_regdump.attr, +#endif +#ifdef SMI_GYRO_USE_FIFO + &dev_attr_fifo_mode.attr, + &dev_attr_fifo_framecount.attr, + &dev_attr_fifo_overrun.attr, + &dev_attr_fifo_data_frame.attr, + &dev_attr_fifo_data_sel.attr, + &dev_attr_fifo_tag.attr, +#endif + NULL +}; + +static struct attribute_group smi_gyro_attribute_group = { + .attrs = smi_gyro_attributes +}; + + +static int smi_gyro_input_init(struct smi_gyro_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = input_allocate_device(); + if (NULL == dev) + return -ENOMEM; + + dev->name = SENSOR_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_X, SMI_GYRO_VALUE_MIN, SMI_GYRO_VALUE_MAX, 0, 0); + input_set_abs_params(dev, ABS_Y, SMI_GYRO_VALUE_MIN, SMI_GYRO_VALUE_MAX, 0, 0); + input_set_abs_params(dev, ABS_Z, SMI_GYRO_VALUE_MIN, SMI_GYRO_VALUE_MAX, 0, 0); + input_set_capability(dev, EV_MSC, MSC_GESTURE); + input_set_capability(dev, EV_MSC, MSC_RAW); + input_set_capability(dev, EV_MSC, MSC_SCAN); + input_set_capability(dev, EV_MSC, MSC_TIME); + input_set_drvdata(dev, client_data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + client_data->input = dev; + + return 0; +} + +static void smi_gyro_input_destroy(struct smi_gyro_client_data *client_data) +{ + struct input_dev *dev = client_data->input; + + input_unregister_device(dev); + input_free_device(dev); +} +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static void store_gyro_boot_sample(struct smi_gyro_client_data *client_data, + int x, int y, int z, struct timespec ts) +{ + if (false == client_data->gyro_buffer_smi130_samples) + return; + if (ts.tv_sec < client_data->max_buffer_time) { + if (client_data->gyro_bufsample_cnt < SMI_GYRO_MAXSAMPLE) { + client_data->smi130_gyro_samplist[client_data-> + gyro_bufsample_cnt]->xyz[0] = x; + client_data->smi130_gyro_samplist[client_data-> + gyro_bufsample_cnt]->xyz[1] = y; + client_data->smi130_gyro_samplist[client_data-> + gyro_bufsample_cnt]->xyz[2] = z; + client_data->smi130_gyro_samplist[client_data-> + gyro_bufsample_cnt]->tsec = ts.tv_sec; + client_data->smi130_gyro_samplist[client_data-> + gyro_bufsample_cnt]->tnsec = ts.tv_nsec; + client_data->gyro_bufsample_cnt++; + } + } else { + PINFO("End of GYRO buffering %d", + client_data->gyro_bufsample_cnt); + client_data->gyro_buffer_smi130_samples = false; + } +} +#else +static void store_gyro_boot_sample(struct smi_gyro_client_data *client_data, + int x, int y, int z, struct timespec ts) +{ +} +#endif + + +#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING +static int smi130_gyro_early_buff_init(struct smi_gyro_client_data *client_data) +{ + int i = 0, err = 0; + + client_data->gyro_bufsample_cnt = 0; + client_data->report_evt_cnt = 5; + client_data->max_buffer_time = 40; + + client_data->smi_gyro_cachepool = kmem_cache_create("gyro_sensor_sample" + , sizeof(struct smi_gyro_sample), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!client_data->smi_gyro_cachepool) { + PERR("smi_gyro_cachepool cache create failed\n"); + err = -ENOMEM; + return 0; + } + + for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++) { + client_data->smi130_gyro_samplist[i] = + kmem_cache_alloc(client_data->smi_gyro_cachepool, + GFP_KERNEL); + if (!client_data->smi130_gyro_samplist[i]) { + err = -ENOMEM; + goto clean_exit1; + } + } + + + client_data->gyrobuf_dev = input_allocate_device(); + if (!client_data->gyrobuf_dev) { + err = -ENOMEM; + PERR("input device allocation failed\n"); + goto clean_exit1; + } + client_data->gyrobuf_dev->name = "smi130_gyrobuf"; + client_data->gyrobuf_dev->id.bustype = BUS_I2C; + input_set_events_per_packet(client_data->gyrobuf_dev, + client_data->report_evt_cnt * SMI_GYRO_MAXSAMPLE); + set_bit(EV_ABS, client_data->gyrobuf_dev->evbit); + input_set_abs_params(client_data->gyrobuf_dev, ABS_X, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->gyrobuf_dev, ABS_Y, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->gyrobuf_dev, ABS_Z, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->gyrobuf_dev, ABS_RX, + -G_MAX, G_MAX, 0, 0); + input_set_abs_params(client_data->gyrobuf_dev, ABS_RY, + -G_MAX, G_MAX, 0, 0); + err = input_register_device(client_data->gyrobuf_dev); + if (err) { + PERR("unable to register input device %s\n", + client_data->gyrobuf_dev->name); + goto clean_exit2; + } + + client_data->gyro_buffer_smi130_samples = true; + + smi130_gyro_set_mode(SMI130_GYRO_MODE_NORMAL); + smi130_gyro_delay(5); + + smi130_gyro_set_bw(5); + smi130_gyro_delay(5); + + smi130_gyro_set_range_reg(4); + smi130_gyro_delay(5); + + smi130_gyro_set_mode(SMI130_GYRO_MODE_NORMAL); + smi130_gyro_delay(5); + + smi130_gyro_set_range_reg(4); + smi130_gyro_delay(5); + + smi130_gyro_set_data_en(SMI130_GYRO_ENABLE); + + return 1; + +clean_exit2: + input_free_device(client_data->gyrobuf_dev); +clean_exit1: + for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++) + kmem_cache_free(client_data->smi_gyro_cachepool, + client_data->smi130_gyro_samplist[i]); + kmem_cache_destroy(client_data->smi_gyro_cachepool); + + return 0; +} + +static void smi130_gyro_input_cleanup(struct smi_gyro_client_data *client_data) +{ + int i = 0; + + input_unregister_device(client_data->gyrobuf_dev); + input_free_device(client_data->gyrobuf_dev); + for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++) + kmem_cache_free(client_data->smi_gyro_cachepool, + client_data->smi130_gyro_samplist[i]); + kmem_cache_destroy(client_data->smi_gyro_cachepool); +} + +static int smi130_enable_int1(void) +{ + return smi130_gyro_set_data_en(SMI130_GYRO_DISABLE); +} +#else +static int smi130_gyro_early_buff_init(struct smi_gyro_client_data *client_data) +{ + return 1; +} +static void smi130_gyro_input_cleanup(struct smi_gyro_client_data *client_data) +{ +} +static int smi130_enable_int1(void) +{ + return smi130_gyro_set_data_en(SMI130_GYRO_ENABLE); +} +#endif + + +#if defined(SMI130_GYRO_ENABLE_INT1) || defined(SMI130_GYRO_ENABLE_INT2) +static irqreturn_t smi130_gyro_irq_work_func(int irq, void *handle) +{ + struct smi_gyro_client_data *client_data = handle; + struct smi130_gyro_data_t gyro_data; + struct timespec ts; + ts = ns_to_timespec(client_data->timestamp); + + SMI_GYRO_CALL_API(get_dataXYZ)(&gyro_data); + /*remapping for SMI130_GYRO sensor*/ + smi130_gyro_remap_sensor_data(&gyro_data, client_data); + input_event(client_data->input, EV_MSC, MSC_TIME, + ts.tv_sec); + input_event(client_data->input, EV_MSC, MSC_TIME, + ts.tv_nsec); + input_event(client_data->input, EV_MSC, + MSC_GESTURE, gyro_data.datax); + input_event(client_data->input, EV_MSC, + MSC_RAW, gyro_data.datay); + input_event(client_data->input, EV_MSC, + MSC_SCAN, gyro_data.dataz); + input_sync(client_data->input); + store_gyro_boot_sample(client_data, gyro_data.datax, + gyro_data.datay, gyro_data.dataz, ts); + return IRQ_HANDLED; +} + +static irqreturn_t smi_gyro_irq_handler(int irq, void *handle) +{ + struct smi_gyro_client_data *client_data = handle; + client_data->timestamp= smi130_gyro_get_alarm_timestamp(); + return IRQ_WAKE_THREAD; +} +#endif +static int smi_gyro_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = 0; + struct smi_gyro_client_data *client_data = NULL; + PINFO("function entrance"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + PERR("i2c_check_functionality error!"); + err = -EIO; + goto exit_err_clean; + } + + if (NULL == smi_gyro_client) { + smi_gyro_client = client; + } else { + PERR("this driver does not support multiple clients"); + err = -EINVAL; + goto exit_err_clean; + } + + /* check chip id */ + err = smi_gyro_check_chip_id(client); + if (!err) { + PINFO("Bosch Sensortec Device %s detected", SENSOR_NAME); + } else { + PERR("Bosch Sensortec Device not found, chip id mismatch"); + err = -1; + goto exit_err_clean; + } + + /* do soft reset */ + smi130_gyro_delay(5); + err = smi_gyro_set_soft_reset(client); + if (err < 0) { + PERR("erro soft reset!\n"); + err = -EINVAL; + goto exit_err_clean; + } + smi130_gyro_delay(30); + + + client_data = kzalloc(sizeof(struct smi_gyro_client_data), GFP_KERNEL); + if (NULL == client_data) { + PERR("no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + i2c_set_clientdata(client, client_data); + client_data->client = client; + + mutex_init(&client_data->mutex_op_mode); + mutex_init(&client_data->mutex_enable); + + /* input device init */ + err = smi_gyro_input_init(client_data); + if (err < 0) + goto exit_err_clean; + + /* sysfs node creation */ + err = sysfs_create_group(&client_data->input->dev.kobj, + &smi_gyro_attribute_group); + + if (err < 0) + goto exit_err_sysfs; + + if (NULL != client->dev.platform_data) { + client_data->bosch_pd = kzalloc(sizeof(*client_data->bosch_pd), + GFP_KERNEL); + + if (NULL != client_data->bosch_pd) { + memcpy(client_data->bosch_pd, client->dev.platform_data, + sizeof(*client_data->bosch_pd)); + PINFO("%s sensor driver set place: p%d", + SENSOR_NAME, + client_data->bosch_pd->place); + } + } + + /* workqueue init */ + INIT_DELAYED_WORK(&client_data->work, smi_gyro_work_func); + atomic_set(&client_data->delay, SMI_GYRO_DELAY_DEFAULT); + + /* h/w init */ + client_data->device.bus_read = smi_gyro_i2c_read_wrapper; + client_data->device.bus_write = smi_gyro_i2c_write_wrapper; + client_data->device.delay_msec = smi130_gyro_delay; + SMI_GYRO_CALL_API(init)(&client_data->device); + + smi_gyro_dump_reg(client); + + client_data->enable = 0; + client_data->fifo_datasel = 0; + client_data->fifo_count = 0; + + /*workqueue init*/ + INIT_WORK(&client_data->report_data_work, + smi130_gyro_work_func); + reportdata_wq = create_singlethread_workqueue("smi130_gyro_wq"); + if (NULL == reportdata_wq) + PERR("fail to create the reportdta_wq %d", -ENOMEM); + hrtimer_init(&client_data->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + client_data->timer.function = reportdata_timer_fun; + client_data->work_delay_kt = ns_to_ktime(10000000); + client_data->is_timer_running = 0; + client_data->time_odr = 500000; +#ifdef SMI130_GYRO_ENABLE_INT1 + err = SMI_GYRO_CALL_API(set_mode)(SMI130_GYRO_MODE_NORMAL); + smi130_gyro_delay(5); + /*config the interrupt and map the interrupt*/ + /*high level trigger*/ + err += smi130_gyro_set_int_lvl(SMI130_GYRO_INT1_DATA, 1); + smi130_gyro_delay(5); + err += smi130_gyro_set_int_od(SMI130_GYRO_INT1, 0); + smi130_gyro_delay(5); + err += smi130_gyro_set_int_data(SMI130_GYRO_INT1_DATA, SMI130_GYRO_ENABLE); + smi130_gyro_delay(5); + err += smi130_enable_int1(); + smi130_gyro_delay(5); + /*default odr is 100HZ*/ + err += SMI_GYRO_CALL_API(set_bw)(7); + smi130_gyro_delay(5); + if (err) + PERR("config sensor data ready interrupt failed"); +#endif +#ifdef SMI130_GYRO_ENABLE_INT2 + err = SMI_GYRO_CALL_API(set_mode)(SMI130_GYRO_MODE_NORMAL); + /*config the interrupt and map the interrupt*/ + /*high level trigger*/ + err += smi130_gyro_set_int_lvl(SMI130_GYRO_INT2_DATA, 1); + smi130_gyro_delay(3); + err += smi130_gyro_set_int_od(SMI130_GYRO_INT2, 0); + smi130_gyro_delay(5); + err += smi130_gyro_set_int_data(SMI130_GYRO_INT2_DATA, SMI130_GYRO_ENABLE); + smi130_gyro_delay(3); + err += smi130_gyro_set_data_en(SMI130_GYRO_ENABLE); + /*default odr is 100HZ*/ + err += SMI_GYRO_CALL_API(set_bw)(7); + smi130_gyro_delay(5); + if (err) + PERR("config sensor data ready interrupt failed"); +#endif + err += SMI_GYRO_CALL_API(set_mode)( + SMI_GYRO_VAL_NAME(MODE_SUSPEND)); + if (err < 0) + goto exit_err_sysfs; +#ifdef CONFIG_HAS_EARLYSUSPEND + client_data->early_suspend_handler.suspend = smi_gyro_early_suspend; + client_data->early_suspend_handler.resume = smi_gyro_late_resume; + register_early_suspend(&client_data->early_suspend_handler); +#endif +#if defined(SMI130_GYRO_ENABLE_INT1) || defined(SMI130_GYRO_ENABLE_INT2) + client_data->gpio_pin = of_get_named_gpio_flags( + client->dev.of_node, + "smi130_gyro,gpio_irq", 0, NULL); + PDEBUG("smi130_gyro qpio number:%d\n", client_data->gpio_pin); + err = gpio_request_one(client_data->gpio_pin, + GPIOF_IN, "bm160_interrupt"); + if (err < 0) { + PDEBUG("requestgpio failed\n"); + client_data->gpio_pin = 0; + } + if (client_data->gpio_pin != 0) { + err = gpio_direction_input(client_data->gpio_pin); + if (err < 0) { + PDEBUG("request failed\n"); + } + client_data->IRQ = gpio_to_irq(client_data->gpio_pin); + err = request_threaded_irq(client_data->IRQ, + smi_gyro_irq_handler, smi130_gyro_irq_work_func, + IRQF_TRIGGER_RISING, SENSOR_NAME, client_data); + if (err < 0) + PDEBUG("request handle failed\n"); + } +#endif + + err = smi130_gyro_early_buff_init(client_data); + if (!err) + return err; + + PINFO("sensor %s probed successfully", SENSOR_NAME); + + dev_dbg(&client->dev, + "i2c_client: %p client_data: %p i2c_device: %p input: %p", + client, client_data, &client->dev, client_data->input); + + return 0; + +exit_err_sysfs: + if (err) + smi_gyro_input_destroy(client_data); + +exit_err_clean: + if (err) { + if (client_data != NULL) { + kfree(client_data); + client_data = NULL; + } + + smi_gyro_client = NULL; + } + + return err; +} + +static int smi_gyro_pre_suspend(struct i2c_client *client) +{ + int err = 0; + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)i2c_get_clientdata(client); + PINFO("function entrance"); + + mutex_lock(&client_data->mutex_enable); + if (client_data->enable) { + cancel_delayed_work_sync(&client_data->work); + PINFO("cancel work"); + } + mutex_unlock(&client_data->mutex_enable); + if (client_data->is_timer_running) { + hrtimer_cancel(&client_data->timer); + client_data->base_time = 0; + client_data->timestamp = 0; + client_data->fifo_time = 0; + client_data->gyro_count = 0; + } + return err; +} + +static int smi_gyro_post_resume(struct i2c_client *client) +{ + int err = 0; + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)i2c_get_clientdata(client); + + PINFO("function entrance"); + mutex_lock(&client_data->mutex_enable); + if (client_data->enable) { + schedule_delayed_work(&client_data->work, + msecs_to_jiffies( + atomic_read(&client_data->delay))); + } + mutex_unlock(&client_data->mutex_enable); + if (client_data->is_timer_running) { + hrtimer_start(&client_data->timer, + ns_to_ktime(client_data->time_odr), + HRTIMER_MODE_REL); + client_data->base_time = 0; + client_data->timestamp = 0; + client_data->is_timer_running = 1; + client_data->gyro_count = 0; + } + return err; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void smi_gyro_early_suspend(struct early_suspend *handler) +{ + int err = 0; + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)container_of(handler, + struct smi_gyro_client_data, early_suspend_handler); + struct i2c_client *client = client_data->client; + + PINFO("function entrance"); + + mutex_lock(&client_data->mutex_op_mode); + if (client_data->enable) { + err = smi_gyro_pre_suspend(client); + err = SMI_GYRO_CALL_API(set_mode)( + SMI_GYRO_VAL_NAME(MODE_SUSPEND)); + } + mutex_unlock(&client_data->mutex_op_mode); +} + +static void smi_gyro_late_resume(struct early_suspend *handler) +{ + + int err = 0; + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)container_of(handler, + struct smi_gyro_client_data, early_suspend_handler); + struct i2c_client *client = client_data->client; + + PINFO("function entrance"); + + mutex_lock(&client_data->mutex_op_mode); + + if (client_data->enable) + err = SMI_GYRO_CALL_API(set_mode)(SMI_GYRO_VAL_NAME(MODE_NORMAL)); + + /* post resume operation */ + smi_gyro_post_resume(client); + + mutex_unlock(&client_data->mutex_op_mode); +} +#else +static int smi_gyro_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int err = 0; + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)i2c_get_clientdata(client); + + PINFO("function entrance"); + + mutex_lock(&client_data->mutex_op_mode); + if (client_data->enable) { + err = smi_gyro_pre_suspend(client); + err = SMI_GYRO_CALL_API(set_mode)( + SMI_GYRO_VAL_NAME(MODE_SUSPEND)); + } + mutex_unlock(&client_data->mutex_op_mode); + return err; +} + +static int smi_gyro_resume(struct i2c_client *client) +{ + + int err = 0; + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)i2c_get_clientdata(client); + + PINFO("function entrance"); + + mutex_lock(&client_data->mutex_op_mode); + + if (client_data->enable) + err = SMI_GYRO_CALL_API(set_mode)(SMI_GYRO_VAL_NAME(MODE_NORMAL)); + + /* post resume operation */ + smi_gyro_post_resume(client); + + mutex_unlock(&client_data->mutex_op_mode); + return err; +} +#endif + +void smi_gyro_shutdown(struct i2c_client *client) +{ + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)i2c_get_clientdata(client); + + mutex_lock(&client_data->mutex_op_mode); + SMI_GYRO_CALL_API(set_mode)( + SMI_GYRO_VAL_NAME(MODE_DEEPSUSPEND)); + mutex_unlock(&client_data->mutex_op_mode); +} + +static int smi_gyro_remove(struct i2c_client *client) +{ + int err = 0; + u8 op_mode; + + struct smi_gyro_client_data *client_data = + (struct smi_gyro_client_data *)i2c_get_clientdata(client); + + if (NULL != client_data) { +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&client_data->early_suspend_handler); +#endif + smi130_gyro_input_cleanup(client_data); + mutex_lock(&client_data->mutex_op_mode); + SMI_GYRO_CALL_API(get_mode)(&op_mode); + if (SMI_GYRO_VAL_NAME(MODE_NORMAL) == op_mode) { + cancel_delayed_work_sync(&client_data->work); + PINFO("cancel work"); + } + mutex_unlock(&client_data->mutex_op_mode); + + err = SMI_GYRO_CALL_API(set_mode)( + SMI_GYRO_VAL_NAME(MODE_SUSPEND)); + smi130_gyro_delay(SMI_GYRO_I2C_WRITE_DELAY_TIME); + + sysfs_remove_group(&client_data->input->dev.kobj, + &smi_gyro_attribute_group); + smi_gyro_input_destroy(client_data); + kfree(client_data); + smi_gyro_client = NULL; + } + + return err; +} + +static const struct i2c_device_id smi_gyro_id[] = { + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, smi_gyro_id); +static const struct of_device_id smi130_gyro_of_match[] = { + { .compatible = "smi130_gyro", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, smi130_gyro_of_match); + +static struct i2c_driver smi_gyro_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = smi130_gyro_of_match, + }, + .class = I2C_CLASS_HWMON, + .id_table = smi_gyro_id, + .probe = smi_gyro_probe, + .remove = smi_gyro_remove, + .shutdown = smi_gyro_shutdown, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = smi_gyro_suspend, + .resume = smi_gyro_resume, +#endif +}; + +static int __init SMI_GYRO_init(void) +{ + return i2c_add_driver(&smi_gyro_driver); +} + +static void __exit SMI_GYRO_exit(void) +{ + i2c_del_driver(&smi_gyro_driver); +} + +MODULE_AUTHOR("contact@bosch-sensortec.com>"); +MODULE_DESCRIPTION("SMI_GYRO GYROSCOPE SENSOR DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(SMI_GYRO_init); +module_exit(SMI_GYRO_exit); diff --git a/drivers/input/sensors/smi130/smi130_i2c.c b/drivers/input/sensors/smi130/smi130_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..09c4d29e395934abe44412d59ba0bf50858f0134 --- /dev/null +++ b/drivers/input/sensors/smi130/smi130_i2c.c @@ -0,0 +1,472 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename smi130_i2c.c + * @date 2014/11/25 14:40 + * @Modification Date 2018/08/28 18:20 + * @id "20f77db" + * @version 1.3 + * + * @brief + * This file implements moudle function, which add + * the driver to I2C core. +*/ + +#include +#include +#include +#include "smi130_driver.h" + +/*! @defgroup smi130_i2c_src + * @brief smi130 i2c driver module + @{*/ + +static struct i2c_client *smi_client; +/*! + * @brief define i2c wirte function + * + * @param client the pointer of i2c client + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +/* i2c read routine for API*/ +static s8 smi_i2c_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) + { +#if !defined SMI_USE_BASIC_I2C_FUNC + s32 dummy; + if (NULL == client) + return -EINVAL; + + while (0 != len--) { +#ifdef SMI_SMBUS + dummy = i2c_smbus_read_byte_data(client, reg_addr); + if (dummy < 0) { + dev_err(&client->dev, "i2c smbus read error"); + return -EIO; + } + *data = (u8)(dummy & 0xff); +#else + dummy = i2c_master_send(client, (char *)®_addr, 1); + if (dummy < 0) { + dev_err(&client->dev, "i2c bus master write error"); + return -EIO; + } + + dummy = i2c_master_recv(client, (char *)data, 1); + if (dummy < 0) { + dev_err(&client->dev, "i2c bus master read error"); + return -EIO; + } +#endif + reg_addr++; + data++; + } + return 0; +#else + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < SMI_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, + ARRAY_SIZE(msg)) > 0) + break; + else + usleep_range(SMI_I2C_WRITE_DELAY_TIME * 1000, + SMI_I2C_WRITE_DELAY_TIME * 1000); + } + + if (SMI_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + + return 0; +#endif + } + + +static s8 smi_i2c_burst_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u16 len) +{ + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < SMI_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + usleep_range(SMI_I2C_WRITE_DELAY_TIME * 1000, + SMI_I2C_WRITE_DELAY_TIME * 1000); + } + + if (SMI_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + + return 0; +} + + +/* i2c write routine for */ +static s8 smi_i2c_write(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ +#if !defined SMI_USE_BASIC_I2C_FUNC + s32 dummy; + +#ifndef SMI_SMBUS + u8 buffer[2]; +#endif + + if (NULL == client) + return -EPERM; + + while (0 != len--) { +#ifdef SMI_SMBUS + dummy = i2c_smbus_write_byte_data(client, reg_addr, *data); +#else + buffer[0] = reg_addr; + buffer[1] = *data; + dummy = i2c_master_send(client, (char *)buffer, 2); +#endif + reg_addr++; + data++; + if (dummy < 0) { + dev_err(&client->dev, "error writing i2c bus"); + return -EPERM; + } + + } + usleep_range(SMI_I2C_WRITE_DELAY_TIME * 1000, + SMI_I2C_WRITE_DELAY_TIME * 1000); + return 0; +#else + u8 buffer[2]; + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buffer, + }, + }; + + while (0 != len--) { + buffer[0] = reg_addr; + buffer[1] = *data; + for (retry = 0; retry < SMI_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, + ARRAY_SIZE(msg)) > 0) { + break; + } else { + usleep_range(SMI_I2C_WRITE_DELAY_TIME * 1000, + SMI_I2C_WRITE_DELAY_TIME * 1000); + } + } + if (SMI_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + reg_addr++; + data++; + } + + usleep_range(SMI_I2C_WRITE_DELAY_TIME * 1000, + SMI_I2C_WRITE_DELAY_TIME * 1000); + return 0; +#endif +} + + +static s8 smi_i2c_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + int err = 0; + err = smi_i2c_read(smi_client, reg_addr, data, len); + return err; +} + +static s8 smi_i2c_write_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + int err = 0; + err = smi_i2c_write(smi_client, reg_addr, data, len); + return err; +} + +s8 smi_burst_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u16 len) +{ + int err = 0; + err = smi_i2c_burst_read(smi_client, reg_addr, data, len); + return err; +} +EXPORT_SYMBOL(smi_burst_read_wrapper); +/*! + * @brief SMI probe function via i2c bus + * + * @param client the pointer of i2c client + * @param id the pointer of i2c device id + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int smi_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct smi_client_data *client_data = NULL; + + dev_info(&client->dev, "SMI130 i2c function probe entrance"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c_check_functionality error!"); + err = -EIO; + goto exit_err_clean; + } + + if (NULL == smi_client) { + smi_client = client; + } else { + dev_err(&client->dev, + "this driver does not support multiple clients"); + err = -EBUSY; + goto exit_err_clean; + } + + client_data = kzalloc(sizeof(struct smi_client_data), + GFP_KERNEL); + if (NULL == client_data) { + dev_err(&client->dev, "no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + client_data->device.bus_read = smi_i2c_read_wrapper; + client_data->device.bus_write = smi_i2c_write_wrapper; + + return smi_probe(client_data, &client->dev); + +exit_err_clean: + if (err) + smi_client = NULL; + return err; +} +/* +static int smi_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int err = 0; + err = smi_suspend(&client->dev); + return err; +} + +static int smi_i2c_resume(struct i2c_client *client) +{ + int err = 0; + + err = smi_resume(&client->dev); + + return err; +} +*/ + +static int smi_i2c_remove(struct i2c_client *client) +{ + int err = 0; + err = smi_remove(&client->dev); + smi_client = NULL; + + return err; +} + + + +static const struct i2c_device_id smi_id[] = { + {SENSOR_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, smi_id); + +static const struct of_device_id smi130_of_match[] = { + { .compatible = "bosch-sensortec,smi130", }, + { .compatible = "smi130", }, + { .compatible = "bosch, smi130", }, + { } +}; +MODULE_DEVICE_TABLE(of, smi130_of_match); + +static struct i2c_driver smi_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = smi130_of_match, + }, + .class = I2C_CLASS_HWMON, + .id_table = smi_id, + .probe = smi_i2c_probe, + .remove = smi_i2c_remove, + /*.suspend = smi_i2c_suspend, + .resume = smi_i2c_resume,*/ +}; + +static int __init SMI_i2c_init(void) +{ + return i2c_add_driver(&smi_i2c_driver); +} + +static void __exit SMI_i2c_exit(void) +{ + i2c_del_driver(&smi_i2c_driver); +} + +MODULE_AUTHOR("Contact "); +MODULE_DESCRIPTION("driver for " SENSOR_NAME); +MODULE_LICENSE("GPL v2"); + +module_init(SMI_i2c_init); +module_exit(SMI_i2c_exit); + diff --git a/drivers/input/sensors/smi130/smi130_spi.c b/drivers/input/sensors/smi130/smi130_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..b02efbf111b1405f5fb48251c6d5e308b64e6b3d --- /dev/null +++ b/drivers/input/sensors/smi130/smi130_spi.c @@ -0,0 +1,402 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * (C) Modification Copyright 2018 Robert Bosch Kft All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * Special: Description of the Software: + * + * This software module (hereinafter called "Software") and any + * information on application-sheets (hereinafter called "Information") is + * provided free of charge for the sole purpose to support your application + * work. + * + * As such, the Software is merely an experimental software, not tested for + * safety in the field and only intended for inspiration for further development + * and testing. Any usage in a safety-relevant field of use (like automotive, + * seafaring, spacefaring, industrial plants etc.) was not intended, so there are + * no precautions for such usage incorporated in the Software. + * + * The Software is specifically designed for the exclusive use for Bosch + * Sensortec products by personnel who have special experience and training. Do + * not use this Software if you do not have the proper experience or training. + * + * This Software package is provided as is and without any expressed or + * implied warranties, including without limitation, the implied warranties of + * merchantability and fitness for a particular purpose. + * + * Bosch Sensortec and their representatives and agents deny any liability for + * the functional impairment of this Software in terms of fitness, performance + * and safety. Bosch Sensortec and their representatives and agents shall not be + * liable for any direct or indirect damages or injury, except as otherwise + * stipulated in mandatory applicable law. + * The Information provided is believed to be accurate and reliable. Bosch + * Sensortec assumes no responsibility for the consequences of use of such + * Information nor for any infringement of patents or other rights of third + * parties which may result from its use. + * + *------------------------------------------------------------------------------ + * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software + * which is licensed under the Apache License, Version 2.0 as stated above. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Product Disclaimer + * + * Common: + * + * Assessment of Products Returned from Field + * + * Returned products are considered good if they fulfill the specifications / + * test data for 0-mileage and field listed in this document. + * + * Engineering Samples + * + * Engineering samples are marked with (e) or (E). Samples may vary from the + * valid technical specifications of the series product contained in this + * data sheet. Therefore, they are not intended or fit for resale to + * third parties or for use in end products. Their sole purpose is internal + * client testing. The testing of an engineering sample may in no way replace + * the testing of a series product. Bosch assumes no liability for the use + * of engineering samples. The purchaser shall indemnify Bosch from all claims + * arising from the use of engineering samples. + * + * Intended use + * + * Provided that SMI130 is used within the conditions (environment, application, + * installation, loads) as described in this TCD and the corresponding + * agreed upon documents, Bosch ensures that the product complies with + * the agreed properties. Agreements beyond this require + * the written approval by Bosch. The product is considered fit for the intended + * use when the product successfully has passed the tests + * in accordance with the TCD and agreed upon documents. + * + * It is the responsibility of the customer to ensure the proper application + * of the product in the overall system/vehicle. + * + * Bosch does not assume any responsibility for changes to the environment + * of the product that deviate from the TCD and the agreed upon documents + * as well as all applications not released by Bosch + * + * The resale and/or use of products are at the purchaser’s own risk and + * responsibility. The examination and testing of the SMI130 + * is the sole responsibility of the purchaser. + * + * The purchaser shall indemnify Bosch from all third party claims + * arising from any product use not covered by the parameters of + * this product data sheet or not approved by Bosch and reimburse Bosch + * for all costs and damages in connection with such claims. + * + * The purchaser must monitor the market for the purchased products, + * particularly with regard to product safety, and inform Bosch without delay + * of all security relevant incidents. + * + * Application Examples and Hints + * + * With respect to any application examples, advice, normal values + * and/or any information regarding the application of the device, + * Bosch hereby disclaims any and all warranties and liabilities of any kind, + * including without limitation warranties of + * non-infringement of intellectual property rights or copyrights + * of any third party. + * The information given in this document shall in no event be regarded + * as a guarantee of conditions or characteristics. They are provided + * for illustrative purposes only and no evaluation regarding infringement + * of intellectual property rights or copyrights or regarding functionality, + * performance or error has been made. + * + * @filename smi130_spi.c + * @date 2014/11/25 14:40 + * @Modification Date 2018/08/28 18:20 + * @id "20f77db" + * @version 1.3 + * + * @brief + * This file implements moudle function, which add + * the driver to SPI core. +*/ + +#include +#include +#include +#include "smi130_driver.h" + +/*! @defgroup smi130_spi_src + * @brief smi130 spi driver module + @{*/ +/*! the maximum of transfer buffer size */ +#define SMI_MAX_BUFFER_SIZE 32 + +static struct spi_device *smi_spi_client; + +/*! + * @brief define spi wirte function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static char smi_spi_write_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + struct spi_device *client = smi_spi_client; + u8 buffer[SMI_MAX_BUFFER_SIZE + 1]; + struct spi_transfer xfer = { + .tx_buf = buffer, + .len = len + 1, + }; + struct spi_message msg; + + if (len > SMI_MAX_BUFFER_SIZE) + return -EINVAL; + + buffer[0] = reg_addr&0x7F;/* write: MSB = 0 */ + memcpy(&buffer[1], data, len); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + return spi_sync(client, &msg); +} + +/*! + * @brief define spi read function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to read + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static char smi_spi_read_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + struct spi_device *client = smi_spi_client; + u8 reg = reg_addr | 0x80;/* read: MSB = 1 */ + struct spi_transfer xfer[2] = { + [0] = { + .tx_buf = ®, + .len = 1, + }, + [1] = { + .rx_buf = data, + .len = len, + } + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer[0], &msg); + spi_message_add_tail(&xfer[1], &msg); + return spi_sync(client, &msg); +} + +s8 smi_burst_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u16 len) +{ + struct spi_device *client = smi_spi_client; + u8 reg = reg_addr | 0x80;/* read: MSB = 1 */ + struct spi_transfer xfer[2] = { + [0] = { + .tx_buf = ®, + .len = 1, + }, + [1] = { + .rx_buf = data, + .len = len, + } + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer[0], &msg); + spi_message_add_tail(&xfer[1], &msg); + return spi_sync(client, &msg); +} +EXPORT_SYMBOL(smi_burst_read_wrapper); +/*! + * @brief SMI probe function via spi bus + * + * @param client the pointer of spi client + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int smi_spi_probe(struct spi_device *client) +{ + int status; + int err = 0; + struct smi_client_data *client_data = NULL; + + if (NULL == smi_spi_client) + smi_spi_client = client; + else{ + dev_err(&client->dev, "This driver does not support multiple clients!\n"); + return -EBUSY; + } + + client->bits_per_word = 8; + status = spi_setup(client); + if (status < 0) { + dev_err(&client->dev, "spi_setup failed!\n"); + return status; + } + + client_data = kzalloc(sizeof(struct smi_client_data), GFP_KERNEL); + if (NULL == client_data) { + dev_err(&client->dev, "no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + client_data->device.bus_read = smi_spi_read_block; + client_data->device.bus_write = smi_spi_write_block; + + return smi_probe(client_data, &client->dev); + +exit_err_clean: + if (err) + smi_spi_client = NULL; + return err; +} + +/*! + * @brief shutdown smi device in spi driver + * + * @param client the pointer of spi client + * + * @return no return value +*/ +static void smi_spi_shutdown(struct spi_device *client) +{ +#ifdef CONFIG_PM + smi_suspend(&client->dev); +#endif +} + +/*! + * @brief remove smi spi client + * + * @param client the pointer of spi client + * + * @return zero + * @retval zero +*/ +static int smi_spi_remove(struct spi_device *client) +{ + int err = 0; + err = smi_remove(&client->dev); + smi_spi_client = NULL; + + return err; +} + +#ifdef CONFIG_PM +/*! + * @brief suspend smi device in spi driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int smi_spi_suspend(struct device *dev) +{ + int err = 0; + err = smi_suspend(dev); + return err; +} + +/*! + * @brief resume smi device in spi driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int smi_spi_resume(struct device *dev) +{ + int err = 0; + /* post resume operation */ + err = smi_resume(dev); + + return err; +} + +/*! + * @brief register spi device power manager hooks +*/ +static const struct dev_pm_ops smi_spi_pm_ops = { + /**< device suspend */ + .suspend = smi_spi_suspend, + /**< device resume */ + .resume = smi_spi_resume +}; +#endif + +/*! + * @brief register spi device id +*/ +static const struct spi_device_id smi_id[] = { + { SENSOR_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, smi_id); + +/*! + * @brief register spi driver hooks +*/ +static struct spi_driver smi_spi_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, +#ifdef CONFIG_PM + .pm = &smi_spi_pm_ops, +#endif + }, + .id_table = smi_id, + .probe = smi_spi_probe, + .shutdown = smi_spi_shutdown, + .remove = smi_spi_remove +}; + +/*! + * @brief initialize smi spi module + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int __init smi_spi_init(void) +{ + return spi_register_driver(&smi_spi_driver); +} + +/*! + * @brief remove smi spi module + * + * @return no return value +*/ +static void __exit smi_spi_exit(void) +{ + spi_unregister_driver(&smi_spi_driver); +} + + +MODULE_AUTHOR("Contact "); +MODULE_DESCRIPTION("SMI130 SPI DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(smi_spi_init); +module_exit(smi_spi_exit); +/*@}*/ + diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 160b705869f3148df5416578dfe883f105e30784..b12a58392d59c1cc6a70bdd2add46b21895f0dd7 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -514,6 +514,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"), }, }, + { + /* TUXEDO BU1406 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), + DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), + }, + }, { } }; @@ -595,6 +602,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "20046"), }, }, + { + /* Lenovo ThinkPad L460 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"), + }, + }, { /* Clevo P650RS, 650RP6, Sager NP8152-S, and others */ .matches = { @@ -698,6 +712,20 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { { } }; +static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = { + { + /* + * Sony Vaio VGN-CS series require MUX or the touch sensor + * buttons will disturb touchpad operation + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"), + }, + }, + { } +}; + /* * Some Wistron based laptops need us to explicitly enable the 'Dritek * keyboard extension' to make their extra keys start generating scancodes. @@ -804,6 +832,13 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "P34"), }, }, + { + /* Gigabyte P57 - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "P57"), + }, + }, { /* Schenker XMG C504 - Elantech touchpad */ .matches = { @@ -1103,6 +1138,9 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_nomux_table)) i8042_nomux = true; + if (dmi_check_system(i8042_dmi_forcemux_table)) + i8042_nomux = false; + if (dmi_check_system(i8042_dmi_notimeout_table)) i8042_notimeout = true; diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 0d4a9fad4a78bc68bc5d51aa41ad27b64c707a3a..5b4efcdff47dfaaf93d5fd8bd3f174ffd09d7cc4 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -126,7 +126,7 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, int data, n, ret; if (!np) return -ENODEV; - np = of_find_node_by_name(np, "touch"); + np = of_get_child_by_name(np, "touch"); if (!np) { dev_err(&pdev->dev, "Can't find touch node\n"); return -EINVAL; @@ -144,13 +144,13 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, if (data) { ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); if (ret < 0) - return -EINVAL; + goto err_put_node; } /* set tsi prebias time */ if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) { ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); if (ret < 0) - return -EINVAL; + goto err_put_node; } /* set prebias & prechg time of pen detect */ data = 0; @@ -161,10 +161,18 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, if (data) { ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); if (ret < 0) - return -EINVAL; + goto err_put_node; } of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); + + of_node_put(np); + return 0; + +err_put_node: + of_node_put(np); + + return -EINVAL; } #else #define pm860x_touch_dt_init(x, y, z) (-1) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a508e7b52ccd60e5081fe9b4c7dc5cd6dd05c6c8..4273975164648453aec33da7416128ca6da99b0c 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1172,6 +1172,19 @@ config TOUCHSCREEN_MAXIM_STI module will be called maxim_sti. source "drivers/input/touchscreen/gt9xx/Kconfig" +source "drivers/input/touchscreen/focaltech_touch/Kconfig" + +config TOUCHSCREEN_HIMAX_CHIPSET + bool "Himax touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Himax CHIPSET touchscreen. + HIMAX controllers are multi touch controllers which can + report 10 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/hxchipset/Kconfig" config TOUCHSCREEN_FT5346 bool "FOCALTECH touchpanel FT5346 series" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 709041c5d0fd67ec4e5f5129931e30594b3bfdbc..3acfc2542723e757d9f288819284a9400a1cb103 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -97,3 +97,4 @@ obj-$(CONFIG_TOUCHSCREEN_IST3038C) += ist3038c/ obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ obj-$(CONFIG_TOUCHSCREEN_GT9XX_MIDO) += gt9xx_mido/ obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index ba30578e296e4efa3032b307388975d7a6ec9172..845bfda99d7461752b64d86743c5ffcf79df7b15 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -152,7 +152,7 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume); static const struct i2c_device_id ar1021_i2c_id[] = { - { "MICROCHIP_AR1021_I2C", 0 }, + { "ar1021", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); diff --git a/drivers/input/touchscreen/focaltech_touch/Kconfig b/drivers/input/touchscreen/focaltech_touch/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..00deec747a3eb243e2c25632146b27bccdfc7142 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/Kconfig @@ -0,0 +1,18 @@ +# +# Focaltech Touchscreen driver configuration +# +menuconfig TOUCHSCREEN_FTS + bool "Focaltech Touchscreen" + depends on I2C + default n + help + Say Y here if you have Focaltech touch panel. + If unsure, say N. + +config TOUCHSCREEN_FTS_DIRECTORY + string "Focaltech ts directory name" + default "focaltech_touch" + depends on TOUCHSCREEN_FTS + help + Specify the path for the driver directory. + Path should be relative to driver/input/touchscreen/. diff --git a/drivers/input/touchscreen/focaltech_touch/Makefile b/drivers/input/touchscreen/focaltech_touch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c5824166b37cfcfaf187654abdcd7ab8529c1369 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for the focaltech touchscreen drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_core.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_ex_fun.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_ex_mode.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_flash.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_gesture.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_esdcheck.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_i2c.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_sensor.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_point_report_check.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_flash/ + diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_common.h b/drivers/input/touchscreen/focaltech_touch/focaltech_common.h new file mode 100644 index 0000000000000000000000000000000000000000..712cc60a2633acfcd7b774a144b3c50e9d4fe259 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_common.h @@ -0,0 +1,217 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_common.h +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-16 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +#ifndef __LINUX_FOCALTECH_COMMON_H__ +#define __LINUX_FOCALTECH_COMMON_H__ + +#include "focaltech_config.h" + +/***************************************************************************** +* Macro definitions using #define +*****************************************************************************/ +#define FTS_DRIVER_VERSION "Focaltech V1.3 20170306" + +#define FLAGBIT(x) (0x00000001 << (x)) +#define FLAGBITS(x, y) ((0xFFFFFFFF >> (32 - (y) - 1)) << (x)) + +#define FLAG_ICSERIALS_LEN 5 +#define FLAG_IDC_BIT 11 + +#define IC_SERIALS (FTS_CHIP_TYPE & \ + FLAGBITS(0, FLAG_ICSERIALS_LEN-1)) +#define FTS_CHIP_IDC ((FTS_CHIP_TYPE & FLAGBIT(FLAG_IDC_BIT)) \ + == FLAGBIT(FLAG_IDC_BIT)) + +#define FTS_CHIP_TYPE_MAPPING { \ + {0x01, 0x58, 0x22, 0x58, 0x22, 0x00, 0x00, 0x58, 0x2C}, \ + {0x02, 0x54, 0x22, 0x54, 0x22, 0x00, 0x00, 0x54, 0x2C}, \ + {0x03, 0x64, 0x26, 0x64, 0x26, 0x00, 0x00, 0x79, 0x1C}, \ + {0x04, 0x33, 0x67, 0x64, 0x26, 0x00, 0x00, 0x79, 0x1C}, \ + {0x05, 0x87, 0x16, 0x87, 0x16, 0x87, 0xA6, 0x00, 0x00}, \ + {0x06, 0x87, 0x36, 0x87, 0x36, 0x87, 0xC6, 0x00, 0x00}, \ + {0x07, 0x80, 0x06, 0x80, 0x06, 0x80, 0xC6, 0x80, 0xB6}, \ + {0x08, 0x86, 0x06, 0x86, 0x06, 0x86, 0xA6, 0x00, 0x00}, \ + {0x09, 0x86, 0x07, 0x86, 0x07, 0x86, 0xA7, 0x00, 0x00}, \ + {0x0A, 0xE7, 0x16, 0x87, 0x16, 0xE7, 0xA6, 0x87, 0xB6}, \ +} + +#define I2C_BUFFER_LENGTH_MAXINUM 256 +#define FILE_NAME_LENGTH 128 +#define ENABLE 1 +#define DISABLE 0 +/*register address*/ +#define FTS_REG_INT_CNT 0x8F +#define FTS_REG_FLOW_WORK_CNT 0x91 +#define FTS_REG_WORKMODE 0x00 +#define FTS_REG_WORKMODE_FACTORY_VALUE 0x40 +#define FTS_REG_WORKMODE_WORK_VALUE 0x00 +#define FTS_REG_CHIP_ID 0xA3 +#define FTS_REG_CHIP_ID2 0x9F +#define FTS_REG_POWER_MODE 0xA5 +#define FTS_REG_POWER_MODE_SLEEP_VALUE 0x03 +#define FTS_REG_FW_VER 0xA6 +#define FTS_REG_VENDOR_ID 0xA8 +#define FTS_REG_LCD_BUSY_NUM 0xAB +#define FTS_REG_FACE_DEC_MODE_EN 0xB0 +#define FTS_REG_GLOVE_MODE_EN 0xC0 +#define FTS_REG_COVER_MODE_EN 0xC1 +#define FTS_REG_CHARGER_MODE_EN 0x8B +#define FTS_REG_GESTURE_EN 0xD0 +#define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3 +#define FTS_REG_ESD_SATURATE 0xED + + + +/***************************************************************************** +* Alternative mode (When something goes wrong, +* the modules may be able to solve the problem.) +*****************************************************************************/ +/* + * point report check + * default: disable + */ +#define FTS_POINT_REPORT_CHECK_EN 0 + + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +struct ft_chip_t { + unsigned long type; + unsigned char chip_idh; + unsigned char chip_idl; + unsigned char rom_idh; + unsigned char rom_idl; + unsigned char pramboot_idh; + unsigned char pramboot_idl; + unsigned char bootloader_idh; + unsigned char bootloader_idl; +}; + +/* i2c communication*/ +int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue); +int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue); +int fts_i2c_read(struct i2c_client *client, char *writebuf, int writelen, + char *readbuf, int readlen); +int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen); +int fts_i2c_init(void); +int fts_i2c_exit(void); + +/* Gesture functions */ +#if FTS_GESTURE_EN +int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client); +int fts_gesture_exit(struct i2c_client *client); +void fts_gesture_recovery(struct i2c_client *client); +int fts_gesture_readdata(struct i2c_client *client); +int fts_gesture_suspend(struct i2c_client *i2c_client); +int fts_gesture_resume(struct i2c_client *client); +#endif + +/* Apk and functions */ +#if FTS_APK_NODE_EN +int fts_create_apk_debug_channel(struct i2c_client *client); +void fts_release_apk_debug_channel(void); +#endif + +/* ADB functions */ +#if FTS_SYSFS_NODE_EN +int fts_create_sysfs(struct i2c_client *client); +int fts_remove_sysfs(struct i2c_client *client); +#endif + +/* ESD */ +#if FTS_ESDCHECK_EN +int fts_esdcheck_init(void); +int fts_esdcheck_exit(void); +int fts_esdcheck_switch(bool enable); +int fts_esdcheck_proc_busy(bool proc_debug); +int fts_esdcheck_set_intr(bool intr); +int fts_esdcheck_suspend(void); +int fts_esdcheck_resume(void); +int fts_esdcheck_get_status(void); +#endif + +/* Production test */ +#if FTS_TEST_EN +int fts_test_init(struct i2c_client *client); +int fts_test_exit(struct i2c_client *client); +#endif + +/* Point Report Check*/ +#if FTS_POINT_REPORT_CHECK_EN +int fts_point_report_check_init(void); +int fts_point_report_check_exit(void); +void fts_point_report_check_queue_work(void); +#endif + +/* Other */ +extern int g_show_log; +int fts_reset_proc(int hdelayms); +int fts_wait_tp_to_valid(struct i2c_client *client); +void fts_tp_state_recovery(struct i2c_client *client); +int fts_ex_mode_init(struct i2c_client *client); +int fts_ex_mode_exit(struct i2c_client *client); +int fts_ex_mode_recovery(struct i2c_client *client); + +void fts_irq_disable(void); +void fts_irq_enable(void); + +/***************************************************************************** +* DEBUG function define here +*****************************************************************************/ +#if FTS_DEBUG_EN +#define FTS_DEBUG_LEVEL 1 + +#if (FTS_DEBUG_LEVEL == 2) +#define FTS_DEBUG(fmt, args...) pr_err("[FTS][%s]"fmt"\n", __func__, ##args) +#else +#define FTS_DEBUG(fmt, args...) pr_err("[FTS]"fmt"\n", ##args) +#endif + +#define FTS_FUNC_ENTER() pr_err("[FTS]%s: Enter\n", __func__) +#define FTS_FUNC_EXIT() pr_err("[FTS]%s: Exit(%d)\n", __func__, __LINE__) +#else +#define FTS_DEBUG(fmt, args...) +#define FTS_FUNC_ENTER() +#define FTS_FUNC_EXIT() +#endif + +#define FTS_INFO(fmt, args...) do { \ + if (g_show_log) \ + pr_err("[FTS][Info]"fmt"\n", ##args); \ + } while (0) + +#define FTS_ERROR(fmt, args...) do { \ + if (g_show_log) \ + pr_err("[FTS][Error]"fmt"\n", ##args); \ + } while (0) + + +#endif /* __LINUX_FOCALTECH_COMMON_H__ */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_config.h b/drivers/input/touchscreen/focaltech_touch/focaltech_config.h new file mode 100644 index 0000000000000000000000000000000000000000..8393061892ce66aed6357f1c8ed1c43bee60695f --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_config.h @@ -0,0 +1,248 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved. + * + * 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_config.h +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: global configurations +* +* Version: v1.0 +* +************************************************************************/ +#ifndef _LINUX_FOCLATECH_CONFIG_H_ +#define _LINUX_FOCLATECH_CONFIG_H_ + +/**************************************************/ +/****** G: A, I: B, S: C, U: D ******************/ +/****** chip type defines, do not modify *********/ +#define _FT8716 0x87160805 +#define _FT8736 0x87360806 +#define _FT8006 0x80060807 +#define _FT8606 0x86060808 +#define _FT8607 0x86070809 +#define _FTE716 0xE716080a + +#define _FT5416 0x54160002 +#define _FT5426 0x54260002 +#define _FT5435 0x54350002 +#define _FT5436 0x54360002 +#define _FT5526 0x55260002 +#define _FT5526I 0x5526B002 +#define _FT5446 0x54460002 +#define _FT5346 0x53460002 +#define _FT5446I 0x5446B002 +#define _FT5346I 0x5346B002 +#define _FT7661 0x76610002 +#define _FT7511 0x75110002 +#define _FT7421 0x74210002 +#define _FT7681 0x76810002 +#define _FT3C47U 0x3C47D002 +#define _FT3417 0x34170002 +#define _FT3517 0x35170002 +#define _FT3327 0x33270002 +#define _FT3427 0x34270002 + +#define _FT5626 0x56260001 +#define _FT5726 0x57260001 +#define _FT5826B 0x5826B001 +#define _FT5826S 0x5826C001 +#define _FT7811 0x78110001 +#define _FT3D47 0x3D470001 +#define _FT3617 0x36170001 +#define _FT3717 0x37170001 +#define _FT3817B 0x3817B001 + +#define _FT6236U 0x6236D003 +#define _FT6336G 0x6336A003 +#define _FT6336U 0x6336D003 +#define _FT6436U 0x6436D003 + +#define _FT3267 0x32670004 +#define _FT3367 0x33670004 + + + +/*************************************************/ + +/* + * choose your ic chip type of focaltech + */ +#define FTS_CHIP_TYPE _FT3267 + +/******************* Enables *********************/ +/*********** 1 to enable, 0 to disable ***********/ + +/* + * show debug log info + * enable it for debug, disable it for release + */ +#define FTS_DEBUG_EN 0 + +/* + * Linux MultiTouch Protocol + * 1: Protocol B(default), 0: Protocol A + */ +#define FTS_MT_PROTOCOL_B_EN 1 + + +/* + * Report Pressure in multitouch + * 1:enable(default),0:disable +*/ +#define FTS_REPORT_PRESSURE_EN 1 + +/* + * Force touch support + * different pressure for multitouch + * 1: true pressure for force touch + * 0: constant pressure(default) + */ +#define FTS_FORCE_TOUCH_EN 0 + +/* + * Gesture function enable + * default: disable + */ +#define FTS_GESTURE_EN 1 + +/* + * ESD check & protection + * default: disable + */ +#define FTS_ESDCHECK_EN 0 + +/* + * Production test enable + * 1: enable, 0:disable(default) + */ +#define FTS_TEST_EN 0 + +/* + * Glove mode enable + * 1: enable, 0:disable(default) + */ +#define FTS_GLOVE_EN 0 +/* + * cover enable + * 1: enable, 0:disable(default) + */ +#define FTS_COVER_EN 0 +/* + * Charger enable + * 1: enable, 0:disable(default) + */ +#define FTS_CHARGER_EN 0 + +/* + * Proximity sensor + * default: disable + */ +#define FTS_PSENSOR_EN 0 + +/* + * Nodes for tools, please keep enable + */ +#define FTS_SYSFS_NODE_EN 1 +#define FTS_APK_NODE_EN 1 + +/* + * Customer power enable + * enable it when customer need control TP power + * default: disable + */ +#define FTS_POWER_SOURCE_CUST_EN 1 + +/****************************************************/ + +/********************** Upgrade ****************************/ +/* + * auto upgrade, please keep enable + */ +#define FTS_AUTO_UPGRADE_EN 1 + +/* + * auto upgrade for lcd cfg + * default: 0 + */ +#define FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN 0 + +/* auto cb check + * default: disable + */ +#define FTS_AUTO_CLB_EN 0 + +/* + * Check vendor_id number + * 0:No check vendor_id (default) + * 1/2/3: Check vendor_id for vendor compatibility + */ +#define FTS_GET_VENDOR_ID_NUM 0 + +/* + * vendor_id(s) for vendor(s) to be compatible with. + * a confirmation of vendor_id(s) is recommended. + * FTS_GET_VENDOR_ID_NUM == 0, no check vendor id, you may ignore them + * FTS_GET_VENDOR_ID_NUM >= 1, compatible with FTS_VENDOR_1_ID + * FTS_GET_VENDOR_ID_NUM >= 2, compatible with FTS_VENDOR_2_ID + * FTS_GET_VENDOR_ID_NUM == 3, compatible with FTS_VENDOR_3_ID + */ +#define FTS_VENDOR_1_ID 0x00 +#define FTS_VENDOR_2_ID 0x00 +#define FTS_VENDOR_3_ID 0x00 + +/* + * FW_APP.i file for auto upgrade, you must replace it with your own + * define your own fw_app, the sample one to be replaced is invalid + * NOTE: if FTS_GET_VENDOR_ID_NUM >= 1, + * it's the fw corresponding with FTS_VENDOR_1_ID + */ +#define FTS_UPGRADE_FW_APP "include/firmware/FT8716_app_sample.i" + +/* + * if FTS_GET_VENDOR_ID_NUM >= 2, fw corrsponding with FTS_VENDOR_2_ID + * define your own fw_app, the sample one is invalid + */ +#define FTS_UPGRADE_FW2_APP "include/firmware/FT8716_app_sample.i" + +/* + * if FTS_GET_VENDOR_ID_NUM == 3, fw corrsponding with FTS_VENDOR_3_ID + * define your own fw_app, the sample one is invalid + */ +#define FTS_UPGRADE_FW3_APP "include/firmware/FT8716_app_sample.i" + +/* + * lcd_cfg.i file for lcd cfg upgrade + * define your own lcd_cfg.i, the sample one is invalid + */ +#define FTS_UPGRADE_LCD_CFG "include/firmware/lcd_cfg.i" + +/* + * upgrade stress test for debug + * enable it for upgrade debug if needed + * default: disable + */ +#define FTS_UPGRADE_STRESS_TEST 0 +/* stress test times, default: 1000 */ +#define FTS_UPGRADE_TEST_NUMBER 1000 + +/*********************************************************/ + +#endif /* _LINUX_FOCLATECH_CONFIG_H_ */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c new file mode 100644 index 0000000000000000000000000000000000000000..a3674b876d72517de21cb8a6b78d0df5d28380c4 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c @@ -0,0 +1,1476 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved. + * + * 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_core.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#define FTS_SUSPEND_LEVEL 1 /* Early-suspend level */ +#endif + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define FTS_DRIVER_NAME "fts_ts" +#define INTERVAL_READ_REG 20 /* interval time per read reg unit:ms */ +#define TIMEOUT_READ_REG 300 /* timeout of read reg unit:ms */ +#if FTS_POWER_SOURCE_CUST_EN +#define FTS_VTG_MIN_UV 2600000 +#define FTS_VTG_MAX_UV 3300000 +#define FTS_I2C_VTG_MIN_UV 1800000 +#define FTS_I2C_VTG_MAX_UV 1800000 +#endif +#define FTS_READ_TOUCH_BUFFER_DIVIDED 0 +/***************************************************************************** +* Global variable or extern global variabls/functions +******************************************************************************/ +struct i2c_client *fts_i2c_client; +struct fts_ts_data *fts_wq_data; +struct input_dev *fts_input_dev; + +#if FTS_DEBUG_EN +int g_show_log = 1; +#else +int g_show_log = 0; +#endif + +#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2)) +char g_sz_debug[1024] = {0}; +#endif + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +static void fts_release_all_finger(void); +static int fts_ts_suspend(struct device *dev); +static int fts_ts_resume(struct device *dev); + + +/***************************************************************************** +* Name: fts_wait_tp_to_valid +* Brief: Read chip id until TP FW become valid, +* need call when reset/power on/resume... +* 1. Read Chip ID per INTERVAL_READ_REG(20ms) +* 2. Timeout: TIMEOUT_READ_REG(300ms) +* Input: +* Output: +* Return: 0 - Get correct Device ID +*****************************************************************************/ +int fts_wait_tp_to_valid(struct i2c_client *client) +{ + int ret = 0; + int cnt = 0; + u8 reg_value = 0; + + do { + ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID, ®_value); + if ((ret < 0) || (reg_value != chip_types.chip_idh)) { + FTS_INFO("TP Not Ready, ReadData = 0x%x", reg_value); + } else if (reg_value == chip_types.chip_idh) { + FTS_INFO("TP Ready, Device ID = 0x%x", reg_value); + return 0; + } + cnt++; + msleep(INTERVAL_READ_REG); + } while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG); + + /* error: not get correct reg data */ + return -EINVAL; +} + +/***************************************************************************** +* Name: fts_recover_state +* Brief: Need execute this function when reset +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_tp_state_recovery(struct i2c_client *client) +{ + /* wait tp stable */ + fts_wait_tp_to_valid(client); + /* recover TP charger state 0x8B */ + /* recover TP glove state 0xC0 */ + /* recover TP cover state 0xC1 */ + fts_ex_mode_recovery(client); + /* recover TP gesture state 0xD0 */ +#if FTS_GESTURE_EN + fts_gesture_recovery(client); +#endif +} + + +/***************************************************************************** +* Name: fts_reset_proc +* Brief: Execute reset operation +* Input: hdelayms - delay time unit:ms +* Output: +* Return: +*****************************************************************************/ +int fts_reset_proc(int hdelayms) +{ + gpio_direction_output(fts_wq_data->pdata->reset_gpio, 0); + msleep(20); + gpio_direction_output(fts_wq_data->pdata->reset_gpio, 1); + msleep(hdelayms); + + return 0; +} + +/***************************************************************************** +* Name: fts_irq_disable +* Brief: disable irq +* Input: +* sync: +* Output: +* Return: +*****************************************************************************/ +void fts_irq_disable(void) +{ + unsigned long irqflags; + + spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags); + + if (!fts_wq_data->irq_disable) { + disable_irq_nosync(fts_wq_data->client->irq); + fts_wq_data->irq_disable = 1; + } + + spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags); +} + +/***************************************************************************** +* Name: fts_irq_enable +* Brief: enable irq +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_irq_enable(void) +{ + unsigned long irqflags = 0; + + spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags); + + if (fts_wq_data->irq_disable) { + enable_irq(fts_wq_data->client->irq); + fts_wq_data->irq_disable = 0; + } + + spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags); +} + +/***************************************************************************** +* Name: fts_input_dev_init +* Brief: input dev init +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_input_dev_init(struct i2c_client *client, + struct fts_ts_data *data, struct input_dev *input_dev, + struct fts_ts_platform_data *pdata) +{ + int err, len; + + FTS_FUNC_ENTER(); + + /* Init and register Input device */ + input_dev->name = FTS_DRIVER_NAME; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + + input_set_drvdata(input_dev, data); + i2c_set_clientdata(client, data); + + __set_bit(EV_KEY, input_dev->evbit); + if (data->pdata->have_key) { + FTS_DEBUG("set key capabilities"); + for (len = 0; len < data->pdata->key_number; len++) + input_set_capability(input_dev, EV_KEY, + data->pdata->keys[len]); + } + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + +#if FTS_MT_PROTOCOL_B_EN + input_mt_init_slots(input_dev, pdata->max_touch_number, + INPUT_MT_DIRECT); +#else + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0f, 0, 0); +#endif + input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, + pdata->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, + pdata->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0); +#if FTS_REPORT_PRESSURE_EN + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0); +#endif + + err = input_register_device(input_dev); + if (err) { + FTS_ERROR("Input device registration failed"); + goto free_inputdev; + } + + FTS_FUNC_EXIT(); + + return 0; + +free_inputdev: + input_free_device(input_dev); + FTS_FUNC_EXIT(); + return err; + +} + +/***************************************************************************** +* Power Control +*****************************************************************************/ +#if FTS_POWER_SOURCE_CUST_EN +static int fts_power_source_init(struct fts_ts_data *data) +{ + int rc; + + FTS_FUNC_ENTER(); + + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + rc = PTR_ERR(data->vdd); + FTS_ERROR("Regulator get failed vdd rc=%d", rc); + } + + if (regulator_count_voltages(data->vdd) > 0) { + rc = regulator_set_voltage(data->vdd, FTS_VTG_MIN_UV, + FTS_VTG_MAX_UV); + if (rc) { + FTS_ERROR("Regulator set_vtg failed vdd rc=%d", rc); + goto reg_vdd_put; + } + } + + data->vcc_i2c = regulator_get(&data->client->dev, "vcc-i2c"); + if (IS_ERR(data->vcc_i2c)) { + rc = PTR_ERR(data->vcc_i2c); + FTS_ERROR("Regulator get failed vcc-i2c rc=%d", rc); + goto reg_vdd_set_vtg; + } + + if (regulator_count_voltages(data->vcc_i2c) > 0) { + rc = regulator_set_voltage(data->vcc_i2c, FTS_I2C_VTG_MIN_UV, + FTS_I2C_VTG_MAX_UV); + if (rc) { + FTS_ERROR("Regulator set_vtg failed vcc-i2c rc=%d", + rc); + goto reg_vcc_i2c_put; + } + } + + FTS_FUNC_EXIT(); + return 0; + +reg_vcc_i2c_put: + regulator_put(data->vcc_i2c); +reg_vdd_set_vtg: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, FTS_VTG_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + FTS_FUNC_EXIT(); + return rc; +} + +static int fts_power_source_ctrl(struct fts_ts_data *data, int enable) +{ + int rc; + + FTS_FUNC_ENTER(); + if (enable) { + rc = regulator_enable(data->vdd); + if (rc) + FTS_ERROR("Regulator vdd enable failed rc=%d", rc); + + rc = regulator_enable(data->vcc_i2c); + if (rc) + FTS_ERROR("Regulator vcc_i2c enable failed rc=%d", rc); + } else { + rc = regulator_disable(data->vdd); + if (rc) + FTS_ERROR("Regulator vdd disable failed rc=%d", rc); + + rc = regulator_disable(data->vcc_i2c); + if (rc) + FTS_ERROR("Regulator vcc_i2c disable failed rc=%d", + rc); + } + FTS_FUNC_EXIT(); + return 0; +} + +#endif + + +/***************************************************************************** +* Reprot related +*****************************************************************************/ +/***************************************************************************** +* Name: fts_release_all_finger +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_release_all_finger(void) +{ +#if FTS_MT_PROTOCOL_B_EN + unsigned int finger_count = 0; +#endif + + mutex_lock(&fts_wq_data->report_mutex); +#if FTS_MT_PROTOCOL_B_EN + for (finger_count = 0; + finger_count < fts_wq_data->pdata->max_touch_number; + finger_count++) { + input_mt_slot(fts_input_dev, finger_count); + input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER, + false); + } +#else + input_mt_sync(fts_input_dev); +#endif + input_report_key(fts_input_dev, BTN_TOUCH, 0); + input_sync(fts_input_dev); + mutex_unlock(&fts_wq_data->report_mutex); +} + + +#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2)) +static void fts_show_touch_buffer(u8 *buf, int point_num) +{ + int len = point_num * FTS_ONE_TCH_LEN; + int count = 0; + int i; + + memset(g_sz_debug, 0, 1024); + if (len > (POINT_READ_BUF-3)) + len = POINT_READ_BUF-3; + else if (len == 0) { + len += FTS_ONE_TCH_LEN; + + count += snprintf(g_sz_debug, 1024, "%02X,%02X,%02X", + buf[0], buf[1], buf[2]); + for (i = 0; i < len; i++) + count += snprintf(g_sz_debug+count, 1024-count, + ",%02X", buf[i+3]); + + FTS_DEBUG("buffer: %s", g_sz_debug); +} +#endif + +static int fts_input_dev_report_key_event(struct ts_event *event, + struct fts_ts_data *data) +{ + int i; + + if (!data->pdata->have_key) + return -EINVAL; + + if ((1 == event->touch_point || 1 == event->point_num) && + (event->au16_y[0] == data->pdata->key_y_coord)) { + + if (event->point_num == 0) { + FTS_DEBUG("Keys All Up!"); + for (i = 0; i < data->pdata->key_number; i++) { + input_report_key(data->input_dev, + data->pdata->keys[i], 0); + } + + input_sync(data->input_dev); + return 0; + } + for (i = 0; i < data->pdata->key_number; i++) { + if (event->au16_x[0] > (data->pdata->key_x_coords[i] + - FTS_KEY_WIDTH) && (event->au16_x[0] < + (data->pdata->key_x_coords[i] + + FTS_KEY_WIDTH))) { + if (event->au8_touch_event[i] == 0 || + event->au8_touch_event[i] == 2) { + input_report_key(data->input_dev, + data->pdata->keys[i], 1); + FTS_DEBUG("Key%d(%d, %d) DOWN!", + i, event->au16_x[0], + event->au16_y[0]); + } else { + input_report_key(data->input_dev, + data->pdata->keys[i], 0); + FTS_DEBUG("Key%d(%d, %d) Up!", + i, event->au16_x[0], + event->au16_y[0]); + } + break; + } + } + input_sync(data->input_dev); + return 0; + } + + return -EINVAL; +} + +#if FTS_MT_PROTOCOL_B_EN +static int fts_input_dev_report_b(struct ts_event *event, + struct fts_ts_data *data) +{ + int i = 0; + int uppoint = 0; + int touchs = 0; + + for (i = 0; i < event->touch_point; i++) { + if (event->au8_finger_id[i] >= data->pdata->max_touch_number) + break; + + input_mt_slot(data->input_dev, event->au8_finger_id[i]); + + if (event->au8_touch_event[i] == FTS_TOUCH_DOWN || + event->au8_touch_event[i] == FTS_TOUCH_CONTACT) { + input_mt_report_slot_state(data->input_dev, + MT_TOOL_FINGER, true); + +#if FTS_REPORT_PRESSURE_EN +#if FTS_FORCE_TOUCH_EN + if (event->pressure[i] <= 0) { + FTS_ERROR("[B]Illegal pressure: %d", + event->pressure[i]); + event->pressure[i] = 1; + } +#else + event->pressure[i] = 0x3f; +#endif + input_report_abs(data->input_dev, ABS_MT_PRESSURE, + event->pressure[i]); +#endif + + if (event->area[i] <= 0) { + FTS_ERROR("[B]Illegal touch-major: %d", + event->area[i]); + event->area[i] = 1; + } + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, + event->area[i]); + + input_report_abs(data->input_dev, ABS_MT_POSITION_X, + event->au16_x[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, + event->au16_y[i]); + touchs |= BIT(event->au8_finger_id[i]); + data->touchs |= BIT(event->au8_finger_id[i]); + +#if FTS_REPORT_PRESSURE_EN + FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!", + event->au8_finger_id[i], + event->au16_x[i], event->au16_y[i], + event->pressure[i], event->area[i]); +#else + FTS_DEBUG("[B]P%d(%d, %d)[tm:%d] DOWN!", + event->au8_finger_id[i], + event->au16_x[i], event->au16_y[i], + event->area[i]); +#endif + } else { + uppoint++; + input_mt_report_slot_state(data->input_dev, + MT_TOOL_FINGER, false); +#if FTS_REPORT_PRESSURE_EN + input_report_abs(data->input_dev, ABS_MT_PRESSURE, 0); +#endif + data->touchs &= ~BIT(event->au8_finger_id[i]); + FTS_DEBUG("[B]P%d UP!", event->au8_finger_id[i]); + } + } + + if (unlikely(data->touchs ^ touchs)) { + for (i = 0; i < data->pdata->max_touch_number; i++) { + if (BIT(i) & (data->touchs ^ touchs)) { + FTS_DEBUG("[B]P%d UP!", i); + input_mt_slot(data->input_dev, i); + input_mt_report_slot_state(data->input_dev, + MT_TOOL_FINGER, false); +#if FTS_REPORT_PRESSURE_EN + input_report_abs(data->input_dev, + ABS_MT_PRESSURE, 0); +#endif + } + } + } + + data->touchs = touchs; + if (event->touch_point == uppoint) { + FTS_DEBUG("Points All Up!"); + input_report_key(data->input_dev, BTN_TOUCH, 0); + } else { + input_report_key(data->input_dev, BTN_TOUCH, + event->touch_point > 0); + } + + input_sync(data->input_dev); + + return 0; + +} + +#else +static int fts_input_dev_report_a(struct ts_event *event, + struct fts_ts_data *data) +{ + int i = 0; + int uppoint = 0; + int touchs = 0; + + for (i = 0; i < event->touch_point; i++) { + + if (event->au8_touch_event[i] == FTS_TOUCH_DOWN || + event->au8_touch_event[i] == FTS_TOUCH_CONTACT) { + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, + event->au8_finger_id[i]); +#if FTS_REPORT_PRESSURE_EN +#if FTS_FORCE_TOUCH_EN + if (event->pressure[i] <= 0) { + FTS_ERROR("[B]Illegal pressure: %d", + event->pressure[i]); + event->pressure[i] = 1; + } +#else + event->pressure[i] = 0x3f; +#endif + input_report_abs(data->input_dev, ABS_MT_PRESSURE, + event->pressure[i]); +#endif + + if (event->area[i] <= 0) { + FTS_ERROR("[B]Illegal touch-major: %d", + event->area[i]); + event->area[i] = 1; + } + + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, + event->area[i]); + + input_report_abs(data->input_dev, ABS_MT_POSITION_X, + event->au16_x[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, + event->au16_y[i]); + + input_mt_sync(data->input_dev); + +#if FTS_REPORT_PRESSURE_EN + FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!", + event->au8_finger_id[i], + event->au16_x[i], event->au16_y[i], + event->pressure[i], event->area[i]); +#else + FTS_DEBUG("[B]P%d(%d, %d)[tm:%d] DOWN!", + event->au8_finger_id[i], + event->au16_x[i], event->au16_y[i], + event->area[i]); +#endif + } else { + uppoint++; + } + } + + data->touchs = touchs; + if (event->touch_point == uppoint) { + FTS_DEBUG("Points All Up!"); + input_report_key(data->input_dev, BTN_TOUCH, 0); + input_mt_sync(data->input_dev); + } else { + input_report_key(data->input_dev, BTN_TOUCH, + event->touch_point > 0); + } + + input_sync(data->input_dev); + + return 0; +} +#endif + +/***************************************************************************** +* Name: fts_read_touchdata +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_read_touchdata(struct fts_ts_data *data) +{ + u8 buf[POINT_READ_BUF] = { 0 }; + u8 pointid = FTS_MAX_ID; + int ret = -1; + int i; + struct ts_event *event = &(data->event); + +#if FTS_GESTURE_EN + u8 state; + + if (data->suspended && data->pdata->wakeup_gestures_en) { + fts_i2c_read_reg(data->client, FTS_REG_GESTURE_EN, &state); + if (state == 1) { + fts_gesture_readdata(data->client); + return 1; + } + } +#endif + +#if FTS_PSENSOR_EN + if ((fts_sensor_read_data(data) != 0) && (data->suspended == 1)) + return 1; +#endif + + +#if FTS_READ_TOUCH_BUFFER_DIVIDED + memset(buf, 0xFF, POINT_READ_BUF); + memset(event, 0, sizeof(struct ts_event)); + + buf[0] = 0x00; + ret = fts_i2c_read(data->client, buf, 1, buf, (3 + FTS_ONE_TCH_LEN)); + if (ret < 0) { + FTS_ERROR("%s read touchdata failed.", __func__); + return ret; + } + event->touch_point = 0; + event->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F; + if (event->point_num > data->pdata->max_touch_number) + event->point_num = data->pdata->max_touch_number; + + if (event->point_num > 1) { + buf[9] = 0x09; + fts_i2c_read(data->client, buf+9, 1, buf+9, + (event->point_num - 1) * FTS_ONE_TCH_LEN); + } +#else + ret = fts_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF); + if (ret < 0) { + FTS_ERROR("[B]Read touchdata failed, ret: %d", ret); + return ret; + } + +#if FTS_POINT_REPORT_CHECK_EN + fts_point_report_check_queue_work(); +#endif + + memset(event, 0, sizeof(struct ts_event)); + event->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F; + if (event->point_num > data->pdata->max_touch_number) + event->point_num = data->pdata->max_touch_number; + event->touch_point = 0; +#endif + +#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2)) + fts_show_touch_buffer(buf, event->point_num); +#endif + + for (i = 0; i < data->pdata->max_touch_number; i++) { + pointid = (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4; + if (pointid >= FTS_MAX_ID) + break; + + event->touch_point++; + + event->au16_x[i] = + (s16) (buf[FTS_TOUCH_X_H_POS + FTS_ONE_TCH_LEN * i] + & 0x0F) << 8 | (s16) buf[FTS_TOUCH_X_L_POS + + FTS_ONE_TCH_LEN * i]; + event->au16_y[i] = + (s16) (buf[FTS_TOUCH_Y_H_POS + FTS_ONE_TCH_LEN * i] + & 0x0F) << 8 | (s16) buf[FTS_TOUCH_Y_L_POS + + FTS_ONE_TCH_LEN * i]; + event->au8_touch_event[i] = + buf[FTS_TOUCH_EVENT_POS + FTS_ONE_TCH_LEN * i] >> 6; + event->au8_finger_id[i] = + (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4; + event->area[i] = + (buf[FTS_TOUCH_AREA_POS + FTS_ONE_TCH_LEN * i]) >> 4; + event->pressure[i] = + (s16) buf[FTS_TOUCH_PRE_POS + FTS_ONE_TCH_LEN * i]; + + if (0 == event->area[i]) + event->area[i] = 0x09; + + if (0 == event->pressure[i]) + event->pressure[i] = 0x3f; + + if ((event->au8_touch_event[i] == 0 || + event->au8_touch_event[i] == 2) && + (event->point_num == 0)) { + FTS_DEBUG("abnormal touch data from fw"); + return -EINVAL; + } + } + + if (event->touch_point == 0) + return -EINVAL; + + return 0; +} + +/***************************************************************************** +* Name: fts_report_value +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_report_value(struct fts_ts_data *data) +{ + struct ts_event *event = &data->event; + + + FTS_DEBUG("point number: %d, touch point: %d", event->point_num, + event->touch_point); + + if (0 == fts_input_dev_report_key_event(event, data)) + return; + +#if FTS_MT_PROTOCOL_B_EN + fts_input_dev_report_b(event, data); +#else + fts_input_dev_report_a(event, data); +#endif + + + return; + +} + +/***************************************************************************** +* Name: fts_ts_interrupt +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static irqreturn_t fts_ts_interrupt(int irq, void *dev_id) +{ + struct fts_ts_data *fts_ts = dev_id; + int ret = -1; + + if (!fts_ts) { + FTS_ERROR("[INTR]: Invalid fts_ts"); + return IRQ_HANDLED; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_set_intr(1); +#endif + + ret = fts_read_touchdata(fts_wq_data); + + if (ret == 0) { + mutex_lock(&fts_wq_data->report_mutex); + fts_report_value(fts_wq_data); + mutex_unlock(&fts_wq_data->report_mutex); + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_set_intr(0); +#endif + + return IRQ_HANDLED; +} + +/***************************************************************************** +* Name: fts_gpio_configure +* Brief: Configure IRQ&RESET GPIO +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_gpio_configure(struct fts_ts_data *data) +{ + int err = 0; + + FTS_FUNC_ENTER(); + /* request irq gpio */ + if (gpio_is_valid(data->pdata->irq_gpio)) { + err = gpio_request(data->pdata->irq_gpio, "fts_irq_gpio"); + if (err) { + FTS_ERROR("[GPIO]irq gpio request failed"); + goto err_irq_gpio_req; + } + + err = gpio_direction_input(data->pdata->irq_gpio); + if (err) { + FTS_ERROR("[GPIO]set_direction for irq gpio failed"); + goto err_irq_gpio_dir; + } + } + /* request reset gpio */ + if (gpio_is_valid(data->pdata->reset_gpio)) { + err = gpio_request(data->pdata->reset_gpio, "fts_reset_gpio"); + if (err) { + FTS_ERROR("[GPIO]reset gpio request failed"); + goto err_irq_gpio_dir; + } + + err = gpio_direction_output(data->pdata->reset_gpio, 1); + if (err) { + FTS_ERROR("[GPIO]set_direction for reset gpio failed"); + goto err_reset_gpio_dir; + } + } + + FTS_FUNC_EXIT(); + return 0; + +err_reset_gpio_dir: + if (gpio_is_valid(data->pdata->reset_gpio)) + gpio_free(data->pdata->reset_gpio); +err_irq_gpio_dir: + if (gpio_is_valid(data->pdata->irq_gpio)) + gpio_free(data->pdata->irq_gpio); +err_irq_gpio_req: + FTS_FUNC_EXIT(); + return err; +} + + +/***************************************************************************** +* Name: fts_get_dt_coords +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_get_dt_coords(struct device *dev, char *name, + struct fts_ts_platform_data *pdata) +{ + u32 coords[FTS_COORDS_ARR_SIZE]; + struct property *prop; + struct device_node *np = dev->of_node; + int coords_size, rc; + + prop = of_find_property(np, name, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + + coords_size = prop->length / sizeof(u32); + if (coords_size != FTS_COORDS_ARR_SIZE) { + FTS_ERROR("invalid %s", name); + return -EINVAL; + } + + rc = of_property_read_u32_array(np, name, coords, coords_size); + if (rc && (rc != -EINVAL)) { + FTS_ERROR("Unable to read %s", name); + return rc; + } + + if (!strcmp(name, "focaltech,display-coords")) { + pdata->x_min = coords[0]; + pdata->y_min = coords[1]; + pdata->x_max = coords[2]; + pdata->y_max = coords[3]; + } else { + FTS_ERROR("unsupported property %s", name); + return -EINVAL; + } + + return 0; +} + +/***************************************************************************** +* Name: fts_parse_dt +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + u32 temp_val; + + FTS_FUNC_ENTER(); + + rc = fts_get_dt_coords(dev, "focaltech,display-coords", pdata); + if (rc) + FTS_ERROR("Unable to get display-coords"); + + /* key */ + pdata->have_key = of_property_read_bool(np, "focaltech,have-key"); + if (pdata->have_key) { + rc = of_property_read_u32(np, "focaltech,key-number", + &pdata->key_number); + if (rc) + FTS_ERROR("Key number undefined!"); + + rc = of_property_read_u32_array(np, "focaltech,keys", + pdata->keys, pdata->key_number); + if (rc) + FTS_ERROR("Keys undefined!"); + + rc = of_property_read_u32(np, "focaltech,key-y-coord", + &pdata->key_y_coord); + if (rc) + FTS_ERROR("Key Y Coord undefined!"); + + rc = of_property_read_u32_array(np, "focaltech,key-x-coords", + pdata->key_x_coords, pdata->key_number); + if (rc) + FTS_ERROR("Key X Coords undefined!"); + + FTS_DEBUG("%d: (%d, %d, %d), [%d, %d, %d][%d]", + pdata->key_number, pdata->keys[0], + pdata->keys[1], pdata->keys[2], + pdata->key_x_coords[0], + pdata->key_x_coords[1], + pdata->key_x_coords[2], + pdata->key_y_coord); + } + + /* reset, irq gpio info */ + pdata->reset_gpio = of_get_named_gpio_flags(np, + "focaltech,reset-gpio", 0, + &pdata->reset_gpio_flags); + if (pdata->reset_gpio < 0) + FTS_ERROR("Unable to get reset_gpio"); + + pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio", + 0, &pdata->irq_gpio_flags); + if (pdata->irq_gpio < 0) + FTS_ERROR("Unable to get irq_gpio"); + + rc = of_property_read_u32(np, "focaltech,max-touch-number", &temp_val); + if (!rc) { + pdata->max_touch_number = temp_val; + FTS_DEBUG("max_touch_number=%d", pdata->max_touch_number); + } else { + FTS_ERROR("Unable to get max-touch-number"); + pdata->max_touch_number = FTS_MAX_POINTS; + } + + pdata->wakeup_gestures_en = of_property_read_bool(np, + "focaltech,wakeup-gestures-en"); + + FTS_FUNC_EXIT(); + return 0; +} + +#if defined(CONFIG_FB) +/***************************************************************************** +* Name: fb_notifier_callback +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct fts_ts_data *fts_data = + container_of(self, struct fts_ts_data, fb_notif); + + if (evdata && evdata->data && event == FB_EVENT_BLANK && + fts_data && fts_data->client) { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK) + fts_ts_resume(&fts_data->client->dev); + else if (*blank == FB_BLANK_POWERDOWN || + *blank == FB_BLANK_VSYNC_SUSPEND) + fts_ts_suspend(&fts_data->client->dev); + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) +/***************************************************************************** +* Name: fts_ts_early_suspend +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_ts_early_suspend(struct early_suspend *handler) +{ + struct fts_ts_data *data = container_of(handler, + struct fts_ts_data, + early_suspend); + + fts_ts_suspend(&data->client->dev); +} + +/***************************************************************************** +* Name: fts_ts_late_resume +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_ts_late_resume(struct early_suspend *handler) +{ + struct fts_ts_data *data = container_of(handler, + struct fts_ts_data, + early_suspend); + + fts_ts_resume(&data->client->dev); +} +#endif + +/***************************************************************************** +* Name: fts_ts_probe +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct fts_ts_platform_data *pdata; + struct fts_ts_data *data; + struct input_dev *input_dev; + int err; + + FTS_FUNC_ENTER(); + /* 1. Get Platform data */ + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct fts_ts_platform_data), + GFP_KERNEL); + if (!pdata) { + FTS_ERROR("[MEMORY]Failed to allocate memory"); + FTS_FUNC_EXIT(); + return -ENOMEM; + } + + err = fts_parse_dt(&client->dev, pdata); + if (err) + FTS_ERROR("[DTS]DT parsing failed"); + } else { + pdata = client->dev.platform_data; + } + + if (!pdata) { + FTS_ERROR("Invalid pdata"); + FTS_FUNC_EXIT(); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + FTS_ERROR("I2C not supported"); + FTS_FUNC_EXIT(); + return -ENODEV; + } + + data = devm_kzalloc(&client->dev, sizeof(struct fts_ts_data), + GFP_KERNEL); + if (!data) { + FTS_ERROR("[MEMORY]Failed to allocate memory"); + FTS_FUNC_EXIT(); + return -ENOMEM; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + FTS_ERROR("[INPUT]Failed to allocate input device"); + FTS_FUNC_EXIT(); + return -ENOMEM; + } + + data->input_dev = input_dev; + data->client = client; + data->pdata = pdata; + + fts_wq_data = data; + fts_i2c_client = client; + fts_input_dev = input_dev; + + spin_lock_init(&fts_wq_data->irq_lock); + mutex_init(&fts_wq_data->report_mutex); + + fts_input_dev_init(client, data, input_dev, pdata); + +#if FTS_POWER_SOURCE_CUST_EN + fts_power_source_init(data); + fts_power_source_ctrl(data, 1); +#endif + + fts_ctpm_get_upgrade_array(); + + err = fts_gpio_configure(data); + if (err < 0) { + FTS_ERROR("[GPIO]Failed to configure the gpios"); + goto free_gpio; + } + + fts_reset_proc(200); + fts_wait_tp_to_valid(client); + + err = request_threaded_irq(client->irq, NULL, fts_ts_interrupt, + pdata->irq_gpio_flags | IRQF_ONESHOT | + IRQF_TRIGGER_FALLING, + client->dev.driver->name, data); + if (err) { + FTS_ERROR("Request irq failed!"); + goto free_gpio; + } + + fts_irq_disable(); + +#if FTS_PSENSOR_EN + if (fts_sensor_init(data) != 0) { + FTS_ERROR("fts_sensor_init failed!"); + FTS_FUNC_EXIT(); + return 0; + } +#endif + +#if FTS_APK_NODE_EN + fts_create_apk_debug_channel(client); +#endif + +#if FTS_SYSFS_NODE_EN + fts_create_sysfs(client); +#endif + +#if FTS_POINT_REPORT_CHECK_EN + fts_point_report_check_init(); +#endif + + fts_ex_mode_init(client); + +#if FTS_GESTURE_EN + fts_gesture_init(input_dev, client); +#endif + +#if FTS_ESDCHECK_EN + fts_esdcheck_init(); +#endif + + fts_irq_enable(); + +#if FTS_AUTO_UPGRADE_EN + fts_ctpm_upgrade_init(); +#endif + +#if FTS_TEST_EN + fts_test_init(client); +#endif + +#if defined(CONFIG_FB) + data->fb_notif.notifier_call = fb_notifier_callback; + err = fb_register_client(&data->fb_notif); + if (err) + FTS_ERROR("[FB]Unable to register fb_notifier: %d", err); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + + FTS_SUSPEND_LEVEL; + data->early_suspend.suspend = fts_ts_early_suspend; + data->early_suspend.resume = fts_ts_late_resume; + register_early_suspend(&data->early_suspend); +#endif + + FTS_FUNC_EXIT(); + return 0; + +free_gpio: + if (gpio_is_valid(pdata->reset_gpio)) + gpio_free(pdata->reset_gpio); + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); + return err; + +} + +/***************************************************************************** +* Name: fts_ts_remove +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_remove(struct i2c_client *client) +{ + struct fts_ts_data *data = i2c_get_clientdata(client); + + FTS_FUNC_ENTER(); + cancel_work_sync(&data->touch_event_work); + +#if FTS_PSENSOR_EN + fts_sensor_remove(data); +#endif + +#if FTS_POINT_REPORT_CHECK_EN + fts_point_report_check_exit(); +#endif + +#if FTS_APK_NODE_EN + fts_release_apk_debug_channel(); +#endif + +#if FTS_SYSFS_NODE_EN + fts_remove_sysfs(client); +#endif + + fts_ex_mode_exit(client); + +#if FTS_AUTO_UPGRADE_EN + cancel_work_sync(&fw_update_work); +#endif + +#if defined(CONFIG_FB) + if (fb_unregister_client(&data->fb_notif)) + FTS_ERROR("Error occurred while unregistering fb_notifier."); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&data->early_suspend); +#endif + free_irq(client->irq, data); + + if (gpio_is_valid(data->pdata->reset_gpio)) + gpio_free(data->pdata->reset_gpio); + + if (gpio_is_valid(data->pdata->irq_gpio)) + gpio_free(data->pdata->irq_gpio); + + input_unregister_device(data->input_dev); + +#if FTS_TEST_EN + fts_test_exit(client); +#endif + +#if FTS_ESDCHECK_EN + fts_esdcheck_exit(); +#endif + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_ts_suspend +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_suspend(struct device *dev) +{ + struct fts_ts_data *data = dev_get_drvdata(dev); + int retval = 0; + + FTS_FUNC_ENTER(); + if (data->suspended) { + FTS_INFO("Already in suspend state"); + FTS_FUNC_EXIT(); + return -EINVAL; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_suspend(); +#endif + +#if FTS_GESTURE_EN + if (data->pdata->wakeup_gestures_en) { + retval = fts_gesture_suspend(data->client); + if (retval == 0) { + /* Enter into gesture mode(suspend) */ + retval = enable_irq_wake(fts_wq_data->client->irq); + if (retval) + FTS_ERROR("%s: set_irq_wake failed", __func__); + data->suspended = true; + FTS_FUNC_EXIT(); + return 0; + } + } +#endif + +#if FTS_PSENSOR_EN + if (fts_sensor_suspend(data) != 0) { + enable_irq_wake(data->client->irq); + data->suspended = true; + return 0; + } +#endif + + fts_irq_disable(); + + /* TP enter sleep mode */ + retval = fts_i2c_write_reg(data->client, FTS_REG_POWER_MODE, + FTS_REG_POWER_MODE_SLEEP_VALUE); + if (retval < 0) + FTS_ERROR("Set TP to sleep mode fail, ret=%d!", retval); + + data->suspended = true; + + FTS_FUNC_EXIT(); + + return 0; +} + +/***************************************************************************** +* Name: fts_ts_resume +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_resume(struct device *dev) +{ + struct fts_ts_data *data = dev_get_drvdata(dev); + + FTS_FUNC_ENTER(); + if (!data->suspended) { + FTS_DEBUG("Already in awake state"); + FTS_FUNC_EXIT(); + return -EINVAL; + } + + fts_release_all_finger(); + +#if (!FTS_CHIP_IDC) + fts_reset_proc(200); +#endif + + fts_tp_state_recovery(data->client); + +#if FTS_ESDCHECK_EN + fts_esdcheck_resume(); +#endif + +#if FTS_GESTURE_EN + if (data->pdata->wakeup_gestures_en) { + if (fts_gesture_resume(data->client) == 0) { + int err; + + err = disable_irq_wake(data->client->irq); + if (err) + FTS_ERROR("%s: disable_irq_wake failed", + __func__); + data->suspended = false; + FTS_FUNC_EXIT(); + return 0; + } + } +#endif + +#if FTS_PSENSOR_EN + if (fts_sensor_resume(data) != 0) { + disable_irq_wake(data->client->irq); + data->suspended = false; + FTS_FUNC_EXIT(); + return 0; + } +#endif + + data->suspended = false; + + fts_irq_enable(); + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* I2C Driver +*****************************************************************************/ +static const struct i2c_device_id fts_ts_id[] = { + {FTS_DRIVER_NAME, 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, fts_ts_id); + +static struct of_device_id fts_match_table[] = { + { .compatible = "focaltech,fts", }, + { }, +}; + +static struct i2c_driver fts_ts_driver = { + .probe = fts_ts_probe, + .remove = fts_ts_remove, + .driver = { + .name = FTS_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = fts_match_table, + }, + .id_table = fts_ts_id, +}; + +/***************************************************************************** +* Name: fts_ts_init +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int __init fts_ts_init(void) +{ + int ret = 0; + + FTS_FUNC_ENTER(); + ret = i2c_add_driver(&fts_ts_driver); + if (ret != 0) + FTS_ERROR("Focaltech touch screen driver init failed!"); + + FTS_FUNC_EXIT(); + return ret; +} + +/***************************************************************************** +* Name: fts_ts_exit +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void __exit fts_ts_exit(void) +{ + i2c_del_driver(&fts_ts_driver); +} + +module_init(fts_ts_init); +module_exit(fts_ts_exit); + +MODULE_DESCRIPTION("FocalTech Touchscreen Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.h b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h new file mode 100644 index 0000000000000000000000000000000000000000..f0e0adeaa8faa53731c1b3024b991575474fb14a --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h @@ -0,0 +1,194 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_core.h + +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +#ifndef __LINUX_FOCALTECH_CORE_H__ +#define __LINUX_FOCALTECH_CORE_H__ +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "focaltech_common.h" +#include "focaltech_flash.h" +#if FTS_PSENSOR_EN +#include +#endif +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define LEN_FLASH_ECC_MAX 0xFFFE + +#define FTS_WORKQUEUE_NAME "fts_wq" + +#define FTS_MAX_POINTS 10 +#define FTS_KEY_WIDTH 50 +#define FTS_ONE_TCH_LEN 6 +#define POINT_READ_BUF (3 + FTS_ONE_TCH_LEN * FTS_MAX_POINTS) + +#define FTS_MAX_ID 0x0F +#define FTS_TOUCH_X_H_POS 3 +#define FTS_TOUCH_X_L_POS 4 +#define FTS_TOUCH_Y_H_POS 5 +#define FTS_TOUCH_Y_L_POS 6 +#define FTS_TOUCH_PRE_POS 7 +#define FTS_TOUCH_AREA_POS 8 +#define FTS_TOUCH_POINT_NUM 2 +#define FTS_TOUCH_EVENT_POS 3 +#define FTS_TOUCH_ID_POS 5 +#define FTS_COORDS_ARR_SIZE 4 + +#define FTS_TOUCH_DOWN 0 +#define FTS_TOUCH_UP 1 +#define FTS_TOUCH_CONTACT 2 + +#define FTS_SYSFS_ECHO_ON(buf) ((strnicmp(buf, "1", 1) == 0) || \ + (strnicmp(buf, "on", 2) == 0)) +#define FTS_SYSFS_ECHO_OFF(buf) ((strnicmp(buf, "0", 1) == 0) || \ + (strnicmp(buf, "off", 3) == 0)) + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + + +struct fts_ts_platform_data { + int irq_gpio; + u32 irq_gpio_flags; + int reset_gpio; + u32 reset_gpio_flags; + bool have_key; + u32 key_number; + u32 keys[4]; + u32 key_y_coord; + u32 key_x_coords[4]; + u32 x_max; + u32 y_max; + u32 x_min; + u32 y_min; + u32 max_touch_number; + bool wakeup_gestures_en; +}; + +struct ts_event { + u16 au16_x[FTS_MAX_POINTS]; /*x coordinate */ + u16 au16_y[FTS_MAX_POINTS]; /*y coordinate */ + u16 pressure[FTS_MAX_POINTS]; + u8 au8_touch_event[FTS_MAX_POINTS]; /* touch event: + 0 -- down; + 1-- up; + 2 -- contact */ + u8 au8_finger_id[FTS_MAX_POINTS]; /* touch ID */ + u8 area[FTS_MAX_POINTS]; + u8 touch_point; + u8 point_num; +}; + +struct fts_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + const struct fts_ts_platform_data *pdata; +#if FTS_PSENSOR_EN + struct fts_psensor_platform_data *psensor_pdata; +#endif + struct work_struct touch_event_work; + struct workqueue_struct *ts_workqueue; + struct regulator *vdd; + struct regulator *vcc_i2c; + spinlock_t irq_lock; + struct mutex report_mutex; + u16 addr; + bool suspended; + u8 fw_ver[3]; + u8 fw_vendor_id; + int touchs; + int irq_disable; + +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +}; + + +#if FTS_PSENSOR_EN +struct fts_psensor_platform_data { + struct input_dev *input_psensor_dev; + struct sensors_classdev ps_cdev; + int tp_psensor_opened; + char tp_psensor_data; /* 0 near, 1 far */ + struct fts_ts_data *data; +}; + +int fts_sensor_init(struct fts_ts_data *data); +int fts_sensor_read_data(struct fts_ts_data *data); +int fts_sensor_suspend(struct fts_ts_data *data); +int fts_sensor_resume(struct fts_ts_data *data); +int fts_sensor_remove(struct fts_ts_data *data); +#endif + +/***************************************************************************** +* Static variables +*****************************************************************************/ +extern struct i2c_client *fts_i2c_client; +extern struct fts_ts_data *fts_wq_data; +extern struct input_dev *fts_input_dev; + +#endif /* __LINUX_FOCALTECH_CORE_H__ */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c b/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c new file mode 100644 index 0000000000000000000000000000000000000000..83e00569833fc61a6796a079b0a513566c3900c3 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c @@ -0,0 +1,473 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved. + * + * 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_esdcheck.c +* +* Author: luoguojin +* +* Created: 2016-08-03 +* +* Abstract: ESD check function +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By luougojin 2016-08-03 +* v1.1: By luougojin 2017-02-15 +* 1. Add LCD_ESD_PATCH to control idc_esdcheck_lcderror +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +#if FTS_ESDCHECK_EN +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define ESDCHECK_WAIT_TIME 1000 /* ms */ +#define LCD_ESD_PATCH 0 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +struct fts_esdcheck_st { + u8 active : 1; /* 1- esd check active, need check esd + 0- no esd check */ + u8 suspend : 1; + u8 proc_debug : 1; /* apk or adb is accessing I2C */ + u8 intr : 1; /* 1- Interrupt trigger */ + u8 unused : 4; + u8 flow_work_hold_cnt; /* Flow Work Cnt(reg0x91) + keep a same value for x times. + >=5 times is ESD, need reset */ + u8 flow_work_cnt_last; /* Save Flow Work Cnt(reg0x91) value */ + u32 hardware_reset_cnt; + u32 i2c_nack_cnt; + u32 i2c_dataerror_cnt; +}; + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct delayed_work fts_esdcheck_work; +static struct workqueue_struct *fts_esdcheck_workqueue; +static struct fts_esdcheck_st fts_esdcheck_data; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ +#if LCD_ESD_PATCH +/***************************************************************************** +* Name: lcd_esdcheck +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +int lcd_need_reset; +static int tp_need_recovery; /* LCD reset cause Tp reset */ +int idc_esdcheck_lcderror(void) +{ + u8 val; + int ret; + + FTS_DEBUG("[ESD]Check LCD ESD"); + if ((tp_need_recovery == 1) && (lcd_need_reset == 0)) { + tp_need_recovery = 0; + /* LCD reset, need recover TP state */ + fts_tp_state_recovery(fts_i2c_client); + } + + ret = fts_i2c_read_reg(fts_i2c_client, FTS_REG_ESD_SATURATE, &val); + if (ret < 0) { + FTS_ERROR("[ESD]: Read ESD_SATURATE(0xED) failed ret=%d", ret); + return -EIO; + } + + if (val == 0xAA) { + /* + * 1. Set flag lcd_need_reset = 1; + * 2. LCD driver need reset(recovery) LCD and + * set lcd_need_reset to 0 + * 3. recover TP state + */ + FTS_INFO("LCD ESD, Execute LCD reset!"); + lcd_need_reset = 1; + tp_need_recovery = 1; + } + + return 0; +} +#endif + +/***************************************************************************** +* Name: fts_esdcheck_tp_reset +* Brief: esd check algorithm +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_esdcheck_tp_reset(void) +{ + FTS_FUNC_ENTER(); + + fts_esdcheck_data.flow_work_hold_cnt = 0; + fts_esdcheck_data.hardware_reset_cnt++; + + fts_reset_proc(200); + fts_tp_state_recovery(fts_i2c_client); + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: get_chip_id +* Brief: Read Chip Id 3 times +* Input: +* Output: +* Return: 1 - Read Chip Id 3 times failed +* 0 - Read Chip Id pass +*****************************************************************************/ +static bool get_chip_id(void) +{ + int err = 0; + int i = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + + for (i = 0; i < 3; i++) { + reg_addr = FTS_REG_CHIP_ID; + err = fts_i2c_read(fts_i2c_client, ®_addr, 1, + ®_value, 1); + + if (err < 0) { + FTS_ERROR("[ESD]: Read Reg 0xA3 failed ret = %d!!", + err); + fts_esdcheck_data.i2c_nack_cnt++; + } else { + /* Upgrade sometimes can't detect */ + if ((reg_value == chip_types.chip_idh) + || (reg_value == 0xEF)) + break; + + fts_esdcheck_data.i2c_dataerror_cnt++; + } + } + + /* if can't get correct data in 3 times, then need hardware reset */ + if (i >= 3) { + FTS_ERROR("[ESD]: Read Chip id failed, need TP reset!!"); + return 1; + } + + return 0; +} + +/***************************************************************************** +* Name: get_flow_cnt +* Brief: Read flow cnt(0x91) +* Input: +* Output: +* Return: 1 - Reg 0x91(flow cnt) abnormal: hold a value for 5 times +* 0 - Reg 0x91(flow cnt) normal +*****************************************************************************/ +static bool get_flow_cnt(void) +{ + int err = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + + reg_addr = FTS_REG_FLOW_WORK_CNT; + err = fts_i2c_read(fts_i2c_client, ®_addr, 1, ®_value, 1); + if (err < 0) { + FTS_ERROR("[ESD]: Read Reg 0x91 failed ret = %d!!", err); + fts_esdcheck_data.i2c_nack_cnt++; + } else { + if (reg_value == fts_esdcheck_data.flow_work_cnt_last) + fts_esdcheck_data.flow_work_hold_cnt++; + else + fts_esdcheck_data.flow_work_hold_cnt = 0; + + fts_esdcheck_data.flow_work_cnt_last = reg_value; + } + + /* if read flow work cnt 5 times and the value are all the same, + * then need hardware_reset */ + if (fts_esdcheck_data.flow_work_hold_cnt >= 5) { + FTS_DEBUG("[ESD]: Flow Work Cnt, need execute TP reset!!"); + return 1; + } + + return 0; +} + +/***************************************************************************** +* Name: esdcheck_algorithm +* Brief: esd check algorithm +* Input: +* Output: +* Return: +*****************************************************************************/ +static int esdcheck_algorithm(void) +{ + int err = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + bool hardware_reset = 0; + + /* 1. esdcheck is interrupt, then return */ + if (fts_esdcheck_data.intr == 1) { + FTS_INFO("[ESD]: In interrupt state, not check esd, return!!"); + return 0; + } + + /* 2. check power state, if suspend, no need check esd */ + if (fts_esdcheck_data.suspend == 1) { + FTS_INFO("[ESD]: In suspend, not check esd, return!!"); + /* because in suspend state, adb can be used, when upgrade FW, + * will active ESD check(active = 1). + * But in suspend, then will don't queue_delayed_work, + * when resume, don't check ESD again + */ + fts_esdcheck_data.active = 0; + return 0; + } + + /* 3. check fts_esdcheck_data.proc_debug state, + * if 1-proc busy, no need check esd*/ + if (fts_esdcheck_data.proc_debug == 1) { + FTS_INFO("[ESD]: In cmd mode, not check esd, return!!"); + return 0; + } + + /* 4. In factory mode, can't check esd */ + reg_addr = FTS_REG_WORKMODE; + err = fts_i2c_read(fts_i2c_client, ®_addr, 1, ®_value, 1); + if (err < 0) { + fts_esdcheck_data.i2c_nack_cnt++; + } else if ((reg_value & 0x70) == FTS_REG_WORKMODE_FACTORY_VALUE) { + FTS_INFO("[ESD]: In factory mode, not check esd, return!!"); + return 0; + } + + /* 5. IDC esd check lcd default:close */ +#if LCD_ESD_PATCH + idc_esdcheck_lcderror(); +#endif + + /* 6. Get Chip ID */ + hardware_reset = get_chip_id(); + + /* 7. get Flow work cnt: 0x91 If no change for 5 times, + * then ESD and reset */ + if (!hardware_reset) + hardware_reset = get_flow_cnt(); + + /* 8. If need hardware reset, then handle it here */ + if (hardware_reset == 1) + fts_esdcheck_tp_reset(); + + FTS_INFO("[ESD]: NoACK=%d, Error Data=%d, Hardware Reset=%d\n", + fts_esdcheck_data.i2c_nack_cnt, + fts_esdcheck_data.i2c_dataerror_cnt, + fts_esdcheck_data.hardware_reset_cnt); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_func +* Brief: fts_esdcheck_func +* Input: +* Output: +* Return: +*****************************************************************************/ +static void esdcheck_func(struct work_struct *work) +{ + FTS_FUNC_ENTER(); + + esdcheck_algorithm(); + + if (fts_esdcheck_data.suspend == 0) { + queue_delayed_work(fts_esdcheck_workqueue, + &fts_esdcheck_work, + msecs_to_jiffies(ESDCHECK_WAIT_TIME)); + } + + FTS_FUNC_EXIT(); +} + +/***************************************************************************** +* Name: fts_esdcheck_set_intr +* Brief: interrupt flag (main used in interrupt tp report) +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_set_intr(bool intr) +{ + /* interrupt don't add debug message */ + fts_esdcheck_data.intr = intr; + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_get_status(void) +* Brief: get current status +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_get_status(void) +{ + /* interrupt don't add debug message */ + return fts_esdcheck_data.active; +} + +/***************************************************************************** +* Name: fts_esdcheck_proc_busy +* Brief: When APK or ADB command access TP via driver, then need +* set proc_debug, then will not check ESD. +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_proc_busy(bool proc_debug) +{ + fts_esdcheck_data.proc_debug = proc_debug; + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_switch +* Brief: FTS esd check function switch. +* Input: enable: 1 - Enable esd check +* 0 - Disable esd check +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_switch(bool enable) +{ + FTS_FUNC_ENTER(); + if (enable == 1) { + if (fts_esdcheck_data.active == 0) { + FTS_INFO("[ESD]: ESD check start!!"); + fts_esdcheck_data.active = 1; + queue_delayed_work(fts_esdcheck_workqueue, + &fts_esdcheck_work, + msecs_to_jiffies(ESDCHECK_WAIT_TIME)); + } + } else { + if (fts_esdcheck_data.active == 1) { + FTS_INFO("[ESD]: ESD check stop!!"); + fts_esdcheck_data.active = 0; + cancel_delayed_work_sync(&fts_esdcheck_work); + } + } + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_suspend +* Brief: Run when tp enter into suspend +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_suspend(void) +{ + FTS_FUNC_ENTER(); + fts_esdcheck_switch(DISABLE); + fts_esdcheck_data.suspend = 1; + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_resume +* Brief: Run when tp resume +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_resume(void) +{ + FTS_FUNC_ENTER(); + fts_esdcheck_switch(ENABLE); + fts_esdcheck_data.suspend = 0; + FTS_FUNC_EXIT(); + return 0; +} + + +/***************************************************************************** +* Name: fts_esdcheck_init +* Brief: Init and create a queue work to check esd +* Input: +* Output: +* Return: < 0: Fail to create esd check queue +*****************************************************************************/ +int fts_esdcheck_init(void) +{ + FTS_FUNC_ENTER(); + + INIT_DELAYED_WORK(&fts_esdcheck_work, esdcheck_func); + fts_esdcheck_workqueue = create_workqueue("fts_esdcheck_wq"); + if (fts_esdcheck_workqueue == NULL) + FTS_INFO("[ESD]: Failed to create esd work queue!!"); + + memset((u8 *)&fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st)); + + fts_esdcheck_switch(ENABLE); + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_exit +* Brief: When FTS TP driver is removed, then call this function +* to destroy work queue +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_exit(void) +{ + FTS_FUNC_ENTER(); + + destroy_workqueue(fts_esdcheck_workqueue); + + FTS_FUNC_EXIT(); + return 0; +} +#endif /* FTS_ESDCHECK_EN */ + diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c new file mode 100644 index 0000000000000000000000000000000000000000..db0f8a4a49094f1d8824a44de405e3e1dcfabc07 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c @@ -0,0 +1,1145 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_ex_fun.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +/*create apk debug channel*/ +#define PROC_UPGRADE 0 +#define PROC_READ_REGISTER 1 +#define PROC_WRITE_REGISTER 2 +#define PROC_AUTOCLB 4 +#define PROC_UPGRADE_INFO 5 +#define PROC_WRITE_DATA 6 +#define PROC_READ_DATA 7 +#define PROC_SET_TEST_FLAG 8 +#define PROC_SET_SLAVE_ADDR 10 +#define PROC_HW_RESET 11 +#define PROC_NAME "ftxxxx-debug" +#define WRITE_BUF_SIZE 512 +#define READ_BUF_SIZE 512 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static unsigned char proc_operate_mode = PROC_UPGRADE; +static struct proc_dir_entry *fts_proc_entry; +static struct +{ + int op; /* 0: read, 1: write */ + int reg; /* register */ + int value; /* read: return value, write: op return */ + int result; /* 0: success, otherwise: fail */ +} g_rwreg_result; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if FTS_ESDCHECK_EN +static void esd_process(u8 *writebuf, int buflen, bool flag) +{ + if (flag) { + if ((writebuf[1] == 0xFC) && (writebuf[2] == 0x55) + && (buflen == 0x03)) { + /* Upgrade command */ + FTS_DEBUG("[ESD]: Upgrade command(%x %x %x)!!", + writebuf[0], writebuf[1], writebuf[2]); + fts_esdcheck_switch(DISABLE); + } else if ((writebuf[1] == 0x00) && (writebuf[2] == 0x40) + && (buflen == 0x03)) { + /* factory mode bit 4 5 6 */ + FTS_DEBUG("[ESD]: Entry factory mode(%x %x %x)!!", + writebuf[0], writebuf[1], writebuf[2]); + fts_esdcheck_switch(DISABLE); + } else if ((writebuf[1] == 0x00) && (writebuf[2] == 0x00) + && (buflen == 0x03)) { + /* normal mode bit 4 5 6 */ + FTS_DEBUG("[ESD]: Exit factory mode(%x %x %x)!!", + writebuf[0], writebuf[1], writebuf[2]); + fts_esdcheck_switch(ENABLE); + } else { + fts_esdcheck_proc_busy(1); + } + } else { + if ((writebuf[1] == 0x07) && (buflen == 0x02)) { + FTS_DEBUG("[ESD]: Upgrade finish-trigger (07)(%x %x)!!", + writebuf[0], writebuf[1]); + fts_esdcheck_switch(ENABLE); + } else { + fts_esdcheck_proc_busy(0); + } + } +} +#endif + +/*interface of write proc*/ +/************************************************************************ +* Name: fts_debug_write +* Brief:interface of write proc +* Input: file point, data buf, data len, no use +* Output: no +* Return: data len +***********************************************************************/ +static ssize_t fts_debug_write(struct file *filp, const char __user *buff, + size_t count, loff_t *ppos) +{ + unsigned char writebuf[WRITE_BUF_SIZE]; + char upgrade_file_path[FILE_NAME_LENGTH]; + int buflen = count; + int writelen = 0; + int ret = 0; + char tmp[25]; + + if (copy_from_user(&writebuf, buff, buflen)) { + FTS_DEBUG("[APK]: copy from user error!!"); + return -EFAULT; + } +#if FTS_ESDCHECK_EN + esd_process(writebuf, buflen, 1); +#endif + proc_operate_mode = writebuf[0]; + switch (proc_operate_mode) { + case PROC_UPGRADE: + + memset(upgrade_file_path, 0, sizeof(upgrade_file_path)); + snprintf(upgrade_file_path, FILE_NAME_LENGTH, + "%s", writebuf + 1); + upgrade_file_path[buflen-1] = '\0'; + FTS_DEBUG("%s\n", upgrade_file_path); + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + if (fts_updatefun_curr.upgrade_with_app_bin_file) + ret = fts_updatefun_curr. + upgrade_with_app_bin_file(fts_i2c_client, + upgrade_file_path); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + if (ret < 0) + FTS_ERROR("[APK]: upgrade failed!!"); + break; + + case PROC_SET_TEST_FLAG: + FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x!!", writebuf[1]); +#if FTS_ESDCHECK_EN + if (writebuf[1] == 0) + fts_esdcheck_switch(DISABLE); + else + fts_esdcheck_switch(ENABLE); +#endif + break; + case PROC_READ_REGISTER: + writelen = 1; + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + FTS_ERROR("[APK]: write iic error!!"); + break; + case PROC_WRITE_REGISTER: + writelen = 2; + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + FTS_ERROR("[APK]: write iic error!!"); + break; + case PROC_SET_SLAVE_ADDR: + ret = fts_i2c_client->addr; + FTS_DEBUG("Original i2c addr 0x%x ", ret << 1); + if (writebuf[1] != fts_i2c_client->addr) { + fts_i2c_client->addr = writebuf[1]; + FTS_DEBUG("Change i2c addr 0x%x to 0x%x", ret << 1, + writebuf[1] << 1); + + } + break; + + case PROC_HW_RESET: + + snprintf(tmp, 25, "%s", writebuf + 1); + tmp[buflen - 1] = '\0'; + if (memcmp(tmp, "focal_driver", 12) == 0) { + FTS_DEBUG("Begin HW Reset"); + fts_reset_proc(1); + } + + break; + + case PROC_AUTOCLB: + FTS_DEBUG("[APK]: autoclb!!"); + fts_ctpm_auto_clb(fts_i2c_client); + break; + case PROC_READ_DATA: + case PROC_WRITE_DATA: + writelen = count - 1; + if (writelen > 0) { + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, + writelen); + if (ret < 0) + FTS_ERROR("[APK]: write iic error!!"); + } + break; + default: + break; + } + +#if FTS_ESDCHECK_EN + esd_process(writebuf, buflen, 0); +#endif + + if (ret < 0) + return ret; + else + return count; +} + +/* interface of read proc */ +/************************************************************************ +* Name: fts_debug_read +* Brief:interface of read proc +* Input: point to the data, no use, no use, read len, no use, no use +* Output: page point to data +* Return: read char number +***********************************************************************/ +static ssize_t fts_debug_read(struct file *filp, char __user *buff, + size_t count, loff_t *ppos) +{ + int ret = 0; + int num_read_chars = 0; + int readlen = 0; + u8 regvalue = 0x00, regaddr = 0x00; + unsigned char buf[READ_BUF_SIZE]; + + memset(buf, 0, READ_BUF_SIZE); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + switch (proc_operate_mode) { + case PROC_UPGRADE: + /* after calling fts_debug_write to upgrade */ + regaddr = FTS_REG_FW_VER; + ret = fts_i2c_read_reg(fts_i2c_client, regaddr, ®value); + if (ret < 0) + num_read_chars = snprintf(buf, READ_BUF_SIZE, "%s", + "get fw version failed.\n"); + else + num_read_chars = snprintf(buf, READ_BUF_SIZE, + "current fw ver:0x%02x\n", regvalue); + break; + case PROC_READ_REGISTER: + readlen = 1; + ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen); + if (ret < 0) { +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + FTS_ERROR("[APK]: read iic error!!"); + return ret; + } + num_read_chars = 1; + break; + case PROC_READ_DATA: + readlen = count; + ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen); + if (ret < 0) { +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + FTS_ERROR("[APK]: read iic error!!"); + return ret; + } + + num_read_chars = readlen; + break; + case PROC_WRITE_DATA: + break; + default: + break; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + + if (copy_to_user(buff, buf, num_read_chars)) { + FTS_ERROR("[APK]: copy to user error!!"); + return -EFAULT; + } + + return num_read_chars; +} + +static const struct file_operations fts_proc_fops = { + .owner = THIS_MODULE, + .read = fts_debug_read, + .write = fts_debug_write, +}; + +/************************************************************************ +* Name: fts_create_apk_debug_channel +* Brief: create apk debug channel +* Input: i2c info +* Output: no +* Return: success =0 +***********************************************************************/ +int fts_create_apk_debug_channel(struct i2c_client *client) +{ + fts_proc_entry = proc_create(PROC_NAME, 0777, NULL, &fts_proc_fops); + if (NULL == fts_proc_entry) { + FTS_ERROR("Couldn't create proc entry!"); + return -ENOMEM; + } + + FTS_INFO("Create proc entry success!"); + + return 0; +} + +/************************************************************************ +* Name: fts_release_apk_debug_channel +* Brief: release apk debug channel +* Input: no +* Output: no +* Return: no +***********************************************************************/ +void fts_release_apk_debug_channel(void) +{ + if (fts_proc_entry) + proc_remove(fts_proc_entry); +} + +/* + * fts_hw_reset interface + */ +static ssize_t fts_hw_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} +static ssize_t fts_hw_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + + fts_reset_proc(200); + + count = snprintf(buf, PAGE_SIZE, "hw reset executed\n"); + + return count; +} + +/* + * fts_irq interface + */ +static ssize_t fts_irq_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_INFO("[EX-FUN]enable irq"); + fts_irq_enable(); + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_INFO("[EX-FUN]disable irq"); + fts_irq_disable(); + } + + return count; +} + +static ssize_t fts_irq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return -EPERM; +} + +/************************************************************************ +* Name: fts_tpfwver_show +* Brief: show tp fw vwersion +* Input: device, device attribute, char buf +* Output: no +* Return: char number +***********************************************************************/ +static ssize_t fts_tpfwver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t num_read_chars = 0; + u8 fwver = 0; + + mutex_lock(&fts_input_dev->mutex); + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + if (fts_i2c_read_reg(fts_i2c_client, FTS_REG_FW_VER, &fwver) < 0) + num_read_chars = snprintf(buf, PAGE_SIZE, + "I2c transfer error!\n"); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + if (fwver == 255) + num_read_chars = snprintf(buf, PAGE_SIZE, + "get tp fw version fail!\n"); + else + num_read_chars = snprintf(buf, PAGE_SIZE, "%02X\n", fwver); + + mutex_unlock(&fts_input_dev->mutex); + + return num_read_chars; +} +/************************************************************************ +* Name: fts_tpfwver_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_tpfwver_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +static int fts_is_hex_char(const char ch) +{ + int result = 0; + + if (ch >= '0' && ch <= '9') + result = 1;/* (int)(ch - '0'); */ + else if (ch >= 'a' && ch <= 'f') + result = 1;/* (int)(ch - 'a') + 10; */ + else if (ch >= 'A' && ch <= 'F') + result = 1;/* (int)(ch - 'A') + 10; */ + else + result = 0; + + return result; +} + +static int fts_hex_char_to_int(const char ch) +{ + int result = 0; + + if (ch >= '0' && ch <= '9') + result = (int)(ch - '0'); + else if (ch >= 'a' && ch <= 'f') + result = (int)(ch - 'a') + 10; + else if (ch >= 'A' && ch <= 'F') + result = (int)(ch - 'A') + 10; + else + result = -1; + + return result; +} + +static int fts_hex_to_str(char *hex, int iHexLen, char *ch, int *iChLen) +{ + int high = 0; + int low = 0; + int tmp = 0; + int i = 0; + int iCharLen = 0; + + if (hex == NULL || ch == NULL) + return -EINVAL; + + FTS_DEBUG("iHexLen: %d in function:%s!!\n\n", iHexLen, __func__); + + if (iHexLen % 2 == 1) + return -EINVAL; + + for (i = 0; i < iHexLen; i += 2) { + high = fts_hex_char_to_int(hex[i]); + if (high < 0) { + ch[iCharLen] = '\0'; + return -EINVAL; + } + + low = fts_hex_char_to_int(hex[i+1]); + if (low < 0) { + ch[iCharLen] = '\0'; + return -EINVAL; + } + + tmp = (high << 4) + low; + ch[iCharLen++] = (char)tmp; + } + + ch[iCharLen] = '\0'; + *iChLen = iCharLen; + FTS_DEBUG("iCharLen: %d, iChLen: %d in function:%s!!\n\n", iCharLen, + *iChLen, __func__); + + return 0; +} + +static void fts_str_to_bytes(char *bufStr, int iLen, + char *uBytes, int *iBytesLen) +{ + int i = 0; + int iNumChLen = 0; + + *iBytesLen = 0; + + for (i = 0; i < iLen; i++) { + if (fts_is_hex_char(bufStr[i])) /* filter illegal chars */ + bufStr[iNumChLen++] = bufStr[i]; + } + + bufStr[iNumChLen] = '\0'; + + fts_hex_to_str(bufStr, iNumChLen, uBytes, iBytesLen); +} +/************************************************************************ +* Name: fts_tprwreg_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_tprwreg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + + mutex_lock(&fts_input_dev->mutex); + + if (!g_rwreg_result.op) { + if (g_rwreg_result.result == 0) + count = snprintf(buf, PAGE_SIZE, "Read %02X: %02X\n", + g_rwreg_result.reg, + g_rwreg_result.value); + else + count = snprintf(buf, PAGE_SIZE, + "Read %02X failed, ret: %d\n", + g_rwreg_result.reg, + g_rwreg_result.result); + } else { + if (g_rwreg_result.result == 0) + count = snprintf(buf, PAGE_SIZE, + "Write %02X, %02X success\n", + g_rwreg_result.reg, + g_rwreg_result.value); + else + count = snprintf(buf, PAGE_SIZE, + "Write %02X failed, ret: %d\n", + g_rwreg_result.reg, + g_rwreg_result.result); + } + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_tprwreg_store +* Brief: read/write register +* Input: device, device attribute, char buf, char count +* Output: print register value +* Return: char count +***********************************************************************/ +static ssize_t fts_tprwreg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + ssize_t num_read_chars = 0; + int retval; + unsigned long int wmreg = 0; + u8 regaddr = 0xff, regvalue = 0xff; + u8 valbuf[5] = {0}; + + memset(valbuf, 0, sizeof(valbuf)); + mutex_lock(&fts_input_dev->mutex); + num_read_chars = count - 1; + if (num_read_chars != 2) { + if (num_read_chars != 4) { + FTS_ERROR("please input 2 or 4 character"); + goto error_return; + } + } + memcpy(valbuf, buf, num_read_chars); + retval = kstrtoul(valbuf, 16, &wmreg); + fts_str_to_bytes((char *)buf, num_read_chars, valbuf, &retval); + + if (1 == retval) { + regaddr = valbuf[0]; + retval = 0; + } else if (2 == retval) { + regaddr = valbuf[0]; + regvalue = valbuf[1]; + retval = 0; + } else + retval = -1; + + if (0 != retval) { + FTS_ERROR("ERROR: Can't convert to number %s", buf); + goto error_return; + } +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + if (2 == num_read_chars) { + g_rwreg_result.op = 0; + g_rwreg_result.reg = regaddr; + /*read register*/ + regaddr = wmreg; + g_rwreg_result.result = fts_i2c_read_reg(client, regaddr, + ®value); + if (g_rwreg_result.result < 0) { + FTS_ERROR("Could not read the register(0x%02x)", + regaddr); + } else { + FTS_INFO("the register(0x%02x) is 0x%02x", regaddr, + regvalue); + g_rwreg_result.value = regvalue; + g_rwreg_result.result = 0; + } + } else { + regaddr = wmreg>>8; + regvalue = wmreg; + + g_rwreg_result.op = 1; + g_rwreg_result.reg = regaddr; + g_rwreg_result.value = regvalue; + g_rwreg_result.result = fts_i2c_write_reg(client, regaddr, + regvalue); + if (g_rwreg_result.result < 0) { + FTS_ERROR("Could not write the register(0x%02x)", + regaddr); + + } else { + FTS_INFO("Write 0x%02x to (0x%02x) successful", + regvalue, regaddr); + g_rwreg_result.result = 0; + } + } +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif +error_return: + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_fwupdate_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_fwupdate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_fwupdate_store +* Brief: upgrade from *.i +* Input: device, device attribute, char buf, char count +* Output: no +* Return: char count +***********************************************************************/ +static ssize_t fts_fwupdate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + mutex_lock(&fts_input_dev->mutex); + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + if (fts_updatefun_curr.upgrade_with_app_i_file) + fts_updatefun_curr.upgrade_with_app_i_file(client); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_fwupgradeapp_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_fwupgradeapp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_fwupgradeapp_store +* Brief: upgrade from app.bin +* Input: device, device attribute, char buf, char count +* Output: no +* Return: char count +***********************************************************************/ +static ssize_t fts_fwupgradeapp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char fwname[FILE_NAME_LENGTH]; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + memset(fwname, 0, sizeof(fwname)); + snprintf(fwname, FILE_NAME_LENGTH, "%s", buf); + fwname[count-1] = '\0'; + + mutex_lock(&fts_input_dev->mutex); + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + if (fts_updatefun_curr.upgrade_with_app_bin_file) + fts_updatefun_curr.upgrade_with_app_bin_file(client, fwname); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_driverversion_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_driverversion_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + + mutex_lock(&fts_input_dev->mutex); + + count = snprintf(buf, PAGE_SIZE, FTS_DRIVER_VERSION "\n"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_driverversion_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_driverversion_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +#if FTS_ESDCHECK_EN +/************************************************************************ +* Name: fts_esdcheck_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_esdcheck_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + mutex_lock(&fts_input_dev->mutex); + + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_DEBUG("enable esdcheck"); + fts_esdcheck_switch(ENABLE); + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_DEBUG("disable esdcheck"); + fts_esdcheck_switch(DISABLE); + } + + mutex_unlock(&fts_input_dev->mutex); + + return -EPERM; +} + +/************************************************************************ +* Name: fts_esdcheck_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_esdcheck_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + + mutex_lock(&fts_input_dev->mutex); + + count = snprintf(buf, PAGE_SIZE, "Esd check: %s\n", + fts_esdcheck_get_status() ? "On" : "Off"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +#endif +/************************************************************************ +* Name: fts_module_config_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_module_config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count = 0; + + mutex_lock(&fts_input_dev->mutex); + + count += snprintf(buf, PAGE_SIZE, "FTS_CHIP_TYPE: \t\t\t%04X\n", + FTS_CHIP_TYPE); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_DEBUG_EN: \t\t\t%s\n", + FTS_DEBUG_EN ? "ON" : "OFF"); +#if defined(FTS_MT_PROTOCOL_B_EN) + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_MT_PROTOCOL_B_EN: \t\t%s\n", + FTS_MT_PROTOCOL_B_EN ? "ON" : "OFF"); +#endif + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_GESTURE_EN: \t\t%s\n", + FTS_GESTURE_EN ? "ON" : "OFF"); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_ESDCHECK_EN: \t\t%s\n", + FTS_ESDCHECK_EN ? "ON" : "OFF"); +#if defined(FTS_PSENSOR_EN) + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_PSENSOR_EN: \t\t%s\n", + FTS_PSENSOR_EN ? "ON" : "OFF"); +#endif + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_GLOVE_EN: \t\t\t%s\n", + FTS_GLOVE_EN ? "ON" : "OFF"); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_COVER_EN: \t\t%s\n", + FTS_COVER_EN ? "ON" : "OFF"); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_CHARGER_EN: \t\t\t%s\n", + FTS_CHARGER_EN ? "ON" : "OFF"); + + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_REPORT_PRESSURE_EN: \t\t%s\n", + FTS_REPORT_PRESSURE_EN ? "ON" : "OFF"); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_FORCE_TOUCH_EN: \t\t%s\n", + FTS_FORCE_TOUCH_EN ? "ON" : "OFF"); + + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_TEST_EN: \t\t\t%s\n", + FTS_TEST_EN ? "ON" : "OFF"); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_APK_NODE_EN: \t\t%s\n", + FTS_APK_NODE_EN ? "ON" : "OFF"); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_POWER_SOURCE_CUST_EN: \t%s\n", + FTS_POWER_SOURCE_CUST_EN ? "ON" : "OFF"); + count += snprintf(buf+count, PAGE_SIZE - count, + "FTS_AUTO_UPGRADE_EN: \t\t%s\n", + FTS_AUTO_UPGRADE_EN ? "ON" : "OFF"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_module_config_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_module_config_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_show_log_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_show_log_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + + mutex_lock(&fts_input_dev->mutex); + + count = snprintf(buf, PAGE_SIZE, + "Log: %s\n", g_show_log ? "On" : "Off"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_show_log_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_show_log_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + + mutex_lock(&fts_input_dev->mutex); + + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_DEBUG("enable show log info/error"); + g_show_log = 1; + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_DEBUG("disable show log info/error"); + g_show_log = 0; + } + + mutex_unlock(&fts_input_dev->mutex); + return count; +} +/************************************************************************ +* Name: fts_dumpreg_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_dumpreg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_dumpreg_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_dumpreg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char tmp[256]; + int count = 0; + u8 regvalue = 0; + struct i2c_client *client; + + mutex_lock(&fts_input_dev->mutex); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + client = container_of(dev, struct i2c_client, dev); + /* power mode 0:active 1:monitor 3:sleep */ + fts_i2c_read_reg(client, FTS_REG_POWER_MODE, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "Power Mode:0x%02x\n", regvalue); + + /* FWver */ + fts_i2c_read_reg(client, FTS_REG_FW_VER, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "FW Ver:0x%02x\n", regvalue); + + /* Vendor ID */ + fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "Vendor ID:0x%02x\n", regvalue); + + /* LCD Busy number */ + fts_i2c_read_reg(client, FTS_REG_LCD_BUSY_NUM, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "LCD Busy Number:0x%02x\n", regvalue); + + /* 1 Gesture mode,0 Normal mode */ + fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "Gesture Mode:0x%02x\n", regvalue); + + /* 3 charge in */ + fts_i2c_read_reg(client, FTS_REG_CHARGER_MODE_EN, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "charge stat:0x%02x\n", regvalue); + + /* Interrupt counter */ + fts_i2c_read_reg(client, FTS_REG_INT_CNT, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "INT count:0x%02x\n", regvalue); + + /* Flow work counter */ + fts_i2c_read_reg(client, FTS_REG_FLOW_WORK_CNT, ®value); + count += snprintf(tmp + count, PAGE_SIZE - count, + "ESD count:0x%02x\n", regvalue); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + memcpy(buf, tmp, count); + mutex_unlock(&fts_input_dev->mutex); + return count; +} + +/****************************************/ +/* sysfs */ +/* get the fw version +* example:cat fw_version +*/ +static DEVICE_ATTR(fts_fw_version, S_IRUGO|S_IWUSR, + fts_tpfwver_show, fts_tpfwver_store); + +/* upgrade from *.i +* example: echo 1 > fw_update +*/ +static DEVICE_ATTR(fts_fw_update, S_IRUGO|S_IWUSR, + fts_fwupdate_show, fts_fwupdate_store); + +/* read and write register +* read example: echo 88 > rw_reg ---read register 0x88 +* write example:echo 8807 > rw_reg ---write 0x07 into register 0x88 +* +* note:the number of input must be 2 or 4.if it not enough, +* please fill in the 0. +*/ +static DEVICE_ATTR(fts_rw_reg, S_IRUGO|S_IWUSR, + fts_tprwreg_show, fts_tprwreg_store); + +/* upgrade from app.bin +* example:echo "*_app.bin" > upgrade_app +*/ +static DEVICE_ATTR(fts_upgrade_app, S_IRUGO|S_IWUSR, + fts_fwupgradeapp_show, fts_fwupgradeapp_store); +static DEVICE_ATTR(fts_driver_version, S_IRUGO|S_IWUSR, + fts_driverversion_show, fts_driverversion_store); +static DEVICE_ATTR(fts_dump_reg, S_IRUGO|S_IWUSR, + fts_dumpreg_show, fts_dumpreg_store); +static DEVICE_ATTR(fts_show_log, S_IRUGO|S_IWUSR, + fts_show_log_show, fts_show_log_store); +static DEVICE_ATTR(fts_module_config, S_IRUGO|S_IWUSR, + fts_module_config_show, fts_module_config_store); +static DEVICE_ATTR(fts_hw_reset, S_IRUGO|S_IWUSR, + fts_hw_reset_show, fts_hw_reset_store); +static DEVICE_ATTR(fts_irq, S_IRUGO|S_IWUSR, + fts_irq_show, fts_irq_store); + +#if FTS_ESDCHECK_EN +static DEVICE_ATTR(fts_esd_check, S_IRUGO|S_IWUSR, + fts_esdcheck_show, fts_esdcheck_store); +#endif + +/* add your attr in here*/ +static struct attribute *fts_attributes[] = { + &dev_attr_fts_fw_version.attr, + &dev_attr_fts_fw_update.attr, + &dev_attr_fts_rw_reg.attr, + &dev_attr_fts_dump_reg.attr, + &dev_attr_fts_upgrade_app.attr, + &dev_attr_fts_driver_version.attr, + &dev_attr_fts_show_log.attr, + &dev_attr_fts_module_config.attr, + &dev_attr_fts_hw_reset.attr, + &dev_attr_fts_irq.attr, +#if FTS_ESDCHECK_EN + &dev_attr_fts_esd_check.attr, +#endif + NULL +}; + +static struct attribute_group fts_attribute_group = { + .attrs = fts_attributes +}; + +/************************************************************************ +* Name: fts_create_sysfs +* Brief: create sysfs for debug +* Input: i2c info +* Output: no +* Return: success =0 +***********************************************************************/ +int fts_create_sysfs(struct i2c_client *client) +{ + int err; + + err = sysfs_create_group(&client->dev.kobj, &fts_attribute_group); + if (0 != err) { + FTS_ERROR("[EX]: sysfs_create_group() failed!!"); + sysfs_remove_group(&client->dev.kobj, &fts_attribute_group); + return -EIO; + } + + FTS_INFO("[EX]: sysfs_create_group() succeeded!!"); + + return err; +} +/************************************************************************ +* Name: fts_remove_sysfs +* Brief: remove sys +* Input: i2c info +* Output: no +* Return: no +***********************************************************************/ +int fts_remove_sysfs(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &fts_attribute_group); + return 0; +} diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c new file mode 100644 index 0000000000000000000000000000000000000000..e234a9cfc10268ff59389c022cd61fec1cf296f1 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c @@ -0,0 +1,347 @@ +/* + * + * FocalTech ftxxxx TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_ex_mode.c +* +* Author: Liu WeiGuang +* +* Created: 2016-08-31 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* 2.Private constant and macro definitions using #define +*****************************************************************************/ + +/***************************************************************************** +* 3.Private enumerations, structures and unions using typedef +*****************************************************************************/ +struct fts_mode_flag { + int fts_glove_mode_flag; + int fts_cover_mode_flag; + int fts_charger_mode_flag; +}; + +static struct fts_mode_flag g_fts_mode_flag; + +/***************************************************************************** +* 4.Static variables +*****************************************************************************/ + +/***************************************************************************** +* 5.Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* 6.Static function prototypes +*******************************************************************************/ + +#if FTS_GLOVE_EN +static ssize_t fts_touch_glove_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "Glove: %s\n", + g_fts_mode_flag.fts_glove_mode_flag ? "On" : "Off"); +} + +static ssize_t fts_touch_glove_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + + if (FTS_SYSFS_ECHO_ON(buf)) { + if (!g_fts_mode_flag.fts_glove_mode_flag) { + FTS_INFO("[Mode]enter glove mode"); + ret = fts_enter_glove_mode(fts_i2c_client, true); + if (ret >= 0) + g_fts_mode_flag.fts_glove_mode_flag = true; + } + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + if (g_fts_mode_flag.fts_glove_mode_flag) { + FTS_INFO("[Mode]exit glove mode"); + ret = fts_enter_glove_mode(fts_i2c_client, false); + if (ret >= 0) + g_fts_mode_flag.fts_glove_mode_flag = false; + } + } + + FTS_INFO("[Mode]glove mode status: %d", + g_fts_mode_flag.fts_glove_mode_flag); + return count; +} + +/************************************************************************ +* Name: fts_enter_glove_mode +* Brief: change glove mode +* Input: glove mode +* Output: no +* Return: success >=0, otherwise failed +***********************************************************************/ +int fts_enter_glove_mode(struct i2c_client *client, int mode) +{ + int ret = 0; + static u8 buf_addr[2] = { 0 }; + static u8 buf_value[2] = { 0 }; + + buf_addr[0] = FTS_REG_GLOVE_MODE_EN; /* glove control */ + + if (mode) + buf_value[0] = 0x01; + else + buf_value[0] = 0x00; + + ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]); + if (ret < 0) + FTS_ERROR("[Mode]fts_enter_glove_mode write value fail"); + + return ret; + +} + +/* read and write glove mode +* read example: cat fts_touch_glove_mode---read glove mode +* write example:echo 01 > fts_touch_glove_mode ---write glove mode to 01 +* +*/ +static DEVICE_ATTR(fts_glove_mode, S_IRUGO|S_IWUSR, + fts_touch_glove_show, fts_touch_glove_store); + +#endif + +#if FTS_COVER_EN +static ssize_t fts_touch_cover_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "Cover: %s\n", + g_fts_mode_flag.fts_cover_mode_flag ? "On" : "Off"); +} + +static ssize_t fts_touch_cover_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + + if (FTS_SYSFS_ECHO_ON(buf)) { + if (!g_fts_mode_flag.fts_cover_mode_flag) { + FTS_INFO("[Mode]enter cover mode"); + ret = fts_enter_cover_mode(fts_i2c_client, true); + if (ret >= 0) + g_fts_mode_flag.fts_cover_mode_flag = true; + } + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + if (g_fts_mode_flag.fts_cover_mode_flag) { + FTS_INFO("[Mode]exit cover mode"); + ret = fts_enter_cover_mode(fts_i2c_client, false); + if (ret >= 0) + g_fts_mode_flag.fts_cover_mode_flag = false; + } + } + + FTS_INFO("[Mode]cover mode status: %d", + g_fts_mode_flag.fts_cover_mode_flag); + return count; +} + +/************************************************************************ +* Name: fts_enter_cover_mode +* Brief: change cover mode +* Input: cover mode +* Output: no +* Return: success >=0, otherwise failed +***********************************************************************/ +int fts_enter_cover_mode(struct i2c_client *client, int mode) +{ + int ret = 0; + static u8 buf_addr[2] = { 0 }; + static u8 buf_value[2] = { 0 }; + + buf_addr[0] = FTS_REG_COVER_MODE_EN; /* cover control */ + + if (mode) + buf_value[0] = 0x01; + else + buf_value[0] = 0x00; + + ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]); + if (ret < 0) + FTS_ERROR("[Mode] fts_enter_cover_mode write value fail\n"); + + return ret; + +} + +/* read and write cover mode +* read example: cat fts_touch_cover_mode---read cover mode +* write example:echo 01 > fts_touch_cover_mode ---write cover mode to 01 +* +*/ +static DEVICE_ATTR(fts_cover_mode, S_IRUGO|S_IWUSR, + fts_touch_cover_show, fts_touch_cover_store); + +#endif + +#if FTS_CHARGER_EN +static ssize_t fts_touch_charger_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "Charger: %s\n", + g_fts_mode_flag.fts_charger_mode_flag ? "On" : "Off"); +} + +static ssize_t fts_touch_charger_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + + if (FTS_SYSFS_ECHO_ON(buf)) { + if (!g_fts_mode_flag.fts_charger_mode_flag) { + FTS_INFO("[Mode]enter charger mode"); + ret = fts_enter_charger_mode(fts_i2c_client, true); + if (ret >= 0) + g_fts_mode_flag.fts_charger_mode_flag = true; + } + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + if (g_fts_mode_flag.fts_charger_mode_flag) { + FTS_INFO("[Mode]exit charger mode"); + ret = fts_enter_charger_mode(fts_i2c_client, false); + if (ret >= 0) + g_fts_mode_flag.fts_charger_mode_flag = false; + } + } + + FTS_INFO("[Mode]charger mode status: %d", + g_fts_mode_flag.fts_charger_mode_flag); + return count; +} + +/************************************************************************ +* Name: fts_enter_charger_mode +* Brief: change charger mode +* Input: charger mode +* Output: no +* Return: success >=0, otherwise failed +***********************************************************************/ +int fts_enter_charger_mode(struct i2c_client *client, int mode) +{ + int ret = 0; + static u8 buf_addr[2] = { 0 }; + static u8 buf_value[2] = { 0 }; + + buf_addr[0] = FTS_REG_CHARGER_MODE_EN; /* charger control */ + + if (mode) + buf_value[0] = 0x01; + else + buf_value[0] = 0x00; + + ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]); + if (ret < 0) + FTS_DEBUG("[Mode]fts_enter_charger_mode write value fail"); + + return ret; + +} + +/* read and write charger mode +* read example: cat fts_touch_charger_mode---read charger mode +* write example:echo 01 > fts_touch_charger_mode ---write charger mode to 01 +* +*/ +static DEVICE_ATTR(fts_charger_mode, S_IRUGO|S_IWUSR, + fts_touch_charger_show, fts_touch_charger_store); + +#endif + +static struct attribute *fts_touch_mode_attrs[] = { +#if FTS_GLOVE_EN + &dev_attr_fts_glove_mode.attr, +#endif + +#if FTS_COVER_EN + &dev_attr_fts_cover_mode.attr, +#endif + +#if FTS_CHARGER_EN + &dev_attr_fts_charger_mode.attr, +#endif + + NULL, +}; + +static struct attribute_group fts_touch_mode_group = { + .attrs = fts_touch_mode_attrs, +}; + +int fts_ex_mode_init(struct i2c_client *client) +{ + int err = 0; + + g_fts_mode_flag.fts_glove_mode_flag = false; + g_fts_mode_flag.fts_cover_mode_flag = false; + g_fts_mode_flag.fts_charger_mode_flag = false; + + err = sysfs_create_group(&client->dev.kobj, &fts_touch_mode_group); + if (0 != err) { + FTS_ERROR("[Mode]create sysfs failed."); + sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group); + return -EIO; + } + + FTS_DEBUG("[Mode]create sysfs succeeded"); + + return err; + +} + +int fts_ex_mode_exit(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group); + return 0; +} + +int fts_ex_mode_recovery(struct i2c_client *client) +{ + int ret = 0; +#if FTS_GLOVE_EN + if (g_fts_mode_flag.fts_glove_mode_flag) + ret = fts_enter_glove_mode(client, true); +#endif + +#if FTS_COVER_EN + if (g_fts_mode_flag.fts_cover_mode_flag) + ret = fts_enter_cover_mode(client, true); +#endif + +#if FTS_CHARGER_EN + if (g_fts_mode_flag.fts_charger_mode_flag) + ret = fts_enter_charger_mode(client, true); +#endif + + return ret; +} + diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash.c new file mode 100644 index 0000000000000000000000000000000000000000..96a4947b161d25eeeccd3551536aa722ff8317ed --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash.c @@ -0,0 +1,664 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_flash.c +* +* Author: fupeipei +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" +#include "focaltech_flash.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +struct ft_chip_t chip_types; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +/* Upgrade FW/PRAMBOOT/LCD CFG */ +#if (FTS_GET_VENDOR_ID_NUM >= 1) +u8 CTPM_FW[] = { +#include FTS_UPGRADE_FW_APP +}; +#endif + +#if (FTS_GET_VENDOR_ID_NUM >= 2) +u8 CTPM_FW2[] = { +#include FTS_UPGRADE_FW2_APP +}; +#endif + +#if (FTS_GET_VENDOR_ID_NUM >= 3) +u8 CTPM_FW3[] = { +#include FTS_UPGRADE_FW3_APP +}; +#endif + +u8 aucFW_PRAM_BOOT[] = { +#ifdef FTS_UPGRADE_PRAMBOOT +#include FTS_UPGRADE_PRAMBOOT +#endif +}; + +#if (FTS_CHIP_TYPE == _FT8006) +u8 CTPM_LCD_CFG[] = { +#ifdef FTS_UPGRADE_LCD_CFG +#include FTS_UPGRADE_LCD_CFG +#endif +}; +#endif + +struct fts_upgrade_fun fts_updatefun_curr; +struct workqueue_struct *touch_wq; +struct work_struct fw_update_work; +u8 *g_fw_file; +int g_fw_len; +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/************************************************************************ +* Name: fts_ctpm_upgrade_delay +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +void fts_ctpm_upgrade_delay(u32 i) +{ + do { + i--; + } while (i > 0); +} + +/************************************************************************ +* Name: fts_ctpm_i2c_hid2std +* Brief: HID to I2C +* Input: i2c info +* Output: no +* Return: fail =0 +***********************************************************************/ +int fts_ctpm_i2c_hid2std(struct i2c_client *client) +{ +#if (FTS_CHIP_IDC) + return 0; +#else + u8 buf[5] = {0}; + int bRet = 0; + + buf[0] = 0xeb; + buf[1] = 0xaa; + buf[2] = 0x09; + bRet = fts_i2c_write(client, buf, 3); + msleep(20); + buf[0] = buf[1] = buf[2] = 0; + fts_i2c_read(client, buf, 0, buf, 3); + + if ((0xeb == buf[0]) && (0xaa == buf[1]) && (0x08 == buf[2])) { + FTS_DEBUG("hidi2c change to stdi2c successful!!"); + bRet = 1; + } else { + FTS_ERROR("hidi2c change to stdi2c error!!"); + bRet = 0; + } + + return bRet; +#endif +} + +/************************************************************************ +* Name: fts_get_chip_types +* Brief: get correct chip information +* Input: +* Output: +* Return: +***********************************************************************/ +static void fts_get_chip_types(void) +{ + struct ft_chip_t ctype[] = FTS_CHIP_TYPE_MAPPING; + int ic_type = 0; + + if (sizeof(ctype) != sizeof(struct ft_chip_t)) /* only one array */ + ic_type = IC_SERIALS - 1; + + chip_types = ctype[ic_type]; + + FTS_INFO("CHIP TYPE ID = 0x%02x%02x", + chip_types.chip_idh, chip_types.chip_idl); +} + +/************************************************************************ +* Name: fts_ctpm_get_upgrade_array +* Brief: decide which ic +* Input: no +* Output: get ic info in fts_updateinfo_curr +* Return: no +***********************************************************************/ +void fts_ctpm_get_upgrade_array(void) +{ + + FTS_FUNC_ENTER(); + + fts_get_chip_types(); + + fts_ctpm_i2c_hid2std(fts_i2c_client); + + /* Get functin pointer */ + memcpy(&fts_updatefun_curr, &fts_updatefun, + sizeof(struct fts_upgrade_fun)); + + FTS_FUNC_EXIT(); +} + +/************************************************************************ +* Name: fts_ctpm_rom_or_pram_reset +* Brief: RST CMD(07), reset to romboot(maybe->bootloader) +* Input: +* Output: +* Return: +***********************************************************************/ +void fts_ctpm_rom_or_pram_reset(struct i2c_client *client) +{ + u8 rst_cmd = FTS_REG_RESET_FW; + + FTS_INFO("[UPGRADE]******Reset to romboot/bootloader******"); + fts_i2c_write(client, &rst_cmd, 1); + /* The delay can't be changed */ + msleep(300); +} + +/************************************************************************ +* Name: fts_ctpm_auto_clb +* Brief: auto calibration +* Input: i2c info +* Output: no +* Return: 0 +***********************************************************************/ +int fts_ctpm_auto_clb(struct i2c_client *client) +{ +#if FTS_AUTO_CLB_EN + u8 uc_temp = 0x00; + u8 i = 0; + + /*start auto CLB */ + msleep(200); + + fts_i2c_write_reg(client, 0, FTS_REG_WORKMODE_FACTORY_VALUE); + /*make sure already enter factory mode */ + msleep(100); + /*write command to start calibration */ + fts_i2c_write_reg(client, 2, 0x4); + msleep(300); + if ((chip_types.chip_idh == 0x11) || (chip_types.chip_idh == 0x12) + || (chip_types.chip_idh == 0x13) + || (chip_types.chip_idh == 0x14)) { + /* 5x36,5x36i */ + for (i = 0; i < 100; i++) { + fts_i2c_read_reg(client, 0x02, &uc_temp); + if (0x02 == uc_temp || + 0xFF == uc_temp) + break; + msleep(20); + } + } else { + for (i = 0; i < 100; i++) { + fts_i2c_read_reg(client, 0, &uc_temp); + if (0x0 == ((uc_temp&0x70)>>4)) + break; + msleep(20); + } + } + + fts_i2c_write_reg(client, 0, 0x40); + msleep(200); + fts_i2c_write_reg(client, 2, 0x5); + msleep(300); + fts_i2c_write_reg(client, 0, FTS_REG_WORKMODE_WORK_VALUE); + msleep(300); +#endif + + return 0; +} + +/************************************************************************ +* Name: fts_getsize +* Brief: Get different file's size +* Input: +* Output: +* Return: file's size +***********************************************************************/ +u32 fts_getsize(u8 fw_type) +{ + int fw_len = 0; + +#if FTS_CHIP_IDC + if (fw_type == PRAMBOOT_SIZE) + fw_len = sizeof(aucFW_PRAM_BOOT); +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 1) + else if (fw_type == FW_SIZE) + fw_len = sizeof(CTPM_FW); +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + else if (fw_type == FW2_SIZE) + fw_len = sizeof(CTPM_FW2); +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + else if (fw_type == FW3_SIZE) + fw_len = sizeof(CTPM_FW3); +#endif +#if (FTS_CHIP_TYPE == _FT8006) + else if (fw_type == LCD_CFG_SIZE) + fw_len = sizeof(CTPM_LCD_CFG); +#endif + + return fw_len; +} + +/************************************************************************ +* Name: fts_ctpm_get_pram_or_rom_id +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +enum FW_STATUS fts_ctpm_get_pram_or_rom_id(struct i2c_client *client) +{ + u8 buf[4]; + u8 reg_val[2] = {0}; + enum FW_STATUS inRomBoot = FTS_RUN_IN_ERROR; + + fts_ctpm_i2c_hid2std(client); + + /*Enter upgrade mode*/ + /*send 0x55 in time windows*/ + buf[0] = FTS_UPGRADE_55; + buf[1] = FTS_UPGRADE_AA; + fts_i2c_write(client, buf, 2); + + msleep(20); + + buf[0] = 0x90; + buf[1] = buf[2] = buf[3] = 0x00; + fts_i2c_read(client, buf, 4, reg_val, 2); + + FTS_DEBUG("[UPGRADE] Read ROM/PRAM/Bootloader id:0x%02x%02x", + reg_val[0], reg_val[1]); + if ((reg_val[0] == 0x00) || (reg_val[0] == 0xFF)) + inRomBoot = FTS_RUN_IN_ERROR; + else if (reg_val[0] == chip_types.pramboot_idh + && reg_val[1] == chip_types.pramboot_idl) + inRomBoot = FTS_RUN_IN_PRAM; + else if (reg_val[0] == chip_types.rom_idh + && reg_val[1] == chip_types.rom_idl) + inRomBoot = FTS_RUN_IN_ROM; + else if (reg_val[0] == chip_types.bootloader_idh + && reg_val[1] == chip_types.bootloader_idl) + inRomBoot = FTS_RUN_IN_BOOTLOADER; + + return inRomBoot; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_file +* Brief: get app file by Vendor ID +* Input: +* Output: +* Return: <0: vendor id not correct,not upgrade +***********************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret; + + if (fts_updatefun_curr.get_i_file) + ret = fts_updatefun_curr.get_i_file(client, fw_valid); + else + ret = -EIO; + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_ver +* Brief: get app file version +* Input: +* Output: +* Return: fw version +***********************************************************************/ +int fts_ctpm_get_app_ver(void) +{ + int i_ret = 0; + + if (fts_updatefun_curr.get_app_i_file_ver) + i_ret = fts_updatefun_curr.get_app_i_file_ver(); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade +* Brief: fw upgrade entry funciotn +* Input: +* Output: +* Return: 0 - upgrade successfully +* <0 - upgrade failed +***********************************************************************/ +int fts_ctpm_fw_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + + if (fts_updatefun_curr.upgrade_with_app_i_file) + i_ret = fts_updatefun_curr.upgrade_with_app_i_file(client); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade +* Brief: fw upgrade entry funciotn +* Input: +* Output: +* Return: 0 - upgrade successfully +* <0 - upgrade failed +***********************************************************************/ +int fts_ctpm_lcd_cfg_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + + if (fts_updatefun_curr.upgrade_with_lcd_cfg_i_file) + i_ret = fts_updatefun_curr.upgrade_with_lcd_cfg_i_file(client); + + return i_ret; +} + +#if (!(FTS_UPGRADE_STRESS_TEST)) +/************************************************************************ +* Name: fts_ctpm_check_fw_status +* Brief: Check App is valid or not +* Input: +* Output: +* Return: -EIO - I2C communication error +* FTS_RUN_IN_APP - APP valid +* 0 - APP invalid +***********************************************************************/ +static int fts_ctpm_check_fw_status(struct i2c_client *client) +{ + u8 chip_id1 = 0; + u8 chip_id2 = 0; + int fw_status = FTS_RUN_IN_ERROR; + int i = 0; + int ret = 0; + int i2c_noack_retry = 0; + + for (i = 0; i < 5; i++) { + ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID, &chip_id1); + if (ret < 0) { + i2c_noack_retry++; + continue; + } + + ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID2, &chip_id2); + if (ret < 0) { + i2c_noack_retry++; + continue; + } + + if ((chip_id1 == chip_types.chip_idh) +#if FTS_CHIP_IDC + && (chip_id2 == chip_types.chip_idl) +#endif + ) { + fw_status = FTS_RUN_IN_APP; + break; + } + } + + FTS_DEBUG("[UPGRADE]: chip_id = %02x%02x", chip_id1, chip_id2); + FTS_DEBUG("[UPGRADE]:chip_types.chip_idh = %02x%02x", + chip_types.chip_idh, chip_types.chip_idl); + + /* I2C No ACK 5 times, then return -EIO */ + if (i2c_noack_retry >= 5) + return -EIO; + + /* I2C communication ok, but not get correct ID, + * need check pram/rom/bootloader */ + if (i >= 5) + fw_status = fts_ctpm_get_pram_or_rom_id(client); + + return fw_status; +} + +/************************************************************************ +* Name: fts_ctpm_check_fw_ver +* Brief: Check vendor id is valid or not +* Input: +* Output: +* Return: 1 - vendor id valid +* 0 - vendor id invalid +***********************************************************************/ +static int fts_ctpm_check_fw_ver(struct i2c_client *client) +{ + u8 uc_tp_fm_ver = 0; + u8 uc_host_fm_ver = 0; + + fts_i2c_read_reg(client, FTS_REG_FW_VER, &uc_tp_fm_ver); + uc_host_fm_ver = fts_ctpm_get_app_ver(); + + FTS_DEBUG("[UPGRADE]: uc_tp_fm_ver = 0x%x, uc_host_fm_ver = 0x%x!!", + uc_tp_fm_ver, uc_host_fm_ver); + if (uc_tp_fm_ver < uc_host_fm_ver) + return 1; + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_check_need_upgrade +* Brief: +* Input: +* Output: +* Return: 1 - Need upgrade +* 0 - No upgrade +***********************************************************************/ +static int fts_ctpm_check_need_upgrade(struct i2c_client *client) +{ + int fw_status = 0; + int bUpgradeFlag = false; + + FTS_FUNC_ENTER(); + + /* 1. veriry FW APP is valid or not */ + fw_status = fts_ctpm_check_fw_status(client); + FTS_DEBUG("[UPGRADE]: fw_status = %d!!", fw_status); + if (fw_status < 0) { + /* I2C no ACK, return immediately */ + FTS_ERROR("[UPGRADE]******I2C NO ACK,exit upgrade******"); + return -EIO; + } else if (fw_status == FTS_RUN_IN_ERROR) { + FTS_ERROR("[UPGRADE]******IC Type Fail******"); + } else if (fw_status == FTS_RUN_IN_APP) { + FTS_INFO("[UPGRADE]**********FW APP valid**********"); + + if (fts_ctpm_get_i_file(client, 1) != 0) { + FTS_DEBUG("[UPGRADE]***Get upgrade file(fw) fail***"); + return -EIO; + } + + if (fts_ctpm_check_fw_ver(client) == 1) { + FTS_DEBUG("[UPGRADE]******need upgrade fw******"); + bUpgradeFlag = true; + } else { + FTS_DEBUG("[UPGRADE]****Don't need upgrade fw****"); + bUpgradeFlag = false; + } + } else { + /* if app is invalid, reset to run ROM */ + FTS_INFO("[UPGRADE]**********FW APP invalid**********"); + fts_ctpm_rom_or_pram_reset(client); + if (fts_ctpm_get_i_file(client, 0) != 0) { + FTS_DEBUG("[UPGRADE]**Get upgrade file(flash) fail**"); + fts_ctpm_rom_or_pram_reset(client); + return -EIO; + } + fts_ctpm_rom_or_pram_reset(client); + bUpgradeFlag = true; + } + + FTS_FUNC_EXIT(); + + return bUpgradeFlag; +} + +/************************************************************************ +* Name: fts_ctpm_auto_upgrade +* Brief: auto upgrade +* Input: +* Output: +* Return: 0 - no upgrade +***********************************************************************/ +int fts_ctpm_auto_upgrade(struct i2c_client *client) +{ + u8 uc_tp_fm_ver = 0; + int i_ret = 0; + int bUpgradeFlag = false; + u8 uc_upgrade_times = 0; + + FTS_DEBUG("[UPGRADE]**********check upgrade need or not**********"); + bUpgradeFlag = fts_ctpm_check_need_upgrade(client); + FTS_DEBUG("[UPGRADE]**********bUpgradeFlag = 0x%x**********", + bUpgradeFlag); + + if (bUpgradeFlag <= 0) { + FTS_DEBUG("[UPGRADE]**********No Upgrade, exit**********"); + return 0; + } + + /* FW Upgrade */ + do { + uc_upgrade_times++; + FTS_DEBUG("[UPGRADE]*********star upgrade(%d)*************", + uc_upgrade_times); + + i_ret = fts_ctpm_fw_upgrade(client); + if (i_ret == 0) { + /* upgrade success */ + fts_i2c_read_reg(client, FTS_REG_FW_VER, &uc_tp_fm_ver); + FTS_DEBUG("[UPGRADE] Success upgrade to ver 0x%x", + uc_tp_fm_ver); + + fts_ctpm_auto_clb(client); + break; + } + + /* upgrade fail, reset to run ROM BOOT.. + * if app in flash is ok, TP will work success + */ + FTS_ERROR("[UPGRADE]*****upgrade fail, reset now*****"); + fts_ctpm_rom_or_pram_reset(client); + + /* if upgrade fail, upgrade again. then return */ + } while (uc_upgrade_times < 2); + + return i_ret; +} +#endif + +#if FTS_AUTO_UPGRADE_EN +static void fts_ctpm_update_work_func(struct work_struct *work) +{ + int i_ret = 0; + + FTS_DEBUG("[UPGRADE]*****FTS enter upgrade*******"); + fts_irq_disable(); + + /* esd check */ +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + + i_ret = fts_ctpm_auto_upgrade(fts_i2c_client); + if (i_ret < 0) + FTS_ERROR("[UPGRADE]**********TP FW upgrade failed**********"); + +#if FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN + msleep(2000); + + /* lcd_cfg upgrade */ + i_ret = fts_ctpm_lcd_cfg_upgrade(fts_i2c_client); + if (i_ret < 0) + FTS_ERROR("[UPGRADE]**********LCD cfg upgrade failed*********"); +#endif + +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + + FTS_DEBUG("[UPGRADE]**********FTS exit upgrade*************"); +} + +/***************************************************************************** +* Name: fts_ctpm_upgrade_init +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_ctpm_upgrade_init(void) +{ + FTS_FUNC_ENTER(); + + touch_wq = create_singlethread_workqueue("touch_wq"); + if (touch_wq) { + INIT_WORK(&fw_update_work, fts_ctpm_update_work_func); + queue_work(touch_wq, &fw_update_work); + } else + FTS_ERROR("[UPGRADE]create_singlethread_workqueue failed\n"); + + FTS_FUNC_EXIT(); +} + +/***************************************************************************** +* Name: fts_ctpm_upgrade_exit +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_ctpm_upgrade_exit(void) +{ + FTS_FUNC_ENTER(); + destroy_workqueue(touch_wq); + FTS_FUNC_EXIT(); +} + +#endif /* #if FTS_AUTO_UPGRADE_EN */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash.h b/drivers/input/touchscreen/focaltech_touch/focaltech_flash.h new file mode 100644 index 0000000000000000000000000000000000000000..c36a65b45517565a7f821b2123d6103b3bffd300 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash.h @@ -0,0 +1,137 @@ +/************************************************************************ +* Copyright (C) 2010-2017, Focaltech Systems (R)£¬All Rights Reserved. +* +* File Name: focaltech_flash.h +* +* Author: fupeipei +* +* Created: 2016-08-07 +* +* Abstract: +* +************************************************************************/ +#ifndef __LINUX_FOCALTECH_FLASH_H__ +#define __LINUX_FOCALTECH_FLASH_H__ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_flash/focaltech_upgrade_common.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define FTS_REG_ECC 0xCC +#define FTS_RST_CMD_REG2 0xBC +#define FTS_READ_ID_REG 0x90 +#define FTS_ERASE_APP_REG 0x61 +#define FTS_ERASE_PARAMS_CMD 0x63 +#define FTS_FW_WRITE_CMD 0xBF +#define FTS_REG_RESET_FW 0x07 +#define FTS_RST_CMD_REG1 0xFC +#define LEN_FLASH_ECC_MAX 0xFFFE + +#define FTS_PACKET_LENGTH 128 +#define FTS_SETTING_BUF_LEN 128 + +#define FTS_UPGRADE_LOOP 30 +#define AUTO_CLB_NEED 1 +#define AUTO_CLB_NONEED 0 +#define FTS_UPGRADE_AA 0xAA +#define FTS_UPGRADE_55 0x55 +#define FTXXXX_INI_FILEPATH_CONFIG "/sdcard/" + +enum FW_STATUS { + FTS_RUN_IN_ERROR, + FTS_RUN_IN_APP, + FTS_RUN_IN_ROM, + FTS_RUN_IN_PRAM, + FTS_RUN_IN_BOOTLOADER +}; + +enum FILE_SIZE_TYPE { + FW_SIZE, + FW2_SIZE, + FW3_SIZE, + PRAMBOOT_SIZE, + LCD_CFG_SIZE +}; + +/* pramboot */ +#define FTS_PRAMBOOT_8716 "include/pramboot/FT8716_Pramboot_V0.5_20160723.i" +#define FTS_PRAMBOOT_E716 "include/pramboot/FT8716_Pramboot_V0.5_20160723.i" +#define FTS_PRAMBOOT_8736 "include/pramboot/FT8736_Pramboot_V0.4_20160627.i" +#define FTS_PRAMBOOT_8607 "include/pramboot/FT8607_Pramboot_V0.3_20160727.i" +#define FTS_PRAMBOOT_8606 "include/pramboot/FT8606_Pramboot_V0.7_20150507.i" + +/* ic types */ +#if (FTS_CHIP_TYPE == _FT8716) +#define FTS_UPGRADE_PRAMBOOT FTS_PRAMBOOT_8716 +#elif (FTS_CHIP_TYPE == _FTE716) +#define FTS_UPGRADE_PRAMBOOT FTS_PRAMBOOT_E716 +#elif (FTS_CHIP_TYPE == _FT8736) +#define FTS_UPGRADE_PRAMBOOT FTS_PRAMBOOT_8736 +#elif (FTS_CHIP_TYPE == _FT8607) +#define FTS_UPGRADE_PRAMBOOT FTS_PRAMBOOT_8607 +#elif (FTS_CHIP_TYPE == _FT8606) +#define FTS_UPGRADE_PRAMBOOT FTS_PRAMBOOT_8606 +#endif + +/* remove pramboot */ +#undef FTS_UPGRADE_PRAMBOOT + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +/* IC info */ + +struct fts_upgrade_fun { + int (*get_i_file)(struct i2c_client *, int); + int (*get_app_bin_file_ver)(struct i2c_client *, char *); + int (*get_app_i_file_ver)(void); + int (*upgrade_with_app_i_file)(struct i2c_client *); + int (*upgrade_with_app_bin_file)(struct i2c_client *, char *); + int (*upgrade_with_lcd_cfg_i_file)(struct i2c_client *); + int (*upgrade_with_lcd_cfg_bin_file)(struct i2c_client *, char *); +}; +extern struct fts_upgrade_fun fts_updatefun; + +/***************************************************************************** +* Static variables +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +extern u8 CTPM_FW[]; +extern u8 CTPM_FW2[]; +extern u8 CTPM_FW3[]; +extern u8 aucFW_PRAM_BOOT[]; +extern u8 CTPM_LCD_CFG[]; +extern u8 *g_fw_file; +extern int g_fw_len; +extern struct fts_upgrade_fun fts_updatefun_curr; +extern struct ft_chip_t chip_types; + +#if FTS_AUTO_UPGRADE_EN +extern struct workqueue_struct *touch_wq; +extern struct work_struct fw_update_work; +#endif + +void fts_ctpm_upgrade_init(void); +void fts_ctpm_upgrade_exit(void); +void fts_ctpm_upgrade_delay(u32 i); +void fts_ctpm_get_upgrade_array(void); +int fts_ctpm_auto_upgrade(struct i2c_client *client); +int fts_fw_upgrade(struct device *dev, bool force); +int fts_ctpm_auto_clb(struct i2c_client *client); + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +u32 fts_getsize(u8 fw_type); +int fts_ctpm_i2c_hid2std(struct i2c_client *client); +void fts_ctpm_rom_or_pram_reset(struct i2c_client *client); +enum FW_STATUS fts_ctpm_get_pram_or_rom_id(struct i2c_client *client); +#endif + diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/Makefile b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9b3a4bbc49bc190b49fe15f4dadaaa4595b73625 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for the focaltech touchscreen drivers. +# + +# Each configuration option enables a list of files. + + +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft5x46.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft5822.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft6336gu.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft8006.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft8606.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft8607.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft8716.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft8736.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_idc.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_test.o \ No newline at end of file diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_common.h b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_common.h new file mode 100644 index 0000000000000000000000000000000000000000..cf9ed3e680a5e855c0604e1d110baf2ca862e198 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_common.h @@ -0,0 +1,60 @@ +/************************************************************************ +* Copyright (C) 2010-2017, Focaltech Systems (R)£¬All Rights Reserved. +* +* File Name: focaltech_upgrade_common.h +* +* Author: fupeipei +* +* Created: 2016-08-16 +* +* Abstract: +* +************************************************************************/ +#ifndef __LINUX_FOCALTECH_UPGRADE_COMMON_H__ +#define __LINUX_FOCALTECH_UPGRADE_COMMON_H__ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_flash.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +int fts_ctpm_erase_flash(struct i2c_client *client); +int fts_ctpm_pramboot_ecc(struct i2c_client *client); +bool fts_ctpm_check_run_state(struct i2c_client *client, int state); +void fts_ctpm_start_pramboot(struct i2c_client *client); +int fts_ctpm_start_fw_upgrade(struct i2c_client *client); +bool fts_ctpm_check_in_pramboot(struct i2c_client *client); +int fts_ctpm_upgrade_idc_init(struct i2c_client *client); +int fts_ctpm_write_app_for_idc(struct i2c_client *client, + u32 length, u8 *readbuf); +int fts_ctpm_upgrade_ecc(struct i2c_client *client, u32 startaddr, u32 length); +int fts_ctpm_write_pramboot_for_idc(struct i2c_client *client, + u32 length, u8 *readbuf); +int fts_writeflash(struct i2c_client *client, u32 writeaddr, + u32 length, u8 *readbuf, u32 cnt); +bool fts_check_app_bin_valid_idc(u8 *pbt_buf); + +int fts_ctpm_get_app_ver(void); +int fts_ctpm_fw_upgrade(struct i2c_client *client); +int fts_ctpm_lcd_cfg_upgrade(struct i2c_client *client); + +#endif diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft5822.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft5822.c new file mode 100644 index 0000000000000000000000000000000000000000..0643807978e3e88cba44e96db0475fbdbf604218 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft5822.c @@ -0,0 +1,645 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft5822.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (IC_SERIALS == 0x01) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (60 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10A) +#define APP_FILE_VENDORID_MAPPING (0x108) +#define APP_FILE_CHIPID_MAPPING (0x11E) +#define CONFIG_START_ADDR (0xFFB0) +#define CONFIG_VENDOR_ID_OFFSET (0x4) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ft5822_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ft5822_get_app_i_file_ver(void); +static int fts_ft5822_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name); +static int fts_ft5822_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ft5822_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + + .get_i_file = fts_ft5822_get_i_file, + .get_app_bin_file_ver = fts_ft5822_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ft5822_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ft5822_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ft5822_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = NULL, + .upgrade_with_lcd_cfg_bin_file = NULL, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ft5822_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ft5822_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + u8 reg_val[2] = {0}; + u32 i = 0; + u8 rw_buf[10]; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + rw_buf[0] = FTS_UPGRADE_55; + rw_buf[1] = FTS_UPGRADE_AA; + i_ret = fts_i2c_write(client, rw_buf, 2); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa!!"); + continue; + } + + /*check run in bootloader or not*/ + usleep_range(1000, 2000); + rw_buf[0] = FTS_READ_ID_REG; + rw_buf[1] = rw_buf[2] = rw_buf[3] = 0x00; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, rw_buf, 4, reg_val, 2); + + FTS_DEBUG("[UPGRADE]: ID1 = 0x%x,ID2 = 0x%x!!", + reg_val[0], reg_val[1]); + if ((reg_val[0] == chip_types.bootloader_idh) + && (reg_val[1] == chip_types.bootloader_idl)) { + FTS_DEBUG("[UPGRADE]: read bootloader id ok!!"); + break; + } + + FTS_ERROR("[UPGRADE]: read bootloader id fail!!"); + } + + if (i >= FTS_UPGRADE_LOOP) + return -EIO; + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + usleep_range(10000, 20000); /*must wait, otherwise read vendor id fail*/ + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ft5822_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ft5822_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = 0; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + else + ret = fts_ft5822_get_vendor_id_flash(client, &vendor_id); + + FTS_DEBUG("[UPGRADE] tp_vendor_id=%x", vendor_id); + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + + FTS_INFO("[UPGRADE]tp vendor id:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#else + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ft5822_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ft5822_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + int fw_ver = 0; + int ret; + + FTS_FUNC_ENTER(); + + ret = request_firmware(&fw, firmware_name, &client->dev); + if (ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw->size); + else + fw_ver = fw->data[APP_FILE_VER_MAPPING]; + + release_firmware(fw); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ft5822_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ft5822_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +#define AL2_FCS_COEF ((1 << 7) + (1 << 6) + (1 << 5)) +/***************************************************************************** +* Name: ecc_calc +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static u8 ecc_calc(u8 *pbt_buf, u16 start, u16 length) +{ + u8 cFcs = 0; + u16 i, j; + + for (i = 0; i < length; i++) { + cFcs ^= pbt_buf[start++]; + for (j = 0; j < 8; j++) { + if (cFcs & 1) + cFcs = (u8)((cFcs >> 1) ^ AL2_FCS_COEF); + else + cFcs >>= 1; + } + } + return cFcs; +} + +/***************************************************************************** +* Name: fts_check_app_bin_valid +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static bool fts_check_app_bin_valid(u8 *pbt_buf) +{ + u8 ecc1; + u8 ecc2; + u8 ecc3; + u8 ecc4; + u16 len1; + u16 len2; + u8 cal_ecc1; + u8 cal_ecc2; + u16 usAddrInfo; + + /* 1. First Byte */ + if (pbt_buf[0] != 0x02) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- the first byte(%x) error", + pbt_buf[0]); + return false; + } + + usAddrInfo = 0x100; + + /* 2.len */ + len1 = pbt_buf[usAddrInfo++] << 8; + len1 += pbt_buf[usAddrInfo++]; + + len2 = pbt_buf[usAddrInfo++] << 8; + len2 += pbt_buf[usAddrInfo++]; + + if ((len1 + len2) != 0xFFFF) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- LENGTH(%04x) XOR error", + len1); + return false; + } + + /* 3.ecc */ + ecc1 = pbt_buf[usAddrInfo++]; + ecc2 = pbt_buf[usAddrInfo++]; + ecc3 = pbt_buf[usAddrInfo++]; + ecc4 = pbt_buf[usAddrInfo++]; + + if (((ecc1 + ecc2) != 0xFF) || ((ecc3 + ecc4) != 0xFF)) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC(%x %x) XOR error", + ecc1, ecc2); + return false; + } + + cal_ecc1 = ecc_calc(pbt_buf, 0x0, 0x100); + cal_ecc2 = ecc_calc(pbt_buf, 0x100 + 0x20, len1 - (0x100 + 0x20)); + if ((ecc1 != cal_ecc1) || (ecc3 != cal_ecc2)) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC calc error"); + return false; + } + return true; +} + +/************************************************************************ +* Name: fts_ft5822_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ft5822_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u8 reg_val[4] = {0}; + u32 i = 0; + u32 packet_number; + u32 j = 0; + u32 temp; + u32 length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 upgrade_ecc; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + /*********Step 1:Reset CTPM *****/ + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA); + usleep_range(10000, 20000); + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55); + msleep(200); + + /*********Step 2:Enter upgrade mode *****/ + fts_ctpm_i2c_hid2std(client); + usleep_range(5000, 10000); + + auc_i2c_write_buf[0] = FTS_UPGRADE_55; + auc_i2c_write_buf[1] = FTS_UPGRADE_AA; + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 2); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa!!"); + continue; + } + + /*********Step 3:Check bootloader ID *****/ + usleep_range(1000, 2000); + auc_i2c_write_buf[0] = FTS_READ_ID_REG; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + FTS_DEBUG("[UPGRADE]:ID1 = 0x%x,ID2 = 0x%x!!", + reg_val[0], reg_val[1]); + if ((reg_val[0] == chip_types.bootloader_idh) + && (reg_val[1] == chip_types.bootloader_idl)) { + FTS_DEBUG("[UPGRADE]: read bootload id ok!!"); + break; + } + + FTS_ERROR("[UPGRADE]: read bootload id fail!!"); + } + + if (i >= FTS_UPGRADE_LOOP) { + FTS_ERROR("[UPGRADE]:failed writing 0x55 and 0xaa:i = %d!!", i); + return -EIO; + } + + /*Step 4:erase app and panel paramenter area*/ + FTS_DEBUG("[UPGRADE]: erase app and panel paramenter area!!"); + auc_i2c_write_buf[0] = FTS_ERASE_APP_REG; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1350); + for (i = 0; i < 15; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + if ((0xF0 == reg_val[0]) && (0xAA == reg_val[1])) + break; + msleep(50); + } + FTS_DEBUG("[UPGRADE]:erase app area reg_val[0] = %x reg_val[1] = %x!!", + reg_val[0], reg_val[1]); + + auc_i2c_write_buf[0] = 0xB0; + auc_i2c_write_buf[1] = (u8) ((dw_length >> 16) & 0xFF); + auc_i2c_write_buf[2] = (u8) ((dw_length >> 8) & 0xFF); + auc_i2c_write_buf[3] = (u8) (dw_length & 0xFF); + fts_i2c_write(client, auc_i2c_write_buf, 4); + + /*********Step 5:write firmware(FW) to ctpm flash*********/ + upgrade_ecc = 0; + FTS_DEBUG("[UPGRADE]: write FW to ctpm flash!!"); + temp = 0; + packet_number = (dw_length) / FTS_PACKET_LENGTH; + packet_buf[0] = FTS_FW_WRITE_CMD; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + length = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (length >> 8); + packet_buf[5] = (u8) length; + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + + fts_i2c_write(client, packet_buf, FTS_PACKET_LENGTH + 6); + usleep_range(10000, 20000); + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + if ((j + 0x1000) == (((reg_val[0]) << 8) | reg_val[1])) + break; + FTS_DEBUG("[UPGRADE]: reg_val[0] = %x reg_val[1] = %x", + reg_val[0], reg_val[1]); + /* msleep(1); */ + fts_ctpm_upgrade_delay(1000); + } + } + + if ((dw_length) % FTS_PACKET_LENGTH > 0) { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_length) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number + * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + usleep_range(10000, 20000); + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((0x1000 + ((packet_number * FTS_PACKET_LENGTH) + /((dw_length) % FTS_PACKET_LENGTH))) + == (((reg_val[0]) << 8) | reg_val[1])) + break; + FTS_DEBUG("[UPGRADE]: reg_val[0] = %x!!", reg_val[0]); + FTS_DEBUG("[UPGRADE]: reg_val[1] = %x!!", reg_val[1]); + FTS_DEBUG("[UPGRADE]: reg_val[2] = %x!!", + (((packet_number * FTS_PACKET_LENGTH) + /((dw_length) % FTS_PACKET_LENGTH))+0x1000)); + /* msleep(1); */ + fts_ctpm_upgrade_delay(1000); + } + } + + msleep(50); + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + FTS_DEBUG("[UPGRADE]: read out checksum!!"); + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + temp = 0; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = dw_length; + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_length/256); + + for (i = 0; i < 100; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + FTS_DEBUG("[UPGRADE]: reg_val[0]=%02x reg_val[0]=%02x!!", + reg_val[0], reg_val[1]); + if ((0xF0 == reg_val[0]) && (0x55 == reg_val[1])) + break; + usleep_range(1000, 2000); + } + auc_i2c_write_buf[0] = 0x66; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) { + FTS_ERROR("[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!", + reg_val[0], upgrade_ecc); + return -EIO; + } + + FTS_DEBUG("[UPGRADE]: checksum %x %x!!", reg_val[0], upgrade_ecc); + + FTS_DEBUG("[UPGRADE]: reset the new FW!!"); + auc_i2c_write_buf[0] = FTS_REG_RESET_FW; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(200); + + fts_ctpm_i2c_hid2std(client); + + return 0; +} + +/************************************************************************ +* Name: fts_ft5822_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ft5822_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ft5822_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ft5822_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ft5822_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + i_ret = request_firmware(&fw, firmware_name, &client->dev); + if (i_ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return i_ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + pbt_buf = (u8 *)fw->data; + if (pbt_buf[APP_FILE_CHIPID_MAPPING] != chip_types.chip_idh) { + FTS_ERROR("[UPGRADE]: chip id error, app.bin upgrade failed!!"); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + ecc_ok = fts_check_app_bin_valid(pbt_buf); + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ft5822_upgrade_use_buf(client, pbt_buf, fw->size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + +ERROR_BIN: + release_firmware(fw); + return i_ret; +} +#endif /* FT5822 */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft5x46.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft5x46.c new file mode 100644 index 0000000000000000000000000000000000000000..561ae578dea8845046a2576a79640b28367306ad --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft5x46.c @@ -0,0 +1,625 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft5x46.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (IC_SERIALS == 0x02) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (60 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define CONFIG_START_ADDR (0xD780) +#define CONFIG_VENDOR_ID_OFFSET (0x04) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ft5x46_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ft5x46_get_app_i_file_ver(void); +static int fts_ft5x46_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name); +static int fts_ft5x46_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ft5x46_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + + .get_i_file = fts_ft5x46_get_i_file, + .get_app_bin_file_ver = fts_ft5x46_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ft5x46_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ft5x46_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ft5x46_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = NULL, + .upgrade_with_lcd_cfg_bin_file = NULL, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ft5x46_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ft5x46_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + u8 reg_val[2] = {0}; + u32 i = 0; + u8 rw_buf[10]; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + rw_buf[0] = FTS_UPGRADE_55; + rw_buf[1] = FTS_UPGRADE_AA; + i_ret = fts_i2c_write(client, rw_buf, 2); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa!!"); + continue; + } + + /*check run in bootloader or not*/ + usleep_range(1000, 2000); + rw_buf[0] = FTS_READ_ID_REG; + rw_buf[1] = rw_buf[2] = rw_buf[3] = 0x00; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, rw_buf, 4, reg_val, 2); + + FTS_DEBUG("[UPGRADE]:ID1 = 0x%x,ID2 = 0x%x!!", + reg_val[0], reg_val[1]); + if ((reg_val[0] == chip_types.bootloader_idh) + && (reg_val[1] == chip_types.bootloader_idl)) { + FTS_DEBUG("[UPGRADE]: read bootloader id ok!!"); + break; + } + + FTS_ERROR("[UPGRADE]: read bootloader id fail!!"); + } + + if (i >= FTS_UPGRADE_LOOP) + return -EIO; + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + usleep_range(10000, 20000); /*must wait, otherwise read vendor id fail*/ + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ft5x46_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ft5x46_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = 0; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + else + ret = fts_ft5x46_get_vendor_id_flash(client, &vendor_id); + + FTS_DEBUG("[UPGRADE] tp_vendor_id=%x", vendor_id); + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + + FTS_INFO("[UPGRADE]tp vendor id:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#else + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ft5x46_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ft5x46_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + int fw_ver = 0; + int ret; + + FTS_FUNC_ENTER(); + + ret = request_firmware(&fw, firmware_name, &client->dev); + if (ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return ret; + } + + if (fw->size > 2) + fw_ver = fw->data[fw->size - 2]; + + release_firmware(fw); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ft5x46_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ft5x46_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[fwsize-2]; +} + +#define AL2_FCS_COEF ((1 << 7) + (1 << 6) + (1 << 5)) +/***************************************************************************** +* Name: ecc_calc +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static u8 ecc_calc(u8 *pbt_buf, u16 start, u16 length) +{ + u8 cFcs = 0; + u16 i, j; + + for (i = 0; i < length; i++) { + cFcs ^= pbt_buf[start++]; + for (j = 0; j < 8; j++) { + if (cFcs & 1) + cFcs = (u8)((cFcs >> 1) ^ AL2_FCS_COEF); + else + cFcs >>= 1; + } + } + return cFcs; +} + +/***************************************************************************** +* Name: fts_check_app_bin_valid +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static bool fts_check_app_bin_valid(u8 *pbt_buf, u32 dw_length) +{ + u8 ecc1; + u8 ecc2; + u16 len1; + u16 len2; + u8 cal_ecc; + u16 usAddrInfo; + + /* 1. First Byte */ + if (pbt_buf[0] != 0x02) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- the first byte(%x) error", + pbt_buf[0]); + return false; + } + + usAddrInfo = dw_length - 8; + + /* 2.len */ + len1 = pbt_buf[usAddrInfo++] << 8; + len1 += pbt_buf[usAddrInfo++]; + + len2 = pbt_buf[usAddrInfo++] << 8; + len2 += pbt_buf[usAddrInfo++]; + + if ((len1 + len2) != 0xFFFF) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- LENGTH(%04x) XOR error", + len1); + return false; + } + + /* 3.ecc */ + ecc1 = pbt_buf[usAddrInfo++]; + ecc2 = pbt_buf[usAddrInfo++]; + + if ((ecc1 + ecc2) != 0xFF) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC(%x) XOR error", ecc1); + return false; + } + + cal_ecc = ecc_calc(pbt_buf, 0x0, len1); + + if (ecc1 != cal_ecc) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC calc error"); + return false; + } + return true; +} + + +/************************************************************************ +* Name: fts_ft5x46_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ft5x46_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u8 reg_val[4] = {0}; + u32 i = 0; + u32 packet_number; + u32 j = 0; + u32 temp; + u32 length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 upgrade_ecc; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + /*********Step 1:Reset CTPM *****/ + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA); + usleep_range(10000, 20000); + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55); + msleep(200); + + /*********Step 2:Enter upgrade mode *****/ + fts_ctpm_i2c_hid2std(client); + usleep_range(5000, 10000); + + auc_i2c_write_buf[0] = FTS_UPGRADE_55; + auc_i2c_write_buf[1] = FTS_UPGRADE_AA; + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 2); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa!!"); + continue; + } + + /*********Step 3:Check bootloader ID *****/ + usleep_range(1000, 2000); + auc_i2c_write_buf[0] = FTS_READ_ID_REG; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + FTS_DEBUG("[UPGRADE]: ID1 = 0x%x,ID2 = 0x%x!!", + reg_val[0], reg_val[1]); + if ((reg_val[0] == chip_types.bootloader_idh) + && (reg_val[1] == chip_types.bootloader_idl)) { + FTS_DEBUG("[UPGRADE]: read bootload id ok!!"); + break; + } + + FTS_ERROR("[UPGRADE]: read bootload id fail!!"); + } + + if (i >= FTS_UPGRADE_LOOP) { + FTS_ERROR("[UPGRADE]:failed writing 0x55 and 0xaa:i = %d!!", i); + return -EIO; + } + + /*Step 4:erase app and panel paramenter area*/ + FTS_DEBUG("[UPGRADE]: erase app and panel paramenter area!!"); + auc_i2c_write_buf[0] = FTS_ERASE_APP_REG; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1350); + for (i = 0; i < 15; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + if ((0xF0 == reg_val[0]) && (0xAA == reg_val[1])) + break; + msleep(50); + } + FTS_DEBUG("[UPGRADE]:erase app area reg_val[0] = %x reg_val[1] = %x!!", + reg_val[0], reg_val[1]); + + auc_i2c_write_buf[0] = 0xB0; + auc_i2c_write_buf[1] = (u8) ((dw_length >> 16) & 0xFF); + auc_i2c_write_buf[2] = (u8) ((dw_length >> 8) & 0xFF); + auc_i2c_write_buf[3] = (u8) (dw_length & 0xFF); + fts_i2c_write(client, auc_i2c_write_buf, 4); + + /*********Step 5:write firmware(FW) to ctpm flash*********/ + upgrade_ecc = 0; + FTS_DEBUG("[UPGRADE]: write FW to ctpm flash!!"); + temp = 0; + packet_number = (dw_length) / FTS_PACKET_LENGTH; + packet_buf[0] = FTS_FW_WRITE_CMD; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + length = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (length >> 8); + packet_buf[5] = (u8) length; + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, FTS_PACKET_LENGTH + 6); + usleep_range(10000, 20000); + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + if ((j + 0x1000) == (((reg_val[0]) << 8) | reg_val[1])) + break; + FTS_DEBUG("[UPGRADE]:reg_val[0] = %x reg_val[1] = %x!!", + reg_val[0], reg_val[1]); + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(1000); + } + } + + if ((dw_length) % FTS_PACKET_LENGTH > 0) { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_length) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number + * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + usleep_range(10000, 20000); + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((0x1000 + ((packet_number * FTS_PACKET_LENGTH) + /((dw_length) % FTS_PACKET_LENGTH))) == + (((reg_val[0]) << 8) | reg_val[1])) + break; + FTS_DEBUG("[UPGRADE]: reg_val[0] = %x!!", reg_val[0]); + FTS_DEBUG("[UPGRADE]: reg_val[1] = %x!!", reg_val[1]); + FTS_DEBUG("[UPGRADE]: reg_val[2] = 0x%x!!", + (((packet_number * FTS_PACKET_LENGTH) + /((dw_length) % FTS_PACKET_LENGTH))+0x1000)); + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(1000); + } + } + + msleep(50); + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + FTS_DEBUG("[UPGRADE]: read out checksum!!"); + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + temp = 0; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = dw_length; + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_length/256); + + for (i = 0; i < 100; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + FTS_DEBUG("[UPGRADE]: reg_val[0]=%02x reg_val[0]=%02x!!", + reg_val[0], reg_val[1]); + if ((0xF0 == reg_val[0]) && (0x55 == reg_val[1])) + break; + usleep_range(1000, 2000); + } + auc_i2c_write_buf[0] = 0x66; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) { + FTS_ERROR("[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!", + reg_val[0], upgrade_ecc); + return -EIO; + } + FTS_DEBUG("[UPGRADE]: checksum %x %x!!", reg_val[0], upgrade_ecc); + + FTS_DEBUG("[UPGRADE]: reset the new FW!!"); + auc_i2c_write_buf[0] = FTS_REG_RESET_FW; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(200); + + fts_ctpm_i2c_hid2std(client); + + return 0; +} + +/************************************************************************ +* Name: fts_ft5x46_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ft5x46_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ft5x46_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ft5x46_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ft5x46_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + i_ret = request_firmware(&fw, firmware_name, &client->dev); + if (i_ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return i_ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + pbt_buf = (u8 *)fw->data; + ecc_ok = fts_check_app_bin_valid(pbt_buf, fw->size); + + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ft5x46_upgrade_use_buf(client, pbt_buf, fw->size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + +ERROR_BIN: + release_firmware(fw); + return i_ret; +} +#endif /* FT5X46 */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft6336gu.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft6336gu.c new file mode 100644 index 0000000000000000000000000000000000000000..6053b92fed633e700288612651a34894ca50990d --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft6336gu.c @@ -0,0 +1,605 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft6336GU.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if ((IC_SERIALS == 0x03) || (IC_SERIALS == 0x04)) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (60 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10A) +#define APP_FILE_VENDORID_MAPPING (0x10C) +#define CONFIG_START_ADDR (0x7B0) +#define CONFIG_VENDOR_ID_OFFSET (0x4) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) + +#define APP_LEN 0x00 +#define APP_LEN_NE 0x02 +#define APP_P1_ECC 0x04 +#define APP_P1_ECC_NE 0x05 +#define APP_P2_ECC 0x06 +#define APP_P2_ECC_NE 0x07 + +#define APP1_START 0x00 +#define APP1_LEN 0x100 +#define APP_VERIF_ADDR (APP1_START + APP1_LEN) +#define APP_VERIF_LEN 0x20 +#define APP1_ECC_ADDR (APP_VERIF_ADDR + APP_P1_ECC) +#define APP2_START (APP_VERIF_ADDR + APP_VERIF_LEN) +#define APP2_ECC_ADDR (APP_VERIF_ADDR + APP_P2_ECC) +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ft6x36gu_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ft6x36gu_get_app_i_file_ver(void); +static int fts_ft6x36gu_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name); +static int fts_ft6x36gu_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ft6x36gu_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + + .get_i_file = fts_ft6x36gu_get_i_file, + .get_app_bin_file_ver = fts_ft6x36gu_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ft6x36gu_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ft6x36gu_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ft6x36gu_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = NULL, + .upgrade_with_lcd_cfg_bin_file = NULL, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ft6x36gu_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ft6x36gu_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + u8 reg_val[2] = {0}; + u32 i = 0; + u8 rw_buf[10]; + int i_ret; + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + rw_buf[0] = FTS_UPGRADE_55; + rw_buf[1] = FTS_UPGRADE_AA; + i_ret = fts_i2c_write(client, rw_buf, 2); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa!!"); + continue; + } + + /*check run in bootloader or not*/ + usleep_range(1000, 2000); + rw_buf[0] = FTS_READ_ID_REG; + rw_buf[1] = rw_buf[2] = rw_buf[3] = 0x00; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, rw_buf, 4, reg_val, 2); + + FTS_DEBUG("[UPGRADE]: ID1 = 0x%x,ID2 = 0x%x!!", + reg_val[0], reg_val[1]); + if ((reg_val[0] == chip_types.bootloader_idh) + && (reg_val[1] == chip_types.bootloader_idl)) { + FTS_DEBUG("[UPGRADE]: read bootloader id ok!! "); + break; + } + FTS_ERROR("[UPGRADE]: read bootloader id fail!!"); + } + + if (i >= FTS_UPGRADE_LOOP) + return -EIO; + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + usleep_range(10000, 20000); /*must wait, otherwise read vendor id fail*/ + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ft6x36gu_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ft6x36gu_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = -EIO; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + else + ret = fts_ft6x36gu_get_vendor_id_flash(client, &vendor_id); + + FTS_DEBUG("[UPGRADE] tp_vendor_id=%x", vendor_id); + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + + FTS_INFO("[UPGRADE]tp vendor id:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ft6x36gu_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ft6x36gu_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + int fw_ver = 0; + int ret; + + FTS_FUNC_ENTER(); + + ret = request_firmware(&fw, firmware_name, &client->dev); + if (ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw->size); + else + fw_ver = fw->data[APP_FILE_VER_MAPPING]; + + release_firmware(fw); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ft6x36gu_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ft6x36gu_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +/***************************************************************************** +* Name: fts_check_app_bin_valid +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static bool fts_check_app_bin_valid(u8 *buf) +{ + int i; + u16 len; + u16 len_neg; + u16 ecc2_len = 0; + u8 cal_ecc = 0; + u8 cal_ecc2 = 0; + + FTS_INFO("[UPGRADE] Check APP.BIN ECC"); + + /* 1. start code byte */ + if (buf[0] != 0x02) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- the first byte(%x) error", + buf[0]); + return false; + } + + /* 2. len */ + len = ((u16)buf[APP_VERIF_ADDR + APP_LEN] << 8) + + buf[APP_VERIF_ADDR + APP_LEN + 1]; + len_neg = (u16)(buf[APP_VERIF_ADDR + APP_LEN_NE] << 8) + + buf[APP_VERIF_ADDR + APP_LEN_NE + 1]; + if ((len ^ len_neg) != 0xFFFF) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- LENGTH(%04x) XOR error", + len); + return false; + } + + /* 3. ecc */ + if (((buf[APP1_ECC_ADDR] ^ buf[APP1_ECC_ADDR+1]) != 0xFF) + || ((buf[APP2_ECC_ADDR] ^ buf[APP2_ECC_ADDR+1]) != 0xFF)) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC(%x %x) XOR error", + buf[APP1_ECC_ADDR], buf[APP2_ECC_ADDR]); + return false; + } + + /* APP1 */ + for (i = 0; i < APP1_LEN; i++) + cal_ecc ^= buf[APP1_START+i]; + /* APP2 */ + ecc2_len = ((u16)buf[APP_VERIF_ADDR+0x10] << 8) + + buf[APP_VERIF_ADDR+0x11]; + ecc2_len = len - APP1_LEN - APP_VERIF_LEN - ecc2_len; + for (i = 0; i < ecc2_len; i++) + cal_ecc2 ^= buf[APP2_START+i]; + + if ((cal_ecc != buf[APP1_ECC_ADDR]) + || (cal_ecc2 != buf[APP2_ECC_ADDR])) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC(%x %x) calc error", + cal_ecc, cal_ecc2); + return false; + } + + return true; +} + + +/************************************************************************ +* Name: fts_ft6x36gu_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ft6x36gu_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u8 reg_val[2] = {0}; + u32 i = 0; + u32 packet_number; + u32 j; + u32 temp; + u32 length; + u32 fw_length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 upgrade_ecc; + + FTS_FUNC_ENTER(); + + /*if the first byte of app is not 0x02, + *the app is invaild, can not upgrade*/ + if (pbt_buf[0] != 0x02) { + FTS_ERROR("[UPGRADE]: app first byte != 0x02. cannot upgrade!"); + return -EINVAL; + } + + /*check app length*/ + if (dw_length > 0x11f) { + fw_length = ((u32)pbt_buf[0x100]<<8) + pbt_buf[0x101]; + if (dw_length < fw_length) { + FTS_ERROR("[UPGRADE]: Fw length error!!"); + return -EINVAL; + } + } else { + FTS_ERROR("[UPGRADE]: Fw length error!!"); + return -EINVAL; + } + + /*send upgrade commond*/ + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + /*send 0xAA and 0x55 to fw(0xFC reg), and start upgrade*/ + fts_i2c_write_reg(client, FTS_RST_CMD_REG2, FTS_UPGRADE_AA); + usleep_range(10000, 20000); + fts_i2c_write_reg(client, FTS_RST_CMD_REG2, FTS_UPGRADE_55); + usleep_range(10000, 20000); + + /*upgrade init in ROM*/ + auc_i2c_write_buf[0] = FTS_UPGRADE_55; + fts_i2c_write(client, auc_i2c_write_buf, 1); + auc_i2c_write_buf[0] = FTS_UPGRADE_AA; + fts_i2c_write(client, auc_i2c_write_buf, 1); + usleep_range(10000, 20000); + + /*check run in ROM now*/ + auc_i2c_write_buf[0] = FTS_READ_ID_REG; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] + = auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + + if (reg_val[0] == chip_types.bootloader_idh + && reg_val[1] == chip_types.bootloader_idl) + break; + } + + if (i >= FTS_UPGRADE_LOOP) { + FTS_ERROR("[UPGRADE]: get bootload id error !!"); + return -EIO; + } + + /*erase app in flash*/ + FTS_INFO("[UPGRADE]: erase app!!"); + auc_i2c_write_buf[0] = FTS_ERASE_APP_REG; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(2000); + + for (i = 0; i < 200; i++) { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + if (0xb0 == reg_val[0] && 0x02 == reg_val[1]) { + FTS_INFO("[UPGRADE]: erase app finished!!"); + break; + } + msleep(50); + } + + /*write app to flash*/ + upgrade_ecc = 0; + FTS_INFO("[UPGRADE]: write app to flash!!"); + + dw_length = fw_length; + packet_number = (dw_length) / FTS_PACKET_LENGTH; + packet_buf[0] = FTS_FW_WRITE_CMD; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + length = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (length >> 8); + packet_buf[5] = (u8) length; + + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + + fts_i2c_write(client, packet_buf, FTS_PACKET_LENGTH + 6); + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + if (0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) + == (((reg_val[0] & 0x0f) << 8) | reg_val[1])) + break; + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(1000); + } + } + + if ((dw_length) % FTS_PACKET_LENGTH > 0) { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_length) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number + * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + + fts_i2c_write(client, packet_buf, temp + 6); + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + if (0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) + == (((reg_val[0] & 0x0f) << 8) | reg_val[1])) + break; + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(1000); + } + } + + /*read out checksum*/ + FTS_INFO("[UPGRADE]: read out checksum!!"); + auc_i2c_write_buf[0] = FTS_REG_ECC; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + /*check sum error, upgrade fail*/ + if (reg_val[0] != upgrade_ecc) { + FTS_ERROR("[UPGRADE]: ecc error : FW=%02x upgrade_ecc=%02x!!", + reg_val[0], upgrade_ecc); + return -EIO; + } + FTS_INFO("[UPGRADE]: ecc ok!!"); + + /*upgrade success, reset the new FW*/ + FTS_INFO("[UPGRADE]: reset the new FW!!"); + auc_i2c_write_buf[0] = 0x07; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ft6x36gu_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ft6x36gu_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ft6x36gu_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ft6x36gu_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ft6x36gu_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + i_ret = request_firmware(&fw, firmware_name, &client->dev); + if (i_ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return i_ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + pbt_buf = (u8 *)fw->data; + ecc_ok = fts_check_app_bin_valid(pbt_buf); + + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ft6x36gu_upgrade_use_buf(client, pbt_buf, fw->size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + +ERROR_BIN: + release_firmware(fw); + return i_ret; +} +#endif /* FT6x36GU */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8006.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8006.c new file mode 100644 index 0000000000000000000000000000000000000000..3b3ba3af6a18e836e9c2b19ebcb538dce3f26bb1 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8006.c @@ -0,0 +1,895 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft8006.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (FTS_CHIP_TYPE == _FT8006) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (93 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10E) +#define APP_FILE_VENDORID_MAPPING (0x10C) +#define APP_FILE_CHIPID_MAPPING (0x11E) +#define CONFIG_START_ADDR (0xF80) +#define CONFIG_START_ADDR_LEN (0x80) +#define CONFIG_VENDOR_ID_OFFSET (0x04) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) +#define LCD_CFG_MAX_SIZE (4 * 1024) +#define LCD_CFG_MIN_SIZE (8) + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ctpm_get_app_i_file_ver(void); +static int fts_ctpm_get_app_bin_file_ver(char *firmware_name); +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); +static int fts_ctpm_fw_upgrade_with_lcd_cfg_i_file(struct i2c_client *client); +static int fts_ctpm_fw_upgrade_with_lcd_cfg_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + + .get_i_file = fts_ctpm_get_i_file, + .get_app_bin_file_ver = fts_ctpm_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ctpm_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ctpm_fw_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ctpm_fw_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = fts_ctpm_fw_upgrade_with_lcd_cfg_i_file, + .upgrade_with_lcd_cfg_bin_file = + fts_ctpm_fw_upgrade_with_lcd_cfg_bin_file, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ctpm_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ctpm_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + bool inbootloader = false; + u8 rw_buf[10]; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*Enter upgrade mode*/ + fts_ctpm_i2c_hid2std(client); + usleep_range(10000, 20000); + + inbootloader = fts_ctpm_check_run_state(client, FTS_RUN_IN_BOOTLOADER); + if (!inbootloader) { + FTS_ERROR("[UPGRADE]: not run in bootloader, upgrade fail!!"); + return -EIO; + } + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + /* must wait, otherwise read vendor id wrong */ + usleep_range(10000, 20000); + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ft5x46_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = 0; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + else + ret = fts_ctpm_get_vendor_id_flash(client, &vendor_id); + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + FTS_INFO("[UPGRADE] vendor id tp=%x", vendor_id); + FTS_INFO("[UPGRADE] vendor id driver:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#else + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_bin_file_ver(char *firmware_name) +{ + u8 *pbt_buf = NULL; + int fwsize = 0; + int fw_ver = 0; + + FTS_FUNC_ENTER(); + + fwsize = fts_GetFirmwareSize(firmware_name); + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return -EIO; + } + + pbt_buf = kmalloc(fwsize + 1, GFP_KERNEL); + if (fts_ReadFirmware(firmware_name, pbt_buf)) { + FTS_ERROR("[UPGRADE]: request_firmware failed!!"); + kfree(pbt_buf); + return -EIO; + } + + fw_ver = pbt_buf[APP_FILE_VER_MAPPING]; + + kfree(pbt_buf); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u8 reg_val[4] = {0}; + u32 i = 0; + u32 packet_number; + u32 j = 0; + u32 temp; + u32 length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 upgrade_ecc; + int i_ret = 0; + bool inbootloader = false; + + fts_ctpm_i2c_hid2std(client); + + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*Enter upgrade mode*/ + fts_ctpm_i2c_hid2std(client); + usleep_range(10000, 20000); + + inbootloader = fts_ctpm_check_run_state(client, FTS_RUN_IN_BOOTLOADER); + if (!inbootloader) { + FTS_ERROR("[UPGRADE]: not run in bootloader, upgrade fail!!"); + return -EIO; + } + + /*send upgrade type to reg 0x09: 0x0B: upgrade; 0x0A: download*/ + auc_i2c_write_buf[0] = 0x09; + auc_i2c_write_buf[1] = 0x0B; + fts_i2c_write(client, auc_i2c_write_buf, 2); + + /* + * All.bin <= 128K + * APP.bin <= 94K + * LCD_CFG <= 4K + */ + auc_i2c_write_buf[0] = 0xB0; + auc_i2c_write_buf[1] = (u8) ((dw_length >> 16) & 0xFF); + auc_i2c_write_buf[2] = (u8) ((dw_length >> 8) & 0xFF); + auc_i2c_write_buf[3] = (u8) (dw_length & 0xFF); + fts_i2c_write(client, auc_i2c_write_buf, 4); + + + /*erase the app erea in flash*/ + i_ret = fts_ctpm_erase_flash(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: erase flash error!!"); + return i_ret; + } + + /*write FW to ctpm flash*/ + upgrade_ecc = 0; + FTS_DEBUG("[UPGRADE]: write FW to ctpm flash!!"); + temp = 0; + packet_number = (dw_length) / FTS_PACKET_LENGTH; + packet_buf[0] = FTS_FW_WRITE_CMD; + + for (j = 0; j < packet_number; j++) { + temp = 0x5000 + j * FTS_PACKET_LENGTH; + packet_buf[1] = (u8) (temp >> 16); + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + length = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (length >> 8); + packet_buf[5] = (u8) length; + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, FTS_PACKET_LENGTH + 6); + /* usleep_range(1000, 2000); */ + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((j + 0x1000 + (0x5000/FTS_PACKET_LENGTH)) + == (((reg_val[0]) << 8) | reg_val[1])) + break; + + if (i > 15) { + usleep_range(1000, 2000); + FTS_DEBUG("[UPGRADE]: write flash:host :%x!!", + (j + 0x1000 + + (0x5000/FTS_PACKET_LENGTH))); + FTS_DEBUG("[UPGRADE]: write flash:status :%x!!", + (((reg_val[0]) << 8) | reg_val[1])); + } + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(10000); + } + } + + if ((dw_length) % FTS_PACKET_LENGTH > 0) { + temp = 0x5000 + packet_number * FTS_PACKET_LENGTH; + packet_buf[1] = (u8) (temp >> 16); + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_length) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number + * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + /* usleep_range(1000, 2000); */ + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((0x1000 + ((0x5000 + packet_number + * FTS_PACKET_LENGTH)/((dw_length) + % FTS_PACKET_LENGTH))) + == (((reg_val[0]) << 8) | reg_val[1])) + break; + + if (i > 15) { + usleep_range(1000, 2000); + FTS_DEBUG("[UPGRADE]: write flash:host :%x!!", + (j + 0x1000 + + (0x5000/FTS_PACKET_LENGTH))); + FTS_DEBUG("[UPGRADE]: write flash:status :%x!!", + (((reg_val[0]) << 8) | reg_val[1])); + } + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(10000); + } + } + + msleep(50); + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + FTS_DEBUG("[UPGRADE]: read out checksum!!"); + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + temp = 0x5000; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = (64*1024-1); + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_length/256); + + temp = (0x5000+(64*1024-1)); + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = (dw_length-(64*1024-1)); + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_length/256); + + for (i = 0; i < 100; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0 == reg_val[0] && 0x55 == reg_val[1]) { + FTS_DEBUG("[UPGRADE]: reg_val[0]=%02x reg_val[0]=%02x!", + reg_val[0], reg_val[1]); + break; + } + usleep_range(1000, 2000); + + } + auc_i2c_write_buf[0] = 0x66; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) { + FTS_ERROR("[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!", + reg_val[0], upgrade_ecc); + return -EIO; + } + FTS_DEBUG("[UPGRADE]: checksum %x %x!!", reg_val[0], upgrade_ecc); + + FTS_DEBUG("[UPGRADE]: reset the new FW!!"); + auc_i2c_write_buf[0] = FTS_REG_RESET_FW; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1000); + + fts_ctpm_i2c_hid2std(client); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_lcd_cfg_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u8 reg_val[4] = {0}; + u8 cfg_backup[CONFIG_START_ADDR_LEN+1] = { 0 }; + u32 i = 0; + u32 packet_number; + u32 j = 0; + u32 temp; + u32 length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 upgrade_ecc; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + /*write 0xaa to register FTS_RST_CMD_REG1 */ + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA); + usleep_range(10000, 20000); + + /*write 0x55 to register FTS_RST_CMD_REG1*/ + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55); + msleep(200); + + /*Enter upgrade mode*/ + fts_ctpm_i2c_hid2std(client); + + usleep_range(10000, 20000); + auc_i2c_write_buf[0] = FTS_UPGRADE_55; + auc_i2c_write_buf[1] = FTS_UPGRADE_AA; + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 2); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa!!"); + continue; + } + + /*check run in bootloader or not*/ + usleep_range(1000, 2000); + auc_i2c_write_buf[0] = FTS_READ_ID_REG; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] + = auc_i2c_write_buf[3] = 0x00; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + FTS_DEBUG("[UPGRADE]:ID1 = 0x%x,ID2 = 0x%x!!", + reg_val[0], reg_val[1]); + + if (reg_val[0] == chip_types.bootloader_idh + && reg_val[1] == chip_types.bootloader_idl) { + FTS_DEBUG("[UPGRADE]: read bootloader id ok!!"); + break; + } + FTS_DEBUG("[UPGRADE]: read bootloader id fail!!"); + } + + if (i >= FTS_UPGRADE_LOOP) + return -EIO; + + /* Backup FW configuratin area */ + reg_val[0] = 0x03; + reg_val[1] = (u8)((CONFIG_START_ADDR-1) >> 16); + reg_val[2] = (u8)((CONFIG_START_ADDR-1) >> 8); + reg_val[3] = (u8)((CONFIG_START_ADDR-1)); + i_ret = fts_i2c_read(client, reg_val, 4, + cfg_backup, CONFIG_START_ADDR_LEN+1); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE] Read Config area error, don't upgrade"); + return -EIO; + } + + /*send upgrade type to reg 0x09: 0x0B: upgrade; 0x0A: download*/ + auc_i2c_write_buf[0] = 0x09; + auc_i2c_write_buf[1] = 0x0C; + fts_i2c_write(client, auc_i2c_write_buf, 2); + + /*Step 4:erase app and panel paramenter area*/ + FTS_DEBUG("[UPGRADE]: erase app and panel paramenter area!!"); + auc_i2c_write_buf[0] = FTS_ERASE_APP_REG; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1000); + + for (i = 0; i < 15; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + if (0xF0 == reg_val[0] && 0xAA == reg_val[1]) + break; + msleep(50); + } + FTS_DEBUG("[UPGRADE]: erase app area reg_val = %x %x!!", + reg_val[0], reg_val[1]); + + auc_i2c_write_buf[0] = 0xB0; + auc_i2c_write_buf[1] = 0; + auc_i2c_write_buf[2] = (u8) ((dw_length >> 8) & 0xFF); + auc_i2c_write_buf[3] = (u8) (dw_length & 0xFF); + fts_i2c_write(client, auc_i2c_write_buf, 4); + + /*write FW to ctpm flash*/ + upgrade_ecc = 0; + FTS_DEBUG("[UPGRADE]: write FW to ctpm flash!!"); + temp = 0; + packet_number = (dw_length) / FTS_PACKET_LENGTH; + packet_buf[0] = FTS_FW_WRITE_CMD; + packet_buf[1] = 0; + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + length = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (length >> 8); + packet_buf[5] = (u8) length; + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, FTS_PACKET_LENGTH + 6); + /* usleep_range(1000, 2000); */ + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((j + 0x1000) == (((reg_val[0]) << 8) | reg_val[1])) + break; + + if (i > 15) { + usleep_range(1000, 2000); + FTS_DEBUG("[UPGRADE]: write flash:host : %x!", + (j + 0x1000 + + (0x5000/FTS_PACKET_LENGTH)), + (((reg_val[0]) << 8) | reg_val[1])); + FTS_DEBUG("[UPGRADE]: write flash:status : %x!", + (((reg_val[0]) << 8) | reg_val[1])); + } + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(10000); + } + } + + if ((dw_length) % FTS_PACKET_LENGTH > 0) { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_length) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number + * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + /* usleep_range(1000, 2000); */ + + for (i = 0; i < 30; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((0x1000 + ((packet_number * FTS_PACKET_LENGTH) + /((dw_length) % FTS_PACKET_LENGTH))) + == (((reg_val[0]) << 8) | reg_val[1])) + break; + + if (i > 15) { + usleep_range(1000, 2000); + FTS_DEBUG("[UPGRADE]: write flash:host : %x!", + (j + 0x1000 + + (0x5000/FTS_PACKET_LENGTH)), + (((reg_val[0]) << 8) | reg_val[1])); + FTS_DEBUG("[UPGRADE]: write flash:status : %x!", + (((reg_val[0]) << 8) | reg_val[1])); + } + /* usleep_range(1000, 2000); */ + fts_ctpm_upgrade_delay(10000); + } + } + + /* Write Back FW configuratin area */ + packet_buf[0] = FTS_FW_WRITE_CMD; + packet_buf[1] = (u8)(CONFIG_START_ADDR >> 16); + packet_buf[2] = (u8)(CONFIG_START_ADDR >> 8); + packet_buf[3] = (u8)(CONFIG_START_ADDR); + packet_buf[4] = (u8)(CONFIG_START_ADDR_LEN >> 8); + packet_buf[5] = (u8)(CONFIG_START_ADDR_LEN); + memcpy(&packet_buf[6], &cfg_backup[1], CONFIG_START_ADDR_LEN); + i_ret = fts_i2c_write(client, packet_buf, CONFIG_START_ADDR_LEN + 6); + if (i_ret < 0) + FTS_ERROR("[UPGRADE] Write Configuration area error"); + + msleep(50); + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + FTS_DEBUG("[UPGRADE]: read out checksum!!"); + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + temp = 0x00; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = 0; + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = dw_length; + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_length/256); + + for (i = 0; i < 100; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0 == reg_val[0] && 0x55 == reg_val[1]) { + FTS_DEBUG("[UPGRADE]:reg_val[0]=%02x reg_val[0]=%02x!", + reg_val[0], reg_val[1]); + break; + } + usleep_range(1000, 2000); + + } + auc_i2c_write_buf[0] = 0x66; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) { + FTS_ERROR("[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!", + reg_val[0], upgrade_ecc); + return -EIO; + } + FTS_DEBUG("[UPGRADE]: checksum %x %x!!", reg_val[0], upgrade_ecc); + + FTS_DEBUG("[UPGRADE]: reset the new FW!!"); + auc_i2c_write_buf[0] = FTS_REG_RESET_FW; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1000); + + fts_ctpm_i2c_hid2std(client); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ctpm_fw_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + fwsize = fts_GetFirmwareSize(firmware_name); + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + return -EIO; + } + + pbt_buf = kmalloc(fwsize + 1, GFP_KERNEL); + if (NULL == pbt_buf) { + FTS_ERROR(" malloc pbt_buf failed "); + goto ERROR_BIN; + } + + if (fts_ReadFirmware(firmware_name, pbt_buf)) { + FTS_ERROR("[UPGRADE]: request_firmware failed!!"); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + ecc_ok = fts_check_app_bin_valid_idc(pbt_buf); + + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ctpm_fw_upgrade_use_buf(client, pbt_buf, fwsize); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + + kfree(pbt_buf); + return i_ret; +ERROR_BIN: + kfree(pbt_buf); + return -EIO; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_lcd_cfg_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_lcd_cfg_i_file(struct i2c_client *client) +{ + int i_ret = 0; + int lcd_cfg_size = 0; + + FTS_DEBUG("[UPGRADE]**********upgrade with lcd_cfg.i**********"); + + lcd_cfg_size = fts_getsize(LCD_CFG_SIZE); + if (lcd_cfg_size < LCD_CFG_MIN_SIZE + || lcd_cfg_size > LCD_CFG_MAX_SIZE) { + FTS_ERROR("[UPGRADE] lcd_cfg.i length(%x) error", lcd_cfg_size); + return -EIO; + } + + /*FW upgrade*/ + i_ret = fts_ctpm_lcd_cfg_upgrade_use_buf(client, + CTPM_LCD_CFG, lcd_cfg_size); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] lcd_cfg.i upgrade fail, ret=%d", i_ret); + else + FTS_INFO("[UPGRADE] lcd_cfg.i upgrade succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_lcd_cfg_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_lcd_cfg_bin_file(struct i2c_client *client, + char *firmware_name) +{ + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int lcd_cfg_size = fts_GetFirmwareSize(firmware_name); + + FTS_DEBUG("[UPGRADE]**********upgrade with lcd_cfg.bin**********"); + + if (lcd_cfg_size < LCD_CFG_MIN_SIZE + || lcd_cfg_size > LCD_CFG_MAX_SIZE) { + FTS_ERROR("[UPGRADE] lcd_cfg.bin length(%x) error", + lcd_cfg_size); + return -EIO; + } + + pbt_buf = kmalloc(lcd_cfg_size + 1, GFP_KERNEL); + if (fts_ReadFirmware(firmware_name, pbt_buf)) { + FTS_ERROR("[UPGRADE]: request_firmware failed!!"); + goto ERROR_LCD_CFG_BIN; + } + + /*check the app.bin invalid or not*/ + ecc_ok = 1; + + if (ecc_ok) { + FTS_INFO("[UPGRADE]: lcd_cfg.bin ecc ok!!"); + i_ret = fts_ctpm_lcd_cfg_upgrade_use_buf(client, + pbt_buf, lcd_cfg_size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: lcd_cfg.bin upgrade failed!!"); + goto ERROR_LCD_CFG_BIN; + } else { + FTS_INFO("[UPGRADE]: lcd_cfg.bin upgrade succeed!!"); + } + } else { + FTS_ERROR("[UPGRADE]: lcd_cfg.bin ecc failed!!"); + + } + + kfree(pbt_buf); + return i_ret; + +ERROR_LCD_CFG_BIN: + kfree(pbt_buf); + return -EIO; +} +#endif /* #if (FTS_CHIP_TYPE == _FT8006) */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8606.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8606.c new file mode 100644 index 0000000000000000000000000000000000000000..1e1488eb7d00b94e256d74c18af02e9e9cb0d3c0 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8606.c @@ -0,0 +1,585 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft8606.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (FTS_CHIP_TYPE == _FT8606) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (64 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10A) +#define APP_FILE_VENDORID_MAPPING (0x108) +#define APP_FILE_CHIPID_MAPPING (0x11E) +#define CONFIG_START_ADDR (0x0780) +#define CONFIG_VENDOR_ID_OFFSET (0x04) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) +#define AL2_FCS_COEF ((1 << 7) + (1 << 6) + (1 << 5)) + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ctpm_get_app_i_file_ver(void); +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name); +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length); +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + .get_i_file = fts_ctpm_get_i_file, + .get_app_bin_file_ver = fts_ctpm_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ctpm_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ctpm_fw_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ctpm_fw_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = NULL, + .upgrade_with_lcd_cfg_bin_file = NULL, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ctpm_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ctpm_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + u8 rw_buf[10]; + int i_ret; + int fw_len; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*check run in pramboot or not! + *if not rum in pramboot, cannot upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + /* must wait, otherwise read vendor id wrong */ + usleep_range(10000, 20000); + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ctpm_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = 0; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + } else { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + if ((ret < 0) || (vendor_id == 0xEF) || (vendor_id == 0xED)) { + /* 8736 can't read vendor id from A8 command */ + ret = fts_ctpm_get_vendor_id_flash(client, &vendor_id); + } + } + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + FTS_INFO("[UPGRADE] vendor id tp=%x", vendor_id); + FTS_INFO("[UPGRADE] vendor id driver:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#else + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + int fw_ver = 0; + int ret; + + FTS_FUNC_ENTER(); + + ret = request_firmware(&fw, firmware_name, &client->dev); + if (ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw->size); + else + fw_ver = fw->data[APP_FILE_VER_MAPPING]; + + release_firmware(fw); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +/************************************************************************ +* Name: fts_ctpm_write_pram +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + int i_ret; + bool inrom = false; + + FTS_FUNC_ENTER(); + + /*check the length of the pramboot*/ + if (dw_length > APP_FILE_MAX_SIZE || dw_length < APP_FILE_MIN_SIZE) { + FTS_ERROR("[UPGRADE] pramboot length(%d) fail", dw_length); + return -EIO; + } + + /*send comond to FW, reset and start write pramboot*/ + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*check run in rom or not! if run in rom, will write pramboot*/ + inrom = fts_ctpm_check_run_state(client, FTS_RUN_IN_ROM); + if (!inrom) { + FTS_ERROR("[UPGRADE]: not run in rom, write pramboot fail!!"); + return -EIO; + } + + /*write pramboot to pram*/ + i_ret = fts_ctpm_write_pramboot_for_idc(client, + dw_length, aucFW_PRAM_BOOT); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write pramboot fail!!"); + return i_ret; + } + + /*read out checksum*/ + i_ret = fts_ctpm_pramboot_ecc(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write pramboot ecc error!!"); + return i_ret; + } + + /*start pram*/ + fts_ctpm_start_pramboot(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_app +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_app(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u32 temp; + int i_ret; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*check run in pramboot or not! + *if not rum in pramboot, can not upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /*upgrade init*/ + i_ret = fts_ctpm_upgrade_idc_init(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: upgrade init error, upgrade fail!!"); + return i_ret; + } + + /*erase the app erea in flash*/ + i_ret = fts_ctpm_erase_flash(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: erase flash error!!"); + return i_ret; + } + + /*start to write app*/ + i_ret = fts_ctpm_write_app_for_idc(client, dw_length, pbt_buf); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write app error!!"); + return i_ret; + } + + /*read check sum*/ + temp = 0x1000; + i_ret = fts_ctpm_upgrade_ecc(client, temp, dw_length); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: ecc error!!"); + return i_ret; + } + + /*upgrade success, reset the FW*/ + fts_ctpm_rom_or_pram_reset(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/***************************************************************************** +* Name: ecc_calc +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static u8 ecc_calc(u8 *pbt_buf, u16 start, u16 length) +{ + u8 cFcs = 0; + u16 i, j; + + for (i = 0; i < length; i++) { + cFcs ^= pbt_buf[start++]; + for (j = 0; j < 8; j++) { + if (cFcs & 1) + cFcs = (u8)((cFcs >> 1) ^ AL2_FCS_COEF); + else + cFcs >>= 1; + } + } + return cFcs; +} + + +/***************************************************************************** +* Name: fts_8606_check_app_bin_valid +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static bool fts_8606_check_app_bin_valid(u8 *pbt_buf) +{ + u8 ecc1; + u8 ecc2; + u8 ecc3; + u8 ecc4; + u16 len1; + u16 len2; + u8 cal_ecc1; + u8 cal_ecc2; + u16 usAddrInfo; + + /* 1. First Byte */ + if (pbt_buf[0] != 0x02) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- the first byte(%x) error", + pbt_buf[0]); + return false; + } + + usAddrInfo = 0x100; + + /* 2.len */ + len1 = pbt_buf[usAddrInfo++] << 8; + len1 += pbt_buf[usAddrInfo++]; + + len2 = pbt_buf[usAddrInfo++] << 8; + len2 += pbt_buf[usAddrInfo++]; + + if ((len1 + len2) != 0xFFFF) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- LENGTH(%04x) XOR error", + len1); + return false; + } + + /* 3.ecc */ + ecc1 = pbt_buf[usAddrInfo++]; + ecc2 = pbt_buf[usAddrInfo++]; + ecc3 = pbt_buf[usAddrInfo++]; + ecc4 = pbt_buf[usAddrInfo++]; + + if (((ecc1 + ecc2) != 0xFF) || ((ecc3 + ecc4) != 0xFF)) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC(%x %x) XOR error", + ecc1, ecc2); + return false; + } + + cal_ecc1 = ecc_calc(pbt_buf, 0x0, 0x100); + cal_ecc2 = ecc_calc(pbt_buf, 0x100 + 0x20, len1 - (0x100 + 0x20)); + if ((ecc1 != cal_ecc1) || (ecc3 != cal_ecc2)) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC calc error"); + return false; + } + return true; +} + + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +* success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 fwsize) +{ + int i_ret = 0; + int fw_len; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*write app*/ + i_ret = fts_ctpm_write_app(client, pbt_buf, fwsize); + + FTS_FUNC_EXIT(); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ctpm_fw_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + i_ret = request_firmware(&fw, firmware_name, &client->dev); + if (i_ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return i_ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + goto ERROR_BIN; + } + + pbt_buf = (u8 *)fw->data; + if ((pbt_buf[APP_FILE_CHIPID_MAPPING] != chip_types.pramboot_idh) + || (pbt_buf[APP_FILE_CHIPID_MAPPING+1] + != chip_types.pramboot_idl)) { + FTS_ERROR("[UPGRADE]: chip id error, app.bin upgrade failed!"); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + ecc_ok = fts_8606_check_app_bin_valid(pbt_buf); + + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ctpm_fw_upgrade_use_buf(client, pbt_buf, fw->size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + +ERROR_BIN: + release_firmware(fw); + return i_ret; +} +#endif /* #if (FTS_CHIP_TYPE == _FT8606) */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8607.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8607.c new file mode 100644 index 0000000000000000000000000000000000000000..c4a59510424fc38df8f3c249c3decc170980ea8d --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8607.c @@ -0,0 +1,497 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft8607.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (FTS_CHIP_TYPE == _FT8607) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (64 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10E) +#define APP_FILE_VENDORID_MAPPING (0x10C) +#define APP_FILE_CHIPID_MAPPING (0x11E) +#define CONFIG_START_ADDR (0x0780) +#define CONFIG_VENDOR_ID_OFFSET (0x04) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ctpm_get_app_i_file_ver(void); +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name); +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length); +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + .get_i_file = fts_ctpm_get_i_file, + .get_app_bin_file_ver = fts_ctpm_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ctpm_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ctpm_fw_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ctpm_fw_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = NULL, + .upgrade_with_lcd_cfg_bin_file = NULL, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ctpm_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ctpm_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + u8 rw_buf[10]; + int i_ret; + int fw_len; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*check run in pramboot or not! + *if not rum in pramboot, can not upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + /* must wait, otherwise read vendor id wrong */ + usleep_range(10000, 20000); + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ctpm_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = 0; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + } else { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + if ((ret < 0) || (vendor_id == 0xEF) || (vendor_id == 0xED)) { + /* 8736 can't read vendor id from A8 command */ + ret = fts_ctpm_get_vendor_id_flash(client, &vendor_id); + } + } + + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + FTS_INFO("[UPGRADE] vendor id tp=%x", vendor_id); + FTS_INFO("[UPGRADE] vendor id driver:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#else + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + int fw_ver = 0; + int ret; + + FTS_FUNC_ENTER(); + + ret = request_firmware(&fw, firmware_name, &client->dev); + if (ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw->size); + else + fw_ver = fw->data[APP_FILE_VER_MAPPING]; + + release_firmware(fw); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +/************************************************************************ +* Name: fts_ctpm_write_pram +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + int i_ret; + bool inrom = false; + + FTS_FUNC_ENTER(); + + /*check the length of the pramboot*/ + if (dw_length > APP_FILE_MAX_SIZE || dw_length < APP_FILE_MIN_SIZE) { + FTS_ERROR("[UPGRADE] pramboot length(%d) fail", dw_length); + return -EIO; + } + + /*send comond to FW, reset and start write pramboot*/ + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*check run in rom or not! if run in rom, will write pramboot*/ + inrom = fts_ctpm_check_run_state(client, FTS_RUN_IN_ROM); + if (!inrom) { + FTS_ERROR("[UPGRADE]: not run in rom, write pramboot fail!!"); + return -EIO; + } + + /*write pramboot to pram*/ + i_ret = fts_ctpm_write_pramboot_for_idc(client, + dw_length, aucFW_PRAM_BOOT); + if (i_ret < 0) { + return i_ret; + FTS_ERROR("[UPGRADE]: write pramboot fail!!"); + } + + /*read out checksum*/ + i_ret = fts_ctpm_pramboot_ecc(client); + if (i_ret < 0) { + return i_ret; + FTS_ERROR("[UPGRADE]: write pramboot ecc error!!"); + } + + /*start pram*/ + fts_ctpm_start_pramboot(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_app +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_app(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u32 temp; + int i_ret; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*check run in pramboot or not! + *if not rum in pramboot, can not upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /*upgrade init*/ + i_ret = fts_ctpm_upgrade_idc_init(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: upgrade init error, upgrade fail!!"); + return i_ret; + } + + /*erase the app erea in flash*/ + i_ret = fts_ctpm_erase_flash(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: erase flash error!!"); + return i_ret; + } + + /*start to write app*/ + i_ret = fts_ctpm_write_app_for_idc(client, dw_length, pbt_buf); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write app error!!"); + return i_ret; + } + + /*read check sum*/ + temp = 0x1000; + i_ret = fts_ctpm_upgrade_ecc(client, temp, dw_length); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: ecc error!!"); + return i_ret; + } + + /*upgrade success, reset the FW*/ + fts_ctpm_rom_or_pram_reset(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +* success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 fwsize) +{ + int i_ret = 0; + int fw_len; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*write app*/ + i_ret = fts_ctpm_write_app(client, pbt_buf, fwsize); + + FTS_FUNC_EXIT(); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ctpm_fw_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + i_ret = request_firmware(&fw, firmware_name, &client->dev); + if (i_ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return i_ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + goto ERROR_BIN; + } + + pbt_buf = (u8 *)fw->data; + if ((pbt_buf[APP_FILE_CHIPID_MAPPING] != chip_types.pramboot_idh) + || (pbt_buf[APP_FILE_CHIPID_MAPPING+1] + != chip_types.pramboot_idl)) { + FTS_ERROR("[UPGRADE]: chip id error, app.bin upgrade failed!"); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + ecc_ok = fts_check_app_bin_valid_idc(pbt_buf); + + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ctpm_fw_upgrade_use_buf(client, pbt_buf, fw->size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + +ERROR_BIN: + release_firmware(fw); + return i_ret; +} +#endif /* #if (FTS_CHIP_TYPE == _FT8607) */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8716.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8716.c new file mode 100644 index 0000000000000000000000000000000000000000..b332eb2ce9d523c0f936c79d80198831b2f4649a --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8716.c @@ -0,0 +1,485 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft8716.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if ((FTS_CHIP_TYPE == _FT8716) || (FTS_CHIP_TYPE == _FTE716)) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (64 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10E) +#define APP_FILE_VENDORID_MAPPING (0x10C) +#define APP_FILE_CHIPID_MAPPING (0x11E) +#define CONFIG_START_ADDR (0x0000) +#define CONFIG_VENDOR_ID_OFFSET (0x04) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ctpm_get_app_i_file_ver(void); +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name); +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length); +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + .get_i_file = fts_ctpm_get_i_file, + .get_app_bin_file_ver = fts_ctpm_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ctpm_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ctpm_fw_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ctpm_fw_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = NULL, + .upgrade_with_lcd_cfg_bin_file = NULL, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ctpm_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ctpm_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + u8 rw_buf[10]; + int i_ret; + int fw_len; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*check run in pramboot or not! + *if not rum in pramboot, can not upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + /* must wait, otherwise read vendor id wrong */ + usleep_range(10000, 20000); + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ctpm_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = -EIO; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + } else { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + if ((ret < 0) || (vendor_id == 0xEF) || (vendor_id == 0xED)) { + /* 8736 can't read vendor id from A8 command */ + ret = fts_ctpm_get_vendor_id_flash(client, &vendor_id); + } + } + + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + FTS_INFO("[UPGRADE] vendor id tp=%x", vendor_id); + FTS_INFO("[UPGRADE] vendor id driver:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + int fw_ver = 0; + int ret; + + FTS_FUNC_ENTER(); + + ret = request_firmware(&fw, firmware_name, &client->dev); + if (ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw->size); + else + fw_ver = fw->data[APP_FILE_VER_MAPPING]; + + release_firmware(fw); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +/************************************************************************ +* Name: fts_ctpm_write_pram +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + int i_ret; + bool inrom = false; + + FTS_FUNC_ENTER(); + + /*check the length of the pramboot*/ + if (dw_length > APP_FILE_MAX_SIZE || dw_length < APP_FILE_MIN_SIZE) { + FTS_ERROR("[UPGRADE] pramboot length(%d) fail", dw_length); + return -EIO; + } + + /*send comond to FW, reset and start write pramboot*/ + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*check run in rom or not! if run in rom, will write pramboot*/ + inrom = fts_ctpm_check_run_state(client, FTS_RUN_IN_ROM); + if (!inrom) { + FTS_ERROR("[UPGRADE]: not run in rom, write pramboot fail!!"); + return -EIO; + } + + /*write pramboot to pram*/ + i_ret = fts_ctpm_write_pramboot_for_idc(client, + dw_length, aucFW_PRAM_BOOT); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write pramboot fail!!"); + return i_ret; + } + + /*read out checksum*/ + i_ret = fts_ctpm_pramboot_ecc(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write pramboot ecc error!!"); + return i_ret; + } + + /*start pram*/ + fts_ctpm_start_pramboot(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_app +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_app(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u32 temp; + int i_ret; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*check run in pramboot or not! + *if not rum in pramboot, can not upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /*upgrade init*/ + i_ret = fts_ctpm_upgrade_idc_init(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: upgrade init error, upgrade fail!!"); + return i_ret; + } + + /*erase the app erea in flash*/ + i_ret = fts_ctpm_erase_flash(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: erase flash error!!"); + return i_ret; + } + + /*start to write app*/ + i_ret = fts_ctpm_write_app_for_idc(client, dw_length, pbt_buf); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write app error!!"); + return i_ret; + } + + /*read check sum*/ + temp = 0x1000; + i_ret = fts_ctpm_upgrade_ecc(client, temp, dw_length); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: ecc error!!"); + return i_ret; + } + + /*upgrade success, reset the FW*/ + fts_ctpm_rom_or_pram_reset(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +* success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 fwsize) +{ + int i_ret = 0; + int fw_len; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*write app*/ + i_ret = fts_ctpm_write_app(client, pbt_buf, fwsize); + + FTS_FUNC_EXIT(); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ctpm_fw_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + i_ret = request_firmware(&fw, firmware_name, &client->dev); + if (i_ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return i_ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + pbt_buf = (u8 *)fw->data; + ecc_ok = fts_check_app_bin_valid_idc(pbt_buf); + + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ctpm_fw_upgrade_use_buf(client, pbt_buf, fw->size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + +ERROR_BIN: + release_firmware(fw); + return i_ret; +} +#endif /* #if (FTS_CHIP_TYPE == _FT8716) */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8736.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8736.c new file mode 100644 index 0000000000000000000000000000000000000000..fb79a6349562c8632ae989e2a65598b4f1d66dbc --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft8736.c @@ -0,0 +1,504 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_ft8736.c +* +* Author: fupeipei +* +* Created: 2016-10-25 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (FTS_CHIP_TYPE == _FT8736) +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define APP_FILE_MAX_SIZE (64 * 1024) +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10E) +#define APP_FILE_VENDORID_MAPPING (0x10C) +#define APP_FILE_CHIPID_MAPPING (0x11E) +#define CONFIG_START_ADDR (0x0F80) +#define CONFIG_VENDOR_ID_OFFSET (0x4) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ctpm_get_app_i_file_ver(void); +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name); +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length); +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name); + +struct fts_upgrade_fun fts_updatefun = { + .get_i_file = fts_ctpm_get_i_file, + .get_app_bin_file_ver = fts_ctpm_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ctpm_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ctpm_fw_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ctpm_fw_upgrade_with_app_bin_file, + .upgrade_with_lcd_cfg_i_file = NULL, + .upgrade_with_lcd_cfg_bin_file = NULL, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ctpm_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ctpm_get_vendor_id_flash(struct i2c_client *client, + u8 *vendor_id) +{ + u8 rw_buf[10]; + int i_ret; + int fw_len; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*check run in pramboot or not! + *if not rum in pramboot, can not upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /* initialization 0x05 0x80 */ + i_ret = fts_ctpm_upgrade_idc_init(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: upgrade init error, upgrade fail!!"); + return i_ret; + } + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + /* must wait, otherwise read vendor id wrong */ + usleep_range(10000, 20000); + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + return -EIO; + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ctpm_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = 0; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + } else { + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + if ((ret < 0) || (vendor_id == 0xEF) || (vendor_id == 0xED)) { + /* 8736 can't read vendor id from A8 command */ + ret = fts_ctpm_get_vendor_id_flash(client, &vendor_id); + } + } + + if (ret < 0) { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + FTS_INFO("[UPGRADE] vendor id tp=%x", vendor_id); + FTS_INFO("[UPGRADE] vendor id driver:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + + ret = 0; + switch (vendor_id) { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#else + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_bin_file_ver(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + int fw_ver = 0; + int ret; + + FTS_FUNC_ENTER(); + + ret = request_firmware(&fw, firmware_name, &client->dev); + if (ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw->size); + else + fw_ver = fw->data[APP_FILE_VER_MAPPING]; + + release_firmware(fw); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +/************************************************************************ +* Name: fts_ctpm_write_pram +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_pram(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + int i_ret; + bool inrom = false; + + FTS_FUNC_ENTER(); + + /*check the length of the pramboot*/ + if (dw_length > APP_FILE_MAX_SIZE || dw_length < APP_FILE_MIN_SIZE) { + FTS_ERROR("[UPGRADE] pramboot length(%d) fail", dw_length); + return -EIO; + } + + /*send comond to FW, reset and start write pramboot*/ + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*check run in rom or not! if run in rom, will write pramboot*/ + inrom = fts_ctpm_check_run_state(client, FTS_RUN_IN_ROM); + if (!inrom) { + FTS_ERROR("[UPGRADE]: not run in rom, write pramboot fail!!"); + return -EIO; + } + + /*write pramboot to pram*/ + i_ret = fts_ctpm_write_pramboot_for_idc(client, + dw_length, aucFW_PRAM_BOOT); + if (i_ret < 0) { + return i_ret; + FTS_ERROR("[UPGRADE]: write pramboot fail!!"); + } + + /*read out checksum*/ + i_ret = fts_ctpm_pramboot_ecc(client); + if (i_ret < 0) { + return i_ret; + FTS_ERROR("[UPGRADE]: write pramboot ecc error!!"); + } + + /*start pram*/ + fts_ctpm_start_pramboot(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_app +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_write_app(struct i2c_client *client, + u8 *pbt_buf, u32 dw_length) +{ + u32 temp; + int i_ret; + bool inpram = false; + + FTS_FUNC_ENTER(); + + /*check run in pramboot or not! + *if not rum in pramboot, can not upgrade*/ + inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM); + if (!inpram) { + FTS_ERROR("[UPGRADE]: not run in pram, upgrade fail!!"); + return -EIO; + } + + /*upgrade init*/ + i_ret = fts_ctpm_upgrade_idc_init(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: upgrade init error, upgrade fail!!"); + return i_ret; + } + + /*erase the app erea in flash*/ + i_ret = fts_ctpm_erase_flash(client); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: erase flash error!!"); + return i_ret; + } + + /*start to write app*/ + i_ret = fts_ctpm_write_app_for_idc(client, dw_length, pbt_buf); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: write app error!!"); + return i_ret; + } + + /*read check sum*/ + temp = 0x1000; + i_ret = fts_ctpm_upgrade_ecc(client, temp, dw_length); + if (i_ret < 0) { + FTS_ERROR("[UPGRADE]: ecc error!!"); + return i_ret; + } + + /*upgrade success, reset the FW*/ + fts_ctpm_rom_or_pram_reset(client); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +* success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_use_buf(struct i2c_client *client, + u8 *pbt_buf, u32 fwsize) +{ + int i_ret = 0; + int fw_len; + + FTS_FUNC_ENTER(); + + /*write pramboot*/ + fw_len = fts_getsize(PRAMBOOT_SIZE); + FTS_DEBUG("[UPGRADE]: pramboot size : %d!!", fw_len); + i_ret = fts_ctpm_write_pram(client, aucFW_PRAM_BOOT, fw_len); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: write pram failed!!"); + return -EIO; + } + + /*write app*/ + i_ret = fts_ctpm_write_app(client, pbt_buf, fwsize); + + FTS_FUNC_EXIT(); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ctpm_fw_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + else + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, + char *firmware_name) +{ + const struct firmware *fw = NULL; + u8 *pbt_buf = NULL; + int i_ret = 0; + bool ecc_ok = false; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + i_ret = request_firmware(&fw, firmware_name, &client->dev); + if (i_ret) { + FTS_ERROR("[UPGRADE]: failed to get fw %s\n", firmware_name); + return i_ret; + } + + if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", + fwsize); + goto ERROR_BIN; + } + + pbt_buf = (u8 *)fw->data; + if ((pbt_buf[APP_FILE_CHIPID_MAPPING] != chip_types.pramboot_idh) + || (pbt_buf[APP_FILE_CHIPID_MAPPING+1] + != chip_types.pramboot_idl)) { + FTS_ERROR("[UPGRADE]: chip id error, app.bin upgrade failed!"); + goto ERROR_BIN; + } + + /*check the app.bin invalid or not*/ + ecc_ok = fts_check_app_bin_valid_idc(pbt_buf); + + if (ecc_ok) { + FTS_INFO("[UPGRADE] app.bin ecc ok"); + i_ret = fts_ctpm_fw_upgrade_use_buf(client, pbt_buf, fw->size); + if (i_ret != 0) { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } else { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + } else { + FTS_ERROR("[UPGRADE] app.bin ecc failed"); + goto ERROR_BIN; + } + +ERROR_BIN: + release_firmware(fw); + return i_ret; +} +#endif /* #if (FTS_CHIP_TYPE == _FT8736) */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_idc.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_idc.c new file mode 100644 index 0000000000000000000000000000000000000000..d73b1f195d138b4e453129a7d306711f2ddde2fe --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_idc.c @@ -0,0 +1,589 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_idc.c +* +* Author: fupeipei +* +* Created: 2016-08-22 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (FTS_CHIP_IDC == 1) +#include "../focaltech_flash.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static u8 upgrade_ecc; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/************************************************************************ +* Name: fts_ctpm_upgrade_idc_init +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_upgrade_idc_init(struct i2c_client *client) +{ + int i_ret = 0; + u8 reg_val_id[4] = {0}; + u8 auc_i2c_write_buf[10]; + + FTS_INFO("[UPGRADE]**********Upgrade setting Init**********"); + + /*read flash ID*/ + auc_i2c_write_buf[0] = 0x05; + reg_val_id[0] = 0x00; + i_ret = fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val_id, 1); + if (i_ret < 0) + return -EIO; + + /*set flash clk*/ + auc_i2c_write_buf[0] = 0x05; + auc_i2c_write_buf[1] = reg_val_id[0];/* 0x80; */ + auc_i2c_write_buf[2] = 0x00; + fts_i2c_write(client, auc_i2c_write_buf, 3); + + /*send upgrade type to reg 0x09: 0x0B: upgrade; 0x0A: download*/ + auc_i2c_write_buf[0] = 0x09; + auc_i2c_write_buf[1] = 0x0B; + fts_i2c_write(client, auc_i2c_write_buf, 2); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_start_pramboot +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +void fts_ctpm_start_pramboot(struct i2c_client *client) +{ + u8 auc_i2c_write_buf[10]; + + FTS_INFO("[UPGRADE]**********start pramboot**********"); + auc_i2c_write_buf[0] = 0x08; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(20); +} + +/************************************************************************ +* Name: fts_ctpm_start_fw_upgrade +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_start_fw_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + + /*send the soft upgrade commond to FW, and start upgrade*/ + FTS_INFO("[UPGRADE]***send 0xAA and 0x55 to FW, start upgrade***\n"); + + i_ret = fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA); + msleep(20); + i_ret = fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55); + msleep(200); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_check_run_state +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +bool fts_ctpm_check_run_state(struct i2c_client *client, int rstate) +{ + int i = 0; + enum FW_STATUS cstate = FTS_RUN_IN_ERROR; + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + cstate = fts_ctpm_get_pram_or_rom_id(client); + FTS_DEBUG("[UPGRADE]: run state = %d", cstate); + + if (cstate == rstate) + return true; + msleep(20); + } + + return false; +} + +/************************************************************************ +* Name: fts_ctpm_pramboot_ecc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_pramboot_ecc(struct i2c_client *client) +{ + u8 auc_i2c_write_buf[10]; + u8 reg_val[4] = {0}; + + FTS_FUNC_ENTER(); + + /* read out checksum, + * if pramboot checksum != host checksum, upgrade fail*/ + FTS_INFO("[UPGRADE]******read out pramboot checksum******"); + auc_i2c_write_buf[0] = 0xcc; + usleep_range(2000, 4000); + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + /*pramboot checksum != host checksum, upgrade fail*/ + if (reg_val[0] != upgrade_ecc) { + FTS_ERROR("[UPGRADE]: checksum fail:pramboot = %X, host = %X!", + reg_val[0], upgrade_ecc); + return -EIO; + } + + FTS_DEBUG("[UPGRADE]: checksum success:pramboot = %X, host = %X!!", + reg_val[0], upgrade_ecc); + msleep(100); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_upgrade_ecc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_upgrade_ecc(struct i2c_client *client, u32 startaddr, u32 length) +{ + u32 i = 0; + u8 auc_i2c_write_buf[10]; + u32 temp; + u8 reg_val[4] = {0}; + int i_ret = 0; + + FTS_INFO("[UPGRADE]**********read out checksum**********"); + + /*check sum init*/ + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + /*send commond to pramboot to start checksum*/ + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(startaddr >> 16); + auc_i2c_write_buf[2] = (u8)(startaddr >> 8); + auc_i2c_write_buf[3] = (u8)(startaddr); + + if (length > LEN_FLASH_ECC_MAX) + temp = LEN_FLASH_ECC_MAX; + else + temp = length; + + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(length/256); + + /*read status : if check sum is finished?*/ + for (i = 0; i < 100; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0 == reg_val[0] && 0x55 == reg_val[1]) + break; + usleep_range(1000, 2000); + + } + + if (length > LEN_FLASH_ECC_MAX) { + temp = LEN_FLASH_ECC_MAX; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = length-LEN_FLASH_ECC_MAX; + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + + msleep(length/256); + + for (i = 0; i < 100; i++) { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0 == reg_val[0] && 0x55 == reg_val[1]) + break; + usleep_range(1000, 2000); + } + } + + /*read out check sum*/ + auc_i2c_write_buf[0] = 0x66; + i_ret = fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + /*if check sum fail, upgrade fail*/ + if (reg_val[0] != upgrade_ecc) { + FTS_ERROR("[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!", + reg_val[0], upgrade_ecc); + return -EIO; + } + + FTS_DEBUG("[UPGRADE]: ecc success : FW=%02x upgrade_ecc=%02x!!", + reg_val[0], upgrade_ecc); + + upgrade_ecc = 0; + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_erase_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_erase_flash(struct i2c_client *client) +{ + u32 i = 0; + u8 auc_i2c_write_buf[10]; + u8 reg_val[4] = {0}; + + FTS_INFO("[UPGRADE]**********erase app now**********"); + + /*send to erase flash*/ + auc_i2c_write_buf[0] = 0x61; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1350); + + for (i = 0; i < 15; i++) { + /* get the erase app status, + * if get 0xF0AA£¬erase flash success*/ + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + /*erase flash success*/ + if (0xF0 == reg_val[0] && 0xAA == reg_val[1]) + break; + msleep(50); + } + + /*erase flash fail*/ + if ((0xF0 != reg_val[0] || 0xAA != reg_val[1]) && (i >= 15)) { + FTS_ERROR("[UPGRADE]: erase app error.reset tp and reload FW!"); + return -EIO; + } + + FTS_DEBUG("[UPGRADE]: erase app ok!!"); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_pramboot_for_idc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_write_pramboot_for_idc(struct i2c_client *client, + u32 length, u8 *readbuf) +{ + u32 i = 0; + u32 j; + u32 temp; + u32 packet_number; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + + upgrade_ecc = 0; + FTS_INFO("[UPGRADE]**********write pramboot to pram**********"); + + temp = 0; + packet_number = (length) / FTS_PACKET_LENGTH; + if ((length) % FTS_PACKET_LENGTH > 0) + packet_number++; + + packet_buf[0] = 0xae; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + if (j < (packet_number-1)) + temp = FTS_PACKET_LENGTH; + else + temp = (length) % FTS_PACKET_LENGTH; + + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = readbuf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + } + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_app_for_idc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_write_app_for_idc(struct i2c_client *client, + u32 length, u8 *readbuf) +{ + u32 j; + u32 i = 0; + u32 packet_number; + u32 temp; + u32 writelenght; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 reg_val[4] = {0}; + + FTS_INFO("[UPGRADE]**********write app to flash**********"); + + upgrade_ecc = 0; + + packet_number = (length) / FTS_PACKET_LENGTH; + if (((length) % FTS_PACKET_LENGTH) > 0) + packet_number++; + + packet_buf[0] = 0xbf; + + for (j = 0; j < packet_number; j++) { + temp = 0x1000+j * FTS_PACKET_LENGTH; + + if (j < (packet_number-1)) + writelenght = FTS_PACKET_LENGTH; + else + writelenght = ((length) % FTS_PACKET_LENGTH); + + packet_buf[1] = (u8) (temp >> 16); + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + packet_buf[4] = (u8) (writelenght >> 8); + packet_buf[5] = (u8) writelenght; + + for (i = 0; i < writelenght; i++) { + packet_buf[6 + i] = readbuf[(temp - 0x1000+i)]; + upgrade_ecc ^= packet_buf[6 + i]; + } + + fts_i2c_write(client, packet_buf, (writelenght + 6)); + + for (i = 0; i < 30; i++) { + /* read status and check + * if the app writing is finished */ + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((j + 0x20+0x1000) == (((reg_val[0]) << 8) + | reg_val[1])) + break; + + fts_ctpm_upgrade_delay(1000); + } + } + + msleep(50); + + return 0; +} + +#define APP_LEN 0x00 +#define APP_LEN_NE 0x02 +#define APP_P1_ECC 0x04 +#define APP_P1_ECC_NE 0x06 +#define APP_P2_ECC 0x08 +#define APP_P2_ECC_NE 0x0A +#define APP_LEN_H 0x12 +#define APP_LEN_H_NE 0x14 +#define APP_BLR_ID 0x1C +#define APP_BLR_ID_NE 0x1D +#define PBOOT_ID_H 0x1E +#define PBOOT_ID_L 0x1F + +#define AL2_FCS_COEF ((1 << 15) + (1 << 10) + (1 << 3)) + +#if ((FTS_CHIP_TYPE == _FT8006) || (FTS_CHIP_TYPE == _FT8736)) +#define FW_CFG_TOTAL_SIZE 0x80 +#else +#define FW_CFG_TOTAL_SIZE 0x00 +#endif +#define APP1_START 0x00 +#define APP1_LEN 0x100 +#define APP_VERIF_ADDR (APP1_START + APP1_LEN) +#define APP_VERIF_LEN 0x20 +#define APP1_ECC_ADDR (APP_VERIF_ADDR + APP_P1_ECC) +#define APP2_START (APP_VERIF_ADDR + APP_VERIF_LEN + FW_CFG_TOTAL_SIZE) +#define APP2_ECC_ADDR (APP_VERIF_ADDR + APP_P2_ECC) +/***************************************************************************** +* Name: DrvReadPram16 +* Brief: Get Word +* Input: +* Output: +* Return: +*****************************************************************************/ +static u16 data_word(u8 *pbt_buf, u32 addr) +{ + return (((u16)pbt_buf[addr]<<8) + pbt_buf[addr+1]); +} + +/****************************************************************************** +* Name: GetCrc16 +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static u16 crc_calc(u8 *pbt_buf, u32 addr, u16 length) +{ + u16 cFcs = 0; + u16 i, j; + + FTS_DEBUG("[UPGRADE][ECC] : %04x data:%04x, len:%04x!!", + (addr), data_word(pbt_buf, (addr)), length); + for (i = 0; i < length; i++) { + cFcs ^= data_word(pbt_buf, (addr+i*2)); + for (j = 0; j < 16; j++) { + if (cFcs & 1) + cFcs = (u16)((cFcs >> 1) ^ AL2_FCS_COEF); + else + cFcs >>= 1; + } + } + + return cFcs; +} + +/***************************************************************************** +* Name: task_check_mem +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static bool ecc_check(u8 *pbt_buf, u32 star_addr, u32 len, u16 ecc_addr) +{ + u16 ecc1; + u16 ecc2; + u16 cal_ecc; + + ecc1 = data_word(pbt_buf, ecc_addr); + ecc2 = data_word(pbt_buf, ecc_addr+2); + + if ((ecc1 + ecc2) != 0xFFFF) + return false; + + cal_ecc = crc_calc(pbt_buf, star_addr, (len/2)); + + FTS_DEBUG("[UPGRADE][ECC] : ecc1 = %x, cal_ecc = %x", ecc1, cal_ecc); + if (ecc1 != cal_ecc) { + FTS_DEBUG("[UPGRADE][ECC] : ecc error!!"); + return false; + } + + return true; +} + +/***************************************************************************** +* Name: fts_check_app_bin_valid_idc +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +bool fts_check_app_bin_valid_idc(u8 *pbt_buf) +{ + u32 len; +#if (FTS_CHIP_TYPE != _FT8006) + /* 1. First Byte */ + if (pbt_buf[0] != 0x02) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- the first byte(%x) error", + pbt_buf[0]); + return false; + } +#endif + /* 2 PART1 ECC */ + if (!ecc_check(pbt_buf, APP1_START, APP1_LEN, APP1_ECC_ADDR)) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- ecc1 error"); + return false; + } + + /* 3. PART2 ECC */ + if ((data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN) + + data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN_NE)) != 0xFFFF) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- Length XOR error"); + return false; + } + + len = data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN); +#if (FTS_CHIP_TYPE == _FT8006) + if ((data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN_H) + + data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN_H_NE)) != 0xFFFF) { + FTS_DEBUG("[UPGRADE]APP.BIN Verify- Length2 XOR error"); + return false; + } + + len += ((u32)data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN_H) << 16); +#endif + FTS_DEBUG("%x %x %x %x", APP2_START, len, + ((u32)data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN_H) << 16), + data_word(pbt_buf, APP_VERIF_ADDR+APP_LEN)); + + len -= APP2_START; + + return ecc_check(pbt_buf, APP2_START, len, APP2_ECC_ADDR); +} + + +#endif /* IDC */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_test.c b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_test.c new file mode 100644 index 0000000000000000000000000000000000000000..74f6fe20989e55c0902733400668eef2dbdeec53 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_test.c @@ -0,0 +1,174 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_upgrade_test.c +* +* Author: fupeipei +* +* Created: 2016-08-22 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" +#include "../focaltech_flash.h" +#include +#include + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define FTS_GET_UPGRADE_TIME 0 + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +#define FTS_DEBUG_UPGRADE(fmt, args...) do {\ + pr_err("[FTS][UPGRADE]:################\n");\ + pr_err("[FTS][UPGRADE]: "fmt"\n", ##args);\ + pr_err("[FTS][UPGRADE]:################\n");\ + } while (0)\ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_UPGRADE_STRESS_TEST) +/************************************************************************ +* Name: fts_ctpm_auto_upgrade_pingpong +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +static int fts_ctpm_auto_upgrade_pingpong(struct i2c_client *client) +{ + u8 uc_tp_fm_ver; + int i_ret = 0; + u8 uc_upgrade_times = 0; + + FTS_FUNC_ENTER(); + + /* pingpong test mode, need upgrade */ + FTS_INFO("[UPGRADE]: pingpong test mode, need upgrade!!"); + do { + uc_upgrade_times++; + + /* fw upgrade */ + i_ret = fts_ctpm_fw_upgrade(client); + + if (i_ret == 0) { + /* upgrade success */ + fts_i2c_read_reg(client, FTS_REG_FW_VER, &uc_tp_fm_ver); + FTS_DEBUG("[UPGRADE]: upgrade to new version 0x%x", + uc_tp_fm_ver); + } else { + /* upgrade fail */ + /* if upgrade fail, reset to run ROM. + * if app in flash is ok. TP will work success */ + FTS_INFO("[UPGRADE]: upgrade fail, reset now!!"); + fts_ctpm_rom_or_pram_reset(client); + } + /* if upgrade fail, upgrade again. then return */ + } while ((i_ret != 0) && (uc_upgrade_times < 2)); + + FTS_FUNC_EXIT(); + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_auto_upgrade +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +void fts_ctpm_display_upgrade_time(bool start_time) +{ +#if FTS_GET_UPGRADE_TIME + static struct timeval tpend; + static struct timeval tpstart; + static int timeuse; + + if (start_time) { + do_gettimeofday(&tpstart); + } else { + do_gettimeofday(&tpend); + timeuse = 1000000 * (tpend.tv_sec-tpstart.tv_sec) + + tpend.tv_usec-tpstart.tv_usec; + timeuse /= 1000000; + FTS_DEBUG("[UPGRADE]: upgrade success : Use time: %d Seconds!!", + timeuse); + } +#endif +} + +/************************************************************************ +* Name: fts_ctpm_auto_upgrade +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +int fts_ctpm_auto_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + static int uc_ErrorTimes; + static int uc_UpgradeTimes; + + + device_init_wakeup(&client->dev, 1); + pm_stay_awake(&client->dev); + + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + + do { + uc_UpgradeTimes++; + + FTS_DEBUG_UPGRADE("start to upgrade %d times !!", + uc_UpgradeTimes); + + fts_ctpm_display_upgrade_time(true); + + i_ret = fts_ctpm_auto_upgrade_pingpong(client); + if (i_ret == 0) + fts_ctpm_display_upgrade_time(false); + else + uc_ErrorTimes++; + + FTS_DEBUG_UPGRADE("upgrade %d times, error %d times!!", + uc_UpgradeTimes, uc_ErrorTimes); + } while (uc_UpgradeTimes < (FTS_UPGRADE_TEST_NUMBER)); + + pm_relax(&client->dev); + device_init_wakeup(&client->dev, 0); + + return 0; +} +#endif + diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c b/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c new file mode 100644 index 0000000000000000000000000000000000000000..fa47b9db39060786c64becfe972fde7b6a9fe4e4 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c @@ -0,0 +1,650 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * 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_gestrue.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" +#if FTS_GESTURE_EN +/****************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define KEY_GESTURE_U KEY_U +#define KEY_GESTURE_UP KEY_UP +#define KEY_GESTURE_DOWN KEY_DOWN +#define KEY_GESTURE_LEFT KEY_LEFT +#define KEY_GESTURE_RIGHT KEY_RIGHT +#define KEY_GESTURE_O KEY_O +#define KEY_GESTURE_E KEY_E +#define KEY_GESTURE_M KEY_M +#define KEY_GESTURE_L KEY_L +#define KEY_GESTURE_W KEY_W +#define KEY_GESTURE_S KEY_S +#define KEY_GESTURE_V KEY_V +#define KEY_GESTURE_C KEY_C +#define KEY_GESTURE_Z KEY_Z + +#define GESTURE_LEFT 0x20 +#define GESTURE_RIGHT 0x21 +#define GESTURE_UP 0x22 +#define GESTURE_DOWN 0x23 +#define GESTURE_DOUBLECLICK 0x24 +#define GESTURE_O 0x30 +#define GESTURE_W 0x31 +#define GESTURE_M 0x32 +#define GESTURE_E 0x33 +#define GESTURE_L 0x44 +#define GESTURE_S 0x46 +#define GESTURE_V 0x54 +#define GESTURE_Z 0x41 +#define GESTURE_C 0x34 +#define FTS_GESTRUE_POINTS 255 +#define FTS_GESTRUE_POINTS_HEADER 8 + +#define GESTURE_SMALL_AREA 0x25 /* TP Coverage < 50% */ +#define GESTURE_LARGE_AREA 0x26 /* TP Coverage > 50% */ + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +/* +* header - byte0:gesture id +* byte1:pointnum +* byte2~7:reserved +* coordinate_x - All gesture point x coordinate +* coordinate_y - All gesture point y coordinate +* mode - 1:enable gesture function(default) +* - 0:disable +* active - 1:enter into gesture(suspend) +* 0:gesture disable or resume +*/ +struct fts_gesture_st { + u8 header[FTS_GESTRUE_POINTS_HEADER]; + u16 coordinate_x[FTS_GESTRUE_POINTS]; + u16 coordinate_y[FTS_GESTRUE_POINTS]; + u8 mode; + u8 active; +}; + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct fts_gesture_st fts_gesture_data; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +static ssize_t fts_gesture_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t fts_gesture_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t fts_gesture_buf_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t fts_gesture_buf_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +/* sysfs gesture node + * read example: cat fts_gesture_mode ---read gesture mode + * write example:echo 01 > fts_gesture_mode ---write gesture mode to 01 + * + */ +static DEVICE_ATTR(fts_gesture_mode, S_IRUGO|S_IWUSR, + fts_gesture_show, fts_gesture_store); +/* + * read example: cat fts_gesture_buf ---read gesture buf + */ +static DEVICE_ATTR(fts_gesture_buf, S_IRUGO|S_IWUSR, + fts_gesture_buf_show, fts_gesture_buf_store); +static struct attribute *fts_gesture_mode_attrs[] = { + + + &dev_attr_fts_gesture_mode.attr, + &dev_attr_fts_gesture_buf.attr, + NULL, +}; + +static struct attribute_group fts_gesture_group = { + + .attrs = fts_gesture_mode_attrs, +}; + +/************************************************************************ +* Name: fts_gesture_show +* Brief: +* Input: device, device attribute, char buf +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + u8 val; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + mutex_lock(&fts_input_dev->mutex); + fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &val); + count = snprintf(buf, PAGE_SIZE, "Gesture Mode: %s\n", + fts_gesture_data.mode ? "On" : "Off"); + count += snprintf(buf + count, PAGE_SIZE - count, + "Reg(0xD0) = %d\n", val); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} + +/************************************************************************ +* Name: fts_gesture_store +* Brief: +* Input: device, device attribute, char buf, char count +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + mutex_lock(&fts_input_dev->mutex); + + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_INFO("[GESTURE]enable gesture"); + fts_gesture_data.mode = ENABLE; + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_INFO("[GESTURE]disable gesture"); + fts_gesture_data.mode = DISABLE; + } + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} + +/************************************************************************ +* Name: fts_gesture_buf_show +* Brief: +* Input: device, device attribute, char buf +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_buf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + int i = 0; + + mutex_lock(&fts_input_dev->mutex); + count = snprintf(buf, PAGE_SIZE, "Gesture ID: 0x%x\n", + fts_gesture_data.header[0]); + count += snprintf(buf + count, PAGE_SIZE, "Gesture PointNum: %d\n", + fts_gesture_data.header[1]); + count += snprintf(buf + count, PAGE_SIZE, "Gesture Point Buf:\n"); + + for (i = 0; i < fts_gesture_data.header[1]; i++) { + count += snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", + i, fts_gesture_data.coordinate_x[i], + fts_gesture_data.coordinate_y[i]); + if ((i + 1)%4 == 0) + count += snprintf(buf + count, PAGE_SIZE, "\n"); + } + count += snprintf(buf + count, PAGE_SIZE, "\n"); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} + +/************************************************************************ +* Name: fts_gesture_buf_store +* Brief: +* Input: device, device attribute, char buf, char count +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_buf_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +/***************************************************************************** +* Name: fts_create_gesture_sysfs +* Brief: +* Input: +* Output: +* Return: 0-success or others-error +*****************************************************************************/ +int fts_create_gesture_sysfs(struct i2c_client *client) +{ + int ret = 0; + + ret = sysfs_create_group(&client->dev.kobj, &fts_gesture_group); + if (ret != 0) { + FTS_ERROR("[GESTURE]fts_gesture_group(sysfs) create failed!"); + sysfs_remove_group(&client->dev.kobj, &fts_gesture_group); + return ret; + } + return 0; +} + +/***************************************************************************** +* Name: fts_gesture_report +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_gesture_report(struct input_dev *input_dev, int gesture_id) +{ + int gesture; + + FTS_FUNC_ENTER(); + FTS_DEBUG("fts gesture_id==0x%x ", gesture_id); + switch (gesture_id) { + case GESTURE_LEFT: + gesture = KEY_GESTURE_LEFT; + break; + case GESTURE_RIGHT: + gesture = KEY_GESTURE_RIGHT; + break; + case GESTURE_UP: + gesture = KEY_GESTURE_UP; + break; + case GESTURE_DOWN: + gesture = KEY_GESTURE_DOWN; + break; + case GESTURE_DOUBLECLICK: + gesture = KEY_GESTURE_U; + break; + case GESTURE_O: + gesture = KEY_GESTURE_O; + break; + case GESTURE_W: + gesture = KEY_GESTURE_W; + break; + case GESTURE_M: + gesture = KEY_GESTURE_M; + break; + case GESTURE_E: + gesture = KEY_GESTURE_E; + break; + case GESTURE_L: + gesture = KEY_GESTURE_L; + break; + case GESTURE_S: + gesture = KEY_GESTURE_S; + break; + case GESTURE_V: + gesture = KEY_GESTURE_V; + break; + case GESTURE_Z: + gesture = KEY_GESTURE_Z; + break; + case GESTURE_C: + gesture = KEY_GESTURE_C; + break; + default: + gesture = -1; + break; + } + + /* report event key */ + if (gesture != -1) { + FTS_DEBUG("Gesture Code=%d", gesture); + input_report_key(input_dev, gesture, 1); + input_sync(input_dev); + input_report_key(input_dev, gesture, 0); + input_sync(input_dev); + } + + FTS_FUNC_EXIT(); +} + +/************************************************************************ +* Name: fts_gesture_readdata +* Brief: read data from TP register +* Input: +* Output: +* Return: fail <0 +***********************************************************************/ +static int fts_gesture_read_buffer(struct i2c_client *client, + u8 *buf, int read_bytes) +{ + int remain_bytes; + int ret; + int i; + + if (read_bytes <= I2C_BUFFER_LENGTH_MAXINUM) { + ret = fts_i2c_read(client, buf, 1, buf, read_bytes); + } else { + ret = fts_i2c_read(client, buf, 1, + buf, I2C_BUFFER_LENGTH_MAXINUM); + remain_bytes = read_bytes - I2C_BUFFER_LENGTH_MAXINUM; + for (i = 1; remain_bytes > 0; i++) { + if (remain_bytes <= I2C_BUFFER_LENGTH_MAXINUM) + ret = fts_i2c_read(client, buf, 0, buf + + I2C_BUFFER_LENGTH_MAXINUM * i, + remain_bytes); + else + ret = fts_i2c_read(client, buf, 0, buf + + I2C_BUFFER_LENGTH_MAXINUM * i, + I2C_BUFFER_LENGTH_MAXINUM); + remain_bytes -= I2C_BUFFER_LENGTH_MAXINUM; + } + } + + return ret; +} + +/************************************************************************ +* Name: fts_gesture_fw +* Brief: Check IC's gesture recognise by FW or not +* Input: +* Output: +* Return: 1- FW 0- Driver +***********************************************************************/ +static int fts_gesture_fw(void) +{ + int ret = 0; + + switch (chip_types.chip_idh) { + case 0x54: + case 0x58: + case 0x64: + case 0x87: + case 0x86: + case 0x80: + case 0xE7: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +/************************************************************************ +* Name: fts_gesture_readdata +* Brief: read data from TP register +* Input: +* Output: +* Return: fail <0 +***********************************************************************/ +int fts_gesture_readdata(struct i2c_client *client) +{ + u8 buf[FTS_GESTRUE_POINTS * 4] = { 0 }; + int ret = -1; + int i = 0; + int gestrue_id = 0; + int read_bytes = 0; + u8 pointnum; + + FTS_FUNC_ENTER(); + /* init variable before read gesture point */ + memset(fts_gesture_data.header, 0, FTS_GESTRUE_POINTS_HEADER); + memset(fts_gesture_data.coordinate_x, 0, + FTS_GESTRUE_POINTS * sizeof(u16)); + memset(fts_gesture_data.coordinate_y, 0, + FTS_GESTRUE_POINTS * sizeof(u16)); + + buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; + ret = fts_i2c_read(client, buf, 1, buf, FTS_GESTRUE_POINTS_HEADER); + if (ret < 0) { + FTS_ERROR("[GESTURE]Read gesture header data failed!!"); + FTS_FUNC_EXIT(); + return ret; + } + + memcpy(fts_gesture_data.header, buf, FTS_GESTRUE_POINTS_HEADER); + gestrue_id = buf[0]; + pointnum = buf[1]; + + if (gestrue_id == GESTURE_SMALL_AREA) { + FTS_INFO("[GESTURE] Wakeup gesture."); + input_report_key(fts_input_dev, KEY_POWER, 1); + input_sync(fts_input_dev); + input_report_key(fts_input_dev, KEY_POWER, 0); + input_sync(fts_input_dev); + + } else if (gestrue_id == GESTURE_LARGE_AREA) { + FTS_INFO("[GESTURE] Large object detected."); + } else if (fts_gesture_fw()) { + /* FW recognize gesture */ + read_bytes = ((int)pointnum) * 4 + 2; + buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; + FTS_DEBUG("[GESTURE]PointNum=%d", pointnum); + ret = fts_gesture_read_buffer(client, buf, read_bytes); + if (ret < 0) { + FTS_ERROR("[GESTURE]Read gesture touch data failed!!"); + FTS_FUNC_EXIT(); + return ret; + } + + fts_gesture_report(fts_input_dev, gestrue_id); + for (i = 0; i < pointnum; i++) { + fts_gesture_data.coordinate_x[i] = + (((s16) buf[0 + (4 * i + 2)]) & 0x0F) << 8 + | (((s16) buf[1 + (4 * i + 2)]) & 0xFF); + fts_gesture_data.coordinate_y[i] = + (((s16) buf[2 + (4 * i + 2)]) & 0x0F) << 8 + | (((s16) buf[3 + (4 * i + 2)]) & 0xFF); + } + + + } else { + FTS_ERROR("[GESTURE]IC 0x%x need lib to support gestures.", + chip_types.chip_idh); + } + + FTS_FUNC_EXIT(); + + return 0; +} + +/***************************************************************************** +* Name: fts_gesture_recovery +* Brief: recovery gesture state when reset or power on +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_gesture_recovery(struct i2c_client *client) +{ + if (fts_gesture_data.mode && fts_gesture_data.active) { + fts_i2c_write_reg(client, 0xD1, 0xff); + fts_i2c_write_reg(client, 0xD2, 0xff); + fts_i2c_write_reg(client, 0xD5, 0xff); + fts_i2c_write_reg(client, 0xD6, 0xff); + fts_i2c_write_reg(client, 0xD7, 0xff); + fts_i2c_write_reg(client, 0xD8, 0xff); + fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, ENABLE); + } +} + +/***************************************************************************** +* Name: fts_gesture_suspend +* Brief: +* Input: +* Output: None +* Return: None +*****************************************************************************/ +int fts_gesture_suspend(struct i2c_client *i2c_client) +{ + int i; + u8 state; + + FTS_FUNC_ENTER(); + + /* gesture not enable, return immediately */ + if (fts_gesture_data.mode == 0) { + FTS_DEBUG("gesture is disabled"); + FTS_FUNC_EXIT(); + return -EINVAL; + } + + for (i = 0; i < 5; i++) { + fts_i2c_write_reg(i2c_client, 0xd1, 0xff); + fts_i2c_write_reg(i2c_client, 0xd2, 0xff); + fts_i2c_write_reg(i2c_client, 0xd5, 0xff); + fts_i2c_write_reg(i2c_client, 0xd6, 0xff); + fts_i2c_write_reg(i2c_client, 0xd7, 0xff); + fts_i2c_write_reg(i2c_client, 0xd8, 0xff); + fts_i2c_write_reg(i2c_client, FTS_REG_GESTURE_EN, 0x01); + usleep_range(1000, 2000); + fts_i2c_read_reg(i2c_client, FTS_REG_GESTURE_EN, &state); + if (state == 1) + break; + } + + if (i >= 5) { + FTS_ERROR("[GESTURE]Enter into gesture(suspend) failed!\n"); + FTS_FUNC_EXIT(); + return -EAGAIN; + } + + fts_gesture_data.active = 1; + FTS_DEBUG("[GESTURE]Enter into gesture(suspend) successfully!"); + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_gesture_resume +* Brief: +* Input: +* Output: None +* Return: None +*****************************************************************************/ +int fts_gesture_resume(struct i2c_client *client) +{ + int i; + u8 state; + + FTS_FUNC_ENTER(); + + /* gesture not enable, return immediately */ + if (fts_gesture_data.mode == 0) { + FTS_DEBUG("gesture is disabled"); + FTS_FUNC_EXIT(); + return -EINVAL; + } + + if (fts_gesture_data.active == 0) { + FTS_DEBUG("gesture is unactive"); + FTS_FUNC_EXIT(); + return -EINVAL; + } + + fts_gesture_data.active = 0; + for (i = 0; i < 5; i++) { + fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, 0x00); + usleep_range(1000, 2000); + fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &state); + if (state == 0) + break; + } + + if (i >= 5) + FTS_ERROR("[GESTURE]Clear gesture(resume) failed!\n"); + + FTS_FUNC_EXIT(); + + return 0; +} + +/***************************************************************************** +* Name: fts_gesture_init +* Brief: +* Input: +* Output: None +* Return: None +*****************************************************************************/ +int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client) +{ + FTS_FUNC_ENTER(); + input_set_capability(input_dev, EV_KEY, KEY_POWER); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C); + + __set_bit(KEY_GESTURE_RIGHT, input_dev->keybit); + __set_bit(KEY_GESTURE_LEFT, input_dev->keybit); + __set_bit(KEY_GESTURE_UP, input_dev->keybit); + __set_bit(KEY_GESTURE_DOWN, input_dev->keybit); + __set_bit(KEY_GESTURE_U, input_dev->keybit); + __set_bit(KEY_GESTURE_O, input_dev->keybit); + __set_bit(KEY_GESTURE_E, input_dev->keybit); + __set_bit(KEY_GESTURE_M, input_dev->keybit); + __set_bit(KEY_GESTURE_W, input_dev->keybit); + __set_bit(KEY_GESTURE_L, input_dev->keybit); + __set_bit(KEY_GESTURE_S, input_dev->keybit); + __set_bit(KEY_GESTURE_V, input_dev->keybit); + __set_bit(KEY_GESTURE_C, input_dev->keybit); + __set_bit(KEY_GESTURE_Z, input_dev->keybit); + + fts_create_gesture_sysfs(client); + fts_gesture_data.mode = 1; + fts_gesture_data.active = 0; + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_gesture_exit +* Brief: call when driver removed +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_gesture_exit(struct i2c_client *client) +{ + FTS_FUNC_ENTER(); + sysfs_remove_group(&client->dev.kobj, &fts_gesture_group); + FTS_FUNC_EXIT(); + + return 0; +} +#endif diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c b/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..45020fcf95c0114c6c3b32377d08140443ba24e7 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c @@ -0,0 +1,206 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved. + * + * 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_i2c.c +* +* Author: fupeipei +* +* Created: 2016-08-04 +* +* Abstract: i2c communication with TP +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By fupeipei 2016-08-04 +************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static DEFINE_MUTEX(i2c_rw_access); + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ + +/************************************************************************ +* Name: fts_i2c_read +* Brief: i2c read +* Input: i2c info, write buf, write len, read buf, read len +* Output: get data in the 3rd buf +* Return: fail <0 +***********************************************************************/ +int fts_i2c_read(struct i2c_client *client, char *writebuf, + int writelen, char *readbuf, int readlen) +{ + int ret = -EIO; + + mutex_lock(&i2c_rw_access); + + 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) + FTS_ERROR("[IIC]: i2c_write error %d!!", ret); + } 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) + FTS_ERROR("[IIC]: i2c_read error %d!!", ret); + } + } + + mutex_unlock(&i2c_rw_access); + + return ret; +} + +/************************************************************************ +* Name: fts_i2c_write +* Brief: i2c write +* Input: i2c info, write buf, write len +* Output: no +* Return: fail <0 +***********************************************************************/ +int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen) +{ + int ret = 0; + + mutex_lock(&i2c_rw_access); + + if (writelen > 0) { + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) + FTS_ERROR("[IIC]: i2c_write error, ret=%d", ret); + } + + mutex_unlock(&i2c_rw_access); + + return ret; +} + +/************************************************************************ +* Name: fts_i2c_write_reg +* Brief: write register +* Input: i2c info, reg address, reg value +* Output: no +* Return: fail <0 +***********************************************************************/ +int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue) +{ + u8 buf[2] = {0}; + + buf[0] = regaddr; + buf[1] = regvalue; + return fts_i2c_write(client, buf, sizeof(buf)); +} + +/************************************************************************ +* Name: fts_i2c_read_reg +* Brief: read register +* Input: i2c info, reg address, reg value +* Output: get reg value +* Return: fail <0 +***********************************************************************/ +int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue) +{ + return fts_i2c_read(client, ®addr, 1, regvalue, 1); +} + +/************************************************************************ +* Name: fts_i2c_init +* Brief: fts i2c init +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_i2c_init(void) +{ + FTS_FUNC_ENTER(); + + FTS_FUNC_EXIT(); + return 0; +} +/************************************************************************ +* Name: fts_i2c_exit +* Brief: fts i2c exit +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_i2c_exit(void) +{ + FTS_FUNC_ENTER(); + + FTS_FUNC_EXIT(); + return 0; +} + diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c b/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c new file mode 100644 index 0000000000000000000000000000000000000000..a24e6256cf41150cd43a2ce7b66e46e8dbbc353a --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c @@ -0,0 +1,155 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved. + * + * 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_point_report_check.c +* +* Author: WangTao +* +* Created: 2016-11-16 +* +* Abstract: point report check function +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By WangTao 2016-11-16 +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +#if FTS_POINT_REPORT_CHECK_EN +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define POINT_REPORT_CHECK_WAIT_TIME 200 /* ms */ + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct delayed_work fts_point_report_check_work; +static struct workqueue_struct *fts_point_report_check_workqueue; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ + + +/***************************************************************************** +* Name: fts_point_report_check_func +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_point_report_check_func(struct work_struct *work) +{ + +#if FTS_MT_PROTOCOL_B_EN + unsigned int finger_count = 0; +#endif + + FTS_FUNC_ENTER(); + mutex_lock(&fts_wq_data->report_mutex); + +#if FTS_MT_PROTOCOL_B_EN + for (finger_count = 0; + finger_count < fts_wq_data->pdata->max_touch_number; + finger_count++) { + input_mt_slot(fts_input_dev, finger_count); + input_mt_report_slot_state(fts_input_dev, + MT_TOOL_FINGER, false); + } +#else + input_mt_sync(fts_input_dev); +#endif + input_report_key(fts_input_dev, BTN_TOUCH, 0); + input_sync(fts_input_dev); + + mutex_unlock(&fts_wq_data->report_mutex); + + FTS_FUNC_EXIT(); +} + +void fts_point_report_check_queue_work(void) +{ + cancel_delayed_work(&fts_point_report_check_work); + queue_delayed_work(fts_point_report_check_workqueue, + &fts_point_report_check_work, + msecs_to_jiffies(POINT_REPORT_CHECK_WAIT_TIME)); +} + +/***************************************************************************** +* Name: fts_point_report_check_init +* Brief: +* Input: +* Output: +* Return: < 0: Fail to create esd check queue +*****************************************************************************/ +int fts_point_report_check_init(void) +{ + FTS_FUNC_ENTER(); + + INIT_DELAYED_WORK(&fts_point_report_check_work, + fts_point_report_check_func); + fts_point_report_check_workqueue = + create_workqueue("fts_point_report_check_func_wq"); + if (fts_point_report_check_workqueue == NULL) + FTS_ERROR("[POINT_REPORT]: Failed to create workqueue!!"); + else + FTS_DEBUG("[POINT_REPORT]: Success to create workqueue!!"); + + FTS_FUNC_EXIT(); + + return 0; +} + +/***************************************************************************** +* Name: fts_point_report_check_exit +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_point_report_check_exit(void) +{ + FTS_FUNC_ENTER(); + + destroy_workqueue(fts_point_report_check_workqueue); + + FTS_FUNC_EXIT(); + return 0; +} +#endif /* FTS_POINT_REPORT_CHECK_EN */ + diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c b/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c new file mode 100644 index 0000000000000000000000000000000000000000..2ff241f8f61a97d9930347ce9b5ee125bd0773d1 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c @@ -0,0 +1,326 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved. + * + * 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_esdcheck.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-03 +* +* Abstract: Sensor +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By luougojin 2016-08-03 +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +#if FTS_PSENSOR_EN +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +/* psensor register address*/ +#define FTS_REG_PSENSOR_ENABLE 0xB0 +#define FTS_REG_PSENSOR_STATUS 0x01 + +/* psensor register bits*/ +#define FTS_PSENSOR_ENABLE_MASK 0x01 +#define FTS_PSENSOR_STATUS_NEAR 0xC0 +#define FTS_PSENSOR_STATUS_FAR 0xE0 +#define FTS_PSENSOR_FAR_TO_NEAR 0 +#define FTS_PSENSOR_NEAR_TO_FAR 1 +#define FTS_PSENSOR_ORIGINAL_STATE_FAR 1 +#define FTS_PSENSOR_WAKEUP_TIMEOUT 500 + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct sensors_classdev __maybe_unused sensors_proximity_cdev = { + + .name = "fts-proximity", + .vendor = "FocalTech", + .version = 1, + .handle = SENSORS_PROXIMITY_HANDLE, + .type = SENSOR_TYPE_PROXIMITY, + .max_range = "5.0", + .resolution = "5.0", + .sensor_power = "0.1", + .min_delay = 0, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; + +/***************************************************************************** +* functions body +*****************************************************************************/ +/***************************************************************************** +* Name: fts_psensor_support_enabled +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static inline bool fts_psensor_support_enabled(void) +{ + /*return config_enabled(CONFIG_TOUCHSCREEN_FTS_PSENSOR);*/ + return FTS_PSENSOR_EN; +} + +/***************************************************************************** +* Name: fts_psensor_enable +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_psensor_enable(struct fts_ts_data *data, int enable) +{ + u8 state; + int ret = -1; + + if (data->client == NULL) + return; + + fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_ENABLE, &state); + if (enable) + state |= FTS_PSENSOR_ENABLE_MASK; + else + state &= ~FTS_PSENSOR_ENABLE_MASK; + + ret = fts_i2c_write_reg(data->client, FTS_REG_PSENSOR_ENABLE, state); + if (ret < 0) + FTS_ERROR("write psensor switch command failed"); + +} + +/***************************************************************************** +* Name: fts_psensor_enable_set +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_psensor_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct fts_psensor_platform_data *psensor_pdata = + container_of(sensors_cdev, + struct fts_psensor_platform_data, ps_cdev); + struct fts_ts_data *data = psensor_pdata->data; + struct input_dev *input_dev = data->psensor_pdata->input_psensor_dev; + + mutex_lock(&input_dev->mutex); + fts_psensor_enable(data, enable); + psensor_pdata->tp_psensor_data = FTS_PSENSOR_ORIGINAL_STATE_FAR; + if (enable) + psensor_pdata->tp_psensor_opened = 1; + else + psensor_pdata->tp_psensor_opened = 0; + + mutex_unlock(&input_dev->mutex); + + return enable; +} + +/***************************************************************************** +* Name: fts_read_tp_psensor_data +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_read_tp_psensor_data(struct fts_ts_data *data) +{ + u8 psensor_status; + char tmp; + int ret = 1; + + fts_i2c_read_reg(data->client, + FTS_REG_PSENSOR_STATUS, &psensor_status); + + tmp = data->psensor_pdata->tp_psensor_data; + if (psensor_status == FTS_PSENSOR_STATUS_NEAR) + data->psensor_pdata->tp_psensor_data = + FTS_PSENSOR_FAR_TO_NEAR; + else if (psensor_status == FTS_PSENSOR_STATUS_FAR) + data->psensor_pdata->tp_psensor_data = + FTS_PSENSOR_NEAR_TO_FAR; + + if (tmp != data->psensor_pdata->tp_psensor_data) { + FTS_ERROR("%s sensor data changed", __func__); + ret = 0; + } + + return ret; +} + + +int fts_sensor_read_data(struct fts_ts_data *data) +{ + int ret = 0; + + if (fts_psensor_support_enabled() + && data->psensor_pdata->tp_psensor_opened) { + ret = fts_read_tp_psensor_data(data); + if (!ret) { + if (data->suspended) + pm_wakeup_event(&data->client->dev, + FTS_PSENSOR_WAKEUP_TIMEOUT); + + input_report_abs(data->psensor_pdata->input_psensor_dev, + ABS_DISTANCE, + data->psensor_pdata->tp_psensor_data); + input_sync(data->psensor_pdata->input_psensor_dev); + } + + return 1; + } + + return 0; +} + +int fts_sensor_suspend(struct fts_ts_data *data) +{ + int ret = 0; + + if (fts_psensor_support_enabled() && + device_may_wakeup(&data->client->dev) && + data->psensor_pdata->tp_psensor_opened) { + ret = enable_irq_wake(data->client->irq); + if (ret != 0) + FTS_ERROR("%s: set_irq_wake failed", __func__); + + data->suspended = true; + return 1; + } + + return 0; +} + + +int fts_sensor_resume(struct fts_ts_data *data) +{ + int ret = 0; + + if (fts_psensor_support_enabled() + && device_may_wakeup(&data->client->dev) + && data->psensor_pdata->tp_psensor_opened) { + ret = disable_irq_wake(data->client->irq); + if (ret) + FTS_ERROR("%s: disable_irq_wake failed", __func__); + + data->suspended = false; + return 1; + } + + return 0; +} + + +int fts_sensor_init(struct fts_ts_data *data) +{ + struct fts_psensor_platform_data *psensor_pdata; + struct input_dev *psensor_input_dev; + int err; + + if (fts_psensor_support_enabled()) { + device_init_wakeup(&data->client->dev, 1); + psensor_pdata = devm_kzalloc(&data->client->dev, + sizeof(struct fts_psensor_platform_data), + GFP_KERNEL); + if (!psensor_pdata) { + FTS_ERROR("Failed to allocate memory"); + goto irq_free; + } + + data->psensor_pdata = psensor_pdata; + + psensor_input_dev = input_allocate_device(); + if (!psensor_input_dev) { + FTS_ERROR("Failed to allocate device"); + goto free_psensor_pdata; + } + + __set_bit(EV_ABS, psensor_input_dev->evbit); + input_set_abs_params(psensor_input_dev, ABS_DISTANCE, + 0, 1, 0, 0); + psensor_input_dev->name = "proximity"; + psensor_input_dev->id.bustype = BUS_I2C; + psensor_input_dev->dev.parent = &data->client->dev; + data->psensor_pdata->input_psensor_dev = psensor_input_dev; + + err = input_register_device(psensor_input_dev); + if (err) { + FTS_ERROR("Unable to register device, err=%d", err); + goto free_psensor_input_dev; + } + + psensor_pdata->ps_cdev = sensors_proximity_cdev; + psensor_pdata->ps_cdev.sensors_enable = fts_psensor_enable_set; + psensor_pdata->data = data; + + err = sensors_classdev_register(&data->client->dev, + &psensor_pdata->ps_cdev); + if (err) + goto unregister_psensor_input_device; + } + + return 0; + +unregister_psensor_input_device: + if (fts_psensor_support_enabled()) + input_unregister_device(data->psensor_pdata->input_psensor_dev); +free_psensor_input_dev: + if (fts_psensor_support_enabled()) + input_free_device(data->psensor_pdata->input_psensor_dev); +free_psensor_pdata: + if (fts_psensor_support_enabled()) { + devm_kfree(&data->client->dev, psensor_pdata); + data->psensor_pdata = NULL; + } +irq_free: + if (fts_psensor_support_enabled()) + device_init_wakeup(&data->client->dev, 0); + free_irq(data->client->irq, data); + + return 1; +} + +int fts_sensor_remove(struct fts_ts_data *data) +{ + if (fts_psensor_support_enabled()) { + device_init_wakeup(&data->client->dev, 0); + sensors_classdev_unregister(&data->psensor_pdata->ps_cdev); + input_unregister_device(data->psensor_pdata->input_psensor_dev); + devm_kfree(&data->client->dev, data->psensor_pdata); + data->psensor_pdata = NULL; + } + return 0; +} +#endif /* FTS_PSENSOR_EN */ diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig index ebf3aa478af51d0991a760a0d871988846c83e49..3dc5a026c851cbd802cf573d46f41dc309ff00f7 100644 --- a/drivers/input/touchscreen/hxchipset/Kconfig +++ b/drivers/input/touchscreen/hxchipset/Kconfig @@ -3,19 +3,44 @@ # config TOUCHSCREEN_HIMAX_I2C - tristate "HIMAX chipset i2c touchscreen" - depends on TOUCHSCREEN_HIMAX_CHIPSET - help + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + Say Y here to enable support for HIMAX CHIPSET over I2C based touchscreens. + If unsure, say N. + + To compile this driver as a module, This enables support for HIMAX CHIPSET over I2C based touchscreens. config TOUCHSCREEN_HIMAX_DEBUG - tristate "HIMAX debug function" - depends on TOUCHSCREEN_HIMAX_I2C - help + tristate "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX debug function. + + If unsure, say N. + + To compile this driver as a module, This enables support for HIMAX debug function. +config TOUCHSCREEN_HIMAX_ITO_TEST + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. + config HMX_DB tristate "HIMAX driver test over Dragon Board" depends on TOUCHSCREEN_HIMAX_I2C help - This enables support for HIMAX driver test over Dragon Board. + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile index 509d4913bc39f4577ba64fa4b8e8fefd5bd1c53a..522907a48956cdbf8ee19720d237dab90d97b387 100644 --- a/drivers/input/touchscreen/hxchipset/Makefile +++ b/drivers/input/touchscreen/hxchipset/Makefile @@ -1,3 +1,4 @@ # Makefile for the Himax touchscreen drivers. obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_ITO_TEST) += himax_ito_test.o \ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c index 417b0c08e3615ee256fba5f4c9f9d1da8bd78f91..d4bc5beb0203e5eece80c10e11d29cfb966cdf16 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -1,4 +1,4 @@ -/* Himax Android Driver Sample Code for Himax chipset + /* Himax Android Driver Sample Code for Himax chipset * * Copyright (C) 2015 Himax Corporation. * @@ -21,107 +21,32 @@ #define FRAME_COUNT 5 #if defined(HX_AUTO_UPDATE_FW) - static unsigned char i_CTPM_FW[]= - { - #include "HX83100_Amber_0901_030B.i" - }; + char *i_CTPM_firmware_name = "HX83100_Amber_0B01_030E.bin"; + const struct firmware *i_CTPM_FW = NULL; #endif -#ifdef HX_ESD_WORKAROUND - extern void HX_report_ESD_event(void); - unsigned char ESD_00_counter = 0; - unsigned char ESD_00_Flag = 0; -#endif - -//static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; // for Virtual key array +/*static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; +// for Virtual key array */ struct himax_ts_data *private_ts; -struct himax_ic_data* ic_data; - -static int HX_TOUCH_INFO_POINT_CNT; - -#ifdef HX_AUTO_UPDATE_FW -extern unsigned long FW_VER_MAJ_FLASH_ADDR; -extern unsigned long FW_VER_MIN_FLASH_ADDR; -extern unsigned long CFG_VER_MAJ_FLASH_ADDR; -extern unsigned long CFG_VER_MIN_FLASH_ADDR; -#endif -extern unsigned long FW_VER_MAJ_FLASH_LENG; -extern unsigned long FW_VER_MIN_FLASH_LENG; -extern unsigned long CFG_VER_MAJ_FLASH_LENG; -extern unsigned long CFG_VER_MIN_FLASH_LENG; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -//PROC-START -#ifdef HX_TP_PROC_FLASH_DUMP -extern void himax_ts_flash_func(void); -extern void setFlashBuffer(void); -extern bool getFlashDumpGoing(void); -extern uint8_t getSysOperation(void); -extern void setSysOperation(uint8_t operation); -#endif - -#ifdef HX_TP_PROC_HITOUCH -extern bool hitouch_is_connect; -#endif - -#ifdef HX_TP_PROC_DIAG - extern int touch_monitor_stop_flag; - extern int touch_monitor_stop_limit; - extern void himax_ts_diag_func(void); - extern int16_t *getMutualBuffer(void); - extern int16_t *getMutualNewBuffer(void); - extern int16_t *getMutualOldBuffer(void); - extern int16_t *getSelfBuffer(void); - extern uint8_t getXChannel(void); - extern uint8_t getYChannel(void); - extern uint8_t getDiagCommand(void); - extern void setXChannel(uint8_t x); - extern void setYChannel(uint8_t y); - extern void setMutualBuffer(void); - extern void setMutualNewBuffer(void); - extern void setMutualOldBuffer(void); - extern uint8_t coordinate_dump_enable; - extern struct file *coordinate_fn; - extern uint8_t diag_coor[128]; -#ifdef HX_TP_PROC_2T2R - extern int16_t *getMutualBuffer_2(void); - extern uint8_t getXChannel_2(void); - extern uint8_t getYChannel_2(void); - extern void setXChannel_2(uint8_t x); - extern void setYChannel_2(uint8_t y); - extern void setMutualBuffer_2(void); -#endif -#endif -//PROC-END -#endif - -extern int himax_parse_dt(struct himax_ts_data *ts, - struct himax_i2c_platform_data *pdata); -extern int himax_ts_pinctrl_init(struct himax_ts_data *ts); - -static uint8_t vk_press; -static uint8_t AA_press; -static uint8_t EN_NoiseFilter; -static uint8_t Last_EN_NoiseFilter; -static int hx_point_num; // for himax_ts_work_func use -static int p_point_num = 0xFFFF; -static int tpd_key; -static int tpd_key_old; -static int probe_fail_flag; -static bool config_load; +struct himax_ic_data *ic_data; + +static int HX_TOUCH_INFO_POINT_CNT; + +static uint8_t vk_press = 0x00; +static uint8_t AA_press = 0x00; +static uint8_t EN_NoiseFilter = 0x00; +static int hx_point_num; /*for himax_ts_work_func use*/ +static int p_point_num = 0xFFFF; +static int tpd_key = 0x00; +static int tpd_key_old = 0x00; +static int probe_fail_flag; +static bool config_load; static struct himax_config *config_selected; -//static int iref_number = 11; -//static bool iref_found = false; +/*static int iref_number = 11;*/ +/*static bool iref_found = false;*/ -#ifdef HX_USB_DETECT2 -extern bool USB_Flag; -#endif #if defined(CONFIG_FB) int fb_notifier_callback(struct notifier_block *self, @@ -134,6 +59,7 @@ static void himax_ts_late_resume(struct early_suspend *h); int himax_input_register(struct himax_ts_data *ts) { int ret; + ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { ret = -ENOMEM; @@ -175,25 +101,36 @@ int himax_input_register(struct himax_ts_data *ts) set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); if (ts->protocol_type == PROTOCOL_TYPE_A) { - //ts->input_dev->mtsize = ts->nFinger_support; + /*ts->input_dev->mtsize = ts->nFinger_support;*/ input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 3, 0, 0); } else {/* PROTOCOL_TYPE_B */ set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); - input_mt_init_slots(ts->input_dev, ts->nFinger_support,0); + input_mt_init_slots(ts->input_dev, ts->nFinger_support, 0); } I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", - ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); - -// input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); -// input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, + ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, + ts->pdata->abs_width_min, ts->pdata->abs_width_max, + ts->pdata->abs_pressure_fuzz, 0); + +/*input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, +((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0);*/ +/*input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, +(BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0);*/ return input_register_device(ts->input_dev); } @@ -201,87 +138,103 @@ int himax_input_register(struct himax_ts_data *ts) static void calcDataSize(uint8_t finger_num) { struct himax_ts_data *ts_data = private_ts; + ts_data->coord_data_size = 4 * finger_num; - ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; - ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; - ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + - (((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0; - I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); + ts_data->area_data_size = ((finger_num / 4) + + (finger_num % 4 ? 1 : 0)) * 4; + ts_data->raw_data_frame_size = 128 - + ts_data->coord_data_size - + ts_data->area_data_size - 4 - 4 - 1; + + ts_data->raw_data_nframes = + ((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) / + ts_data->raw_data_frame_size + (((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) % + ts_data->raw_data_frame_size) ? 1 : 0; + + I("%s: coord_data_size: %d, area_data_size:%d", + __func__, ts_data->coord_data_size, ts_data->area_data_size); + I("raw_data_frame_size:%d, raw_data_nframes:%d", + ts_data->raw_data_frame_size, ts_data->raw_data_nframes); } static void calculate_point_number(void) { - HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4 ; + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4; - if ( (ic_data->HX_MAX_PT % 4) == 0) - HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4 ; + if ((ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4; else - HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ; + HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) + 1) * 4; } -#if 0 +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH static int himax_read_Sensor_ID(struct i2c_client *client) -{ - uint8_t val_high[1], val_low[1], ID0=0, ID1=0; +{ + uint8_t val_high[1], val_low[1], ID0 = 0, ID1 = 0; char data[3]; const int normalRetry = 10; int sensor_id; - - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - //read id pin high + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); + + /*read id pin high*/ i2c_himax_read(client, 0x57, val_high, 1, normalRetry); - data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/*ID pin PULL Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x01;/*ID pin PULL Low*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); - //read id pin low + /*read id pin low*/ i2c_himax_read(client, 0x57, val_low, 1, normalRetry); - if((val_high[0] & 0x01) ==0) - ID0=0x02;/*GND*/ - else if((val_low[0] & 0x01) ==0) - ID0=0x01;/*Floating*/ + if ((val_high[0] & 0x01) == 0) + ID0 = 0x02;/*GND*/ + else if ((val_low[0] & 0x01) == 0) + ID0 = 0x01;/*Floating*/ else - ID0=0x04;/*VCC*/ - - if((val_high[0] & 0x02) ==0) - ID1=0x02;/*GND*/ - else if((val_low[0] & 0x02) ==0) - ID1=0x01;/*Floating*/ - else - ID1=0x04;/*VCC*/ - if((ID0==0x04)&&(ID1!=0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - else if((ID0!=0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); + ID0 = 0x04;/*VCC*/ - } - else if((ID0==0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); + if ((val_high[0] & 0x02) == 0) + ID1 = 0x02;/*GND*/ + else if ((val_low[0] & 0x02) == 0) + ID1 = 0x01;/*Floating*/ + else + ID1 = 0x04;/*VCC*/ + if ((ID0 == 0x04) && (ID1 != 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x01;/*ID pin PULL High,Low*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 != 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x02;/*ID pin PULL Low,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 == 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); - } - sensor_id=(ID1<<4)|ID0; + } + sensor_id = (ID1<<4)|ID0; data[0] = 0xE4; data[1] = sensor_id; - i2c_himax_master_write(client, &data[0],2,normalRetry);/*Write to MCU*/ - usleep_range(1000, 2000); + i2c_himax_master_write(client, + &data[0], 2, normalRetry);/*Write to MCU*/ + usleep(1000); return sensor_id; @@ -290,125 +243,173 @@ static int himax_read_Sensor_ID(struct i2c_client *client) static void himax_power_on_initCMD(struct i2c_client *client) { I("%s:\n", __func__); - himax_touch_information(client); - - //himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM + /*himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM */ } #ifdef HX_AUTO_UPDATE_FW static int i_update_FW(void) { int upgrade_times = 0; - unsigned char* ImageBuffer = i_CTPM_FW; - int fullFileLength = sizeof(i_CTPM_FW); + int fullFileLength = 0; int i_FW_VER = 0, i_CFG_VER = 0; - uint8_t ret = -1, result = 0; -// uint8_t tmp_addr[4]; -// uint8_t tmp_data[4]; + int ret = -1, result = 0; + /*uint8_t tmp_addr[4];*/ + /*uint8_t tmp_data[4];*/ int CRC_from_FW = 0; int CRC_Check_result = 0; - i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; - i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; + ret = himax_load_CRC_bin_file(private_ts->client); + if (ret < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, ret); + ret = -1; + return ret; + } + I("file name = %s\n", i_CTPM_firmware_name); + ret = request_firmware(&i_CTPM_FW, + i_CTPM_firmware_name, private_ts->dev); + if (ret < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, ret); + ret = -2; + return ret; + } + + if (i_CTPM_FW == NULL) { + I("%s: i_CTPM_FW = NULL\n", __func__); + ret = -3; + return ret; + } + fullFileLength = i_CTPM_FW->size; - I("%s: i_fullFileLength = %d\n", __func__,fullFileLength); + i_FW_VER = i_CTPM_FW->data[FW_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[FW_VER_MIN_FLASH_ADDR]; + i_CFG_VER = i_CTPM_FW->data[CFG_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[CFG_VER_MIN_FLASH_ADDR]; + + I("%s: i_fullFileLength = %d\n", __func__, fullFileLength); himax_sense_off(private_ts->client); msleep(500); - CRC_from_FW = himax_check_CRC(private_ts->client,fw_image_64k); - CRC_Check_result = Calculate_CRC_with_AP(ImageBuffer, CRC_from_FW,fw_image_64k); - I("%s: Check sum result = %d\n", __func__,CRC_Check_result); - //I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", __func__,ic_data->vendor_fw_ver, i_FW_VER); - //I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", __func__,ic_data->vendor_config_ver, i_CFG_VER); - - if ((CRC_Check_result == 0)|| ( ic_data->vendor_fw_ver < i_FW_VER ) || ( ic_data->vendor_config_ver < i_CFG_VER )) - { - himax_int_enable(private_ts->client->irq,0); + CRC_from_FW = himax_check_CRC(private_ts->client, fw_image_64k); + CRC_Check_result = + Calculate_CRC_with_AP((unsigned char *)i_CTPM_FW->data, + CRC_from_FW, fw_image_64k); + I("%s: Check sum result = %d\n", __func__, CRC_Check_result); + /*I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", + __func__, ic_data->vendor_fw_ver, i_FW_VER);*/ + /*I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", + __func__, ic_data->vendor_config_ver, i_CFG_VER);*/ + + if ((CRC_Check_result == 0) || + (ic_data->vendor_fw_ver < i_FW_VER) || + (ic_data->vendor_config_ver < i_CFG_VER)) { + himax_int_enable(private_ts->client->irq, 0); update_retry: - if(fullFileLength == FW_SIZE_60k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_64k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_124k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_128k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,ImageBuffer,fullFileLength,false); - } - if(ret == 0){ - upgrade_times++; - E("%s: TP upgrade error, upgrade_times = %d\n", __func__, upgrade_times); - if(upgrade_times < 3) - goto update_retry; - else - { - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - result = -1;//upgrade fail - } - } - else if(ret == 1){ -/* - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 2. Write driver initial code condition - // write value from AHB I2C : 0x8001_C603 = 0x000000FF - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xFF; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 1. Set DDREG_Req = 0 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); -*/ + if (fullFileLength == FW_SIZE_60k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_64k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_124k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_128k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } + if (ret == 0) { + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", + __func__, upgrade_times); + if (upgrade_times < 3) + goto update_retry; + else { himax_sense_on(private_ts->client, 0x01); msleep(120); #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; #endif - - ic_data->vendor_fw_ver = i_FW_VER; - ic_data->vendor_config_ver = i_CFG_VER; - result = 1;//upgrade success - I("%s: TP upgrade OK\n", __func__); + result = -1;/*upgrade fail*/ } - - himax_int_enable(private_ts->client->irq,1); - return result; - } - else - { + } else if (ret == 1) { + /* + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 2. Write driver initial code condition + //write value from AHB I2C:0x8001_C603 = 0x000000FF + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xFF; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 1. Set DDREG_Req = 0(0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + */ himax_sense_on(private_ts->client, 0x01); - return 0;//NO upgrade + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + + ic_data->vendor_fw_ver = i_FW_VER; + ic_data->vendor_config_ver = i_CFG_VER; + result = 1;/*upgrade success*/ + I("%s: TP upgrade OK\n", __func__); } + + himax_int_enable(private_ts->client->irq, 1); + return result; + + } else { + himax_sense_on(private_ts->client, 0x01); + return 0;/*NO upgrade*/ + } } -#endif +#endif #ifdef HX_RST_PIN_FUNC -void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) +void himax_HW_reset(uint8_t loadconfig, uint8_t int_off) { struct himax_ts_data *ts = private_ts; int ret = 0; return; if (ts->rst_gpio) { - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,0); - else { - hrtimer_cancel(&ts->timer); - ret = cancel_work_sync(&ts->work); - } + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 0); + else { + hrtimer_cancel(&ts->timer); + ret = cancel_work_sync(&ts->work); } + } I("%s: Now reset the Touch chip.\n", __func__); @@ -417,51 +418,51 @@ void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) himax_rst_gpio_set(ts->rst_gpio, 1); msleep(20); - if(loadconfig) - himax_loadSensorConfig(private_ts->client,private_ts->pdata); + if (loadconfig) + himax_loadSensorConfig(private_ts->client, + private_ts->pdata); - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,1); - else - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - } + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 1); + else + hrtimer_start(&ts->timer, + ktime_set(1, 0), HRTIMER_MODE_REL); + } } } #endif -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { + int err = -1; if (!client) { E("%s: Necessary parameters client are null!\n", __func__); - return -EINVAL; + return err; } - - if(config_load == false) - { - config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); - if (config_selected == NULL) { - E("%s: alloc config_selected fail!\n", __func__); - return -ENOMEM; - } + if (config_load == false) { + config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); + if (config_selected == NULL) { + E("%s: alloc config_selected fail!\n", __func__); + return err; } + } + himax_power_on_initCMD(client); - himax_power_on_initCMD(client); - - himax_int_enable(client->irq,0); - himax_read_FW_ver(client); + himax_int_enable(client->irq, 0); + himax_read_FW_ver(client); #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif - himax_int_enable(client->irq,1); - I("FW_VER : %X \n",ic_data->vendor_fw_ver); + himax_int_enable(client->irq, 1); + I("FW_VER : %X\n", ic_data->vendor_fw_ver); - ic_data->vendor_sensor_id=0x2602; - I("sensor_id=%x.\n",ic_data->vendor_sensor_id); + ic_data->vendor_sensor_id = 0x2602; + I("sensor_id=%x.\n", ic_data->vendor_sensor_id); - himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM + himax_sense_on(private_ts->client, 0x01);/*1=Flash, 0=SRAM*/ msleep(120); #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; @@ -474,47 +475,49 @@ int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_ #ifdef HX_ESD_WORKAROUND void ESD_HW_REST(void) { - I("START_Himax TP: ESD - Reset\n"); - + I("START_Himax TP: ESD - Reset\n"); + HX_report_ESD_event(); ESD_00_counter = 0; ESD_00_Flag = 0; - /*************************************/ - if (private_ts->protocol_type == PROTOCOL_TYPE_A) + /*************************************/ + if (private_ts->protocol_type == PROTOCOL_TYPE_A) input_mt_sync(private_ts->input_dev); - input_report_key(private_ts->input_dev, BTN_TOUCH, 0); - input_sync(private_ts->input_dev); - /*************************************/ + input_report_key(private_ts->input_dev, BTN_TOUCH, 0); + input_sync(private_ts->input_dev); + /*************************************/ I("END_Himax TP: ESD - Reset\n"); } #endif #ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable) +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable) { uint8_t tmp_data[4]; - if(HSEN_enable) - { + if (HSEN_enable) { I(" %s in", __func__); - HSEN_bit_retry: - himax_set_HSEN_enable(client,HSEN_enable); +HSEN_bit_retry: + himax_set_HSEN_enable(client, HSEN_enable); msleep(20); - himax_get_HSEN_enable(client,tmp_data); - I("%s: Read HSEN bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry HSEN bit write data[0]=%x \n",__func__,tmp_data[0]); - goto HSEN_bit_retry; - } + himax_get_HSEN_enable(client, tmp_data); + I("%s: Read HSEN bit data[0]=%x data[1]=%x", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry HSEN bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto HSEN_bit_retry; + } } } static void himax_HSEN_func(struct work_struct *work) { - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - hsen_work.work); + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, hsen_work.work); himax_set_HSEN_func(ts->client, ts->HSEN_enable); } @@ -525,9 +528,10 @@ static void himax_HSEN_func(struct work_struct *work) #ifdef HX_GESTURE_TRACK static void gest_pt_log_coordinate(int rx, int tx) { - //driver report x y with range 0 - 255 , we scale it up to x/y pixel - gest_pt_x[gest_pt_cnt] = rx*(ic_data->HX_X_RES)/255; - gest_pt_y[gest_pt_cnt] = tx*(ic_data->HX_Y_RES)/255; + /*driver report x y with range 0 - 255*/ + /* And we scale it up to x/y coordinates*/ + gest_pt_x[gest_pt_cnt] = rx * (ic_data->HX_X_RES) / 255; + gest_pt_y[gest_pt_cnt] = tx * (ic_data->HX_Y_RES) / 255; } #endif static int himax_parse_wake_event(struct himax_ts_data *ts) @@ -535,145 +539,143 @@ static int himax_parse_wake_event(struct himax_ts_data *ts) uint8_t buf[64]; unsigned char check_sum_cal = 0; #ifdef HX_GESTURE_TRACK - int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF; + int tmp_max_x = 0x00, tmp_min_x = 0xFFFF, + tmp_max_y = 0x00, tmp_min_y = 0xFFFF; int gest_len; #endif - int i=0, check_FC = 0, gesture_flag = 0; + int i = 0, check_FC = 0, gesture_flag = 0; himax_burst_enable(ts->client, 0); - himax_read_event_stack(ts->client,buf,56); + himax_read_event_stack(ts->client, buf, 56); - for(i=0;igest_pt_x[i]) - tmp_min_x=gest_pt_x[i]; - if(tmp_max_ygest_pt_y[i]) - tmp_min_y=gest_pt_y[i]; - } - I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y); - gest_start_x=gest_pt_x[0]; - gn_gesture_coor[0] = gest_start_x; - gest_start_y=gest_pt_y[0]; - gn_gesture_coor[1] = gest_start_y; - gest_end_x=gest_pt_x[gest_pt_cnt-1]; - gn_gesture_coor[2] = gest_end_x; - gest_end_y=gest_pt_y[gest_pt_cnt-1]; - gn_gesture_coor[3] = gest_end_y; - gest_width = tmp_max_x - tmp_min_x; - gn_gesture_coor[4] = gest_width; - gest_height = tmp_max_y - tmp_min_y; - gn_gesture_coor[5] = gest_height; - gest_mid_x = (tmp_max_x + tmp_min_x)/2; - gn_gesture_coor[6] = gest_mid_x; - gest_mid_y = (tmp_max_y + tmp_min_y)/2; - gn_gesture_coor[7] = gest_mid_y; - gn_gesture_coor[8] = gest_mid_x;//gest_up_x - gn_gesture_coor[9] = gest_mid_y-gest_height/2;//gest_up_y - gn_gesture_coor[10] = gest_mid_x;//gest_down_x - gn_gesture_coor[11] = gest_mid_y+gest_height/2; //gest_down_y - gn_gesture_coor[12] = gest_mid_x-gest_width/2; //gest_left_x - gn_gesture_coor[13] = gest_mid_y; //gest_left_y - gn_gesture_coor[14] = gest_mid_x+gest_width/2; //gest_right_x - gn_gesture_coor[15] = gest_mid_y; //gest_right_y - + if (gest_pt_cnt) { + for (i = 0 ; i < gest_pt_cnt ; i++) { + if (tmp_max_x < gest_pt_x[i]) + tmp_max_x = gest_pt_x[i]; + if (tmp_min_x > gest_pt_x[i]) + tmp_min_x = gest_pt_x[i]; + if (tmp_max_y < gest_pt_y[i]) + tmp_max_y = gest_pt_y[i]; + if (tmp_min_y > gest_pt_y[i]) + tmp_min_y = gest_pt_y[i]; } + I("gest_point x_min= %d, x_max= %d\n", + tmp_min_x, tmp_max_x); + I("y_min= %d, y_max= %d\n", + tmp_min_y, tmp_max_y); + gest_start_x = gest_pt_x[0]; + gn_gesture_coor[0] = gest_start_x; + gest_start_y = gest_pt_y[0]; + gn_gesture_coor[1] = gest_start_y; + gest_end_x = gest_pt_x[gest_pt_cnt - 1]; + gn_gesture_coor[2] = gest_end_x; + gest_end_y = gest_pt_y[gest_pt_cnt - 1]; + gn_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + gn_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + gn_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x) / 2; + gn_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y) / 2; + gn_gesture_coor[7] = gest_mid_y; + /*gest_up_x*/ + gn_gesture_coor[8] = gest_mid_x; + /*gest_up_y*/ + gn_gesture_coor[9] = gest_mid_y - gest_height / 2; + /*gest_down_x*/ + gn_gesture_coor[10] = gest_mid_x; + /*gest_down_y*/ + gn_gesture_coor[11] = gest_mid_y + gest_height / 2; + /*gest_left_x*/ + gn_gesture_coor[12] = gest_mid_x - gest_width / 2; + /*gest_left_y*/ + gn_gesture_coor[13] = gest_mid_y; + /*gest_right_x*/ + gn_gesture_coor[14] = gest_mid_x + gest_width / 2; + /*gest_right_y*/ + gn_gesture_coor[15] = gest_mid_y; + + } } #endif - if(gesture_flag != 0x80) - { - if(!ts->gesture_cust_en[gesture_flag]) - { - I("%s NOT report customer key \n ",__func__); - return 0;//NOT report customer key - } - } - else - { - if(!ts->gesture_cust_en[0]) - { - I("%s NOT report report double click \n",__func__); - return 0;//NOT report power key - } + if (gesture_flag != 0x80) { + if (!ts->gesture_cust_en[gesture_flag]) { + I("%s NOT report customer key\n ", __func__); + return 0;/*NOT report customer key*/ + } + } else { + if (!ts->gesture_cust_en[0]) { + I("%s NOT report report double click\n", __func__); + return 0;/*NOT report power key*/ + } } - if(gesture_flag == 0x80) + if (gesture_flag == 0x80) return EV_GESTURE_PWR; else return gesture_flag; @@ -685,225 +687,242 @@ void himax_wake_check_func(void) ret_event = himax_parse_wake_event(private_ts); switch (ret_event) { - case EV_GESTURE_PWR: - KEY_EVENT = KEY_POWER; + case EV_GESTURE_PWR: + KEY_EVENT = KEY_POWER; break; - case EV_GESTURE_01: - KEY_EVENT = KEY_CUST_01; + case EV_GESTURE_01: + KEY_EVENT = KEY_CUST_01; break; - case EV_GESTURE_02: - KEY_EVENT = KEY_CUST_02; + case EV_GESTURE_02: + KEY_EVENT = KEY_CUST_02; break; - case EV_GESTURE_03: - KEY_EVENT = KEY_CUST_03; + case EV_GESTURE_03: + KEY_EVENT = KEY_CUST_03; break; - case EV_GESTURE_04: - KEY_EVENT = KEY_CUST_04; + case EV_GESTURE_04: + KEY_EVENT = KEY_CUST_04; break; - case EV_GESTURE_05: - KEY_EVENT = KEY_CUST_05; + case EV_GESTURE_05: + KEY_EVENT = KEY_CUST_05; break; - case EV_GESTURE_06: - KEY_EVENT = KEY_CUST_06; + case EV_GESTURE_06: + KEY_EVENT = KEY_CUST_06; break; - case EV_GESTURE_07: - KEY_EVENT = KEY_CUST_07; + case EV_GESTURE_07: + KEY_EVENT = KEY_CUST_07; break; - case EV_GESTURE_08: - KEY_EVENT = KEY_CUST_08; + case EV_GESTURE_08: + KEY_EVENT = KEY_CUST_08; break; - case EV_GESTURE_09: - KEY_EVENT = KEY_CUST_09; + case EV_GESTURE_09: + KEY_EVENT = KEY_CUST_09; break; - case EV_GESTURE_10: - KEY_EVENT = KEY_CUST_10; + case EV_GESTURE_10: + KEY_EVENT = KEY_CUST_10; break; - case EV_GESTURE_11: - KEY_EVENT = KEY_CUST_11; + case EV_GESTURE_11: + KEY_EVENT = KEY_CUST_11; break; - case EV_GESTURE_12: - KEY_EVENT = KEY_CUST_12; + case EV_GESTURE_12: + KEY_EVENT = KEY_CUST_12; break; - case EV_GESTURE_13: - KEY_EVENT = KEY_CUST_13; + case EV_GESTURE_13: + KEY_EVENT = KEY_CUST_13; break; - case EV_GESTURE_14: - KEY_EVENT = KEY_CUST_14; + case EV_GESTURE_14: + KEY_EVENT = KEY_CUST_14; break; - case EV_GESTURE_15: - KEY_EVENT = KEY_CUST_15; + case EV_GESTURE_15: + KEY_EVENT = KEY_CUST_15; break; } - if(ret_event) - { - I(" %s SMART WAKEUP KEY event %x press\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 1); - input_sync(private_ts->input_dev); - //msleep(100); - I(" %s SMART WAKEUP KEY event %x release\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 0); - input_sync(private_ts->input_dev); - FAKE_POWER_KEY_SEND=true; + if (ret_event) { + I(" %s SMART WAKEUP KEY event %x press\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + /*msleep(100);*/ + I(" %s SMART WAKEUP KEY event %x release\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); + FAKE_POWER_KEY_SEND = true; #ifdef HX_GESTURE_TRACK - I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y, - gest_end_x,gest_end_y); - I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height, - gest_mid_x,gest_mid_y); - I("gest_up_x= %d, gest_up_y= %d, gest_down_x= %d, gest_down_y= %d\n",gn_gesture_coor[8],gn_gesture_coor[9], - gn_gesture_coor[10],gn_gesture_coor[11]); - I("gest_left_x= %d, gest_left_y= %d, gest_right_x= %d, gest_right_y= %d\n",gn_gesture_coor[12],gn_gesture_coor[13], - gn_gesture_coor[14],gn_gesture_coor[15]); + I("gest_start_x= %d, gest_start_y= %d\n", + gest_start_x, gest_start_y); + I("gest_end_x= %d, gest_end_y= %d\n", + gest_end_x, gest_end_y); + I("gest_width= %d, gest_height= %d\n", + gest_width, gest_height); + I("gest_mid_x= %d, gest_mid_y= %d\n", + gest_mid_x, gest_mid_y); + I("gest_up_x= %d, gest_up_y= %d\n", + gn_gesture_coor[8], gn_gesture_coor[9]); + I("gest_down_x= %d, gest_down_y= %d\n", + gn_gesture_coor[10], gn_gesture_coor[11]); + I("gest_left_x= %d, gest_left_y= %d\n", + gn_gesture_coor[12], gn_gesture_coor[13]); + I("gest_right_x= %d, gest_right_y= %d\n", + gn_gesture_coor[14], gn_gesture_coor[15]); #endif - } + } } #endif -static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts) +static void himax_ts_button_func(int tp_key_index, struct himax_ts_data *ts) { uint16_t x_position = 0, y_position = 0; -if ( tp_key_index != 0x00) - { - I("virtual key index =%x\n",tp_key_index); - if ( tp_key_index == 0x01) { + + if (tp_key_index != 0x00) { + I("virtual key index =%x\n", tp_key_index); + if (tp_key_index == 0x01) { vk_press = 1; I("back key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[0].index) { - x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2; - y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } + if (ts->pdata->virtual_key) { + if (ts->button[0].index) { + x_position = (ts->button[0].x_range_min + + ts->button[0].x_range_max) / 2; + y_position = (ts->button[0].y_range_min + + ts->button[0].y_range_max) / 2; } - else - input_report_key(ts->input_dev, KEY_BACK, 1); - } - else if ( tp_key_index == 0x02) { + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_BACK, 1); + } else if (tp_key_index == 0x02) { vk_press = 1; I("home key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[1].index) { - x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2; - y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } + if (ts->pdata->virtual_key) { + if (ts->button[1].index) { + x_position = (ts->button[1].x_range_min + + ts->button[1].x_range_max) / 2; + y_position = (ts->button[1].y_range_min + + ts->button[1].y_range_max) / 2; } - else - input_report_key(ts->input_dev, KEY_HOME, 1); - } - else if ( tp_key_index == 0x04) { + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_HOME, 1); + } else if (tp_key_index == 0x04) { vk_press = 1; I("APP_switch key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[2].index) { - x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2; - y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } + if (ts->pdata->virtual_key) { + if (ts->button[2].index) { + x_position = (ts->button[2].x_range_min + + ts->button[2].x_range_max) / 2; + y_position = (ts->button[2].y_range_min + + ts->button[2].y_range_max) / 2; } - else - input_report_key(ts->input_dev, KEY_F10, 1); + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == + PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_F10, 1); } input_sync(ts->input_dev); - } -else/*tp_key_index =0x00*/ - { + } else {/*tp_key_index =0x00*/ I("virtual key released\n"); vk_press = 0; if (ts->protocol_type == PROTOCOL_TYPE_A) { input_mt_sync(ts->input_dev); - } - else if (ts->protocol_type == PROTOCOL_TYPE_B) { + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 0); } input_report_key(ts->input_dev, KEY_BACK, 0); input_report_key(ts->input_dev, KEY_HOME, 0); input_report_key(ts->input_dev, KEY_F10, 0); - input_sync(ts->input_dev); + input_sync(ts->input_dev); } } @@ -915,8 +934,8 @@ void himax_ts_work(struct himax_ts_data *ts) uint8_t finger_on = 0; int32_t loop_i; uint16_t check_sum_cal = 0; - int raw_cnt_max ; - int raw_cnt_rmd ; + int raw_cnt_max; + int raw_cnt_rmd; int hx_touch_info_size; uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; @@ -924,121 +943,111 @@ void himax_ts_work(struct himax_ts_data *ts) int16_t *mutual_data; int16_t *self_data; uint8_t diag_cmd; - int i; - int mul_num; - int self_num; + int i; + int mul_num; + int self_num; int RawDataLen = 0; - //coordinate dump start - char coordinate_char[15+(ic_data->HX_MAX_PT+5)*2*5+2]; - //coordinate dump end + /*coordinate dump start*/ + char coordinate_char[15 + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 2]; + struct timeval t; + struct tm broken; + /*coordinate dump end*/ #endif memset(buf, 0x00, sizeof(buf)); memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); - raw_cnt_max = ic_data->HX_MAX_PT/4; - raw_cnt_rmd = ic_data->HX_MAX_PT%4; - + raw_cnt_max = ic_data->HX_MAX_PT / 4; + raw_cnt_rmd = ic_data->HX_MAX_PT % 4; #if defined(HX_USB_DETECT2) himax_cable_detect_func(); #endif - if (raw_cnt_rmd != 0x00) //more than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+2)*4; - } - else //less than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+1)*4; + if (raw_cnt_rmd != 0x00) { /*more than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 2) * 4; + } else { /*less than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 1) * 4; } #ifdef HX_TP_PROC_DIAG diag_cmd = getDiagCommand(); - if( diag_cmd ){ + if (diag_cmd) { ret = read_event_stack(ts->client, buf, 128); - } - else{ - if(touch_monitor_stop_flag != 0){ + } else { + if (touch_monitor_stop_flag != 0) { ret = read_event_stack(ts->client, buf, 128); - touch_monitor_stop_flag-- ; - } - else{ - ret = read_event_stack(ts->client, buf, hx_touch_info_size); + touch_monitor_stop_flag--; + } else { + ret = read_event_stack(ts->client, + buf, hx_touch_info_size); } } if (!ret) #else - if(!read_event_stack(ts->client, buf, hx_touch_info_size)) -#endif - { - E("%s: can't read data from chip!\n", __func__); - goto err_workqueue_out; - } + if (!read_event_stack(ts->client, buf, hx_touch_info_size)) +#endif + { + E("%s: can't read data from chip!\n", __func__); + goto err_workqueue_out; + } post_read_event_stack(ts->client); #ifdef HX_ESD_WORKAROUND - for(i = 0; i < hx_touch_info_size; i++) - { - if(buf[i] == 0xED)/*case 1 ESD recovery flow*/ - { + for (i = 0; i < hx_touch_info_size; i++) { + if (buf[i] == 0xED) { /*case 1 ESD recovery flow*/ check_sum_cal = 1; - }else if(buf[i] == 0x00) - { + } else if (buf[i] == 0x00) { ESD_00_Flag = 1; - } - else - { + } else { check_sum_cal = 0; ESD_00_counter = 0; - ESD_00_Flag = 0; + ESD_00_Flag = 0; i = hx_touch_info_size; break; - } - } - if (ESD_00_Flag == 1){ - ESD_00_counter ++; + } } - if (ESD_00_counter > 1){ + if (ESD_00_Flag == 1) + ESD_00_counter++; + if (ESD_00_counter > 1) check_sum_cal = 2; + if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) { + I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + ESD_HW_REST(); + return; } - - if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) - { - I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); - ESD_HW_REST(); - return; - } - - if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) - { + if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) { I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); ESD_HW_REST(); return; - } - else if (HX_ESD_RESET_ACTIVATE) - { + } else if (HX_ESD_RESET_ACTIVATE) { #ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(50)); + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(50)); #endif #ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(50)); + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(50)); #endif - HX_ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ - I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); +/*drop 1st interrupts after chip reset*/ + HX_ESD_RESET_ACTIVATE = 0; + I("[HIMAX TP MSG]:%s: Back from reset,ready to serve.\n", + __func__); } #endif - for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) + for (loop_i = 0, check_sum_cal = 0; + loop_i < hx_touch_info_size; loop_i++) check_sum_cal += buf[loop_i]; - - if ((check_sum_cal % 0x100 != 0) ) - { - I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); + + if ((check_sum_cal % 0x100 != 0)) { + I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", + check_sum_cal); return; } - if (ts->debug_log_level & BIT(0)) { I("%s: raw data:\n", __func__); for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { @@ -1048,260 +1057,289 @@ void himax_ts_work(struct himax_ts_data *ts) } } - //touch monitor raw data fetch + /*touch monitor raw data fetch*/ #ifdef HX_TP_PROC_DIAG diag_cmd = getDiagCommand(); - if (diag_cmd >= 1 && diag_cmd <= 6) - { - //Check 124th byte CRC - if(!diag_check_sum(hx_touch_info_size, buf)) - { + if (diag_cmd >= 1 && diag_cmd <= 6) { + /*Check 124th byte CRC*/ + if (!diag_check_sum(hx_touch_info_size, buf)) goto bypass_checksum_failed_packet; - } + #ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_cmd == 4) - { + if (Is_2T2R && diag_cmd == 4) { mutual_data = getMutualBuffer_2(); - self_data = getSelfBuffer(); + self_data = getSelfBuffer(); - // initiallize the block number of mutual and self + /* initiallize the block number of mutual and self*/ mul_num = getXChannel_2() * getYChannel_2(); #ifdef HX_EN_SEL_BUTTON - self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM; + self_num = getXChannel_2() + + getYChannel_2() + ic_data->HX_BT_NUM; #else self_num = getXChannel_2() + getYChannel_2(); #endif - } - else -#endif + } else +#endif { mutual_data = getMutualBuffer(); - self_data = getSelfBuffer(); + self_data = getSelfBuffer(); - // initiallize the block number of mutual and self + /* initiallize the block number of mutual and self*/ mul_num = getXChannel() * getYChannel(); #ifdef HX_EN_SEL_BUTTON - self_num = getXChannel() + getYChannel() + ic_data->HX_BT_NUM; + self_num = getXChannel() + + getYChannel() + ic_data->HX_BT_NUM; #else self_num = getXChannel() + getYChannel(); #endif } - diag_parse_raw_data(hx_touch_info_size, RawDataLen, mul_num, self_num, buf, diag_cmd, mutual_data, self_data); + diag_parse_raw_data(hx_touch_info_size, + RawDataLen, mul_num, self_num, buf, + diag_cmd, mutual_data, self_data); - } - else if (diag_cmd == 7) - { + } else if (diag_cmd == 7) { memcpy(&(diag_coor[0]), &buf[0], 128); } - //coordinate dump start - if (coordinate_dump_enable == 1) - { - for(i=0; i<(15 + (ic_data->HX_MAX_PT+5)*2*5); i++) - { + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + for (i = 0; i < (15 + (ic_data-> + HX_MAX_PT + 5) * 2 * 5); + i++) { coordinate_char[i] = 0x20; } - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5] = 0xD; - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5 + 1] = 0xA; + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5] = 0xD; + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 1] = 0xA; } - //coordinate dump end + /*coordinate dump end*/ bypass_checksum_failed_packet: #endif - EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3); - //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); - EN_NoiseFilter = EN_NoiseFilter & 0x01; - //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); + EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3); + /*I("EN_NoiseFilter=%d\n",EN_NoiseFilter);*/ + EN_NoiseFilter = EN_NoiseFilter & 0x01; + /*I("EN_NoiseFilter2=%d\n",EN_NoiseFilter);*/ #if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) - tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4); - if (tpd_key == 0x0F)/*All (VK+AA)leave*/ - { - tpd_key = 0x00; - } - //I("[DEBUG] tpd_key: %x\r\n", tpd_key); -#else + tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 4); + if (tpd_key == 0x0F) {/*All (VK+AA)leave*/ tpd_key = 0x00; + } + /*I("[DEBUG] tpd_key: %x\r\n", tpd_key);*/ +#else + tpd_key = 0x00; #endif - p_point_num = hx_point_num; - - if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) - hx_point_num = 0; - else - hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; - - // Touch Point information - if (hx_point_num != 0 ) { - if(vk_press == 0x00) - { - uint16_t old_finger = ts->pre_finger_mask; - ts->pre_finger_mask = 0; - finger_num = buf[coordInfoSize - 4] & 0x0F; - finger_on = 1; - AA_press = 1; - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - int base = loop_i * 4; - int x = buf[base] << 8 | buf[base + 1]; - int y = (buf[base + 2] << 8 | buf[base + 3]); - int w = buf[(ts->nFinger_support * 4) + loop_i]; - if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){ - finger_num--; - - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 0) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x * ts->widthFactor >> SHIFTBITS, - y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x, y, w, EN_NoiseFilter); - } - } - } - - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - } - - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); - - if (ts->protocol_type == PROTOCOL_TYPE_A) - { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); - input_mt_sync(ts->input_dev); - } - else - { - ts->last_slot = loop_i; - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); - } - - if (!ts->first_pressed) - { - ts->first_pressed = 1; - I("S1@%d, %d\n", x, y); - } - - ts->pre_finger_data[loop_i][0] = x; - ts->pre_finger_data[loop_i][1] = y; - - - if (ts->debug_log_level & BIT(1)) - I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", - loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); - - ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i); - - } else { - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - - if (loop_i == 0 && ts->first_pressed == 1) - { - ts->first_pressed = 2; - I("E1@%d, %d\n", - ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); - } - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 1) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0], - ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - } - } + p_point_num = hx_point_num; + + if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + hx_point_num = 0; + else + hx_point_num = buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + /* Touch Point information*/ + if ((hx_point_num != 0) && (vk_press == 0x00)) { + uint16_t old_finger = ts->pre_finger_mask; - }else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - //temp_x[0] = 0xFFFF; - //temp_y[0] = 0xFFFF; - //temp_x[1] = 0xFFFF; - //temp_y[1] = 0xFFFF; - himax_ts_button_func(tpd_key,ts); - finger_on = 0; + ts->pre_finger_mask = 0; + finger_num = buf[coordInfoSize - 4] & 0x0F; + finger_on = 1; + AA_press = 1; + for (i = 0; i < ts->nFinger_support; i++) { + int base = i * 4; + int x = buf[base] << 8 | buf[base + 1]; + int y = (buf[base + 2] << 8 | buf[base + 3]); + int w = buf[(ts->nFinger_support * 4) + i]; + + if (x >= 0 && x <= ts->pdata->abs_x_max + && y >= 0 && y <= ts->pdata->abs_y_max) { + finger_num--; + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x * ts->widthFactor >> SHIFTBITS, + y * ts->heightFactor >> SHIFTBITS, + w, EN_NoiseFilter); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x, y, w, EN_NoiseFilter); } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); - } else if (hx_point_num == 0){ - if(AA_press) - { - // leave event - finger_on = 0; - AA_press = 0; - if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - } - } - if (ts->pre_finger_mask > 0) { - for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->useScreenRes) { - I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } else { - I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - ts->pre_finger_mask = 0; + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_slot(ts->input_dev, i); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, w); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, i); + input_mt_sync(ts->input_dev); + } else { + ts->last_slot = i; + input_mt_report_slot_state + (ts->input_dev, + MT_TOOL_FINGER, 1); } - if (ts->first_pressed == 1) { - ts->first_pressed = 2; - I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + if (!ts->first_pressed) { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); } - if (ts->debug_log_level & BIT(1)) - I("All Finger leave\n"); + ts->pre_finger_data[i][0] = x; + ts->pre_finger_data[i][1] = y; + + if (ts->debug_log_level & BIT(1)) { + I("Finger %d=> X:%d,Y:%d,W:%d,", + i + 1, x, y, w); + I("Z:%d,F:%d,N:%d\n", + w, i + 1, EN_NoiseFilter); + } + ts->pre_finger_mask = + ts->pre_finger_mask + (1 << i); + } else { + if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } + if (i == 0 && ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", + ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } } - else if (tpd_key != 0x00) { - himax_ts_button_func(tpd_key,ts); - finger_on = 1; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if ((hx_point_num != 0) + && ((tpd_key_old != 0x00) && (tpd_key == 0x00))) { + /*temp_x[0] = 0xFFFF;*/ + /*temp_y[0] = 0xFFFF;*/ + /*temp_x[1] = 0xFFFF;*/ + /*temp_y[1] = 0xFFFF;*/ + himax_ts_button_func(tpd_key, ts); + finger_on = 0; + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if (hx_point_num == 0) { + if (AA_press) { + /*leave event*/ + finger_on = 0; + AA_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + + for (i = 0 ; i < ts->nFinger_support ; i++) { + if ((((ts->pre_finger_mask >> i) & 1) == 1) + && (ts->protocol_type == PROTOCOL_TYPE_B)) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } } - else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - himax_ts_button_func(tpd_key,ts); - finger_on = 0; + if (ts->pre_finger_mask > 0) { + for (i = 0; i < ts->nFinger_support + && (ts->debug_log_level & BIT(3)) > 0; i++) { + if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && (ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS + ); + } else if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && !(ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } + } + ts->pre_finger_mask = 0; + } + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); + + if (ts->debug_log_level & BIT(1)) + I("All Finger leave\n"); + +#ifdef HX_TP_PROC_DIAG + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + do_gettimeofday(&t); + time_to_tm(t.tv_sec, 0, &broken); + snprintf(&coordinate_char[0], 15, + "%2d:%2d:%2d:%lu,", broken.tm_hour, + broken.tm_min, broken.tm_sec, + t.tv_usec / 1000); + + snprintf(&coordinate_char[15], 10, + "Touch up!"); + + coordinate_fn->f_op->write + (coordinate_fn, &coordinate_char[0], + 15 + (ic_data->HX_MAX_PT + 5) + * 2 * sizeof(char) * 5 + 2, + &coordinate_fn->f_pos); + } + /*coordinate dump end*/ +#endif + } else if (tpd_key != 0x00) { + himax_ts_button_func(tpd_key, ts); + finger_on = 1; + } else if ((tpd_key_old != 0x00) && (tpd_key == 0x00)) { + himax_ts_button_func(tpd_key, ts); + finger_on = 0; } - tpd_key_old = tpd_key; - Last_EN_NoiseFilter = EN_NoiseFilter; + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } + tpd_key_old = tpd_key; workqueue_out: return; @@ -1310,7 +1348,7 @@ err_workqueue_out: I("%s: Now reset the Touch chip.\n", __func__); #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif goto workqueue_out; @@ -1329,6 +1367,7 @@ enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) static void himax_cable_tp_status_handler_func(int connect_status) { struct himax_ts_data *ts; + I("Touch: cable change to %d\n", connect_status); ts = private_ts; if (ts->cable_config) { @@ -1342,18 +1381,23 @@ static void himax_cable_tp_status_handler_func(int connect_status) ts->usb_connected = 0x00; } - i2c_himax_master_write(ts->client, ts->cable_config, - sizeof(ts->cable_config), HIMAX_I2C_RETRY_TIMES); + i2c_himax_master_write(ts->client, + ts->cable_config, + sizeof(ts->cable_config), + HIMAX_I2C_RETRY_TIMES); - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->cable_config[1]); } else - I("%s: Cable status is the same as previous one, ignore.\n", __func__); + I("%s: Cable status is same, ignore.\n", + __func__); } else { if (connect_status) ts->usb_connected = 0x01; else ts->usb_connected = 0x00; - I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected); + I("%s: Cable status remembered: 0x%2.2X\n", + __func__, ts->usb_connected); } } } @@ -1373,16 +1417,20 @@ void himax_cable_detect_func(void) struct himax_ts_data *ts; u32 connect_status = 0; - connect_status = USB_Flag;//upmu_is_chr_det(); + connect_status = USB_Flag;/*upmu_is_chr_det();*/ ts = private_ts; - //I("Touch: cable status=%d, cable_config=%p, usb_connected=%d \n", connect_status,ts->cable_config, ts->usb_connected); + /*I("Touch: cable status=%d, cable_config=%p, + usb_connected=%d\n", connect_status, + ts->cable_config, ts->usb_connected);*/ + if (ts->cable_config) { if ((!!connect_status) != ts->usb_connected) { - //notify USB plug/unplug - // 0x9008_8060 ==> 0x0000_0000/0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; - + /*notify USB plug/unplug*/ + /*0x9008_8060 ==> 0x0000_0000/0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; if (!!connect_status) { tmp_data[0] = 0x01; ts->usb_connected = 0x01; @@ -1393,10 +1441,13 @@ void himax_cable_detect_func(void) himax_flash_write_burst(ts->client, tmp_addr, tmp_data); - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected); - } - //else - //I("%s: Cable status is the same as previous one, ignore.\n", __func__); + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->usb_connected); + } + /*else*/ + /*I("%s: Cable status is the same as previous one, + ignore.\n", __func__);*/ + } } #endif @@ -1417,52 +1468,52 @@ int himax_fb_register(struct himax_ts_data *ts) #endif #ifdef HX_SMART_WAKEUP -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable) +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable) { uint8_t tmp_data[4]; - if(SMWP_enable) - { - SMWP_bit_retry: + if (SMWP_enable) { +SMWP_bit_retry: himax_set_SMWP_enable(client, SMWP_enable); msleep(20); - himax_get_SMWP_enable(client,tmp_data); - I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry SMWP bit write data[0]=%x \n",__func__,tmp_data[0]); - goto SMWP_bit_retry; - } + himax_get_SMWP_enable(client, tmp_data); +I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", +__func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry SMWP bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto SMWP_bit_retry; + } } } static void himax_SMWP_work(struct work_struct *work) { - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - smwp_work.work); + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, smwp_work.work); I(" %s in", __func__); - himax_set_SMWP_func(ts->client,ts->SMWP_enable); + himax_set_SMWP_func(ts->client, ts->SMWP_enable); } #endif -#ifdef HX_TP_PROC_FLASH_DUMP +#ifdef HX_TP_PROC_FLASH_DUMP static void himax_ts_flash_work_func(struct work_struct *work) { himax_ts_flash_func(); } #endif -#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_DIAG static void himax_ts_diag_work_func(struct work_struct *work) { himax_ts_diag_func(); } #endif -void himax_ts_init(struct himax_ts_data *ts) +bool himax_ts_init(struct himax_ts_data *ts) { int ret = 0, err = 0; struct himax_i2c_platform_data *pdata; @@ -1476,15 +1527,14 @@ void himax_ts_init(struct himax_ts_data *ts) /* Set pinctrl in active state */ if (ts->ts_pinctrl) { ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_active); - if (ret < 0) { - E("Failed to set pin in active state %d",ret); - } + ts->pinctrl_state_active); + if (ret < 0) + E("Failed to set pin in active state %d", ret); } himax_burst_enable(client, 0); - //Get Himax IC Type / FW information / Calculate the point number + /*Get Himax IC Type / FW information / Calculate the point number */ if (himax_check_chip_version(ts->client) == false) { E("Himax chip doesn NOT EXIST"); goto err_ic_package_failed; @@ -1496,10 +1546,9 @@ void himax_ts_init(struct himax_ts_data *ts) if (pdata->virtual_key) ts->button = pdata->virtual_key; -#ifdef HX_TP_PROC_FLASH_DUMP +#ifdef HX_TP_PROC_FLASH_DUMP ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); - if (!ts->flash_wq) - { + if (!ts->flash_wq) { E("%s: create flash workqueue failed\n", __func__); err = -ENOMEM; goto err_create_wq_failed; @@ -1511,10 +1560,9 @@ void himax_ts_init(struct himax_ts_data *ts) setFlashBuffer(); #endif -#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_DIAG ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); - if (!ts->himax_diag_wq) - { + if (!ts->himax_diag_wq) { E("%s: create diag workqueue failed\n", __func__); err = -ENOMEM; goto err_create_wq_failed; @@ -1526,40 +1574,42 @@ himax_read_FW_ver(client); #ifdef HX_AUTO_UPDATE_FW I(" %s in", __func__); - if(i_update_FW() == false) - I("NOT Have new FW=NOT UPDATE=\n"); + if (i_update_FW() <= 0) + I("FW NOT UPDATE=\n"); else I("Have new FW=UPDATE=\n"); #endif - //Himax Power On and Load Config + /*Himax Power On and Load Config*/ if (himax_loadSensorConfig(client, pdata) < 0) { - E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); + E("%s: Load Sesnsor config failed,unload driver.\n", + __func__); goto err_detect_failed; } calculate_point_number(); #ifdef HX_TP_PROC_DIAG - setXChannel(ic_data->HX_RX_NUM); // X channel - setYChannel(ic_data->HX_TX_NUM); // Y channel + setXChannel(ic_data->HX_RX_NUM); /*X channel*/ + setYChannel(ic_data->HX_TX_NUM); /*Y channel*/ setMutualBuffer(); setMutualNewBuffer(); setMutualOldBuffer(); if (getMutualBuffer() == NULL) { E("%s: mutual buffer allocate fail failed\n", __func__); - return; + return false; } #ifdef HX_TP_PROC_2T2R - if(Is_2T2R){ - setXChannel_2(ic_data->HX_RX_NUM_2); // X channel - setYChannel_2(ic_data->HX_TX_NUM_2); // Y channel + if (Is_2T2R) { + setXChannel_2(ic_data->HX_RX_NUM_2); /*X channel*/ + setYChannel_2(ic_data->HX_TX_NUM_2); /*Y channel*/ setMutualBuffer_2(); if (getMutualBuffer_2() == NULL) { - E("%s: mutual buffer 2 allocate fail failed\n", __func__); - return; + E("%s: mutual buffer 2 allocate fail failed\n", + __func__); + return false; } } #endif @@ -1572,7 +1622,7 @@ himax_read_FW_ver(client); ts->x_channel = ic_data->HX_RX_NUM; ts->y_channel = ic_data->HX_TX_NUM; ts->nFinger_support = ic_data->HX_MAX_PT; - //calculate the i2c data size + /*calculate the i2c data size*/ calcDataSize(ts->nFinger_support); I("%s: calcDataSize complete\n", __func__); #ifdef CONFIG_OF @@ -1584,14 +1634,13 @@ himax_read_FW_ver(client); pdata->cable_config[1] = 0x00; #endif ts->suspended = false; -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) ts->usb_connected = 0x00; ts->cable_config = pdata->cable_config; #endif ts->protocol_type = pdata->protocol_type; I("%s: Use Protocol Type %c\n", __func__, ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); - ret = himax_input_register(ts); if (ret) { E("%s: Unable to register %s input device\n", @@ -1599,8 +1648,9 @@ himax_read_FW_ver(client); goto err_input_register_device_failed; } #ifdef HX_SMART_WAKEUP - ts->SMWP_enable=0; - wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); + ts->SMWP_enable = 0; + wakeup_source_init(&ts->ts_SMWP_wake_lock, + WAKE_LOCK_SUSPEND, HIMAX_common_NAME); ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); if (!ts->himax_smwp_wq) { @@ -1611,7 +1661,7 @@ himax_read_FW_ver(client); INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); #endif #ifdef HX_HIGH_SENSE - ts->HSEN_enable=0; + ts->HSEN_enable = 0; ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); if (!ts->himax_hsen_wq) { E(" allocate himax_hsen_wq failed\n"); @@ -1633,7 +1683,7 @@ himax_read_FW_ver(client); err = himax_ts_register_interrupt(ts->client); if (err) goto err_register_interrupt_failed; - return; + return true; err_register_interrupt_failed: #ifdef HX_HIGH_SENSE @@ -1641,26 +1691,26 @@ err_hsen_wq_failed: #endif #ifdef HX_SMART_WAKEUP err_smwp_wq_failed: - wake_lock_destroy(&ts->ts_SMWP_wake_lock); + wakeup_source_trash(&ts->ts_SMWP_wake_lock); #endif err_input_register_device_failed: input_free_device(ts->input_dev); err_detect_failed: -#ifdef HX_TP_PROC_FLASH_DUMP +#ifdef HX_TP_PROC_FLASH_DUMP err_create_wq_failed: #endif err_ic_package_failed: - -return; +return false; } -int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id) +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id) { int err = 0; struct himax_ts_data *ts; struct himax_i2c_platform_data *pdata; - //Check I2C functionality + /*Check I2C functionality*/ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { E("%s: i2c check functionality error\n", __func__); err = -ENODEV; @@ -1677,6 +1727,7 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i i2c_set_clientdata(client, ts); ts->client = client; ts->dev = &client->dev; + mutex_init(&ts->rw_lock); pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) { /*Allocate Platform data space*/ @@ -1691,7 +1742,8 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i } #ifdef CONFIG_OF - if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ + /*DeviceTree Init Platform_data*/ + if (client->dev.of_node) { err = himax_parse_dt(ts, pdata); if (err < 0) { I(" pdata is NULL for DT\n"); @@ -1704,12 +1756,11 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i ts->rst_gpio = pdata->gpio_reset; #endif -himax_gpio_power_config(ts->client, pdata); + himax_gpio_power_config(ts->client, pdata); err = himax_ts_pinctrl_init(ts); - if (err || ts->ts_pinctrl == NULL) { + if (err || ts->ts_pinctrl == NULL) E(" Pinctrl init failed\n"); - } #ifndef CONFIG_OF if (pdata->power) { @@ -1736,7 +1787,7 @@ himax_gpio_power_config(ts->client, pdata); } #endif - return 0; + return 0; #ifdef CONFIG_FB err_fb_notif_wq_create: @@ -1783,8 +1834,10 @@ int himax_chip_common_remove(struct i2c_client *client) himax_touch_proc_deinit(); #endif #ifdef CONFIG_FB - if (fb_unregister_client(&ts->fb_notif)) - dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); + if (fb_unregister_client(&ts->fb_notif)) { + dev_err(&client->dev, + "Error occurred while unregistering fb_notifier.\n"); + } #endif if (!ts->use_irq) @@ -1810,7 +1863,7 @@ int himax_chip_common_remove(struct i2c_client *client) } } #ifdef HX_SMART_WAKEUP - wake_lock_destroy(&ts->ts_SMWP_wake_lock); + wakeup_source_trash(&ts->ts_SMWP_wake_lock); #endif kfree(ts); @@ -1822,38 +1875,36 @@ int himax_chip_common_suspend(struct himax_ts_data *ts) { int ret; - if(ts->suspended) - { - I("%s: Already suspended. Skipped. \n", __func__); + if (ts->suspended) { + I("%s: Already suspended. Skipped.\n", __func__); return 0; - } - else - { + + } else { ts->suspended = true; - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); } #ifdef HX_TP_PROC_FLASH_DUMP - if (getFlashDumpGoing()) - { - I("[himax] %s: Flash dump is going, reject suspend\n",__func__); + if (getFlashDumpGoing()) { + I("[himax] %s: Flash dump is going,reject suspend\n", + __func__); return 0; } #endif #ifdef HX_TP_PROC_HITOUCH - if(hitouch_is_connect) - { - I("[himax] %s: Hitouch connect, reject suspend\n",__func__); + if (hitouch_is_connect) { + I("[himax] %s: Hitouch connect,reject suspend\n", + __func__); return 0; } #endif #ifdef HX_SMART_WAKEUP - if(ts->SMWP_enable) - { + if (ts->SMWP_enable) { atomic_set(&ts->suspend_mode, 1); ts->pre_finger_mask = 0; - FAKE_POWER_KEY_SEND=false; - I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",__func__); + FAKE_POWER_KEY_SEND = false; + I("[himax] %s: SMART_WAKEUP enable,reject suspend\n", + __func__); return 0; } #endif @@ -1864,19 +1915,18 @@ int himax_chip_common_suspend(struct himax_ts_data *ts) if (!ts->use_irq) { ret = cancel_work_sync(&ts->work); if (ret) - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); } - //ts->first_pressed = 0; + /*ts->first_pressed = 0;*/ atomic_set(&ts->suspend_mode, 1); ts->pre_finger_mask = 0; if (ts->ts_pinctrl) { ret = pinctrl_select_state(ts->ts_pinctrl, ts->pinctrl_state_suspend); - if (ret < 0) { + if (ret < 0) E("Failed to get idle pinctrl state %d\n", ret); - } } if (ts->pdata->powerOff3V3 && ts->pdata->power) @@ -1889,20 +1939,16 @@ int himax_chip_common_resume(struct himax_ts_data *ts) { int retval; - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); if (ts->pdata->powerOff3V3 && ts->pdata->power) ts->pdata->power(1); - - - /*************************************/ + if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); + input_mt_sync(ts->input_dev); input_report_key(ts->input_dev, BTN_TOUCH, 0); input_sync(ts->input_dev); - /*************************************/ - - + if (ts->ts_pinctrl) { retval = pinctrl_select_state(ts->ts_pinctrl, ts->pinctrl_state_active); @@ -1914,7 +1960,7 @@ int himax_chip_common_resume(struct himax_ts_data *ts) atomic_set(&ts->suspend_mode, 0); - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); ts->suspended = false; #if defined(HX_USB_DETECT2) @@ -1922,10 +1968,12 @@ int himax_chip_common_resume(struct himax_ts_data *ts) himax_cable_detect_func(); #endif #ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(1000)); + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(1000)); #endif #ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(1000)); + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(1000)); #endif return 0; err_pinctrl_select_resume: diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h index 27ce9aafd959cc3bdbcaa7ca9166374398033bae..41c97f7b52049df448c70e6b86b5f19821b0df5e 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -16,9 +16,13 @@ #ifndef HIMAX_COMMON_H #define HIMAX_COMMON_H +#include "himax_platform.h" + #include -#include -#include +/*#include */ +/*#include */ +#include +#include #include #include @@ -34,9 +38,9 @@ #include #include #include +#include #include #include -#include "himax_platform.h" #if defined(CONFIG_FB) #include @@ -48,7 +52,7 @@ #ifdef CONFIG_OF #include #endif -#define HIMAX_DRIVER_VER "0.2.4.0" +#define HIMAX_DRIVER_VER "0.3.1.0" #define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" #define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" @@ -62,39 +66,39 @@ #define HX_TP_PROC_SELF_TEST #define HX_TP_PROC_RESET #define HX_TP_PROC_SENSE_ON_OFF -//#define HX_TP_PROC_2T2R +/*#define HX_TP_PROC_2T2R*/ int himax_touch_proc_init(void); void himax_touch_proc_deinit(void); #endif -//===========Himax Option function============= -//#define HX_RST_PIN_FUNC -//#define HX_AUTO_UPDATE_FW -//#define HX_HIGH_SENSE -//#define HX_SMART_WAKEUP -//#define HX_USB_DETECT -//#define HX_ESD_WORKAROUND -//#define HX_USB_DETECT2 - -//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close -#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close - -#define HX_KEY_MAX_COUNT 4 -#define DEFAULT_RETRY_CNT 3 - -#define HX_VKEY_0 KEY_BACK -#define HX_VKEY_1 KEY_HOME -#define HX_VKEY_2 KEY_RESERVED -#define HX_VKEY_3 KEY_RESERVED -#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} +/*===========Himax Option function=============*/ +/*#define HX_RST_PIN_FUNC*/ +#define HX_AUTO_UPDATE_FW +/*#define HX_HIGH_SENSE*/ +/*#define HX_SMART_WAKEUP*/ +/*#define HX_USB_DETECT*/ +/*#define HX_ESD_WORKAROUND*/ +/*#define HX_USB_DETECT2*/ +/*#define HX_EN_SEL_BUTTON*//* Support Self Virtual key ,default is close*/ +#define HX_EN_MUT_BUTTON/* Support Mutual Virtual Key ,default is close*/ +/*#define HX_EN_CHECK_PATCH*/ + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_VKEY_0 KEY_BACK +#define HX_VKEY_1 KEY_HOME +#define HX_VKEY_2 KEY_RESERVED +#define HX_VKEY_3 KEY_RESERVED +#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} #define SHIFTBITS 5 -//#define FLASH_SIZE 131072 -#define FW_SIZE_60k 61440 -#define FW_SIZE_64k 65536 -#define FW_SIZE_124k 126976 -#define FW_SIZE_128k 131072 +/*#define FLASH_SIZE 131072*/ +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 struct himax_ic_data { int vendor_fw_ver; @@ -183,12 +187,12 @@ struct himax_ts_data { bool suspended; bool probe_done; struct mutex fb_mutex; + struct mutex rw_lock; atomic_t suspend_mode; uint8_t x_channel; uint8_t y_channel; uint8_t useScreenRes; uint8_t diag_command; - uint8_t protocol_type; uint8_t first_pressed; uint8_t coord_data_size; @@ -198,11 +202,9 @@ struct himax_ts_data { uint8_t nFinger_support; uint8_t irq_enabled; uint8_t diag_self[50]; - uint16_t finger_pressed; uint16_t last_slot; uint16_t pre_finger_mask; - uint32_t debug_log_level; uint32_t widthFactor; uint32_t heightFactor; @@ -214,20 +216,20 @@ struct himax_ts_data { uint32_t pl_x_max; uint32_t pl_y_min; uint32_t pl_y_max; - + int use_irq; int (*power)(int on); int pre_finger_data[10][2]; - + struct device *dev; struct workqueue_struct *himax_wq; struct work_struct work; struct input_dev *input_dev; struct hrtimer timer; struct i2c_client *client; - struct himax_i2c_platform_data *pdata; + struct himax_i2c_platform_data *pdata; struct himax_virtual_key *button; - + #if defined(CONFIG_FB) struct notifier_block fb_notif; #elif defined(CONFIG_HAS_EARLYSUSPEND) @@ -235,8 +237,8 @@ struct himax_ts_data { #endif #ifdef HX_TP_PROC_FLASH_DUMP - struct workqueue_struct *flash_wq; - struct work_struct flash_work; + struct workqueue_struct *flash_wq; + struct work_struct flash_work; #endif #ifdef HX_RST_PIN_FUNC @@ -250,7 +252,7 @@ struct himax_ts_data { #ifdef HX_SMART_WAKEUP uint8_t SMWP_enable; uint8_t gesture_cust_en[16]; - struct wake_lock ts_SMWP_wake_lock; + struct wakeup_source ts_SMWP_wake_lock; struct workqueue_struct *himax_smwp_wq; struct delayed_work smwp_work; #endif @@ -261,7 +263,7 @@ struct himax_ts_data { struct delayed_work hsen_work; #endif -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) uint8_t usb_connected; uint8_t *cable_config; #endif @@ -273,30 +275,30 @@ struct himax_ts_data { struct pinctrl_state *pinctrl_state_release; }; -#define HX_CMD_NOP 0x00 -#define HX_CMD_SETMICROOFF 0x35 -#define HX_CMD_SETROMRDY 0x36 -#define HX_CMD_TSSLPIN 0x80 -#define HX_CMD_TSSLPOUT 0x81 -#define HX_CMD_TSSOFF 0x82 -#define HX_CMD_TSSON 0x83 -#define HX_CMD_ROE 0x85 -#define HX_CMD_RAE 0x86 -#define HX_CMD_RLE 0x87 -#define HX_CMD_CLRES 0x88 -#define HX_CMD_TSSWRESET 0x9E -#define HX_CMD_SETDEEPSTB 0xD7 -#define HX_CMD_SET_CACHE_FUN 0xDD -#define HX_CMD_SETIDLE 0xF2 -#define HX_CMD_SETIDLEDELAY 0xF3 -#define HX_CMD_SELFTEST_BUFFER 0x8D +#define HX_CMD_NOP 0x00 +#define HX_CMD_SETMICROOFF 0x35 +#define HX_CMD_SETROMRDY 0x36 +#define HX_CMD_TSSLPIN 0x80 +#define HX_CMD_TSSLPOUT 0x81 +#define HX_CMD_TSSOFF 0x82 +#define HX_CMD_TSSON 0x83 +#define HX_CMD_ROE 0x85 +#define HX_CMD_RAE 0x86 +#define HX_CMD_RLE 0x87 +#define HX_CMD_CLRES 0x88 +#define HX_CMD_TSSWRESET 0x9E +#define HX_CMD_SETDEEPSTB 0xD7 +#define HX_CMD_SET_CACHE_FUN 0xDD +#define HX_CMD_SETIDLE 0xF2 +#define HX_CMD_SETIDLEDELAY 0xF3 +#define HX_CMD_SELFTEST_BUFFER 0x8D #define HX_CMD_MANUALMODE 0x42 -#define HX_CMD_FLASH_ENABLE 0x43 +#define HX_CMD_FLASH_ENABLE 0x43 #define HX_CMD_FLASH_SET_ADDRESS 0x44 #define HX_CMD_FLASH_WRITE_REGISTER 0x45 #define HX_CMD_FLASH_SET_COMMAND 0x47 #define HX_CMD_FLASH_WRITE_BUFFER 0x48 -#define HX_CMD_FLASH_PAGE_ERASE 0x4D +#define HX_CMD_FLASH_PAGE_ERASE 0x4D #define HX_CMD_FLASH_SECTOR_ERASE 0x4E #define HX_CMD_CB 0xCB #define HX_CMD_EA 0xEA @@ -311,7 +313,7 @@ enum input_protocol_type { }; #ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable); #endif #ifdef HX_SMART_WAKEUP @@ -319,18 +321,18 @@ void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); #define GEST_PTLG_HDR_LEN (4) #define GEST_PTLG_HDR_ID1 (0xCC) #define GEST_PTLG_HDR_ID2 (0x44) -#define GEST_PT_MAX_NUM (128) +#define GEST_PT_MAX_NUM (128) #ifdef HX_GESTURE_TRACK static int gest_pt_cnt; static int gest_pt_x[GEST_PT_MAX_NUM]; static int gest_pt_y[GEST_PT_MAX_NUM]; -static int gest_start_x,gest_start_y,gest_end_x,gest_end_y; -static int gest_width,gest_height,gest_mid_x,gest_mid_y; +static int gest_start_x, gest_start_y, gest_end_x, gest_end_y; +static int gest_width, gest_height, gest_mid_x, gest_mid_y; static int gn_gesture_coor[16]; #endif -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable); +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable); extern bool FAKE_POWER_KEY_SEND; enum gesture_event_type { @@ -380,16 +382,91 @@ irqreturn_t himax_ts_thread(int irq, void *ptr); int himax_input_register(struct himax_ts_data *ts); #endif -extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id); -extern int himax_chip_common_remove(struct i2c_client *client); -extern int himax_chip_common_suspend(struct himax_ts_data *ts); -extern int himax_chip_common_resume(struct himax_ts_data *ts); -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata); +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id); +int himax_chip_common_remove(struct i2c_client *client); +int himax_chip_common_suspend(struct himax_ts_data *ts); +int himax_chip_common_resume(struct himax_ts_data *ts); +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata); #ifdef HX_USB_DETECT2 -//extern kal_bool upmu_is_chr_det(void); +/*extern kal_bool upmu_is_chr_det(void);*/ void himax_cable_detect_func(void); #endif +#ifdef HX_AUTO_UPDATE_FW +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +#endif +extern unsigned long FW_VER_MAJ_FLASH_LENG; +extern unsigned long FW_VER_MIN_FLASH_LENG; +extern unsigned long CFG_VER_MAJ_FLASH_LENG; +extern unsigned long CFG_VER_MIN_FLASH_LENG; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +/*PROC-START*/ +#ifdef HX_TP_PROC_FLASH_DUMP +extern void himax_ts_flash_func(void); +extern void setFlashBuffer(void); +extern bool getFlashDumpGoing(void); +extern uint8_t getSysOperation(void); +extern void setSysOperation(uint8_t operation); +#endif + +#ifdef HX_TP_PROC_HITOUCH +extern bool hitouch_is_connect; +#endif + +#ifdef HX_TP_PROC_DIAG + extern int touch_monitor_stop_flag; + + extern int touch_monitor_stop_limit; + + extern void himax_ts_diag_func(void); + + extern int16_t *getMutualBuffer(void); + extern int16_t *getMutualNewBuffer(void); + extern int16_t *getMutualOldBuffer(void); + extern int16_t *getSelfBuffer(void); + extern uint8_t getXChannel(void); + extern uint8_t getYChannel(void); + extern uint8_t getDiagCommand(void); + extern void setXChannel(uint8_t x); + extern void setYChannel(uint8_t y); + extern void setMutualBuffer(void); + extern void setMutualNewBuffer(void); + extern void setMutualOldBuffer(void); + extern uint8_t coordinate_dump_enable; + extern struct file *coordinate_fn; + extern uint8_t diag_coor[128]; +#ifdef HX_TP_PROC_2T2R + extern int16_t *getMutualBuffer_2(void); + extern uint8_t getXChannel_2(void); + extern uint8_t getYChannel_2(void); + extern void setXChannel_2(uint8_t x); + extern void setYChannel_2(uint8_t y); + extern void setMutualBuffer_2(void); +#endif +#endif +/*PROC-END*/ +#endif + +#ifdef HX_USB_DETECT2 + extern bool USB_Flag; +#endif +#ifdef HX_ESD_WORKAROUND + extern void HX_report_ESD_event(void); + unsigned char ESD_00_counter = 0; + unsigned char ESD_00_Flag = 0; +#endif +bool himax_ts_init(struct himax_ts_data *ts); + #endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c index f8bee11b43515e3bb3c84124aaaf00766d312741..55cc7ca92e4c2e127502b57f708a2b54658ce201 100644 --- a/drivers/input/touchscreen/hxchipset/himax_debug.c +++ b/drivers/input/touchscreen/hxchipset/himax_debug.c @@ -16,32 +16,16 @@ #include "himax_debug.h" #include "himax_ic.h" -//struct himax_debug_data* debug_data; - -extern struct himax_ic_data* ic_data; -extern struct himax_ts_data *private_ts; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; -extern int himax_input_register(struct himax_ts_data *ts); -#ifdef QCT -extern irqreturn_t himax_ts_thread(int irq, void *ptr); -#endif -#ifdef MTK -#ifdef CONFIG_OF_TOUCH -extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); -#else -extern void tpd_eint_interrupt_handler(void); -#endif -#endif +/*struct himax_debug_data* debug_data;*/ #ifdef HX_TP_PROC_DIAG #ifdef HX_TP_PROC_2T2R -int HX_RX_NUM_2 = 0; -int HX_TX_NUM_2 = 0; +int HX_RX_NUM_2; +int HX_TX_NUM_2; #endif -int touch_monitor_stop_flag = 0; +int touch_monitor_stop_flag; int touch_monitor_stop_limit = 5; -uint8_t g_diag_arr_num = 0; +uint8_t g_diag_arr_num; #endif #ifdef HX_ESD_WORKAROUND @@ -52,11 +36,11 @@ u8 HX_ESD_RESET_ACTIVATE; bool FAKE_POWER_KEY_SEND; #endif -//============================================================================================================= -// -// Segment : Himax PROC Debug Function -// -//============================================================================================================= +/*======================================================== + +Segment : Himax PROC Debug Function + +==========================================================*/ #if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) static ssize_t himax_vendor_read(struct file *file, char *buf, @@ -65,33 +49,26 @@ static ssize_t himax_vendor_read(struct file *file, char *buf, ssize_t ret = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } + ret += snprintf(temp_buf, len, + "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", + HIMAX_common_NAME, ic_data->vendor_fw_ver, + ic_data->vendor_config_ver, ic_data->vendor_sensor_id); - ret += snprintf(temp_buf, len, "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", HIMAX_common_NAME, - ic_data->vendor_fw_ver, ic_data->vendor_config_ver, ic_data->vendor_sensor_id); - HX_PROC_SEND_FLAG=1; + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } -static const struct file_operations himax_proc_vendor_ops = -{ +const struct file_operations himax_proc_vendor_ops = { .owner = THIS_MODULE, .read = himax_vendor_read, }; @@ -107,29 +84,21 @@ static ssize_t himax_attn_read(struct file *file, char *buf, if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); + ret += snprintf(temp_buf, len, "attn = %x\n", + himax_int_gpio_read(ts_data->pdata->gpio_irq)); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } - -static const struct file_operations himax_proc_attn_ops = -{ +const struct file_operations himax_proc_attn_ops = { .owner = THIS_MODULE, .read = himax_attn_read, }; @@ -143,23 +112,16 @@ static ssize_t himax_int_en_read(struct file *file, char *buf, if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf, len-1, "%d ", ts->irq_enabled); + ret += snprintf(temp_buf, 1, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -167,18 +129,15 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, size_t len, loff_t *pos) { struct himax_ts_data *ts = private_ts; - char buf_tmp[12]= {0}; - int value, ret=0; + char buf_tmp[12] = {0}; + int value, ret = 0; - if (len >= 12) - { + if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf_tmp, buff, len)) - { return -EFAULT; - } if (buf_tmp[0] == '0') value = false; @@ -188,36 +147,43 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, return -EINVAL; if (value) { - if(ic_data->HX_INT_IS_EDGE) - { + if (ic_data->HX_INT_IS_EDGE) { #ifdef MTK #ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); #else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); #endif #endif #ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ts->client->name, ts); #endif - } - else - { + } else { #ifdef MTK #ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); #else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); #endif #endif #ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + ts->client->name, ts); #endif } if (ret == 0) { @@ -225,7 +191,7 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, irq_enable_count = 1; } } else { - himax_int_enable(ts->client->irq,0); + himax_int_enable(ts->client->irq, 0); free_irq(ts->client->irq, ts); ts->irq_enabled = 0; } @@ -233,8 +199,7 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_int_en_ops = -{ +const struct file_operations himax_proc_int_en_ops = { .owner = THIS_MODULE, .read = himax_int_en_read, .write = himax_int_en_write, @@ -249,26 +214,19 @@ static ssize_t himax_layout_read(struct file *file, char *buf, if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_max); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_max); + ret += snprintf(temp_buf, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -283,17 +241,14 @@ static ssize_t himax_layout_write(struct file *file, const char *buff, int layout[4] = {0}; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - for (i = 0; i < 20; i++) { + for (i = 0 ; i < 20 ; i++) { if (buf[i] == ',' || buf[i] == '\n') { memset(buf_tmp, 0x0, sizeof(buf_tmp)); if (i - j <= 5) @@ -310,20 +265,24 @@ static ssize_t himax_layout_write(struct file *file, const char *buff, } } if (k == 4) { - ts->pdata->abs_x_min=layout[0]; - ts->pdata->abs_x_max=layout[1]; - ts->pdata->abs_y_min=layout[2]; - ts->pdata->abs_y_max=layout[3]; - I("%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + ts->pdata->abs_x_min = layout[0]; + ts->pdata->abs_x_max = layout[1]; + ts->pdata->abs_y_min = layout[2]; + ts->pdata->abs_y_max = layout[3]; + I("%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); input_unregister_device(ts->input_dev); himax_input_register(ts); - } else - I("ERR@%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + } else { + I("ERR@%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + } return len; } -static const struct file_operations himax_proc_layout_ops = -{ +const struct file_operations himax_proc_layout_ops = { .owner = THIS_MODULE, .read = himax_layout_read, .write = himax_layout_write, @@ -335,26 +294,21 @@ static ssize_t himax_debug_level_read(struct file *file, char *buf, struct himax_ts_data *ts_data; size_t ret = 0; char *temp_buf; + ts_data = private_ts; if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d\n", ts_data->debug_log_level); + ret += snprintf(temp_buf, len, "%d\n", + ts_data->debug_log_level); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -365,29 +319,26 @@ static ssize_t himax_debug_level_write(struct file *file, const char *buff, struct himax_ts_data *ts; char buf_tmp[11]; int i; + ts = private_ts; - if (len >= 12) - { + if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf_tmp, buff, len)) - { return -EFAULT; - } ts->debug_log_level = 0; - for(i=0; i='0' && buf_tmp[i]<='9' ) - ts->debug_log_level |= (buf_tmp[i]-'0'); - else if( buf_tmp[i]>='A' && buf_tmp[i]<='F' ) - ts->debug_log_level |= (buf_tmp[i]-'A'+10); - else if( buf_tmp[i]>='a' && buf_tmp[i]<='f' ) - ts->debug_log_level |= (buf_tmp[i]-'a'+10); - - if(i!=len-2) + for (i = 0 ; i < len - 1 ; i++) { + if (buf_tmp[i] >= '0' && buf_tmp[i] <= '9') + ts->debug_log_level |= (buf_tmp[i] - '0'); + else if (buf_tmp[i] >= 'A' && buf_tmp[i] <= 'F') + ts->debug_log_level |= (buf_tmp[i]-'A' + 10); + else if (buf_tmp[i] >= 'a' && buf_tmp[i] <= 'f') + ts->debug_log_level |= (buf_tmp[i] - 'a' + 10); + + if (i != len - 2) ts->debug_log_level <<= 4; } @@ -395,8 +346,12 @@ static ssize_t himax_debug_level_write(struct file *file, const char *buff, if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { - ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min); - ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min); + ts->widthFactor = + (ts->pdata->screenWidth << SHIFTBITS) + / (ts->pdata->abs_x_max - ts->pdata->abs_x_min); + ts->heightFactor = + (ts->pdata->screenHeight << SHIFTBITS) + / (ts->pdata->abs_y_max - ts->pdata->abs_y_min); if (ts->widthFactor > 0 && ts->heightFactor > 0) ts->useScreenRes = 1; else { @@ -415,8 +370,7 @@ static ssize_t himax_debug_level_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_debug_level_ops = -{ +const struct file_operations himax_proc_debug_level_ops = { .owner = THIS_MODULE, .read = himax_debug_level_read, .write = himax_debug_level_write, @@ -433,35 +387,33 @@ static ssize_t himax_proc_register_read(struct file *file, char *buf, memset(data, 0x00, sizeof(data)); - I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - if(!HX_PROC_SEND_FLAG) - { + I("himax_register_show: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], register_command[3]); + + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_register_read(private_ts->client, register_command, 1, data); + himax_register_read(private_ts->client, + register_command, 1, data); - ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", + register_command[0], register_command[1], + register_command[2], register_command[3]); - for (loop_i = 0; loop_i < 128; loop_i++) { - ret += snprintf(temp_buf+ret, len-ret, "0x%2.2X ", data[loop_i]); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, + sizeof(data[loop_i]), "0x%2.2X ", data[loop_i]); if ((loop_i % 16) == 15) - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf + ret, 1, "\n"); } - ret += snprintf(temp_buf+ret, len-ret, "\n"); - HX_PROC_SEND_FLAG=1; + ret += snprintf(temp_buf + ret, len, "\n"); + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -475,40 +427,48 @@ static ssize_t himax_proc_register_write(struct file *file, const char *buff, uint8_t write_da[128]; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } memset(buf_tmp, 0x0, sizeof(buf_tmp)); memset(write_da, 0x0, sizeof(write_da)); - I("himax %s \n",buf); + I("himax %s\n", buf); if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { if (buf[2] == 'x') { memcpy(buf_tmp, buf + 3, 8); - if (!kstrtoul(buf_tmp, 16, &result)) - { - register_command[0] = (uint8_t)result; - register_command[1] = (uint8_t)(result >> 8); - register_command[2] = (uint8_t)(result >> 16); - register_command[3] = (uint8_t)(result >> 24); - } + if (!kstrtoul(buf_tmp, 16, &result)) { + register_command[0] = + (uint8_t)result; + register_command[1] = + (uint8_t)(result >> 8); + register_command[2] = + (uint8_t)(result >> 16); + register_command[3] = + (uint8_t)(result >> 24); + } base = 11; - I("CMD: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + I("CMD: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], + register_command[3]); - for (loop_i = 0; loop_i < 128 && (base+10)<80; loop_i++) { + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { if (buf[base] == '\n') { if (buf[0] == 'w') { - himax_register_write(private_ts->client, register_command, 1, write_da); - I("CMD: %x, %x, %x, %x, len=%d\n", write_da[0], write_da[1],write_da[2],write_da[3],length); + himax_register_write + (private_ts->client, + register_command + , 1, write_da); + I("CMD:%x, %x, %x, %x,len=%d\n", + write_da[0], write_da[1], + write_da[2], write_da[3], + length); } I("\n"); return len; @@ -518,12 +478,16 @@ static ssize_t himax_proc_register_write(struct file *file, const char *buff, buf_tmp[11] = '\0'; memcpy(buf_tmp, buf + base + 2, 8); if (!kstrtoul(buf_tmp, 16, &result)) { - write_da[loop_i] = (uint8_t)result; - write_da[loop_i+1] = (uint8_t)(result >> 8); - write_da[loop_i+2] = (uint8_t)(result >> 16); - write_da[loop_i+3] = (uint8_t)(result >> 24); + write_da[loop_i] = + (uint8_t)result; + write_da[loop_i+1] = + (uint8_t)(result >> 8); + write_da[loop_i+2] = + (uint8_t)(result >> 16); + write_da[loop_i+3] = + (uint8_t)(result >> 24); } - length+=4; + length += 4; } base += 10; } @@ -532,8 +496,7 @@ static ssize_t himax_proc_register_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_register_ops = -{ +const struct file_operations himax_proc_register_ops = { .owner = THIS_MODULE, .read = himax_proc_register_read, .write = himax_proc_register_write, @@ -579,15 +542,18 @@ void setYChannel(uint8_t y) } void setMutualBuffer(void) { - diag_mutual = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); + diag_mutual = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); } void setMutualNewBuffer(void) { - diag_mutual_new = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); + diag_mutual_new = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); } void setMutualOldBuffer(void) { - diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); + diag_mutual_old = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); } #ifdef HX_TP_PROC_2T2R @@ -613,94 +579,82 @@ void setYChannel_2(uint8_t y) } void setMutualBuffer_2(void) { - diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); + diag_mutual_2 = kzalloc + (x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); } #endif static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, size_t len, loff_t *pos) { - //struct himax_ts_data *ts = private_ts; + /*struct himax_ts_data *ts = private_ts;*/ char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } g_diag_arr_num = buf[0] - '0'; - I("%s: g_diag_arr_num = %d \n", __func__,g_diag_arr_num); + I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num); return len; } -static const struct file_operations himax_proc_diag_arrange_ops = -{ +const struct file_operations himax_proc_diag_arrange_ops = { .owner = THIS_MODULE, .write = himax_diag_arrange_write, }; -static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose) +static void himax_diag_arrange_print +(struct seq_file *s, int i, int j, int transpose) { - if(transpose) - seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]); + if (transpose) + seq_printf(s, "%6d", diag_mutual[j + i * x_channel]); else - seq_printf(s, "%6d", diag_mutual[ i + j*x_channel]); + seq_printf(s, "%6d", diag_mutual[i + j * x_channel]); } -static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,bool transpose, int j) +static void himax_diag_arrange_inloop +(struct seq_file *s, int in_init, bool transpose, int j) { int i; int in_max = 0; - if(transpose) + if (transpose) in_max = y_channel; else in_max = x_channel; - if (in_init > 0) - { - for(i = in_init-1;i >= 0;i--) - { + if (in_init > 0) { + for (i = in_init - 1 ; i >= 0 ; i--) himax_diag_arrange_print(s, i, j, transpose); - } - } - else - { - for (i = 0; i < in_max; i++) - { + } else { + for (i = 0 ; i < in_max ; i++) himax_diag_arrange_print(s, i, j, transpose); - } } } -static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int out_init, int in_init) +static void himax_diag_arrange_outloop +(struct seq_file *s, int transpose, int out_init, int in_init) { int j; int out_max = 0; - if(transpose) + if (transpose) out_max = x_channel; else out_max = y_channel; - if(out_init > 0) - { - for(j = out_init-1;j >= 0;j--) - { + if (out_init > 0) { + for (j = out_init - 1 ; j >= 0 ; j--) { himax_diag_arrange_inloop(s, in_init, transpose, j); seq_printf(s, " %5d\n", diag_self[j]); } - } - else - { - for(j = 0;j < out_max;j++) - { + } else { + for (j = 0 ; j < out_max ; j++) { himax_diag_arrange_inloop(s, in_init, transpose, j); seq_printf(s, " %5d\n", diag_self[j]); } @@ -709,33 +663,35 @@ static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int ou static void himax_diag_arrange(struct seq_file *s) { - int bit2,bit1,bit0; + int bit2, bit1, bit0; int i; bit2 = g_diag_arr_num >> 2; bit1 = g_diag_arr_num >> 1 & 0x1; bit0 = g_diag_arr_num & 0x1; - if (g_diag_arr_num < 4) - { - himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, bit0 * x_channel); - for (i = y_channel; i < x_channel + y_channel; i++) { + if (g_diag_arr_num < 4) { + himax_diag_arrange_outloop(s, + bit2, bit1 * y_channel, bit0 * x_channel); + + for (i = y_channel ; i < x_channel + y_channel ; i++) seq_printf(s, "%6d", diag_self[i]); - } - } - else - { - himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, bit0 * y_channel); - for (i = x_channel; i < x_channel + y_channel; i++) { + + } else { + himax_diag_arrange_outloop(s, + bit2, bit1 * x_channel, bit0 * y_channel); + + for (i = x_channel ; i < x_channel + y_channel ; i++) seq_printf(s, "%6d", diag_self[i]); - } + } } static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) { - if (*pos>=1) return NULL; - return (void *)((unsigned long) *pos+1); + if (*pos >= 1) + return NULL; + return (void *)((unsigned long) *pos + 1); } static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) @@ -748,87 +704,96 @@ static void himax_diag_seq_stop(struct seq_file *s, void *v) static int himax_diag_seq_read(struct seq_file *s, void *v) { size_t count = 0; - int32_t loop_i;//,loop_j + int32_t loop_i;/*loop_j*/ uint16_t mutual_num, self_num, width; #ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_command == 4) - { + if (Is_2T2R && diag_command == 4) { mutual_num = x_channel_2 * y_channel_2; - self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT + /*don't add KEY_COUNT*/ + self_num = x_channel_2 + y_channel_2; width = x_channel_2; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); - } - else + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel_2, y_channel_2); + } else #endif { mutual_num = x_channel * y_channel; - self_num = x_channel + y_channel; //don't add KEY_COUNT + /*don't add KEY_COUNT*/ + self_num = x_channel + y_channel; width = x_channel; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel, y_channel); } - // start to show out the raw data in adb shell + /* start to show out the raw data in adb shell*/ if (diag_command >= 1 && diag_command <= 6) { if (diag_command <= 3) { himax_diag_arrange(s); - seq_printf(s, "\n\n"); + seq_puts(s, "\n\n"); #ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%6d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) + seq_printf(s, "%6d", + diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); #endif #ifdef HX_TP_PROC_2T2R - }else if(Is_2T2R && diag_command == 4 ) { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { + } else if (Is_2T2R && diag_command == 4) { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { seq_printf(s, "%4d", diag_mutual_2[loop_i]); if ((loop_i % width) == (width - 1)) - seq_printf(s, " %6d\n", diag_self[width + loop_i/width]); + seq_printf(s, " %6d\n", + diag_self[width + loop_i / width]); } - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < width; loop_i++) { + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < width ; loop_i++) { seq_printf(s, "%6d", diag_self[loop_i]); if (((loop_i) % width) == (width - 1)) - seq_printf(s, "\n"); + seq_putc(s, '\n'); } #ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) { + seq_printf(s, "%4d", + diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); + } #endif #endif } else if (diag_command > 4) { - for (loop_i = 0; loop_i < self_num; loop_i++) { + for (loop_i = 0 ; loop_i < self_num ; loop_i++) { seq_printf(s, "%4d", diag_self[loop_i]); - if (((loop_i - mutual_num) % width) == (width - 1)) - seq_printf(s, "\n"); + if (((loop_i - mutual_num) % width) + == (width - 1)) { + seq_putc(s, '\n'); + } } } else { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { seq_printf(s, "%4d", diag_mutual[loop_i]); if ((loop_i % width) == (width - 1)) - seq_printf(s, "\n"); + seq_putc(s, '\n'); } } - seq_printf(s, "ChannelEnd"); - seq_printf(s, "\n"); + seq_puts(s, "ChannelEnd"); + seq_putc(s, '\n'); } else if (diag_command == 7) { - for (loop_i = 0; loop_i < 128 ;loop_i++) { + for (loop_i = 0; loop_i < 128 ; loop_i++) { if ((loop_i % 16) == 0) - seq_printf(s, "LineStart:"); + seq_puts(s, "LineStart:"); seq_printf(s, "%4d", diag_coor[loop_i]); if ((loop_i % 16) == 15) - seq_printf(s, "\n"); + seq_putc(s, '\n'); } - } else if (diag_command == 9 || diag_command == 91 || diag_command == 92){ + } else if (diag_command == 9 || + diag_command == 91 || diag_command == 92) { + himax_diag_arrange(s); - seq_printf(s, "\n"); + seq_putc(s, '\n'); } return count; } -static const struct seq_operations himax_diag_seq_ops = -{ +const struct seq_operations himax_diag_seq_ops = { .start = himax_diag_seq_start, .next = himax_diag_seq_next, .stop = himax_diag_seq_stop, @@ -838,25 +803,24 @@ static int himax_diag_proc_open(struct inode *inode, struct file *file) { return seq_open(file, &himax_diag_seq_ops); }; -bool DSRAM_Flag; +bool DSRAM_Flag = false; -//DSRAM thread +/*DSRAM thread*/ void himax_ts_diag_func(void) { - int i=0, j=0; + int i = 0, j = 0; unsigned int index = 0; int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; uint8_t info_data[total_size]; - int16_t *mutual_data = NULL; - int16_t *mutual_data_new = NULL; - int16_t *mutual_data_old = NULL; + int16_t *mutual_data; + int16_t *mutual_data_new; + int16_t *mutual_data_old; int16_t new_data; himax_burst_enable(private_ts->client, 1); - if(diag_command == 9 || diag_command == 91) - { + if (diag_command == 9 || diag_command == 91) { mutual_data = getMutualBuffer(); - }else if(diag_command == 92){ + } else if (diag_command == 92) { mutual_data = getMutualBuffer(); mutual_data_new = getMutualNewBuffer(); mutual_data_old = getMutualOldBuffer(); @@ -864,49 +828,63 @@ void himax_ts_diag_func(void) himax_get_DSRAM_data(private_ts->client, info_data); index = 0; - for (i = 0; i < ic_data->HX_TX_NUM; i++) - { - for (j = 0; j < ic_data->HX_RX_NUM; j++) - { - new_data = (short)(info_data[index + 1] << 8 | info_data[index]); - if(diag_command == 9){ - mutual_data[i*ic_data->HX_RX_NUM+j] = new_data; - }else if(diag_command == 91){ //Keep max data for 100 frame - if(mutual_data[i * ic_data->HX_RX_NUM + j] < new_data) - mutual_data[i * ic_data->HX_RX_NUM + j] = new_data; - }else if(diag_command == 92){ //Cal data for [N]-[N-1] frame - mutual_data_new[i * ic_data->HX_RX_NUM + j] = new_data; - mutual_data[i * ic_data->HX_RX_NUM + j] = mutual_data_new[i * ic_data->HX_RX_NUM + j] - mutual_data_old[i * ic_data->HX_RX_NUM + j]; + for (i = 0 ; i < ic_data->HX_TX_NUM ; i++) { + for (j = 0 ; j < ic_data->HX_RX_NUM ; j++) { + new_data = (short)(info_data[index + 1] + << 8 | info_data[index]); + if (diag_command == 9) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + /*Keep max data for 100 frame*/ + } else if (diag_command == 91) { + if (mutual_data[i * ic_data->HX_RX_NUM + j] + < new_data) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + } + /*Cal data for [N]-[N-1] frame*/ + } else if (diag_command == 92) { + mutual_data_new[i * ic_data->HX_RX_NUM + j] + = new_data; + + mutual_data[i * ic_data->HX_RX_NUM + j] = + mutual_data_new[i * ic_data->HX_RX_NUM + j] - + mutual_data_old[i * ic_data->HX_RX_NUM + j]; } index += 2; } } - if(diag_command == 92){ - memcpy(mutual_data_old,mutual_data_new,x_channel * y_channel * sizeof(int16_t)); //copy N data to N-1 array + /*copy N data to N-1 array*/ + if (diag_command == 92) { + memcpy(mutual_data_old, mutual_data_new, + x_channel * y_channel * sizeof(int16_t)); } + diag_max_cnt++; - if(diag_command == 9 || diag_command == 92){ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); - }else if(diag_command == 91){ - if(diag_max_cnt > 100) //count for 100 frame - { - //Clear DSRAM flag + if (diag_command == 9 || diag_command == 92) { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } else if (diag_command == 91) { + if (diag_max_cnt > 100) {/*count for 100 frame*/ + /*Clear DSRAM flag*/ DSRAM_Flag = false; - //Enable ISR - himax_int_enable(private_ts->client->irq,1); + /*Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); - //===================================== - // test result command : 0x8002_0324 ==> 0x00 - //===================================== + /*===================================== + test result command : 0x8002_0324 ==> 0x00 + =====================================*/ himax_diag_register_set(private_ts->client, 0x00); - }else{ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } else { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1 / 10 * HZ); } } } -static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) +static ssize_t himax_diag_write +(struct file *filp, const char __user *buff, size_t len, loff_t *data) { char messages[80] = {0}; @@ -915,67 +893,66 @@ static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size memset(receive, 0x00, sizeof(receive)); - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(messages, buff, len)) - { return -EFAULT; - } - if (messages[1] == 0x0A){ - diag_command =messages[0] - '0'; - }else{ - diag_command =(messages[0] - '0')*10 + (messages[1] - '0'); - } - I("[Himax]diag_command=0x%x\n",diag_command); - if (diag_command < 0x04){ - if(DSRAM_Flag) - { - //1. Clear DSRAM flag + if (messages[1] == 0x0A) + diag_command = messages[0] - '0'; + else + diag_command = (messages[0] - '0') * 10 + (messages[1] - '0'); + + + I("[Himax]diag_command=0x%x\n", diag_command); + if (diag_command < 0x04) { + if (DSRAM_Flag) { + /*1. Clear DSRAM flag*/ DSRAM_Flag = false; - //2. Stop DSRAM thread - cancel_delayed_work_sync(&private_ts->himax_diag_delay_wrok); + /*2. Stop DSRAM thread*/ + cancel_delayed_work_sync + (&private_ts->himax_diag_delay_wrok); - //3. Enable ISR - himax_int_enable(private_ts->client->irq,1); + /*3. Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); } command[0] = diag_command; himax_diag_register_set(private_ts->client, command[0]); - } - //coordinate dump start - else if (diag_command == 0x08) { - E("%s: coordinate_dump_file_create error\n", __func__); - } - else if (diag_command == 0x09 || diag_command == 91 || diag_command == 92){ + /*coordinate dump start*/ + } else if (diag_command == 0x09 || + diag_command == 91 || diag_command == 92) { + diag_max_cnt = 0; - memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime + /*Set data 0 everytime*/ + memset(diag_mutual, 0x00, + x_channel * y_channel * sizeof(int16_t)); - //1. Disable ISR - himax_int_enable(private_ts->client->irq,0); + /*1. Disable ISR*/ + himax_int_enable(private_ts->client->irq, 0); - //2. Start DSRAM thread - //himax_diag_register_set(private_ts->client, 0x0A); + /*2. Start DSRAM thread*/ + /*himax_diag_register_set(private_ts->client, 0x0A);*/ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 2*HZ/100); + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 2 * HZ / 100); I("%s: Start get raw data in DSRAM\n", __func__); - //3. Set DSRAM flag + /*3. Set DSRAM flag*/ DSRAM_Flag = true; - }else{ + } else { command[0] = 0x00; himax_diag_register_set(private_ts->client, command[0]); - E("[Himax]Diag command error!diag_command=0x%x\n",diag_command); + E("[Himax]Diag command error!diag_command=0x%x\n", + diag_command); } return len; } -static const struct file_operations himax_proc_diag_ops = -{ +const struct file_operations himax_proc_diag_ops = { .owner = THIS_MODULE, .open = himax_diag_proc_open, .read = seq_read, @@ -989,23 +966,20 @@ static ssize_t himax_reset_write(struct file *file, const char *buff, { char buf_tmp[12]; - if (len >= 12) - { + if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf_tmp, buff, len)) - { return -EFAULT; - } - //if (buf_tmp[0] == '1') - // ESD_HW_REST(); + + /*if (buf_tmp[0] == '1') + ESD_HW_REST();*/ return len; } -static const struct file_operations himax_proc_reset_ops = -{ +const struct file_operations himax_proc_reset_ops = { .owner = THIS_MODULE, .write = himax_reset_write, }; @@ -1018,291 +992,263 @@ static ssize_t himax_debug_read(struct file *file, char *buf, size_t count = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf){ - HX_PROC_SEND_FLAG=0; - return count; - } - - if (debug_level_cmd == 't') - { - if (fw_update_complete) - count += snprintf(temp_buf+count, len-count, "FW Update Complete "); - else - { - count += snprintf(temp_buf+count, len-count, "FW Update Fail "); - } - } - else if (debug_level_cmd == 'h') - { - if (handshaking_result == 0) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Running)\n", handshaking_result); - } - else if (handshaking_result == 1) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Stop)\n", handshaking_result); - } - else if (handshaking_result == 2) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (I2C Error)\n", handshaking_result); - } - else - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = error\n"); - } - } - else if (debug_level_cmd == 'v') - { - count += snprintf(temp_buf+count, len-count, "FW_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_fw_ver); - count += snprintf(temp_buf+count, len-count, "CONFIG_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_config_ver); - count += snprintf(temp_buf+count, len-count, "\n"); - } - else if (debug_level_cmd == 'd') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch IC Information :\n"); - if (IC_TYPE == HX_85XX_D_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : D\n"); - } - else if (IC_TYPE == HX_85XX_E_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : E\n"); - } - else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : ES\n"); - } - else if (IC_TYPE == HX_85XX_F_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : F\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "IC Type error.\n"); + if (debug_level_cmd == 't') { + if (fw_update_complete) { + count += snprintf(temp_buf, len, + "FW Update Complete "); + } else { + count += snprintf(temp_buf, len, + "FW Update Fail "); } - if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n"); + } else if (debug_level_cmd == 'h') { + if (handshaking_result == 0) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Running)\n", + handshaking_result); + } else if (handshaking_result == 1) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Stop)\n", + handshaking_result); + } else if (handshaking_result == 2) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (I2C Error)\n", + handshaking_result); + } else { + count += snprintf(temp_buf, len, + "Handshaking Result = error\n"); } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n"); + } else if (debug_level_cmd == 'v') { + count += snprintf(temp_buf + count, len, + "FW_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_fw_ver); + count += snprintf(temp_buf + count, len, + "CONFIG_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_config_ver); + count += snprintf(temp_buf + count, len, + "\n"); + } else if (debug_level_cmd == 'd') { + count += snprintf(temp_buf + count, len, + "Himax Touch IC Information :\n"); + if (IC_TYPE == HX_85XX_D_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : D\n"); + } else if (IC_TYPE == HX_85XX_E_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : E\n"); + } else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : ES\n"); + } else if (IC_TYPE == HX_85XX_F_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : F\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Type error.\n"); } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\n"); + if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : SW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : HW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) { + count += snprintf(temp_buf + count, len, + "IC Checksum : CRC\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Checksum error.\n"); } - else - { - count += snprintf(temp_buf+count, len-count, "IC Checksum error.\n"); + if (ic_data->HX_INT_IS_EDGE) { + count += snprintf(temp_buf + count, len, + "Interrupt : EDGE TIRGGER\n"); + } else { + count += snprintf(temp_buf + count, len, + "Interrupt : LEVEL TRIGGER\n"); } - - if (ic_data->HX_INT_IS_EDGE) - { - count += snprintf(temp_buf+count, len-count, "Interrupt : EDGE TIRGGER\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "Interrupt : LEVEL TRIGGER\n"); - } - - count += snprintf(temp_buf+count, len-count, "RX Num : %d\n", ic_data->HX_RX_NUM); - count += snprintf(temp_buf+count, len-count, "TX Num : %d\n", ic_data->HX_TX_NUM); - count += snprintf(temp_buf+count, len-count, "BT Num : %d\n", ic_data->HX_BT_NUM); - count += snprintf(temp_buf+count, len-count, "X Resolution : %d\n", ic_data->HX_X_RES); - count += snprintf(temp_buf+count, len-count, "Y Resolution : %d\n", ic_data->HX_Y_RES); - count += snprintf(temp_buf+count, len-count, "Max Point : %d\n", ic_data->HX_MAX_PT); - count += snprintf(temp_buf+count, len-count, "XY reverse : %d\n", ic_data->HX_XY_REVERSE); + count += snprintf(temp_buf + count, len, + "RX Num : %d\n", ic_data->HX_RX_NUM); + count += snprintf(temp_buf + count, len, + "TX Num : %d\n", ic_data->HX_TX_NUM); + count += snprintf(temp_buf + count, len, + "BT Num : %d\n", ic_data->HX_BT_NUM); + count += snprintf(temp_buf + count, len, + "X Resolution : %d\n", ic_data->HX_X_RES); + count += snprintf(temp_buf + count, len, + "Y Resolution : %d\n", ic_data->HX_Y_RES); + count += snprintf(temp_buf + count, len, + "Max Point : %d\n", ic_data->HX_MAX_PT); + count += snprintf(temp_buf + count, len, + "XY reverse : %d\n", ic_data->HX_XY_REVERSE); #ifdef HX_TP_PROC_2T2R - if(Is_2T2R) - { - count += snprintf(temp_buf+count, len-count, "2T2R panel\n"); - count += snprintf(temp_buf+count, len-count, "RX Num_2 : %d\n", HX_RX_NUM_2); - count += snprintf(temp_buf+count, len-count, "TX Num_2 : %d\n", HX_TX_NUM_2); + if (Is_2T2R) { + count += snprintf(temp_buf + count, len, + "2T2R panel\n"); + count += snprintf(temp_buf + count, len, + "RX Num_2 : %d\n", HX_RX_NUM_2); + count += snprintf(temp_buf + count, len, + "TX Num_2 : %d\n", HX_TX_NUM_2); } #endif - } - else if (debug_level_cmd == 'i') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch Driver Version:\n"); - count += snprintf(temp_buf+count, len-count, "%s\n", HIMAX_DRIVER_VER); + } else if (debug_level_cmd == 'i') { + count += snprintf(temp_buf + count, len, + "Himax Touch Driver Version:\n"); + count += snprintf(temp_buf + count, len, + "%s\n", HIMAX_DRIVER_VER); } if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; return count; } static ssize_t himax_debug_write(struct file *file, const char *buff, size_t len, loff_t *pos) { - const struct firmware *fw = NULL; - unsigned char *fw_data = NULL; + int result = 0; char fileName[128]; char buf[80] = {0}; - int result; + const struct firmware *fw = NULL; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if ( buf[0] == 'h') //handshaking - { + if (buf[0] == 'h') {/*handshaking*/ debug_level_cmd = buf[0]; - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); - handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail + /*0:Running, 1:Stop, 2:I2C Fail*/ + handshaking_result = himax_hand_shaking(private_ts->client); - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); return len; - } - - else if ( buf[0] == 'v') //firmware version - { + } else if (buf[0] == 'v') { /*firmware version*/ debug_level_cmd = buf[0]; - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); #ifdef HX_RST_PIN_FUNC - himax_HW_reset(false,false); + himax_HW_reset(false, false); #endif himax_read_FW_ver(private_ts->client); - //himax_check_chip_version(); + /*himax_check_chip_version();*/ #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); return len; - } + } else if (buf[0] == 'd') { /*ic information*/ - else if ( buf[0] == 'd') //ic information - { debug_level_cmd = buf[0]; return len; - } + } else if (buf[0] == 'i') {/*driver version*/ - else if ( buf[0] == 'i') //driver version - { debug_level_cmd = buf[0]; return len; - } - - else if (buf[0] == 't') - { + } else if (buf[0] == 't') { - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); + debug_level_cmd = buf[0]; + fw_update_complete = false; - debug_level_cmd = buf[0]; - fw_update_complete = false; + result = himax_load_CRC_bin_file(private_ts->client); + if (result < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, result); + return result; + } memset(fileName, 0, 128); - // parse the file name +/* parse the file name*/ snprintf(fileName, len-4, "%s", &buf[4]); I("%s: upgrade from file(%s) start!\n", __func__, fileName); - // open file result = request_firmware(&fw, fileName, private_ts->dev); - if (result) { - E("%s: open firmware file failed\n", __func__); - goto firmware_upgrade_done; - //return len; - } - - I("%s: FW len %d\n", __func__, fw->size); - fw_data = (unsigned char *)fw->data; - - I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); - - if (fw_data != NULL) - { - // start to upgrade - himax_int_enable(private_ts->client->irq,0); - - if ((buf[1] == '6') && (buf[2] == '0')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + if (result < 0) { + I("fail to request_firmware fwpath: %s (ret:%d)\n", + fileName, result); + return result; + } + I("%s: FW image: %02X, %02X, %02X, %02X ret=%d\n", __func__, + fw->data[0], fw->data[1], fw->data[2], fw->data[3], result); + if (result >= 0) { + /*start to upgrade*/ + himax_int_enable(private_ts->client->irq, 0); + + if ((buf[1] == '6') && (buf[2] == '0')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else if ((buf[1] == '6') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + } else if ((buf[1] == '6') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else if ((buf[1] == '2') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + } else if ((buf[1] == '2') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else if ((buf[1] == '2') && (buf[2] == '8')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + } else if ((buf[1] == '2') && (buf[2] == '8')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else - { - E("%s: Flash command fail: %d\n", __func__, __LINE__); + } else { + E("%s: Flash command fail: %d\n", + __func__, __LINE__); fw_update_complete = false; } release_firmware(fw); goto firmware_upgrade_done; - //return count; + /*return count;*/ } } - firmware_upgrade_done: +firmware_upgrade_done: #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif himax_sense_on(private_ts->client, 0x01); @@ -1310,16 +1256,15 @@ static ssize_t himax_debug_write(struct file *file, const char *buff, #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; #endif - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); - //todo himax_chip->tp_firmware_upgrade_proceed = 0; - //todo himax_chip->suspend_state = 0; - //todo enable_irq(himax_chip->irq); + /*todo himax_chip->tp_firmware_upgrade_proceed = 0; + todo himax_chip->suspend_state = 0; + todo enable_irq(himax_chip->irq);*/ return len; } -static const struct file_operations himax_proc_debug_ops = -{ +const struct file_operations himax_proc_debug_ops = { .owner = THIS_MODULE, .read = himax_debug_read, .write = himax_debug_write, @@ -1376,9 +1321,9 @@ bool getFlashDumpGoing(void) void setFlashBuffer(void) { - flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL); - if (flash_buffer) - memset(flash_buffer,0x00,Flash_Size); + flash_buffer = kzalloc + (Flash_Size * sizeof(uint8_t), GFP_KERNEL); + memset(flash_buffer, 0x00, Flash_Size); } void setSysOperation(uint8_t operation) @@ -1389,7 +1334,8 @@ void setSysOperation(uint8_t operation) static void setFlashDumpProgress(uint8_t progress) { flash_progress = progress; - //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress); + /*I("setFlashDumpProgress : progress = %d , + flash_progress = %d\n",progress,flash_progress);*/ } static void setFlashDumpComplete(uint8_t status) @@ -1432,130 +1378,113 @@ static ssize_t himax_proc_flash_read(struct file *file, char *buf, { int ret = 0; int loop_i; - uint8_t local_flash_read_step=0; + uint8_t local_flash_read_step = 0; uint8_t local_flash_complete = 0; uint8_t local_flash_progress = 0; uint8_t local_flash_command = 0; uint8_t local_flash_fail = 0; char *temp_buf; + local_flash_complete = getFlashDumpComplete(); local_flash_progress = getFlashDumpProgress(); local_flash_command = getFlashCommand(); local_flash_fail = getFlashDumpFail(); - I("flash_progress = %d \n",local_flash_progress); - if(!HX_PROC_SEND_FLAG) - { + I("flash_progress = %d\n", local_flash_progress); + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - - if (local_flash_fail) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Fail \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (local_flash_fail) { + ret += snprintf(temp_buf + ret, len, + "FlashStart:Fail\n"); + ret += snprintf(temp_buf + ret, len, + "FlashEnd"); + ret += snprintf(temp_buf + ret, len, + "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - if (!local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (!local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Ongoing:0x%2.2x\n", flash_progress); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - if (local_flash_command == 1 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Complete \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (local_flash_command == 1 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Complete\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - if (local_flash_command == 3 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart: \n"); - for(loop_i = 0; loop_i < 128; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2x", flash_buffer[loop_i]); + if (local_flash_command == 3 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, "FlashStart:\n"); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, + "x%2.2x", flash_buffer[loop_i]); if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } + ret += snprintf(temp_buf + ret, len, + "\n"); } - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - //flash command == 0 , report the data + /*flash command == 0 , report the data*/ local_flash_read_step = getFlashReadStep(); - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:%2.2x \n",local_flash_read_step); + ret += snprintf(temp_buf + ret, len, + "FlashStart:%2.2x\n", local_flash_read_step); - for (loop_i = 0; loop_i < 1024; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]); + for (loop_i = 0 ; loop_i < 1024 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, "x%2.2X", + flash_buffer[local_flash_read_step * 1024 + loop_i]); if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } + ret += snprintf(temp_buf + ret, len, "\n"); } - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } -static ssize_t himax_proc_flash_write(struct file *file, const char *buff, - size_t len, loff_t *pos) +static ssize_t himax_proc_flash_write(struct file *file, +const char *buff, size_t len, loff_t *pos) { char buf_tmp[6]; unsigned long result = 0; @@ -1563,85 +1492,74 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, int base = 0; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } memset(buf_tmp, 0x0, sizeof(buf_tmp)); I("%s: buf[0] = %s\n", __func__, buf); - if (getSysOperation() == 1) - { + if (getSysOperation() == 1) { E("%s: PROC is busy , return!\n", __func__); return len; } - if (buf[0] == '0') - { + if (buf[0] == '0') { setFlashCommand(0); - if (buf[1] == ':' && buf[2] == 'x') - { + if (buf[1] == ':' && buf[2] == 'x') { memcpy(buf_tmp, buf + 3, 2); I("%s: read_Step = %s\n", __func__, buf_tmp); - if (!kstrtoul(buf_tmp, 16, &result)) - { - I("%s: read_Step = %lu \n", __func__, result); + if (!kstrtoul(buf_tmp, 16, &result)) { + I("%s: read_Step = %lu\n", __func__, result); setFlashReadStep(result); } } - } - else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k - { + /* 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '1') { + setSysOperation(1); setFlashCommand(1); setFlashDumpProgress(0); setFlashDumpComplete(0); setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ + else if (buf[3] == '4') Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ + else if (buf[3] == '8') Flash_Size = FW_SIZE_128k; - } } queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '2') // 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k - { + /* 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '2') { setSysOperation(1); setFlashCommand(2); setFlashDumpProgress(0); setFlashDumpComplete(0); setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ + else if (buf[3] == '4') Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ + else if (buf[3] == '8') Flash_Size = FW_SIZE_128k; - } + } queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '3') - { + } else if (buf[0] == '3') { setSysOperation(1); setFlashCommand(3); setFlashDumpProgress(0); @@ -1650,20 +1568,14 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, memcpy(buf_tmp, buf + 3, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpSector(result); - } memcpy(buf_tmp, buf + 7, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpPage(result); - } queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '4') - { + } else if (buf[0] == '4') { I("%s: command 4 enter.\n", __func__); setSysOperation(1); setFlashCommand(4); @@ -1673,40 +1585,29 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, memcpy(buf_tmp, buf + 3, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpSector(result); - } else - { E("%s: command 4 , sector error.\n", __func__); return len; - } + memcpy(buf_tmp, buf + 7, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpPage(result); - } else - { E("%s: command 4 , page error.\n", __func__); return len; - } base = 11; I("=========Himax flash page buffer start=========\n"); - for(loop_i=0;loop_i<128 && base<80;loop_i++) - { + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { memcpy(buf_tmp, buf + base, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { + if (!kstrtoul(buf_tmp, 16, &result)) { flash_buffer[loop_i] = result; - I("%d ",flash_buffer[loop_i]); + I("%d ", flash_buffer[loop_i]); if (loop_i % 16 == 15) - { I("\n"); - } } base += 3; } @@ -1717,8 +1618,7 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_flash_ops = -{ +const struct file_operations himax_proc_flash_ops = { .owner = THIS_MODULE, .read = himax_proc_flash_read, .write = himax_proc_flash_write, @@ -1728,31 +1628,44 @@ void himax_ts_flash_func(void) { uint8_t local_flash_command = 0; - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); setFlashDumpGoing(true); - //sector = getFlashDumpSector(); - //page = getFlashDumpPage(); + /*sector = getFlashDumpSector();*/ + /*page = getFlashDumpPage();*/ local_flash_command = getFlashCommand(); msleep(100); - I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command); + I("%s: local_flash_command = %d enter.\n", + __func__, local_flash_command); - if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command==0x0F)) - { - himax_flash_dump_func(private_ts->client, local_flash_command,Flash_Size, flash_buffer); + if ((local_flash_command == 1 || local_flash_command == 2) + || (local_flash_command == 0x0F)) { + himax_flash_dump_func(private_ts->client, + local_flash_command, Flash_Size, flash_buffer); } + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); - if (local_flash_command == 2) - { - E("Flash dump failed\n"); + if (local_flash_command == 2) { + struct file *fn; + struct filename *vts_name; + + vts_name = getname_kernel(FLASH_DUMP_FILE); + fn = file_open_name(vts_name, O_CREAT | O_WRONLY, 0); + if (!IS_ERR(fn)) { + I("%s create file and ready to write\n", __func__); + fn->f_op->write(fn, flash_buffer, + Flash_Size * sizeof(uint8_t), &fn->f_pos); + + filp_close(fn, NULL); + } } - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); setFlashDumpGoing(false); setFlashDumpComplete(1); @@ -1761,7 +1674,7 @@ void himax_ts_flash_func(void) /* Flash_Dump_i2c_transfer_error: - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); setFlashDumpGoing(false); setFlashDumpComplete(0); setFlashDumpFail(1); @@ -1776,53 +1689,47 @@ void himax_ts_flash_func(void) static ssize_t himax_self_test_read(struct file *file, char *buf, size_t len, loff_t *pos) { - int val=0x00; + int val = 0x00; int ret = 0; char *temp_buf; - I("%s: enter, %d \n", __func__, __LINE__); - if(!HX_PROC_SEND_FLAG) - { + I("%s:enter, %d\n", __func__, __LINE__); + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_int_enable(private_ts->client->irq,0);//disable irq + himax_int_enable(private_ts->client->irq, 0);/*disable irq*/ val = himax_chip_self_test(private_ts->client); #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; #endif - himax_int_enable(private_ts->client->irq,1);//enable irq + himax_int_enable(private_ts->client->irq, 1);/*enable irq*/ if (val == 0x01) { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n"); + ret += snprintf(temp_buf + ret, len, + "Self_Test Pass\n"); } else { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Fail\n"); + ret += snprintf(temp_buf + ret, len, + "Self_Test Fail\n"); } - if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } /* -static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count) +static ssize_t himax_chip_self_test_store(struct device *dev, +struct device_attribute *attr, const char *buf, size_t count) { char buf_tmp[2]; unsigned long result = 0; memset(buf_tmp, 0x0, sizeof(buf_tmp)); memcpy(buf_tmp, buf, 2); - if(!kstrtoul(buf_tmp, 16, &result)) + if (!kstrtoul(buf_tmp, 16, &result)) { sel_type = (uint8_t)result; } @@ -1831,8 +1738,7 @@ static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attri } */ -static const struct file_operations himax_proc_self_test_ops = -{ +const struct file_operations himax_proc_self_test_ops = { .owner = THIS_MODULE, .read = himax_self_test_read, }; @@ -1844,42 +1750,33 @@ static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, { char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if(buf[0] == '0') - { + if (buf[0] == '0') { himax_sense_off(private_ts->client); - I("Sense off \n"); - } - else if(buf[0] == '1') - { - if(buf[1] == '1'){ + I("Sense off\n"); + } else if (buf[0] == '1') { + if (buf[1] == '1') { himax_sense_on(private_ts->client, 0x01); - I("Sense on re-map off, run flash \n"); - }else if(buf[1] == '0'){ + I("Sense on re-map off, run flash\n"); + } else if (buf[1] == '0') { himax_sense_on(private_ts->client, 0x00); - I("Sense on re-map on, run sram \n"); - }else{ - I("Do nothing \n"); + I("Sense on re-map on, run sram\n"); + } else { + I("Do nothing\n"); } - } - else - { - I("Do nothing \n"); + } else { + I("Do nothing\n"); } return len; } -static const struct file_operations himax_proc_sense_on_off_ops = -{ +const struct file_operations himax_proc_sense_on_off_ops = { .owner = THIS_MODULE, .write = himax_sense_on_off_write, }; @@ -1893,25 +1790,18 @@ static ssize_t himax_HSEN_read(struct file *file, char *buf, size_t count = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); - HX_PROC_SEND_FLAG=1; + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } + kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return count; } @@ -1922,22 +1812,17 @@ static ssize_t himax_HSEN_write(struct file *file, const char *buff, char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if (buf[0] == '0'){ + if (buf[0] == '0') ts->HSEN_enable = 0; - } - else if (buf[0] == '1'){ + else if (buf[0] == '1') ts->HSEN_enable = 1; - } else return -EINVAL; @@ -1948,8 +1833,7 @@ static ssize_t himax_HSEN_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_HSEN_ops = -{ +const struct file_operations himax_proc_HSEN_ops = { .owner = THIS_MODULE, .read = himax_HSEN_read, .write = himax_HSEN_write, @@ -1964,25 +1848,17 @@ static ssize_t himax_SMWP_read(struct file *file, char *buf, struct himax_ts_data *ts = private_ts; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } - count = snprintf(temp_buf, len, "%d\n", ts->SMWP_enable); + count = snprintf(temp_buf, "%d\n", len, ts->SMWP_enable); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; return count; } @@ -1993,25 +1869,17 @@ static ssize_t himax_SMWP_write(struct file *file, const char *buff, struct himax_ts_data *ts = private_ts; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if (buf[0] == '0') - { ts->SMWP_enable = 0; - } else if (buf[0] == '1') - { ts->SMWP_enable = 1; - } else return -EINVAL; @@ -2022,41 +1890,33 @@ static ssize_t himax_SMWP_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_SMWP_ops = -{ +const struct file_operations himax_proc_SMWP_ops = { .owner = THIS_MODULE, .read = himax_SMWP_read, .write = himax_SMWP_write, }; -static ssize_t himax_GESTURE_read(struct file *file, char *buf, - size_t len, loff_t *pos) +static ssize_t himax_GESTURE_read(struct file *file, +char *buf, size_t len, loff_t *pos) { struct himax_ts_data *ts = private_ts; - int i =0; + int i = 0; int ret = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - for(i=0;i<16;i++) - ret += snprintf(temp_buf+ret, len-ret, "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + for (i = 0 ; i < 16 ; i++) + ret += snprintf(temp_buf + ret, len, + "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - { + } else { HX_PROC_SEND_FLAG = 0; ret = 0; } @@ -2067,35 +1927,30 @@ static ssize_t himax_GESTURE_write(struct file *file, const char *buff, size_t len, loff_t *pos) { struct himax_ts_data *ts = private_ts; - int i =0; + int i = 0; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - I("himax_GESTURE_store= %s \n",buf); - for (i=0;i<16;i++) - { + I("himax_GESTURE_store= %s\n", buf); + for (i = 0 ; i < 16 ; i++) { if (buf[i] == '0') - ts->gesture_cust_en[i]= 0; + ts->gesture_cust_en[i] = 0; else if (buf[i] == '1') - ts->gesture_cust_en[i]= 1; + ts->gesture_cust_en[i] = 1; else - ts->gesture_cust_en[i]= 0; - I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]); + ts->gesture_cust_en[i] = 0; + I("gesture en[%d]=%d\n", i, ts->gesture_cust_en[i]); } return len; } -static const struct file_operations himax_proc_Gesture_ops = -{ +const struct file_operations himax_proc_Gesture_ops = { .owner = THIS_MODULE, .read = himax_GESTURE_read, .write = himax_GESTURE_write, @@ -2104,202 +1959,223 @@ static const struct file_operations himax_proc_Gesture_ops = int himax_touch_proc_init(void) { - himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); - if (himax_touch_proc_dir == NULL) - { + himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL); + if (himax_touch_proc_dir == NULL) { E(" %s: himax_touch_proc_dir file create failed!\n", __func__); return -ENOMEM; } - himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); - if (himax_proc_debug_level_file == NULL) - { + himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); + + if (himax_proc_debug_level_file == NULL) { E(" %s: proc debug_level file create failed!\n", __func__); goto fail_1; } - himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_vendor_ops); - if(himax_proc_vendor_file == NULL) - { + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_vendor_ops); + + if (himax_proc_vendor_file == NULL) { E(" %s: proc vendor file create failed!\n", __func__); goto fail_2; } - himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_attn_ops); - if(himax_proc_attn_file == NULL) - { + himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_attn_ops); + + if (himax_proc_attn_file == NULL) { E(" %s: proc attn file create failed!\n", __func__); goto fail_3; } - himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); - if(himax_proc_int_en_file == NULL) - { + himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); + + if (himax_proc_int_en_file == NULL) { E(" %s: proc int en file create failed!\n", __func__); goto fail_4; } - himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); - if(himax_proc_layout_file == NULL) - { + himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); + + if (himax_proc_layout_file == NULL) { E(" %s: proc layout file create failed!\n", __func__); goto fail_5; } #ifdef HX_TP_PROC_RESET - himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); - if(himax_proc_reset_file == NULL) - { + himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, + (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); + + if (himax_proc_reset_file == NULL) { E(" %s: proc reset file create failed!\n", __func__); goto fail_6; } #endif #ifdef HX_TP_PROC_DIAG - himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); - if(himax_proc_diag_file == NULL) - { + himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); + + if (himax_proc_diag_file == NULL) { E(" %s: proc diag file create failed!\n", __func__); goto fail_7; } - himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_arrange_ops); - if(himax_proc_diag_arrange_file == NULL) - { + himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, + (S_IWUSR | S_IRUGO), + himax_touch_proc_dir, &himax_proc_diag_arrange_ops); + + if (himax_proc_diag_arrange_file == NULL) { E(" %s: proc diag file create failed!\n", __func__); goto fail_7_1; } #endif #ifdef HX_TP_PROC_REGISTER - himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); - if(himax_proc_register_file == NULL) - { + himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); + + if (himax_proc_register_file == NULL) { E(" %s: proc register file create failed!\n", __func__); goto fail_8; } #endif #ifdef HX_TP_PROC_DEBUG - himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); - if(himax_proc_debug_file == NULL) - { + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); + + if (himax_proc_debug_file == NULL) { E(" %s: proc debug file create failed!\n", __func__); goto fail_9; } #endif #ifdef HX_TP_PROC_FLASH_DUMP - himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); - if(himax_proc_flash_dump_file == NULL) - { + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); + + if (himax_proc_flash_dump_file == NULL) { E(" %s: proc flash dump file create failed!\n", __func__); goto fail_10; } #endif #ifdef HX_TP_PROC_SELF_TEST - himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); - if(himax_proc_self_test_file == NULL) - { + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); + + if (himax_proc_self_test_file == NULL) { E(" %s: proc self_test file create failed!\n", __func__); goto fail_11; } #endif #ifdef HX_HIGH_SENSE - himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_HSEN_ops); - if(himax_proc_HSEN_file == NULL) - { + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_HSEN_ops); + + if (himax_proc_HSEN_file == NULL) { E(" %s: proc HSEN file create failed!\n", __func__); goto fail_12; } #endif #ifdef HX_SMART_WAKEUP - himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_SMWP_ops); - if(himax_proc_SMWP_file == NULL) - { + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_SMWP_ops); + + if (himax_proc_SMWP_file == NULL) { E(" %s: proc SMWP file create failed!\n", __func__); goto fail_13; } - himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_Gesture_ops); - if(himax_proc_GESTURE_file == NULL) - { + + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_Gesture_ops); + + if (himax_proc_GESTURE_file == NULL) { E(" %s: proc GESTURE file create failed!\n", __func__); goto fail_14; } #endif #ifdef HX_TP_PROC_SENSE_ON_OFF - himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_sense_on_off_ops); - if(himax_proc_SENSE_ON_OFF_file == NULL) - { + himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_sense_on_off_ops); + + if (himax_proc_SENSE_ON_OFF_file == NULL) { E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); goto fail_15; } #endif - return 0 ; + return 0; #ifdef HX_TP_PROC_SENSE_ON_OFF - fail_15: +fail_15: #endif #ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - fail_14: - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); - fail_13: + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); +fail_14: + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +fail_13: #endif #ifdef HX_HIGH_SENSE - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); - fail_12: + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +fail_12: #endif #ifdef HX_TP_PROC_SELF_TEST - remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir ); - fail_11: + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +fail_11: #endif #ifdef HX_TP_PROC_FLASH_DUMP - remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir ); - fail_10: + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +fail_10: #endif #ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); - fail_9: + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +fail_9: #endif #ifdef HX_TP_PROC_REGISTER - remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir ); - fail_8: + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +fail_8: #endif #ifdef HX_TP_PROC_DIAG - remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir ); - fail_7: - remove_proc_entry( HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir ); - fail_7_1: + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +fail_7: + remove_proc_entry(HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir); +fail_7_1: #endif #ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); - fail_6: + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); +fail_6: #endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); +fail_5: remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); +fail_4: remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); +fail_3: remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +fail_2: remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); +fail_1: remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); return -ENOMEM; } void himax_touch_proc_deinit(void) { #ifdef HX_TP_PROC_SENSE_ON_OFF - remove_proc_entry( HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir); #endif #ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); #endif #ifdef HX_DOT_VIEW - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_SELF_TEST remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); @@ -2308,7 +2184,7 @@ void himax_touch_proc_deinit(void) remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_REGISTER remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); @@ -2317,13 +2193,13 @@ void himax_touch_proc_deinit(void) remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); #endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); } #endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h index 91a7ae2eb7abad857bcc254389074a39239fb4f1..7a24a170eaca95a320c37c3db65431f88b5d75b7 100644 --- a/drivers/input/touchscreen/hxchipset/himax_debug.h +++ b/drivers/input/touchscreen/hxchipset/himax_debug.h @@ -17,7 +17,7 @@ #include "himax_common.h" #if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - #define HIMAX_PROC_TOUCH_FOLDER "android_touch" + #define HIMAX_PROC_TOUCH_FOLDER "android_touch" #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" #define HIMAX_PROC_VENDOR_FILE "vendor" #define HIMAX_PROC_ATTN_FILE "attn" @@ -33,60 +33,76 @@ uint8_t HX_PROC_SEND_FLAG; -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -bool getFlashDumpGoing(void); + extern int himax_touch_proc_init(void); + extern void himax_touch_proc_deinit(void); + bool getFlashDumpGoing(void); + + extern struct himax_ic_data *ic_data; + extern struct himax_ts_data *private_ts; + extern unsigned char IC_TYPE; + extern unsigned char IC_CHECKSUM; + +#ifdef QCT + extern irqreturn_t himax_ts_thread(int irq, void *ptr); +#endif +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); +#else + extern void tpd_eint_interrupt_handler(void); +#endif +#endif #ifdef HX_TP_PROC_REGISTER #define HIMAX_PROC_REGISTER_FILE "register" - struct proc_dir_entry *himax_proc_register_file; + struct proc_dir_entry *himax_proc_register_file = NULL; uint8_t register_command[4]; #endif #ifdef HX_TP_PROC_DIAG #define HIMAX_PROC_DIAG_FILE "diag" - struct proc_dir_entry *himax_proc_diag_file; + struct proc_dir_entry *himax_proc_diag_file = NULL; #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" - struct proc_dir_entry *himax_proc_diag_arrange_file; + struct proc_dir_entry *himax_proc_diag_arrange_file = NULL; #ifdef HX_TP_PROC_2T2R static bool Is_2T2R; static uint8_t x_channel_2; static uint8_t y_channel_2; static uint8_t *diag_mutual_2; - + int16_t *getMutualBuffer_2(void); - uint8_t getXChannel_2(void); - uint8_t getYChannel_2(void); - - void setMutualBuffer_2(void); - void setXChannel_2(uint8_t x); - void setYChannel_2(uint8_t y); + uint8_t getXChannel_2(void); + uint8_t getYChannel_2(void); + + void setMutualBuffer_2(void); + void setXChannel_2(uint8_t x); + void setYChannel_2(uint8_t y); #endif - uint8_t x_channel; - uint8_t y_channel; - int16_t *diag_mutual; - int16_t *diag_mutual_new; - int16_t *diag_mutual_old; - uint8_t diag_max_cnt; - - int diag_command; - uint8_t diag_coor[128];// = {0xFF}; + uint8_t x_channel = 0; + uint8_t y_channel = 0; + int16_t *diag_mutual = NULL; + int16_t *diag_mutual_new = NULL; + int16_t *diag_mutual_old = NULL; + uint8_t diag_max_cnt = 0; + + int diag_command = 0; + uint8_t diag_coor[128];/* = {0xFF};*/ int16_t diag_self[100] = {0}; int16_t *getMutualBuffer(void); int16_t *getMutualNewBuffer(void); int16_t *getMutualOldBuffer(void); int16_t *getSelfBuffer(void); - uint8_t getDiagCommand(void); - uint8_t getXChannel(void); - uint8_t getYChannel(void); - - void setMutualBuffer(void); - void setMutualNewBuffer(void); - void setMutualOldBuffer(void); - void setXChannel(uint8_t x); - void setYChannel(uint8_t y); + uint8_t getDiagCommand(void); + uint8_t getXChannel(void); + uint8_t getYChannel(void); + + void setMutualBuffer(void); + void setMutualNewBuffer(void); + void setMutualOldBuffer(void); + void setXChannel(uint8_t x); + void setYChannel(uint8_t y); uint8_t coordinate_dump_enable = 0; struct file *coordinate_fn; #endif @@ -106,24 +122,24 @@ bool getFlashDumpGoing(void); struct proc_dir_entry *himax_proc_flash_dump_file = NULL; static int Flash_Size = 131072; - static uint8_t *flash_buffer = NULL; - static uint8_t flash_command = 0; - static uint8_t flash_read_step = 0; - static uint8_t flash_progress = 0; - static uint8_t flash_dump_complete = 0; - static uint8_t flash_dump_fail = 0; - static uint8_t sys_operation = 0; - static uint8_t flash_dump_sector = 0; - static uint8_t flash_dump_page = 0; - static bool flash_dump_going = false; + static uint8_t *flash_buffer; + static uint8_t flash_command; + static uint8_t flash_read_step; + static uint8_t flash_progress; + static uint8_t flash_dump_complete; + static uint8_t flash_dump_fail; + static uint8_t sys_operation; + static uint8_t flash_dump_sector; + static uint8_t flash_dump_page; + static bool flash_dump_going; static uint8_t getFlashCommand(void); static uint8_t getFlashDumpComplete(void); static uint8_t getFlashDumpFail(void); static uint8_t getFlashDumpProgress(void); static uint8_t getFlashReadStep(void); - //static uint8_t getFlashDumpSector(void); - //static uint8_t getFlashDumpPage(void); + /*static uint8_t getFlashDumpSector(void);*/ + /*static uint8_t getFlashDumpPage(void);*/ void setFlashBuffer(void); uint8_t getSysOperation(void); @@ -150,8 +166,8 @@ bool getFlashDumpGoing(void); #ifdef HX_TP_PROC_RESET #define HIMAX_PROC_RESET_FILE "reset" -extern void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); -struct proc_dir_entry *himax_proc_reset_file = NULL; +extern void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); +struct proc_dir_entry *himax_proc_reset_file; #endif #ifdef HX_HIGH_SENSE @@ -165,16 +181,16 @@ struct proc_dir_entry *himax_proc_reset_file = NULL; #endif #ifdef HX_RST_PIN_FUNC - void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); + void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); #endif #ifdef HX_SMART_WAKEUP #define HIMAX_PROC_SMWP_FILE "SMWP" -struct proc_dir_entry *himax_proc_SMWP_file = NULL; +struct proc_dir_entry *himax_proc_SMWP_file; #define HIMAX_PROC_GESTURE_FILE "GESTURE" -struct proc_dir_entry *himax_proc_GESTURE_file = NULL; -uint8_t HX_SMWP_EN = 0; -//extern bool FAKE_POWER_KEY_SEND; +struct proc_dir_entry *himax_proc_GESTURE_file; +uint8_t HX_SMWP_EN; +/*extern bool FAKE_POWER_KEY_SEND;*/ #endif #endif diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c index 6ad8dc03149b4b339504ee87e4abeba67dc7d28b..e2934c2d2396086c4727c81d0e86872490ef22fc 100644 --- a/drivers/input/touchscreen/hxchipset/himax_ic.c +++ b/drivers/input/touchscreen/hxchipset/himax_ic.c @@ -15,45 +15,31 @@ #include "himax_ic.h" -static unsigned char i_TP_CRC_FW_128K[]= -{ - #include "HX_CRC_128.i" -}; -static unsigned char i_TP_CRC_FW_64K[]= -{ - #include "HX_CRC_64.i" -}; -static unsigned char i_TP_CRC_FW_124K[]= -{ - #include "HX_CRC_124.i" -}; -static unsigned char i_TP_CRC_FW_60K[]= -{ - #include "HX_CRC_60.i" -}; - - -unsigned long FW_VER_MAJ_FLASH_ADDR; -unsigned long FW_VER_MAJ_FLASH_LENG; -unsigned long FW_VER_MIN_FLASH_ADDR; -unsigned long FW_VER_MIN_FLASH_LENG; -unsigned long CFG_VER_MAJ_FLASH_ADDR; -unsigned long CFG_VER_MAJ_FLASH_LENG; -unsigned long CFG_VER_MIN_FLASH_ADDR; -unsigned long CFG_VER_MIN_FLASH_LENG; - -unsigned char IC_TYPE = 0; -unsigned char IC_CHECKSUM = 0; - -extern struct himax_ic_data* ic_data; - -int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C Fail +const struct firmware *i_TP_CRC_FW_128K; +const struct firmware *i_TP_CRC_FW_64K; +const struct firmware *i_TP_CRC_FW_124K; +const struct firmware *i_TP_CRC_FW_60K; + +unsigned long FW_VER_MAJ_FLASH_ADDR; +unsigned long FW_VER_MAJ_FLASH_LENG; +unsigned long FW_VER_MIN_FLASH_ADDR; +unsigned long FW_VER_MIN_FLASH_LENG; +unsigned long CFG_VER_MAJ_FLASH_ADDR; +unsigned long CFG_VER_MAJ_FLASH_LENG; +unsigned long CFG_VER_MIN_FLASH_ADDR; +unsigned long CFG_VER_MIN_FLASH_LENG; + +unsigned char IC_TYPE; +unsigned char IC_CHECKSUM; + + /*0:Running, 1:Stop, 2:I2C Fail*/ +int himax_hand_shaking(struct i2c_client *client) { int ret, result; uint8_t hw_reset_check[1]; uint8_t hw_reset_check_2[1]; uint8_t buf0[2]; - uint8_t IC_STATUS_CHECK = 0xAA; + uint8_t IC_STATUS_CHECK = 0xAA; memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); @@ -67,45 +53,50 @@ int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C IC_STATUS_CHECK = 0xAA; } - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:write 0xF2 failed line: %d \n",__LINE__); + E("[Himax]:write 0xF2 failed line: %d\n", __LINE__); goto work_func_send_i2c_msg_fail; } - msleep(50); - + msleep(50); + buf0[0] = 0xF2; buf0[1] = 0x00; - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:write 0x92 failed line: %d \n",__LINE__); + E("[Himax]:write 0x92 failed line: %d\n", __LINE__); goto work_func_send_i2c_msg_fail; } - usleep_range(2000, 4000); - - ret = i2c_himax_read(client, 0xD1, hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); + usleep_range(1999, 2000); + + ret = i2c_himax_read(client, 0xD1, + hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", __LINE__); goto work_func_send_i2c_msg_fail; } - - if ((IC_STATUS_CHECK != hw_reset_check[0])) { - usleep_range(2000, 4000); - ret = i2c_himax_read(client, 0xD1, hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); + + if (IC_STATUS_CHECK != hw_reset_check[0]) { + usleep_range(1999, 2000); + ret = i2c_himax_read(client, 0xD1, + hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", + __LINE__); goto work_func_send_i2c_msg_fail; } - - if (hw_reset_check[0] == hw_reset_check_2[0]) { - result = 1; - } else { - result = 0; - } + + if (hw_reset_check[0] == hw_reset_check_2[0]) + result = 1; + else + result = 0; + } else { - result = 0; + result = 0; } - + return result; work_func_send_i2c_msg_fail: @@ -117,66 +108,71 @@ void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) uint8_t tmp_addr[4]; uint8_t tmp_data[4]; - if(diag_command != 0) + if (diag_command != 0) diag_command = diag_command + 5; - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = diag_command; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = diag_command; himax_flash_write_burst(client, tmp_addr, tmp_data); } -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) { - //struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); - -// uint8_t sector = 0; -// uint8_t page = 0; + /*struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, flash_work);*/ + /*uint8_t sector = 0;*/ + /*uint8_t page = 0;*/ uint8_t tmp_addr[4]; uint8_t tmp_data[4]; uint8_t out_buffer[20]; - uint8_t in_buffer[260] = {0}; + uint8_t in_buffer[260]; int page_prog_start = 0; int i = 0; himax_sense_off(client); himax_burst_enable(client, 0); /*=============Dump Flash Start=============*/ - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*=====================================*/ + /* SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780*/ + /*=====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + for (page_prog_start = 0 ; page_prog_start < Flash_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); @@ -184,43 +180,46 @@ void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_comman } himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== + /*===================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + =====================================*/ out_buffer[0] = 0x2C; out_buffer[1] = 0x00; out_buffer[2] = 0x00; out_buffer[3] = 0x80; - i2c_himax_write(client, 0x00 ,out_buffer, 4, 3); + i2c_himax_write(client, 0x00, out_buffer, 4, 3); - //================================== - // Read access : 0x0C ==> 0x00 - //================================== + /*===================================== + Read access : 0x0C ==> 0x00 + =====================================*/ out_buffer[0] = 0x00; - i2c_himax_write(client, 0x0C ,out_buffer, 1, 3); + i2c_himax_write(client, 0x0C, out_buffer, 1, 3); - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[i + page_prog_start] = in_buffer[i]; + /*===================================== + Read 128 bytes two times + =====================================*/ + i2c_himax_read(client, 0x08, in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[i + page_prog_start] + = in_buffer[i]; - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; + i2c_himax_read(client, 0x08 , in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[(i + 128) + page_prog_start] + = in_buffer[i]; I("%s:Verify Progress: %x\n", __func__, page_prog_start); } /*=============Dump Flash End=============*/ - //msleep(100); - /* + /*//msleep(100); for( i=0 ; i<8 ;i++) { for(j=0 ; j<64 ; j++) @@ -239,7 +238,7 @@ int himax_chip_self_test(struct i2c_client *client) { uint8_t tmp_addr[4]; uint8_t tmp_data[128]; - int pf_value=0x00; + int pf_value = 0x00; uint8_t test_result_id = 0; int j; @@ -249,19 +248,24 @@ int himax_chip_self_test(struct i2c_client *client) himax_interface_on(client); himax_sense_off(client); - //Set criteria + /*Set criteria*/ himax_burst_enable(client, 1); - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; - tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99; - - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8); - - //start selftest - // 0x9008_805C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; + tmp_data[3] = 0x14; tmp_data[2] = 0xC8; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_data[7] = 0x13; tmp_data[6] = 0x60; + tmp_data[5] = 0x0A; tmp_data[4] = 0x99; + + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 8); + + /*start selftest*/ + /* 0x9008_805C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; himax_flash_write_burst(client, tmp_addr, tmp_data); himax_sense_on(client, 1); @@ -271,19 +275,21 @@ int himax_chip_self_test(struct i2c_client *client) himax_sense_off(client); msleep(20); - //===================================== - // Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; + /*===================================== + Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; himax_register_read(client, tmp_addr, 1, tmp_data); test_result_id = tmp_data[0]; - I("%s: check test result, test_result_id=%x, test_result=%x\n", __func__ - ,test_result_id,tmp_data[0]); + I("%s: check test result, test_result_id=%x, test_result=%x\n", + __func__ , test_result_id, tmp_data[0]); - if (test_result_id==0xF) { + if (test_result_id == 0xF) { I("[Himax]: self-test pass\n"); pf_value = 0x1; } else { @@ -292,22 +298,28 @@ int himax_chip_self_test(struct i2c_client *client) } himax_burst_enable(client, 1); - for (j = 0;j < 10; j++){ - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; + for (j = 0 ; j < 10 ; j++) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; himax_register_read(client, tmp_addr, 1, tmp_data); I("[Himax]: 9006000C = %d\n", tmp_data[0]); - if (tmp_data[0] != 0){ - tmp_data[3] = 0x90; tmp_data[2] = 0x06; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - i2c_himax_read(client, 0x08, tmp_data, 124,HIMAX_I2C_RETRY_TIMES); - }else{ + if (tmp_data[0] != 0) { + tmp_data[3] = 0x90; tmp_data[2] = 0x06; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + i2c_himax_read(client, 0x08, + tmp_data, 124, HIMAX_I2C_RETRY_TIMES); + } else { break; } } @@ -324,15 +336,18 @@ void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) uint8_t tmp_data[4]; himax_burst_enable(client, 0); - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; himax_flash_write_burst(client, tmp_addr, tmp_data); } -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data) +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data) { uint8_t tmp_addr[4]; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; himax_register_read(client, tmp_addr, 1, tmp_data); } @@ -341,206 +356,232 @@ void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) uint8_t tmp_addr[4]; uint8_t tmp_data[4]; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; himax_flash_write_burst(client, tmp_addr, tmp_data); } -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data) +void himax_get_SMWP_enable(struct i2c_client *client, +uint8_t *tmp_data) { uint8_t tmp_addr[4]; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; himax_register_read(client, tmp_addr, 1, tmp_data); } int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) { uint8_t tmp_data[4]; + int err = -1; tmp_data[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + + if (i2c_himax_write(client, 0x13, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); - return -EBUSY; + return err; } - + tmp_data[0] = (0x10 | auto_add_4_byte); - if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x0D, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); - return -EBUSY; + return err; } return 0; } -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data) +void himax_register_read(struct i2c_client *client, +uint8_t *read_addr, int read_length, uint8_t *read_data) { uint8_t tmp_data[4]; int i = 0; int address = 0; - if(read_length>256) - { + if (read_length > 256) { E("%s: read len over 256!\n", __func__); return; } if (read_length > 1) himax_burst_enable(client, 1); else - himax_burst_enable(client, 0); - address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0]; + himax_burst_enable(client, 0); + + address = (read_addr[3] << 24) + + (read_addr[2] << 16) + + (read_addr[1] << 8) + + read_addr[0]; + i = address; - tmp_data[0] = (uint8_t)i; - tmp_data[1] = (uint8_t)(i >> 8); - tmp_data[2] = (uint8_t)(i >> 16); - tmp_data[3] = (uint8_t)(i >> 24); - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x08 ,read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (i2c_himax_read(client, 0x08, + read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } if (read_length > 1) himax_burst_enable(client, 0); } -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data) +void himax_flash_read(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *read_data) { - uint8_t tmpbyte[2]; - - if ( i2c_himax_write(client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + uint8_t tmpbyte[2]; + + if (i2c_himax_write(client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - tmpbyte[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + tmpbyte[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x08 ,&read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x08, + &read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x09 ,&read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x09, + &read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x0A ,&read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x0A, + &read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x0B ,&read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x0B, + &read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x18 ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x18, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; - }// No bus request + } /* No bus request*/ - if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x0F, + &tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; - }// idle state + } /* idle state*/ } -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data) +void himax_flash_write_burst(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data) { - uint8_t data_byte[8]; + uint8_t data_byte[8]; int i = 0, j = 0; - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < 8; j++) - { - data_byte[j] = write_data[j-4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } + for (i = 0 ; i < 4; i++) + data_byte[i] = reg_byte[i]; + + for (j = 4 ; j < 8; j++) + data_byte[j] = write_data[j-4]; + + if (i2c_himax_write(client, 0x00, + data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } } -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length) +int himax_flash_write_burst_length(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data, int length) { - uint8_t data_byte[256]; - int i = 0, j = 0; + uint8_t data_byte[256]; + int i = 0, j = 0, err = -1; - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < length + 4; j++) - { - data_byte[j] = write_data[j - 4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } + for (i = 0 ; i < 4 ; i++) + data_byte[i] = reg_byte[i]; - return 0; + for (j = 4 ; j < length + 4 ; j++) + data_byte[j] = write_data[j - 4]; + + if (i2c_himax_write(client, 0x00, + data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + return 0; } -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data) +int himax_register_write(struct i2c_client *client, +uint8_t *write_addr, int write_length, uint8_t *write_data) { - int i =0, address = 0; - int ret = 0; + int i = 0, address = 0; + int ret = 0, err = -1; - address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0]; + address = (write_addr[3] << 24) + + (write_addr[2] << 16) + + (write_addr[1] << 8) + + write_addr[0]; - for (i = address; i < address + write_length * 4; i = i + 4) - { - if (write_length > 1) - { + for (i = address ; i < address + write_length * 4; + i = i + 4) { + if (write_length > 1) { ret = himax_burst_enable(client, 1); - if(ret) - return ret; - } - else - { + if (ret) + return err; + } else { ret = himax_burst_enable(client, 0); - if(ret) - return ret; + if (ret) + return err; } - ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4); - if(ret < 0) - return ret; + ret = himax_flash_write_burst_length(client, + write_addr, write_data, write_length * 4); + if (ret < 0) + return err; } return 0; @@ -550,50 +591,62 @@ void himax_sense_off(struct i2c_client *client) { uint8_t wdt_off = 0x00; uint8_t tmp_addr[4]; - uint8_t tmp_data[5]; + uint8_t tmp_data[5]; himax_burst_enable(client, 0); - while(wdt_off == 0x00) - { - // 0x9000_800C ==> 0x0000_AC53 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xAC; tmp_data[0] = 0x53; + while (wdt_off == 0x00) { + /* 0x9000_800C ==> 0x0000_AC53*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0xAC; tmp_data[0] = 0x53; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read Watch Dog disable password : 0x9000_800C ==> 0x0000_AC53 - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + /*=====================================*/ + /* Read Watch Dog disable password : + 0x9000_800C ==> 0x0000_AC53 */ + /*=====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; himax_register_read(client, tmp_addr, 1, tmp_data); - - //Check WDT - if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) + + /*Check WDT*/ + if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC + && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) wdt_off = 0x01; else wdt_off = 0x00; } - // VCOM //0x9008_806C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + /* VCOM //0x9008_806C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; himax_flash_write_burst(client, tmp_addr, tmp_data); msleep(20); - // 0x9000_0010 ==> 0x0000_00DA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xDA; + /* 0x9000_0010 ==> 0x0000_00DA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xDA; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + /*===================================== + Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: CPU clock off password data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + I("%s: CPU clock off password data[0]=%x", + __func__, tmp_data[0]); + I(" data[1]=%x data[2]=%x data[3]=%x\n", + tmp_data[1], tmp_data[2], tmp_data[3]); } @@ -602,11 +655,12 @@ void himax_interface_on(struct i2c_client *client) uint8_t tmp_addr[4]; uint8_t tmp_data[5]; - //=========================================== - // Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 - //=========================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail + /*===================================== + Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + himax_flash_read(client, tmp_addr, tmp_data); /*avoid RD/WR fail*/ } bool wait_wip(struct i2c_client *client, int Timing) @@ -614,55 +668,64 @@ bool wait_wip(struct i2c_client *client, int Timing) uint8_t tmp_addr[4]; uint8_t tmp_data[4]; uint8_t in_buffer[10]; - //uint8_t out_buffer[20]; + /*uint8_t out_buffer[20];*/ int retry_cnt = 0; - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); in_buffer[0] = 0x01; - do - { - //===================================== - // SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x42; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x03; + do { + /*===================================== + SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x42; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x03; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // SPI Command : 0x8000_0024 ==> 0x0000_0005 - // read 0x8000_002C for 0x01, means wait success - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x05; + /*===================================== + SPI Command : 0x8000_0024 ==> 0x0000_0005 + read 0x8000_002C for 0x01, means wait success + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x05; himax_flash_write_burst(client, tmp_addr, tmp_data); - in_buffer[0] = in_buffer[1] = in_buffer[2] = in_buffer[3] = 0xFF; - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + in_buffer[0] = in_buffer[1] = + in_buffer[2] = in_buffer[3] = 0xFF; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; himax_register_read(client, tmp_addr, 1, in_buffer); - + if ((in_buffer[0] & 0x01) == 0x00) return true; retry_cnt++; - - if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 || in_buffer[2] != 0x00 || in_buffer[3] != 0x00) - I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, buffer[1]=%d, buffer[2]=%d, buffer[3]=%d \n", __func__, - retry_cnt,in_buffer[0],in_buffer[1],in_buffer[2],in_buffer[3]); - if (retry_cnt > 100) - { + if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 + || in_buffer[2] != 0x00 || in_buffer[3] != 0x00){ + I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, ", + __func__, retry_cnt, in_buffer[0]); + I("buffer[1]=%d, buffer[2]=%d, buffer[3]=%d\n", + in_buffer[1], in_buffer[2], in_buffer[3]); + } + if (retry_cnt > 100) { E("%s: Wait wip error!\n", __func__); - return false; - } + return false; + } msleep(Timing); - }while ((in_buffer[0] & 0x01) == 0x01); + } while ((in_buffer[0] & 0x01) == 0x01); return true; } @@ -673,74 +736,93 @@ void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) himax_interface_on(client); himax_burst_enable(client, 0); - //CPU reset - // 0x9000_0014 ==> 0x0000_00CA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xCA; + /*CPU reset*/ + /* 0x9000_0014 ==> 0x0000_00CA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xCA; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + /*===================================== + Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); - // 0x9000_0014 ==> 0x0000_0000 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /* 0x9000_0014 ==> 0x0000_0000*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + /*===================================== + Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - - //===================================== - // Reset TCON - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - usleep_range(10000, 20000); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - if (FlashMode == 0x00) //SRAM - { - //===================================== - // Re-map - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + /*===================================== + Reset TCON + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + usleep_range(9999, 10000); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + if (FlashMode == 0x00) { /*SRAM*/ + /*===================================== + Re-map + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xF1; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); I("%s:83100_Chip_Re-map ON\n", __func__); - } - else - { - //===================================== - // Re-map off - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + } else { + /*===================================== + Re-map off + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); I("%s:83100_Chip_Re-map OFF\n", __func__); } - //===================================== - // CPU clock on - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + /*===================================== + CPU clock on + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); } @@ -751,36 +833,45 @@ void himax_chip_erase(struct i2c_client *client) himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Chip Erase - // Erase Command : 0x8000_0024 ==> 0x0000_00C7 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xC7; + /*===================================== + Chip Erase + Erase Command : 0x8000_0024 ==> 0x0000_00C7 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xC7; himax_flash_write_burst(client, tmp_addr, tmp_data); - + msleep(2000); - + if (!wait_wip(client, 100)) E("%s:83100_Chip_Erase Fail\n", __func__); @@ -793,53 +884,64 @@ bool himax_block_erase(struct i2c_client *client) himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Block Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0052 //BE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /*===================================== + Block Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0052 //BE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x52; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x52; himax_flash_write_burst(client, tmp_addr, tmp_data); msleep(1000); - if (!wait_wip(client, 100)) - { + if (!wait_wip(client, 100)) { E("%s:83100_Erase Fail\n", __func__); return false; - } - else - { + } else { return true; } @@ -853,97 +955,110 @@ bool himax_sector_erase(struct i2c_client *client, int start_addr) himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000) - { - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Sector Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0020 //SE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - himax_flash_write_burst(client, tmp_addr, tmp_data); + for (page_prog_start = start_addr; + page_prog_start < start_addr + 0x0F000; + page_prog_start = page_prog_start + 0x1000) { + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x20; - himax_flash_write_burst(client, tmp_addr, tmp_data); + /*===================================== + Sector Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0020 //SE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); - msleep(200); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x20; + himax_flash_write_burst(client, tmp_addr, tmp_data); - if (!wait_wip(client, 100)) - { - E("%s:83100_Erase Fail\n", __func__); - return false; - } - } - return true; + msleep(200); + + if (!wait_wip(client, 100)) { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + } + return true; } void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) { int i = 0; uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - int FW_length = 0x4000; // 0x4000 = 16K bin file - - //himax_sense_off(client); + uint8_t tmp_data[64]; + int FW_length = 0x4000; /* 0x4000 = 16K bin file */ + + /*himax_sense_off(client);*/ - for (i = 0; i < FW_length; i = i + 128) - { + for (i = 0; i < FW_length; i = i + 64) { himax_burst_enable(client, 1); - if (i < 0x100) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = 0x00; + if (i < 0x100) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = (i >> 8); + } else if (i >= 0x100 && i < 0x10000) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = (i >> 8); tmp_addr[0] = i; } - memcpy(&tmp_data[0], &FW_content[i], 128); - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128); + memcpy(&tmp_data[0], &FW_content[i], 64); + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 64); } @@ -951,182 +1066,197 @@ void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) E("%s:83100_Sram_Write Fail\n", __func__); } -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size) +bool himax_sram_verify(struct i2c_client *client, +uint8_t *FW_File, int FW_Size) { int i = 0; uint8_t out_buffer[20]; uint8_t in_buffer[128]; uint8_t *get_fw_content; - get_fw_content = kzalloc(0x4000*sizeof(uint8_t), GFP_KERNEL); - if (!get_fw_content) - return false; + get_fw_content = kzalloc(0x4000 * sizeof(uint8_t), GFP_KERNEL); - for (i = 0; i < 0x4000; i = i + 128) - { + for (i = 0 ; i < 0x4000 ; i = i + 128) { himax_burst_enable(client, 1); - //================================== - // AHB_I2C Burst Read - //================================== - if (i < 0x100) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = 0x00; + /*===================================== + AHB_I2C Burst Read + =====================================*/ + if (i < 0x100) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = 0x00; out_buffer[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = (i >> 8); + } else if (i >= 0x100 && i < 0x10000) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = (i >> 8); out_buffer[0] = i; } - if ( i2c_himax_write(client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, out_buffer, + 4, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return false; } - out_buffer[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + out_buffer[0] = 0x00; + if (i2c_himax_write(client, 0x0C, out_buffer, + 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return false; } - if ( i2c_himax_read(client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x08, in_buffer, + 128, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return false; } memcpy(&get_fw_content[i], &in_buffer[0], 128); } - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != get_fw_content[i]) - { - E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", __func__,i,get_fw_content[i],FW_File[i]); - return false; - } + for (i = 0 ; i < FW_Size ; i++) { + if (FW_File[i] != get_fw_content[i]) { + E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", + __func__, i, get_fw_content[i], FW_File[i]); + return false; } + } kfree(get_fw_content); return true; } -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size) +void himax_flash_programming(struct i2c_client *client, +uint8_t *FW_content, int FW_Size) { int page_prog_start = 0; int program_length = 48; int i = 0, j = 0, k = 0; uint8_t tmp_addr[4]; uint8_t tmp_data[4]; - uint8_t buring_data[256]; // Read for flash data, 128K - // 4 bytes for 0x80002C padding + /* // Read for flash data, 128K //4 bytes for 0x80002C padding */ + uint8_t buring_data[256]; - //himax_interface_on(client); + /*himax_interface_on(client);*/ himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //msleep(5); - //===================================== - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + for (page_prog_start = 0 ; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*msleep(5);*/ + /*===================================== + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================= - // SPI Transfer Control - // Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x61; tmp_data[2] = 0x0F; tmp_data[1] = 0xF0; tmp_data[0] = 0x00; - // data bytes should be 0x6100_0000 + ((word_number)*4-1)*4096 = 0x6100_0000 + 0xFF000 = 0x610F_F000 - // Programmable size = 1 page = 256 bytes, word_number = 256 byte / 4 = 64 + /*===================================== + SPI Transfer Control + Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 + Set read start address : 0x8000_0028 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x61; tmp_data[2] = 0x0F; + tmp_data[1] = 0xF0; tmp_data[0] = 0x00; + /*data bytes should be 0x6100_0000 + + ((word_number)*4-1)*4096 = 0x6100_0000 + + 0xFF000 = 0x610F_F000 + Programmable size = 1 page = 256 bytes, + word_number = 256 byte / 4 = 64*/ himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - //tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; // Flash start address 1st : 0x0000_0000 + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + /* tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + // Flash start address 1st : 0x0000_0000 */ - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; } - - himax_flash_write_burst(client, tmp_addr, tmp_data); + himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================= - // Send 16 bytes data : 0x8000_002C ==> 16 bytes data - //================================= + /*===================================== + Send 16 bytes data : 0x8000_002C ==> 16 bytes data + =====================================*/ buring_data[0] = 0x2C; buring_data[1] = 0x00; buring_data[2] = 0x00; buring_data[3] = 0x80; - - for (i = /*0*/page_prog_start, j = 0; i < 16 + page_prog_start/**/; i++, j++) /// <------ bin file - { + + for (i = /*0*/page_prog_start, j = 0; + i < 16 + page_prog_start/**/; + i++, j++) { /* <------ bin file*/ + buring_data[j + 4] = FW_content[i]; } - - if ( i2c_himax_write(client, 0x00 ,buring_data, 20, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, buring_data, + 20, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - //================================= - // Write command : 0x8000_0024 ==> 0x0000_0002 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x02; + /*===================================== + Write command : 0x8000_0024 ==> 0x0000_0002 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x02; himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================= - // Send 240 bytes data : 0x8000_002C ==> 240 bytes data - //================================= + /*===================================== + Send 240 bytes data : 0x8000_002C ==> 240 bytes data + =====================================*/ - for (j = 0; j < 5; j++) - { - for (i = (page_prog_start + 16 + (j * 48)), k = 0; i < (page_prog_start + 16 + (j * 48)) + program_length; i++, k++) /// <------ bin file - { - buring_data[k+4] = FW_content[i];//(byte)i; + for (j = 0; j < 5; j++) { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; + i < (page_prog_start + 16 + (j * 48)) + program_length; + i++, k++) { /*<------ bin file*/ + buring_data[k+4] = FW_content[i];/*(byte)i;*/ } - if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, buring_data, + program_length + 4, + HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } @@ -1145,52 +1275,61 @@ bool himax_check_chip_version(struct i2c_client *client) uint8_t ret_data = 0x00; int i = 0; int ret = 0; + himax_sense_off(client); - for (i = 0; i < 5; i++) - { - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + + for (i = 0 ; i < 5 ; i++) { + /* 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) */ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) + if (ret) return false; - // 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000) - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /* 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000)*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) + if (ret) return false; - // 3. Read driver ID register RF4H 1 byte (0x8001_F401) - // Driver register RF4H 1 byte value = 0x84H, read back value will become 0x84848484 - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; + /* 3. Read driver ID register RF4H 1 byte (0x8001_F401) + // Driver register RF4H 1 byte value = 0x84H, + read back value will become 0x84848484 */ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; himax_register_read(client, tmp_addr, 1, tmp_data); ret_data = tmp_data[0]; I("%s:Read driver IC ID = %X\n", __func__, ret_data); - if (ret_data == 0x84) - { + if (ret_data == 0x84) { IC_TYPE = HX_83100_SERIES_PWON; - //himax_sense_on(client, 0x01); + /*himax_sense_on(client, 0x01);*/ ret_data = true; break; - } - else - { + + } else { ret_data = false; E("%s:Read driver ID register Fail:\n", __func__); } } - // 4. After read finish, set DDREG_Req = 0 (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /* 4. After read finish, set DDREG_Req = 0 + (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver)*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_register_write(client, tmp_addr, 1, tmp_data); - //himax_sense_on(client, 0x01); + /*himax_sense_on(client, 0x01);*/ return ret_data; } -#if 1 +/*#if 1*/ int himax_check_CRC(struct i2c_client *client, int mode) { bool burnFW_success = false; @@ -1200,52 +1339,70 @@ int himax_check_CRC(struct i2c_client *client, int mode) int CRC_value = 0; memset(tmp_data, 0x00, sizeof(tmp_data)); + if (i_TP_CRC_FW_60K == NULL) { + I("%s: i_TP_CRC_FW_60K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_64K == NULL) { + I("%s: i_TP_CRC_FW_64K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_124K == NULL) { + I("%s: i_TP_CRC_FW_124K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_128K == NULL) { + I("%s: i_TP_CRC_FW_128K = NULL\n", __func__); + return 0; + } - if (1) - { - if(mode == fw_image_60k) - { - himax_sram_write(client, (i_TP_CRC_FW_60K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000); - } - else if(mode == fw_image_64k) - { - himax_sram_write(client, (i_TP_CRC_FW_64K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000); - } - else if(mode == fw_image_124k) - { - himax_sram_write(client, (i_TP_CRC_FW_124K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000); + if (1) { + if (mode == fw_image_60k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_60K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_60K->data, 0x4000); + } else if (mode == fw_image_64k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_64K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_64K->data, 0x4000); + } else if (mode == fw_image_124k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_124K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_124K->data, 0x4000); + } else if (mode == fw_image_128k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_128K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_128K->data, 0x4000); } - else if(mode == fw_image_128k) - { - himax_sram_write(client, (i_TP_CRC_FW_128K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_128K, 0x4000); - } - if (burnFW_success) - { - I("%s: Start to do CRC FW mode=%d \n", __func__,mode); - himax_sense_on(client, 0x00); // run CRC firmware + if (burnFW_success) { + I("%s: Start to do CRC FW mode=%d\n", __func__, mode); + himax_sense_on(client, 0x00); /* run CRC firmware*/ - while(true) - { + while (true) { msleep(100); - - tmp_addr[3] = 0x90; - tmp_addr[2] = 0x08; - tmp_addr[1] = 0x80; + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3], - tmp_data[2],tmp_data[1],tmp_data[0]); - - if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) - { - } - else + himax_register_read(client, + tmp_addr, 1, tmp_data); + + I("%s: CRC from firmware is %x, %x, %x, %x\n", + __func__, tmp_data[3], tmp_data[2], + tmp_data[1], tmp_data[0]); +/* + if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) { + } else break; + */ + if (!(tmp_data[3] == 0xFF + && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF + && tmp_data[0] == 0xFF)) { + break; + } } CRC_value = tmp_data[3]; @@ -1259,30 +1416,32 @@ int himax_check_CRC(struct i2c_client *client, int mode) tmp_value = tmp_data[0] << 24; CRC_value += tmp_value; - I("%s: CRC Value is %x \n", __func__, CRC_value); + I("%s: CRC Value is %x\n", __func__, CRC_value); - //Close Remapping - //===================================== - // Re-map close - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - return CRC_value; - } - else - { + /*Close Remapping*/ + /*===================================== + Re-map close + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, + tmp_addr, tmp_data, 4); + return CRC_value; + + } else { E("%s: SRAM write fail\n", __func__); return 0; - } - } - else - I("%s: NO CRC Check File \n", __func__); + } + } else + I("%s: NO CRC Check File\n", __func__); return 0; } -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode) +bool Calculate_CRC_with_AP(unsigned char *FW_content, +int CRC_from_FW, int mode) { uint8_t tmp_data[4]; int i, j; @@ -1291,42 +1450,35 @@ bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode int CRC = 0xFFFFFFFF; int PolyNomial = 0x82F63B78; int length = 0; - + if (mode == fw_image_128k) length = 0x8000; else if (mode == fw_image_124k) length = 0x7C00; else if (mode == fw_image_64k) length = 0x4000; - else //if (mode == fw_image_60k) + else /*if (mode == fw_image_60k)*/ length = 0x3C00; - for (i = 0; i < length; i++) - { - fw_data = FW_content[i * 4 ]; - - for (j = 1; j < 4; j++) - { + for (i = 0 ; i < length ; i++) { + fw_data = FW_content[i * 4]; + + for (j = 1 ; j < 4 ; j++) { fw_data_2 = FW_content[i * 4 + j]; fw_data += (fw_data_2) << (8 * j); } CRC = fw_data ^ CRC; - for (j = 0; j < 32; j++) - { + for (j = 0 ; j < 32 ; j++) { if ((CRC % 2) != 0) - { - CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; - } + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; else - { - CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF); - } + CRC = (((CRC >> 1) ^ 0x7FFFFFFF) & 0x7FFFFFFF); } } - I("%s: CRC calculate from bin file is %x \n", __func__, CRC); + I("%s: CRC calculate from bin file is %x\n", __func__, CRC); tmp_data[0] = (uint8_t)(CRC >> 24); tmp_data[1] = (uint8_t)(CRC >> 16); @@ -1334,58 +1486,129 @@ bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode tmp_data[3] = (uint8_t) CRC; CRC = tmp_data[0]; - CRC += tmp_data[1] << 8; + CRC += tmp_data[1] << 8; CRC += tmp_data[2] << 16; CRC += tmp_data[3] << 24; - I("%s: CRC calculate from bin file REVERSE %x \n", __func__, CRC); - I("%s: CRC calculate from FWis %x \n", __func__, CRC_from_FW); + I("%s: CRC calculate from bin file REVERSE %x\n", __func__, CRC); + I("%s: CRC calculate from FWis %x\n", __func__, CRC_from_FW); if (CRC_from_FW == CRC) return true; else return false; } -#endif +/*#endif*/ -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int himax_load_CRC_bin_file(struct i2c_client *client) +{ + int err = 0; + char *CRC_60_firmware_name = "HX_CRC_60.bin"; + char *CRC_64_firmware_name = "HX_CRC_64.bin"; + char *CRC_124_firmware_name = "HX_CRC_124.bin"; + char *CRC_128_firmware_name = "HX_CRC_128.bin"; + + I("%s,Entering\n", __func__); + if (i_TP_CRC_FW_60K == NULL) { + I("load file name = %s\n", CRC_60_firmware_name); + err = request_firmware(&i_TP_CRC_FW_60K, + CRC_60_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -1; + goto request_60k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_60K\n", __func__); + + if (i_TP_CRC_FW_64K == NULL) { + I("load file name = %s\n", CRC_64_firmware_name); + err = request_firmware(&i_TP_CRC_FW_64K, + CRC_64_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -2; + goto request_64k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_64K\n", __func__); + + if (i_TP_CRC_FW_124K == NULL) { + I("load file name = %s\n", CRC_124_firmware_name); + err = request_firmware(&i_TP_CRC_FW_124K, + CRC_124_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -3; + goto request_124k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_124K\n", __func__); + + if (i_TP_CRC_FW_128K == NULL) { + I("load file name = %s\n", CRC_128_firmware_name); + err = request_firmware(&i_TP_CRC_FW_128K, + CRC_128_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -4; + goto request_128k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_128K\n", __func__); + + return err; + +request_128k_fw_fail: + release_firmware(i_TP_CRC_FW_124K); +request_124k_fw_fail: + release_firmware(i_TP_CRC_FW_64K); +request_64k_fw_fail: + release_firmware(i_TP_CRC_FW_60K); +request_60k_fw_fail: + return err; +} +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; - } + if (len != 0x10000) {/*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } himax_sense_off(client); msleep(500); himax_interface_on(client); - if (!himax_sector_erase(client, 0x00000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } + if (!himax_sector_erase(client, 0x00000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } himax_flash_programming(client, fw, 0x0F000); - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - CRC_from_FW = himax_check_CRC(client,fw_image_60k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_60k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_60k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_60k); + /*himax_sense_on(client, 0x01);*/ return burnFW_success; } -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; + if (len != 0x10000) { /*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; } himax_sense_off(client); msleep(500); @@ -1393,62 +1616,58 @@ int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char himax_chip_erase(client); himax_flash_programming(client, fw, len); - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - CRC_from_FW = himax_check_CRC(client,fw_image_64k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_64k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_64k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_64k); + /*himax_sense_on(client, 0x01);*/ return burnFW_success; } -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; } himax_sense_off(client); msleep(500); himax_interface_on(client); - if (!himax_block_erase(client)) - { - E("%s:Block erase fail!Please restart the IC.\n", __func__); - return false; - } - - if (!himax_sector_erase(client, 0x10000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } + if (!himax_block_erase(client)) { + E("%s:Block erase fail!Please restart the IC.\n", __func__); + return false; + } + if (!himax_sector_erase(client, 0x10000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } himax_flash_programming(client, fw, 0x1F000); + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_124k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_124k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_124k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_124k); + /*himax_sense_on(client, 0x01);*/ return burnFW_success; } -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; } himax_sense_off(client); msleep(500); @@ -1457,13 +1676,13 @@ int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned cha himax_flash_programming(client, fw, len); - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - CRC_from_FW = himax_check_CRC(client,fw_image_128k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_128k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_128k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_128k); + /*himax_sense_on(client, 0x01); */ return burnFW_success; } @@ -1472,10 +1691,9 @@ void himax_touch_information(struct i2c_client *client) uint8_t cmd[4]; char data[12] = {0}; - I("%s:IC_TYPE =%d\n", __func__,IC_TYPE); + I("%s:IC_TYPE =%d\n", __func__, IC_TYPE); - if(IC_TYPE == HX_83100_SERIES_PWON) - { + if (IC_TYPE == HX_83100_SERIES_PWON) { cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; himax_register_read(client, cmd, 1, data); @@ -1486,11 +1704,11 @@ void himax_touch_information(struct i2c_client *client) cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; himax_register_read(client, cmd, 1, data); - if((data[1] & 0x04) == 0x04) { + if ((data[1] & 0x04) == 0x04) ic_data->HX_XY_REVERSE = true; - } else { + else ic_data->HX_XY_REVERSE = false; - } + ic_data->HX_Y_RES = data[3]*256; cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; himax_register_read(client, cmd, 1, data); @@ -1498,32 +1716,35 @@ void himax_touch_information(struct i2c_client *client) ic_data->HX_X_RES = data[1]*256 + data[2]; cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; himax_register_read(client, cmd, 1, data); - if((data[0] & 0x01) == 1) { + if ((data[0] & 0x01) == 1) ic_data->HX_INT_IS_EDGE = true; - } else { + else ic_data->HX_INT_IS_EDGE = false; - } - if (ic_data->HX_RX_NUM > 40) + + if (ic_data->HX_RX_NUM > 40) ic_data->HX_RX_NUM = 29; - if (ic_data->HX_TX_NUM > 20) + if (ic_data->HX_TX_NUM > 20) ic_data->HX_TX_NUM = 16; - if (ic_data->HX_MAX_PT > 10) + if (ic_data->HX_MAX_PT > 10) ic_data->HX_MAX_PT = 10; - if (ic_data->HX_Y_RES > 2000) + if (ic_data->HX_Y_RES > 2000) ic_data->HX_Y_RES = 1280; - if (ic_data->HX_X_RES > 2000) + if (ic_data->HX_X_RES > 2000) ic_data->HX_X_RES = 720; #ifdef HX_EN_MUT_BUTTON cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; himax_register_read(client, cmd, 1, data); ic_data->HX_BT_NUM = data[3]; #endif - I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__,ic_data->HX_RX_NUM,ic_data->HX_TX_NUM,ic_data->HX_MAX_PT); - I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d \n", __func__,ic_data->HX_XY_REVERSE,ic_data->HX_Y_RES,ic_data->HX_X_RES); - I("%s:HX_INT_IS_EDGE =%d \n", __func__,ic_data->HX_INT_IS_EDGE); - } - else - { + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d\n", + __func__, ic_data->HX_RX_NUM, + ic_data->HX_TX_NUM, ic_data->HX_MAX_PT); + I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d\n", + __func__, ic_data->HX_XY_REVERSE, + ic_data->HX_Y_RES, ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d\n", + __func__, ic_data->HX_INT_IS_EDGE); + } else { ic_data->HX_RX_NUM = 0; ic_data->HX_TX_NUM = 0; ic_data->HX_BT_NUM = 0; @@ -1538,35 +1759,34 @@ void himax_touch_information(struct i2c_client *client) void himax_read_FW_ver(struct i2c_client *client) { uint8_t cmd[4]; - uint8_t data[64] = {0}; + uint8_t data[64]; - //===================================== - // Read FW version : 0x0000_E303 - //===================================== + /*===================================== + Read FW version : 0x0000_E303 + =====================================*/ cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; himax_register_read(client, cmd, 1, data); - ic_data->vendor_config_ver = data[3]<<8; + ic_data->vendor_config_ver = data[3] << 8; cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; himax_register_read(client, cmd, 1, data); ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; - I("CFG_VER : %X \n",ic_data->vendor_config_ver); + I("CFG_VER : %X\n", ic_data->vendor_config_ver); cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; himax_register_read(client, cmd, 1, data); ic_data->vendor_fw_ver = data[0]<<8 | data[1]; - I("FW_VER : %X \n",ic_data->vendor_fw_ver); - + I("FW_VER : %X\n", ic_data->vendor_fw_ver); - return; } bool himax_ic_package_check(struct i2c_client *client) { -#if 0 +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH uint8_t cmd[3]; uint8_t data[3]; @@ -1574,260 +1794,284 @@ bool himax_ic_package_check(struct i2c_client *client) memset(data, 0x00, sizeof(data)); if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) - return false ; + return false; if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) return false; - if((data[0] == 0x85 && data[1] == 0x29)) - { - IC_TYPE = HX_85XX_F_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 64901; //0xFD85 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 64902; //0xFD86 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 64928; //0xFDA0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 64940; //0xFDAC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x F\n"); - } - if((data[0] == 0x85 && data[1] == 0x30) || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) - { - IC_TYPE = HX_85XX_E_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x E\n"); - } - else if((data[0] == 0x85 && data[1] == 0x31)) - { - IC_TYPE = HX_85XX_ES_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x ES\n"); - } - else if ((data[0] == 0x85 && data[1] == 0x28) || (cmd[0] == 0x04 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28))) { - IC_TYPE = HX_85XX_D_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; // 0x00A0 + if ((data[0] == 0x85 && data[1] == 0x29)) { + IC_TYPE = HX_85XX_F_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 64901; /*0xFD85*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 64902; /*0xFD86*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 64928; /*0xFDA0*/ CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; // 0x00AC + CFG_VER_MIN_FLASH_ADDR = 64940; /*0xFDAC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x F\n"); + } + if ((data[0] == 0x85 && data[1] == 0x30) + || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) { + IC_TYPE = HX_85XX_E_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x E\n"); + } else if ((data[0] == 0x85 && data[1] == 0x31)) { + IC_TYPE = HX_85XX_ES_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x ES\n"); + } else if ((data[0] == 0x85 && data[1] == 0x28) + || (cmd[0] == 0x04 && cmd[1] == 0x85 + && (cmd[2] == 0x26 || cmd[2] == 0x27 + || cmd[2] == 0x28))) { + IC_TYPE = HX_85XX_D_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /* 0x00AC*/ CFG_VER_MIN_FLASH_LENG = 12; I("Himax IC package 852x D\n"); - } else if ((data[0] == 0x85 && data[1] == 0x23) || (cmd[0] == 0x03 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28 || cmd[2] == 0x29))) { - IC_TYPE = HX_85XX_C_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 135; // 0x0087 + } else if ((data[0] == 0x85 && data[1] == 0x23) || + (cmd[0] == 0x03 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || + cmd[2] == 0x28 || cmd[2] == 0x29))) { + IC_TYPE = HX_85XX_C_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 135; /*0x0087*/ CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 147; // 0x0093 + CFG_VER_MIN_FLASH_ADDR = 147; /*0x0093*/ CFG_VER_MIN_FLASH_LENG = 12; I("Himax IC package 852x C\n"); } else if ((data[0] == 0x85 && data[1] == 0x26) || - (cmd[0] == 0x02 && cmd[1] == 0x85 && - (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { + (cmd[0] == 0x02 && cmd[1] == 0x85 && + (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { IC_TYPE = HX_85XX_B_SERIES_PWON; IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 728; // 0x02D8 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 692; // 0x02B4 + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 728; /*0x02D8*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 692; /*0x02B4*/ CFG_VER_MAJ_FLASH_LENG = 3; - CFG_VER_MIN_FLASH_ADDR = 704; // 0x02C0 + CFG_VER_MIN_FLASH_ADDR = 704; /*0x02C0*/ CFG_VER_MIN_FLASH_LENG = 3; I("Himax IC package 852x B\n"); } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && - cmd[1] == 0x85 && cmd[2] == 0x19)) { + cmd[1] == 0x85 && cmd[2] == 0x19)) { IC_TYPE = HX_85XX_A_SERIES_PWON; IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; I("Himax IC package 852x A\n"); } else { E("Himax IC package incorrect!!\n"); - }*/ + } #else - IC_TYPE = HX_83100_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 57384; //0xE028 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 57385; //0xE029 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 58115; //0xE303 - CFG_VER_MAJ_FLASH_LENG = 1; - CFG_VER_MIN_FLASH_ADDR = 58116; //0xE304 - CFG_VER_MIN_FLASH_LENG = 1; + IC_TYPE = HX_83100_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 57384; /*0xE028*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 57385; /*0xE029*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 58115; /*0xE303*/ + CFG_VER_MAJ_FLASH_LENG = 1; + CFG_VER_MIN_FLASH_ADDR = 58116; /*0xE304*/ + CFG_VER_MIN_FLASH_LENG = 1; I("Himax IC package 83100_in\n"); #endif return true; } -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length) +void himax_read_event_stack(struct i2c_client *client, +uint8_t *buf, uint8_t length) { uint8_t cmd[4]; - cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); + cmd[3] = 0x90; cmd[2] = 0x06; + cmd[1] = 0x00; cmd[0] = 0x00; + if (i2c_himax_write(client, 0x00, + cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); } - cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); + cmd[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); } - i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); + i2c_himax_read(client, 0x08, + buf, length, HIMAX_I2C_RETRY_TIMES); } -#if 0 -static void himax_83100_Flash_Write(uint8_t * reg_byte, uint8_t * write_data) +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Write(uint8_t *reg_byte, uint8_t *write_data) { uint8_t tmpbyte[2]; - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x03, ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x05, &write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x06, &write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x07, &write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if (isBusrtOn == false) - { - tmpbyte[0] = 0x01; - if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; + if (isBusrtOn == false) { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; } - } + } } #endif -#if 0 -static void himax_83100_Flash_Burst_Write(uint8_t * reg_byte, uint8_t * write_data) +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Burst_Write +(uint8_t *reg_byte, uint8_t *write_data) { - //uint8_t tmpbyte[2]; + /*uint8_t tmpbyte[2];*/ int i = 0; - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - // Write 256 bytes with continue burst mode - for (i = 0; i < 256; i = i + 4) - { - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + /*Write 256 bytes with continue burst mode*/ + for (i = 0 ; i < 256 ; i = i + 4) { + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x05, + &write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x06, + &write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x07, + &write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - } + } - //if (isBusrtOn == false) - //{ - // tmpbyte[0] = 0x01; - // if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, 3) < 0) { - // E("%s: i2c access fail!\n", __func__); - // return; - // } - //} + /*if (isBusrtOn == false) + { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }*/ } #endif -#if 0 +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) { uint8_t tmp_addr[4]; @@ -1835,49 +2079,51 @@ static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) uint8_t out_buffer[20]; uint8_t in_buffer[260]; - int fail_addr=0, fail_cnt=0; + int fail_addr = 0, fail_cnt = 0; int page_prog_start = 0; int i = 0; himax_interface_on(private_ts->client); himax_burst_enable(private_ts->client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_83100_Flash_Write(tmp_addr, tmp_data); - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + for (page_prog_start = 0; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; himax_83100_Flash_Write(tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); @@ -1885,65 +2131,73 @@ static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) } himax_83100_Flash_Write(tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; himax_83100_Flash_Write(tmp_addr, tmp_data); - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== + /*================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + ==================================*/ out_buffer[0] = 0x2C; out_buffer[1] = 0x00; out_buffer[2] = 0x00; out_buffer[3] = 0x80; - i2c_himax_write(private_ts->client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES); + i2c_himax_write(private_ts->client, 0x00, + out_buffer, 4, HIMAX_I2C_RETRY_TIMES); - //================================== - // Read access : 0x0C ==> 0x00 - //================================== + /*================================== + Read access : 0x0C ==> 0x00 + ==================================*/ out_buffer[0] = 0x00; - i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES); - - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + i2c_himax_write(private_ts->client, 0x0C, + out_buffer, 1, HIMAX_I2C_RETRY_TIMES); + + /*================================== + Read 128 bytes two times + ==================================*/ + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); for (i = 0; i < 128; i++) flash_buffer[i + page_prog_start] = in_buffer[i]; - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; - - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - + flash_buffer[(i + 128) + + page_prog_start] = in_buffer[i]; + + /*tmp_addr[3] = 0x80; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + */ I("%s:Verify Progress: %x\n", __func__, page_prog_start); } fail_cnt = 0; - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != flash_buffer[i]) - { + for (i = 0; i < FW_Size; i++) { + if (FW_File[i] != flash_buffer[i]) { if (fail_cnt == 0) fail_addr = i; fail_cnt++; - //E("%s Fail Block:%x\n", __func__, i); - //return false; + /*E("%s Fail Block:%x\n", __func__, i); + return false;*/ } } - if (fail_cnt > 0) - { - E("%s:Start Fail Block:%x and fail block count=%x\n" , __func__,fail_addr,fail_cnt); + if (fail_cnt > 0) { + E("%s:Start Fail Block:%x and fail block count=%x\n", + __func__, fail_addr, fail_cnt); return false; } @@ -1959,56 +2213,60 @@ void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) int cnt = 0; unsigned char tmp_addr[4]; unsigned char tmp_data[4]; - uint8_t max_i2c_size = 32; + uint8_t max_i2c_size = 32; int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; int total_size_4bytes = total_size / 4; int total_read_times = 0; unsigned long address = 0x08000468; - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; + + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; himax_flash_write_burst(client, tmp_addr, tmp_data); - do - { + do { cnt++; himax_register_read(client, tmp_addr, 1, tmp_data); - usleep_range(10000, 20000); + usleep_range(9999, 10000); } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; - if (total_size_4bytes % max_i2c_size == 0) - { + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; + if (total_size_4bytes % max_i2c_size == 0) total_read_times = total_size_4bytes / max_i2c_size; - } else - { total_read_times = total_size_4bytes / max_i2c_size + 1; - } - for (i = 0; i < (total_read_times); i++) - { - if ( total_size_4bytes >= max_i2c_size) - { - himax_register_read(client, tmp_addr, max_i2c_size, &info_data[i*max_i2c_size*4]); + + for (i = 0 ; i < (total_read_times) ; i++) { + if (total_size_4bytes >= max_i2c_size) { + himax_register_read(client, tmp_addr, + max_i2c_size, + &info_data[i*max_i2c_size*4]); total_size_4bytes = total_size_4bytes - max_i2c_size; + } else { + himax_register_read(client, tmp_addr, + total_size_4bytes % max_i2c_size, + &info_data[i*max_i2c_size*4]); } - else - { - himax_register_read(client, tmp_addr, total_size_4bytes % max_i2c_size, &info_data[i*max_i2c_size*4]); - } - address += max_i2c_size*4; - tmp_addr[1] = (uint8_t)((address>>8)&0x00FF); - tmp_addr[0] = (uint8_t)((address)&0x00FF); - } - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44; + address += max_i2c_size * 4; + tmp_addr[1] = (uint8_t)((address>>8) & 0x00FF); + tmp_addr[0] = (uint8_t)((address) & 0x00FF); + } + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x11; tmp_data[2] = 0x22; + tmp_data[1] = 0x33; tmp_data[0] = 0x44; himax_flash_write_burst(client, tmp_addr, tmp_data); } -//ts_work -int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){ +/*ts_work*/ +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max) +{ int RawDataLen; - if (raw_cnt_rmd != 0x00) { - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1; - }else{ - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1; - } + + if (raw_cnt_rmd != 0x00) + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 1; + else + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 1; + return RawDataLen; } @@ -2016,40 +2274,40 @@ bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) { uint8_t cmd[4]; - if(length > 56) + if (length > 56) length = 124; - //===================== - //AHB I2C Burst Read - //===================== + /*===================== + AHB I2C Burst Read + =====================*/ cmd[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x13, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } cmd[0] = 0x10; - if ( i2c_himax_write(client, 0x0D ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x0D, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } - //===================== - //Read event stack - //===================== + /*===================== + Read event stack + =====================*/ cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x0C, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } - i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES); + i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); return 1; - - err_workqueue_out: + +err_workqueue_out: return 0; } @@ -2057,62 +2315,67 @@ bool post_read_event_stack(struct i2c_client *client) { return 1; } -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value +bool diag_check_sum(uint8_t hx_touch_info_size, +uint8_t *buf) /*return checksum value*/ { uint16_t check_sum_cal = 0; int i; - //Check 124th byte CRC - for (i = hx_touch_info_size, check_sum_cal = 0; i < 124; i=i+2) - { - check_sum_cal += (buf[i+1]*256 + buf[i]); - } - if (check_sum_cal % 0x10000 != 0) - { - I("%s: diag check sum fail! check_sum_cal=%X, hx_touch_info_size=%d, \n",__func__,check_sum_cal, hx_touch_info_size); + /*Check 124th byte CRC*/ + for (i = hx_touch_info_size, check_sum_cal = 0 ; i < 124 ; i = i + 2) + check_sum_cal += (buf[i + 1] * 256 + buf[i]); + + if (check_sum_cal % 0x10000 != 0) { + I("%s:diag chksum fail!check_sum_cal=%X,hx_touchinfo_sz=%d,\n", + __func__, check_sum_cal, hx_touch_info_size); return 0; } return 1; } - -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) +void diag_parse_raw_data(int hx_touch_info_size, +int RawDataLen, int mul_num, int self_num, uint8_t *buf, +uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) { int RawDataLen_word; int index = 0; - int temp1, temp2,i; - - if (buf[hx_touch_info_size] == 0x3A && buf[hx_touch_info_size+1] == 0xA3 && buf[hx_touch_info_size+2] > 0 && buf[hx_touch_info_size+3] == diag_cmd+5 ) - { - RawDataLen_word = RawDataLen/2; - index = (buf[hx_touch_info_size+2] - 1) * RawDataLen_word; - //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); - for (i = 0; i < RawDataLen_word; i++) - { + int temp1, temp2, i; + + if (buf[hx_touch_info_size] == 0x3A && + buf[hx_touch_info_size + 1] == 0xA3 && + buf[hx_touch_info_size + 2] > 0 && + buf[hx_touch_info_size + 3] == diag_cmd + 5) { + RawDataLen_word = RawDataLen / 2; + index = (buf[hx_touch_info_size + 2] - 1) * RawDataLen_word; + /*I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num);*/ + for (i = 0; i < RawDataLen_word; i++) { temp1 = index + i; - if (temp1 < mul_num) - { //mutual - mutual_data[index + i] = buf[i*2 + hx_touch_info_size+4+1]*256 + buf[i*2 + hx_touch_info_size+4]; //4: RawData Header, 1:HSB - } - else - {//self + if (temp1 < mul_num) { /*mutual*/ + /*4: RawData Header, 1:HSB */ + mutual_data[index + i] + = buf[i*2 + hx_touch_info_size + 4 + 1] + * 256 + + buf[i * 2 + hx_touch_info_size + 4]; + } else { /*self*/ temp1 = i + index; temp2 = self_num + mul_num; - + if (temp1 >= temp2) - { break; - } - self_data[i+index-mul_num] = buf[i*2 + hx_touch_info_size+4]; //4: RawData Header - self_data[i+index-mul_num+1] = buf[i*2 + hx_touch_info_size+4+1]; + /*4: RawData Header*/ + self_data[i + index - mul_num] + = buf[i * 2 + hx_touch_info_size + 4]; + self_data[i + index - mul_num + 1] + = buf[i * 2 + hx_touch_info_size + 4 + 1]; } } - } - else - { + } else { I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); - I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], + mul_num, self_num); } } diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h index 18cd12b8b36fe3d387537adcbaf1b886c1eca0ed..ce7d0d49c362d102e45d8a2a97f12e53fde2747c 100644 --- a/drivers/input/touchscreen/hxchipset/himax_ic.h +++ b/drivers/input/touchscreen/hxchipset/himax_ic.h @@ -18,7 +18,6 @@ #include - #define HX_85XX_A_SERIES_PWON 1 #define HX_85XX_B_SERIES_PWON 2 #define HX_85XX_C_SERIES_PWON 3 @@ -40,43 +39,110 @@ enum fw_image_type { }; int himax_hand_shaking(struct i2c_client *client); -void himax_set_SMWP_enable(struct i2c_client *client,uint8_t SMWP_enable); -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data); -void himax_set_HSEN_enable(struct i2c_client *client,uint8_t HSEN_enable); -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data); +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable); +void himax_get_SMWP_enable(struct i2c_client *client, uint8_t *tmp_data); +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable); +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data); void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); + +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); + int himax_chip_self_test(struct i2c_client *client); -int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); ////himax_83100_BURST_INC0_EN -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data); ////RegisterRead83100 -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data); ////himax_83100_Flash_Read -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data); ////himax_83100_Flash_Write_Burst -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length); ////himax_83100_Flash_Write_Burst_lenth -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data); ////RegisterWrite83100 -void himax_sense_off(struct i2c_client *client); ////himax_83100_SenseOff -void himax_interface_on(struct i2c_client *client); ////himax_83100_Interface_on + +/*himax_83100_BURST_INC0_EN*/ +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); + +/*RegisterRead83100*/ +void himax_register_read(struct i2c_client *client, + uint8_t *read_addr, int read_length, uint8_t *read_data); + +/*himax_83100_Flash_Read*/ +void himax_flash_read(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *read_data); + +/*himax_83100_Flash_Write_Burst*/ +void himax_flash_write_burst(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data); + +/*himax_83100_Flash_Write_Burst_length*/ +int himax_flash_write_burst_length(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data, int length); + +/*RegisterWrite83100*/ +int himax_register_write(struct i2c_client *client, + uint8_t *write_addr, int write_length, uint8_t *write_data); + +/*himax_83100_SenseOff*/ +void himax_sense_off(struct i2c_client *client); +/*himax_83100_Interface_on*/ +void himax_interface_on(struct i2c_client *client); bool wait_wip(struct i2c_client *client, int Timing); -void himax_sense_on(struct i2c_client *client, uint8_t FlashMode); ////himax_83100_SenseOn -void himax_chip_erase(struct i2c_client *client); ////himax_83100_Chip_Erase -bool himax_block_erase(struct i2c_client *client); ////himax_83100_Block_Erase -bool himax_sector_erase(struct i2c_client *client, int start_addr); ////himax_83100_Sector_Erase -void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); ////himax_83100_Sram_Write -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size); ////himax_83100_Sram_Verify -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size); ////himax_83100_Flash_Programming -bool himax_check_chip_version(struct i2c_client *client); ////himax_83100_CheckChipVersion -int himax_check_CRC(struct i2c_client *client, int mode); ////himax_83100_Check_CRC -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode); -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); + +/*himax_83100_SenseOn*/ +void himax_sense_on(struct i2c_client *client, + uint8_t FlashMode); + +/*himax_83100_Chip_Erase*/ +void himax_chip_erase(struct i2c_client *client); +/*himax_83100_Block_Erase*/ +bool himax_block_erase(struct i2c_client *client); + +/*himax_83100_Sector_Erase*/ +bool himax_sector_erase(struct i2c_client *client, int start_addr); + +/*himax_83100_Sram_Write*/ +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); + +/*himax_83100_Sram_Verify*/ +bool himax_sram_verify(struct i2c_client *client, + uint8_t *FW_File, int FW_Size); + +/*himax_83100_Flash_Programming*/ +void himax_flash_programming(struct i2c_client *client, + uint8_t *FW_content, int FW_Size); + +/*himax_83100_CheckChipVersion*/ +bool himax_check_chip_version(struct i2c_client *client); + +/*himax_83100_Check_CRC*/ +int himax_check_CRC(struct i2c_client *client, int mode); + +bool Calculate_CRC_with_AP(unsigned char *FW_content, + int CRC_from_FW, int mode); + +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + void himax_touch_information(struct i2c_client *client); void himax_read_FW_ver(struct i2c_client *client); bool himax_ic_package_check(struct i2c_client *client); -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length); + +void himax_read_event_stack(struct i2c_client *client, + uint8_t *buf, uint8_t length); + int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); bool post_read_event_stack(struct i2c_client *client); -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf_ts); //return checksum value -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf_ts, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); -void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); \ No newline at end of file + +/*return checksum value*/ +bool diag_check_sum(uint8_t hx_touch_info_size, uint8_t *buf_ts); + +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, + int mul_num, int self_num, uint8_t *buf_ts, + uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; + +int himax_load_CRC_bin_file(struct i2c_client *client); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c index 7e8a1d6572c5121d42a030d3ff7a8d0cb39e8108..309bb5e01073f7fb8e13e1e9dead372135a9ef0a 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -16,6 +16,13 @@ #include "himax_platform.h" #include "himax_common.h" +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#endif + int irq_enable_count = 0; #ifdef HX_SMART_WAKEUP #define TS_WAKE_LOCK_TIMEOUT (2 * HZ) @@ -25,16 +32,7 @@ int irq_enable_count = 0; #define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" #define PINCTRL_STATE_RELEASE "pmx_ts_release" -extern struct himax_ic_data* ic_data; -extern void himax_ts_work(struct himax_ts_data *ts); -extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); -extern int himax_ts_init(struct himax_ts_data *ts); - -extern int tp_rst_gpio; - -#ifdef HX_TP_PROC_DIAG -extern uint8_t getDiagCommand(void); -#endif +/*extern int himax_ts_init(struct himax_ts_data *ts);*/ void himax_vk_parser(struct device_node *dt, struct himax_i2c_platform_data *pdata) @@ -49,30 +47,34 @@ void himax_vk_parser(struct device_node *dt, if (node == NULL) { I(" DT-No vk info in DT"); return; + } else { while ((pp = of_get_next_child(node, pp))) cnt++; if (!cnt) return; - vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL); - if (!vk) - return; + vk = kcalloc(cnt, sizeof(*vk), GFP_KERNEL); pp = NULL; while ((pp = of_get_next_child(node, pp))) { if (of_property_read_u32(pp, "idx", &data) == 0) vk[i].index = data; - if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { - vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1]; - vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3]; + if (of_property_read_u32_array(pp, "range", + coords, 4) == 0) { + vk[i].x_range_min = coords[0], + vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2], + vk[i].y_range_max = coords[3]; } else I(" range faile"); i++; } pdata->virtual_key = vk; for (i = 0; i < cnt; i++) - I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index, - pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max); + I(" vk[%d] idx:%d x_min:%d, y_max:%d", + i, pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, + pdata->virtual_key[i].y_range_max); } } @@ -89,25 +91,31 @@ int himax_parse_dt(struct himax_ts_data *ts, if (prop) { coords_size = prop->length / sizeof(u32); if (coords_size != 4) - D(" %s:Invalid panel coords size %d", __func__, coords_size); + D(" %s:Invalid panel coords size %d", + __func__, coords_size); } - if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { + if (of_property_read_u32_array(dt, "himax,panel-coords", + coords, coords_size) == 0) { pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; - I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, - pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", + __func__, pdata->abs_x_min, pdata->abs_x_max, + pdata->abs_y_min, pdata->abs_y_max); } prop = of_find_property(dt, "himax,display-coords", NULL); if (prop) { coords_size = prop->length / sizeof(u32); if (coords_size != 4) - D(" %s:Invalid display coords size %d", __func__, coords_size); + D(" %s:Invalid display coords size %d", + __func__, coords_size); } - rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); + rc = of_property_read_u32_array(dt, "himax,display-coords", + coords, coords_size); if (rc && (rc != -EINVAL)) { - D(" %s:Fail to read display-coords %d\n", __func__, rc); + D(" %s:Fail to read display-coords %d\n", + __func__, rc); return rc; } pdata->screenWidth = coords[1]; @@ -116,19 +124,19 @@ int himax_parse_dt(struct himax_ts_data *ts, pdata->screenHeight); pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); - if (!gpio_is_valid(pdata->gpio_irq)) { + if (!gpio_is_valid(pdata->gpio_irq)) I(" DT:gpio_irq value is not valid\n"); - } pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); - if (!gpio_is_valid(pdata->gpio_reset)) { + if (!gpio_is_valid(pdata->gpio_reset)) I(" DT:gpio_rst value is not valid\n"); - } + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); - if (!gpio_is_valid(pdata->gpio_3v3_en)) { + if (!gpio_is_valid(pdata->gpio_3v3_en)) I(" DT:gpio_3v3_en value is not valid\n"); - } - I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); + + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", + pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); if (of_property_read_u32(dt, "report_type", &data) == 0) { pdata->protocol_type = data; @@ -140,7 +148,8 @@ int himax_parse_dt(struct himax_ts_data *ts, return 0; } -int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +int i2c_himax_read(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) { int retry; struct i2c_msg msg[] = { @@ -157,7 +166,7 @@ int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, ui .buf = data, } }; - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 2) == 2) break; @@ -166,13 +175,16 @@ int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, ui if (retry == toRetry) { E("%s: i2c_read_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } -int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +int i2c_himax_write(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) { int retry/*, loop_i*/; uint8_t buf[length + 1]; @@ -188,7 +200,7 @@ int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, u buf[0] = command; memcpy(buf+1, data, length); - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 1) == 1) break; @@ -198,13 +210,16 @@ int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, u if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } -int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) +int i2c_himax_read_command(struct i2c_client *client, +uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) { int retry; struct i2c_msg msg[] = { @@ -215,7 +230,7 @@ int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *d .buf = data, } }; - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 1) == 1) break; @@ -224,17 +239,21 @@ int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *d if (retry == toRetry) { E("%s: i2c_read_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } -int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry) +int i2c_himax_write_command(struct i2c_client *client, +uint8_t command, uint8_t toRetry) { return i2c_himax_write(client, command, NULL, 0, toRetry); } -int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry) +int i2c_himax_master_write(struct i2c_client *client, +uint8_t *data, uint8_t length, uint8_t toRetry) { int retry/*, loop_i*/; uint8_t buf[length]; @@ -249,7 +268,7 @@ int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t len }; memcpy(buf, data, length); - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 1) == 1) break; @@ -259,8 +278,10 @@ int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t len if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } @@ -287,62 +308,51 @@ uint8_t himax_int_gpio_read(int pinnum) } #if defined(CONFIG_HMX_DB) -static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +static int himax_regulator_configure(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { - int retval; - pdata->vcc_dig = regulator_get(&client->dev, - "vdd"); - if (IS_ERR(pdata->vcc_dig)) - { - E("%s: Failed to get regulator vdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_dig); - return retval; - } - pdata->vcc_ana = regulator_get(&client->dev, - "avdd"); - if (IS_ERR(pdata->vcc_ana)) - { - E("%s: Failed to get regulator avdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_ana); - regulator_put(pdata->vcc_ana); - return retval; - } - - return 0; + int retval; + + pdata->vcc_dig = regulator_get(&client->dev, "vdd"); + if (IS_ERR(pdata->vcc_dig)) { + E("%s: Failed to get regulator vdd\n", __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + pdata->vcc_ana = regulator_get(&client->dev, "avdd"); + if (IS_ERR(pdata->vcc_ana)) { + E("%s: Failed to get regulator avdd\n", __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_ana); + return retval; + } + + return 0; }; -static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) +static int himax_power_on(struct himax_i2c_platform_data *pdata, +bool on) { - int retval; - - if (on) - { - retval = regulator_enable(pdata->vcc_dig); - if (retval) - { - E("%s: Failed to enable regulator vdd\n", - __func__); - return retval; - } - msleep(100); - retval = regulator_enable(pdata->vcc_ana); - if (retval) - { - E("%s: Failed to enable regulator avdd\n", - __func__); - regulator_disable(pdata->vcc_dig); - return retval; - } - } - else - { - regulator_disable(pdata->vcc_dig); - regulator_disable(pdata->vcc_ana); - } - - return 0; + int retval; + + if (on) { + retval = regulator_enable(pdata->vcc_dig); + if (retval) { + E("%s: Failed to enable regulator vdd\n", __func__); + return retval; + } + msleep(100); + retval = regulator_enable(pdata->vcc_ana); + if (retval) { + E("%s: Failed to enable regulator avdd\n", __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } else { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + return 0; } int himax_ts_pinctrl_init(struct himax_ts_data *ts) @@ -353,41 +363,35 @@ int himax_ts_pinctrl_init(struct himax_ts_data *ts) ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { retval = PTR_ERR(ts->ts_pinctrl); - dev_dbg(&ts->client->dev, - "Target does not use pinctrl %d\n", retval); + dev_dbg(&ts->client->dev, "Target does not use pinctrl %d\n", + retval); goto err_pinctrl_get; } - ts->pinctrl_state_active - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_ACTIVE); + ts->pinctrl_state_active = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_ACTIVE); if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { retval = PTR_ERR(ts->pinctrl_state_active); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_ACTIVE, retval); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); goto err_pinctrl_lookup; } - ts->pinctrl_state_suspend - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_SUSPEND); + ts->pinctrl_state_suspend = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_SUSPEND); if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { retval = PTR_ERR(ts->pinctrl_state_suspend); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_SUSPEND, retval); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); goto err_pinctrl_lookup; } - ts->pinctrl_state_release - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_RELEASE); + ts->pinctrl_state_release = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_RELEASE); if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { retval = PTR_ERR(ts->pinctrl_state_release); - dev_dbg(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_RELEASE, retval); + dev_dbg(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); } return 0; @@ -399,185 +403,161 @@ err_pinctrl_get: return retval; } -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { - int error; + int error; - error = himax_regulator_configure(client, pdata); - if (error) - { - E("Failed to intialize hardware\n"); - goto err_regulator_not_on; - } + error = himax_regulator_configure(client, pdata); + if (error) { + E("Failed to initialize hardware\n"); + goto err_regulator_not_on; + } #ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - /* configure touchscreen reset out gpio */ - error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_reset); - goto err_regulator_on; - } - - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_reset_req; - } - } + if (gpio_is_valid(pdata->gpio_reset)) { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_reset); + goto err_regulator_on; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } #endif - error = himax_power_on(pdata, true); - if (error) - { - E("Failed to power on hardware\n"); - goto err_gpio_reset_req; - } + error = himax_power_on(pdata, true); + if (error) { + E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } #ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_irq); - goto err_power_on; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_irq); - goto err_gpio_irq_req; - } - client->irq = gpio_to_irq(pdata->gpio_irq); - } - else - { - E("irq gpio not provided\n"); - goto err_power_on; - } + /* configure touchscreen irq gpio */ + if (gpio_is_valid(pdata->gpio_irq)) { + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + goto err_power_on; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_req; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + goto err_power_on; + } #endif - - msleep(20); + msleep(20); #ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_irq_req; - } - } + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_irq_req; + } + } #endif - return 0; + return 0; #ifdef HX_RST_PIN_FUNC - err_gpio_irq_req: +err_gpio_irq_req: #endif #ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - gpio_free(pdata->gpio_irq); - err_power_on: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +err_power_on: #endif - himax_power_on(pdata, false); - err_gpio_reset_req: + himax_power_on(pdata, false); +err_gpio_reset_req: #ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - gpio_free(pdata->gpio_reset); - err_regulator_on: + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +err_regulator_on: #endif - err_regulator_not_on: +err_regulator_not_on: - return error; + return error; } #else -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { - int error=0; - + int error = 0; + #ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_request(pdata->gpio_reset, "himax-reset"); - if (error < 0) - { - E("%s: request reset pin failed\n", __func__); - return error; - } - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } + if (pdata->gpio_reset >= 0) { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + if (error < 0) { + E("%s: request reset pin failed\n", __func__); + return error; } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } #endif - if (pdata->gpio_3v3_en >= 0) - { - error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); - if (error < 0) - { - E("%s: request 3v3_en pin failed\n", __func__); - return error; - } - gpio_direction_output(pdata->gpio_3v3_en, 1); - I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + if (pdata->gpio_3v3_en >= 0) { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + if (error < 0) { + E("%s: request 3v3_en pin failed\n", __func__); + return error; } + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + } #ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n",pdata->gpio_irq); - return error; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n",pdata->gpio_irq); - return error; - } - client->irq = gpio_to_irq(pdata->gpio_irq); + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + return error; } - else - { - E("irq gpio not provided\n"); + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); return error; } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + return error; + } #endif - msleep(20); - + msleep(20); + #ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } + if (pdata->gpio_reset >= 0) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; } - msleep(20); -#endif - - return error; } + msleep(20); +#endif + + return error; +} #endif static void himax_ts_isr_func(struct himax_ts_data *ts) @@ -595,34 +575,40 @@ irqreturn_t himax_ts_thread(int irq, void *ptr) if (ts->debug_log_level & BIT(2)) { getnstimeofday(&timeStart); - usleep_range(5000, 7000); - //I(" Irq start time = %ld.%06ld s\n", - // timeStart.tv_sec, timeStart.tv_nsec/1000); + usleep_range(4999, 5000); + /*I(" Irq start time = %ld.%06ld s\n", + timeStart.tv_sec, timeStart.tv_nsec/1000);*/ } #ifdef HX_SMART_WAKEUP - if (atomic_read(&ts->suspend_mode)&&(!FAKE_POWER_KEY_SEND)&&(ts->SMWP_enable)&&(!diag_cmd)) { - wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + if (atomic_read(&ts->suspend_mode) + && (!FAKE_POWER_KEY_SEND) + && (ts->SMWP_enable) + && (!diag_cmd)) { + __pm_wakeup_event(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); msleep(200); himax_wake_check_func(); return IRQ_HANDLED; } #endif himax_ts_isr_func((struct himax_ts_data *)ptr); - if(ts->debug_log_level & BIT(2)) { - getnstimeofday(&timeEnd); - timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec) - -(timeStart.tv_sec*1000000000+timeStart.tv_nsec); - //I("Irq finish time = %ld.%06ld s\n", - // timeEnd.tv_sec, timeEnd.tv_nsec/1000); - //I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000); + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec + = (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) + - (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + /*I("Irq finish time = %ld.%06ld s\n", + timeEnd.tv_sec, timeEnd.tv_nsec/1000); + I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000);*/ } return IRQ_HANDLED; } static void himax_ts_work_func(struct work_struct *work) { - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, work); + himax_ts_work(ts); } @@ -634,24 +620,26 @@ int himax_ts_register_interrupt(struct i2c_client *client) int ret = 0; ts->irq_enabled = 0; - //Work functon + /*Work functon*/ if (client->irq) {/*INT mode*/ ts->use_irq = 1; - if(ic_data->HX_INT_IS_EDGE) - { - I("%s edge triiger falling\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); - } - else - { - I("%s level trigger low\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); + if (ic_data->HX_INT_IS_EDGE) { + I("%s edge triiger falling\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, client->name, ts); + } else { + I("%s level trigger low\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_LOW + | IRQF_ONESHOT, client->name, ts); } if (ret == 0) { ts->irq_enabled = 1; irq_enable_count = 1; tp_irq = client->irq; - I("%s: irq enabled at qpio: %d\n", __func__, client->irq); + I("%s: irq enabled at qpio: %d\n", + __func__, client->irq); #ifdef HX_SMART_WAKEUP irq_set_irq_wake(client->irq, 1); #endif @@ -662,8 +650,8 @@ int himax_ts_register_interrupt(struct i2c_client *client) } else { I("%s: client->irq is empty, use polling mode.\n", __func__); } - - if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + /*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + if (!ts->use_irq) { ts->himax_wq = create_singlethread_workqueue("himax_touch"); INIT_WORK(&ts->work, himax_ts_work_func); @@ -680,7 +668,7 @@ static int himax_common_suspend(struct device *dev) { struct himax_ts_data *ts = dev_get_drvdata(dev); - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); himax_chip_common_suspend(ts); return 0; @@ -690,7 +678,7 @@ static int himax_common_resume(struct device *dev) { struct himax_ts_data *ts = dev_get_drvdata(dev); - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); himax_chip_common_resume(ts); return 0; @@ -702,23 +690,28 @@ int fb_notifier_callback(struct notifier_block *self, { struct fb_event *evdata = data; int *blank; - struct himax_ts_data *ts= - container_of(self, struct himax_ts_data, fb_notif); + struct himax_ts_data *ts + = container_of(self, struct himax_ts_data, fb_notif); + int ERR = 1; I(" %s\n", __func__); - if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && - ts->client) { + if (evdata && evdata->data && event + == FB_EVENT_BLANK && ts && ts->client) { blank = evdata->data; mutex_lock(&ts->fb_mutex); switch (*blank) { case FB_BLANK_UNBLANK: if (!ts->probe_done) { - himax_ts_init(ts); - ts->probe_done = true; - } else { + if (himax_ts_init(ts) == true) { + I("himax_ts_init return OK\n"); + ts->probe_done = true; + } else { + I("himax_ts_init return Fail\n"); + return -ERR; + } + } else himax_common_resume(&ts->client->dev); - } break; case FB_BLANK_POWERDOWN: @@ -748,7 +741,7 @@ static const struct dev_pm_ops himax_common_pm_ops = { }; #ifdef CONFIG_OF -static const struct of_device_id himax_match_table[] = { +static struct of_device_id himax_match_table[] = { {.compatible = "himax,hxcommon" }, {}, }; @@ -770,16 +763,10 @@ static struct i2c_driver himax_common_driver = { }, }; -static void __init himax_common_init_async(void *unused, async_cookie_t cookie) -{ - I("%s:Enter \n", __func__); - i2c_add_driver(&himax_common_driver); -} - static int __init himax_common_init(void) { I("Himax common touch panel driver init\n"); - async_schedule(himax_common_init_async, NULL); + i2c_add_driver(&himax_common_driver); return 0; } @@ -792,5 +779,5 @@ module_init(himax_common_init); module_exit(himax_common_exit); MODULE_DESCRIPTION("Himax_common driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h index 1223685683aa081af63e3a4cc4f44b7f8995436b..6871e53cd1f21851664cce102460095b53e04057 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.h +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -22,6 +22,7 @@ #include #include #include + #if defined(CONFIG_HMX_DB) #include #endif @@ -31,15 +32,11 @@ #define HIMAX_I2C_RETRY_TIMES 10 #if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -#define D(x...) pr_debug("[HXTP] " x) -#define I(x...) pr_info("[HXTP] " x) -#define W(x...) pr_warning("[HXTP][WARNING] " x) -#define E(x...) pr_err("[HXTP][ERROR] " x) -#define DIF(x...) \ -do {\ - if (debug_flag) \ - pr_debug("[HXTP][DEBUG] " x) \ -} while(0) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#define DIF(x...) do { if (debug_flag) pr_info("[HXTP][DEBUG] " x) } while (0) #else #define D(x...) #define I(x...) @@ -53,24 +50,24 @@ do {\ #define HX_VTG_MIN_UV 2700000 #define HX_VTG_MAX_UV 3300000 #define HX_ACTIVE_LOAD_UA 15000 -#define HX_LPM_LOAD_UA 10 +#define HX_LPM_LOAD_UA 10 /* Digital voltage @1.8 V */ #define HX_VTG_DIG_MIN_UV 1800000 #define HX_VTG_DIG_MAX_UV 1800000 #define HX_ACTIVE_LOAD_DIG_UA 10000 -#define HX_LPM_LOAD_DIG_UA 10 +#define HX_LPM_LOAD_DIG_UA 10 #define HX_I2C_VTG_MIN_UV 1800000 #define HX_I2C_VTG_MAX_UV 1800000 -#define HX_I2C_LOAD_UA 10000 -#define HX_I2C_LPM_LOAD_UA 10 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 #endif -#define HIMAX_common_NAME "himax_tp" +#define HIMAX_common_NAME "himax_tp" #define HIMAX_I2C_ADDR 0x48 #define INPUT_DEV_NAME "himax-touchscreen" -struct himax_i2c_platform_data { +struct himax_i2c_platform_data { int abs_x_min; int abs_x_max; int abs_x_fuzz; @@ -108,28 +105,53 @@ struct himax_i2c_platform_data { int irq_gpio; u32 irq_gpio_flags; - struct regulator *vcc_ana; //For Dragon Board - struct regulator *vcc_dig; //For Dragon Board - struct regulator *vcc_i2c; //For Dragon Board -#endif + struct regulator *vcc_ana; /*For Dragon Board*/ + struct regulator *vcc_dig; /*For Dragon Board*/ + struct regulator *vcc_i2c; /*For Dragon Board*/ +#endif }; extern int irq_enable_count; -extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry); -extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); -extern void himax_int_enable(int irqnum, int enable); -extern int himax_ts_register_interrupt(struct i2c_client *client); -extern void himax_rst_gpio_set(int pinnum, uint8_t value); -extern uint8_t himax_int_gpio_read(int pinnum); - -extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata); +int i2c_himax_read(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write_command(struct i2c_client *client, + uint8_t command, uint8_t toRetry); + +int i2c_himax_master_write(struct i2c_client *client, + uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_read_command(struct i2c_client *client, + uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); + +void himax_int_enable(int irqnum, int enable); +int himax_ts_register_interrupt(struct i2c_client *client); +void himax_rst_gpio_set(int pinnum, uint8_t value); +uint8_t himax_int_gpio_read(int pinnum); + +int himax_gpio_power_config(struct i2c_client *client, + struct himax_i2c_platform_data *pdata); #if defined(CONFIG_FB) -extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); #endif +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; +extern void himax_ts_work(struct himax_ts_data *ts); +extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int tp_rst_gpio; + +#ifdef HX_TP_PROC_DIAG +extern uint8_t getDiagCommand(void); +#endif + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata); +int himax_ts_pinctrl_init(struct himax_ts_data *ts); #endif diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c index f50371c833c0270d1da6966c74363ccf300e7c72..1436a685f7ac4caf1d4d305626a614a693abd2bf 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c @@ -55,8 +55,6 @@ #define TYPE_B_PROTOCOL #endif -#define WAKEUP_GESTURE false - #define NO_0D_WHILE_2D #define REPORT_2D_Z #define REPORT_2D_W @@ -69,6 +67,8 @@ #define IGNORE_FN_INIT_FAILURE #define FB_READY_RESET +#define SDW2500_I2C_ADDR 0x20 + #define FB_READY_WAIT_MS 100 #define FB_READY_TIMEOUT_S 30 @@ -114,6 +114,13 @@ #define F12_WAKEUP_GESTURE_MODE 0x02 #define F12_UDG_DETECT 0x0f +#define PWR_VTG_MIN_UV 2700000 +#define PWR_VTG_MAX_UV 3600000 +#define PWR_ACTIVE_LOAD_UA 2000 +#define I2C_VTG_MIN_UV 1710000 +#define I2C_VTG_MAX_UV 2000000 +#define I2C_ACTIVE_LOAD_UA 7000 + 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); @@ -1013,8 +1020,10 @@ static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev, input = input > 0 ? 1 : 0; - if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) + if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) { rmi4_data->enable_wakeup_gesture = input; + rmi4_data->wakeup_gesture_en = input; + } return count; } @@ -1088,7 +1097,6 @@ static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data, input_sync(rmi4_data->input_dev); input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0); input_sync(rmi4_data->input_dev); - rmi4_data->suspend = false; } return 0; @@ -1249,7 +1257,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, input_sync(rmi4_data->input_dev); input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0); input_sync(rmi4_data->input_dev); - rmi4_data->suspend = false; } return 0; @@ -3113,7 +3120,7 @@ flash_prog_mode: } if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) - rmi4_data->enable_wakeup_gesture = WAKEUP_GESTURE; + rmi4_data->enable_wakeup_gesture = rmi4_data->wakeup_gesture_en; else rmi4_data->enable_wakeup_gesture = false; @@ -3408,6 +3415,66 @@ err_gpio_irq: return retval; } +static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA) +{ + return (regulator_count_voltages(reg) > 0) ? + regulator_set_optimum_mode(reg, load_uA) : 0; +} + +static int synaptics_rmi4_configure_reg(struct synaptics_rmi4_data *rmi4_data, + bool on) +{ + int retval; + + if (on == false) + goto hw_shutdown; + + if (rmi4_data->pwr_reg) { + if (regulator_count_voltages(rmi4_data->pwr_reg) > 0) { + retval = regulator_set_voltage(rmi4_data->pwr_reg, + PWR_VTG_MIN_UV, PWR_VTG_MAX_UV); + if (retval) { + dev_err(rmi4_data->pdev->dev.parent, + "regulator set_vtg failed retval =%d\n", + retval); + goto err_set_vtg_pwr; + } + } + } + + if (rmi4_data->bus_reg) { + if (regulator_count_voltages(rmi4_data->bus_reg) > 0) { + retval = regulator_set_voltage(rmi4_data->bus_reg, + I2C_VTG_MIN_UV, I2C_VTG_MAX_UV); + if (retval) { + dev_err(rmi4_data->pdev->dev.parent, + "regulator set_vtg failed retval =%d\n", + retval); + goto err_set_vtg_bus; + } + } + } + + return 0; + +err_set_vtg_bus: + if (rmi4_data->pwr_reg && + regulator_count_voltages(rmi4_data->pwr_reg) > 0) + regulator_set_voltage(rmi4_data->pwr_reg, 0, PWR_VTG_MAX_UV); +err_set_vtg_pwr: + return retval; + +hw_shutdown: + if (rmi4_data->pwr_reg && + regulator_count_voltages(rmi4_data->pwr_reg) > 0) + regulator_set_voltage(rmi4_data->pwr_reg, 0, PWR_VTG_MAX_UV); + if (rmi4_data->bus_reg && + regulator_count_voltages(rmi4_data->bus_reg) > 0) + regulator_set_voltage(rmi4_data->bus_reg, 0, I2C_VTG_MAX_UV); + + return 0; +} + static int synaptics_rmi4_get_reg(struct synaptics_rmi4_data *rmi4_data, bool get) { @@ -3473,37 +3540,66 @@ static int synaptics_rmi4_enable_reg(struct synaptics_rmi4_data *rmi4_data, } if (rmi4_data->bus_reg) { + retval = reg_set_optimum_mode_check(rmi4_data->bus_reg, + I2C_ACTIVE_LOAD_UA); + if (retval < 0) { + dev_err(rmi4_data->pdev->dev.parent, + "%s: Regulator set_opt failed rc=%d\n", + __func__, retval); + return retval; + } + 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; + goto err_bus_reg_en; } } if (rmi4_data->pwr_reg) { + retval = reg_set_optimum_mode_check(rmi4_data->pwr_reg, + PWR_ACTIVE_LOAD_UA); + if (retval < 0) { + dev_err(rmi4_data->pdev->dev.parent, + "%s: Regulator set_opt failed rc=%d\n", + __func__, retval); + goto disable_bus_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; + goto err_pwr_reg_en; } msleep(bdata->power_delay_ms); } return 0; +err_pwr_reg_en: + reg_set_optimum_mode_check(rmi4_data->pwr_reg, 0); + goto disable_bus_reg; +err_bus_reg_en: + reg_set_optimum_mode_check(rmi4_data->bus_reg, 0); + + return retval; + disable_pwr_reg: - if (rmi4_data->pwr_reg) + if (rmi4_data->pwr_reg) { + reg_set_optimum_mode_check(rmi4_data->pwr_reg, 0); regulator_disable(rmi4_data->pwr_reg); + } disable_bus_reg: - if (rmi4_data->bus_reg) + if (rmi4_data->bus_reg) { + reg_set_optimum_mode_check(rmi4_data->bus_reg, 0); regulator_disable(rmi4_data->bus_reg); + } -exit: return retval; } @@ -3953,6 +4049,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) rmi4_data->suspend = false; rmi4_data->irq_enabled = false; rmi4_data->fingers_on_2d = false; + rmi4_data->wakeup_gesture_en = bdata->wakeup_gesture_en; rmi4_data->reset_device = synaptics_rmi4_reset_device; rmi4_data->irq_enable = synaptics_rmi4_irq_enable; @@ -3976,6 +4073,14 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) goto err_get_reg; } + retval = synaptics_rmi4_configure_reg(rmi4_data, true); + if (retval < 0) { + dev_err(&pdev->dev, + "%s: Failed to configure regulators\n", + __func__); + goto err_configure_reg; + } + retval = synaptics_rmi4_enable_reg(rmi4_data, true); if (retval < 0) { dev_err(&pdev->dev, @@ -4202,6 +4307,8 @@ err_set_gpio: err_enable_reg: synaptics_rmi4_get_reg(rmi4_data, false); +err_configure_reg: + synaptics_rmi4_configure_reg(rmi4_data, false); err_get_reg: kfree(rmi4_data); @@ -4284,6 +4391,7 @@ static int synaptics_rmi4_remove(struct platform_device *pdev) } synaptics_rmi4_enable_reg(rmi4_data, false); + synaptics_rmi4_configure_reg(rmi4_data, false); synaptics_rmi4_get_reg(rmi4_data, false); kfree(rmi4_data); @@ -4422,7 +4530,8 @@ static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, synaptics_secure_touch_stop(rmi4_data, false); } else if (event == FB_EVENT_BLANK) { transition = evdata->data; - if (*transition == FB_BLANK_POWERDOWN) { + if (*transition == FB_BLANK_POWERDOWN || + *transition == FB_BLANK_VSYNC_SUSPEND) { flush_work( &(rmi4_data->fb_notify_work)); synaptics_rmi4_suspend( @@ -4556,6 +4665,7 @@ 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); int retval; + int lpm_uA; if (rmi4_data->stay_awake) return 0; @@ -4563,8 +4673,21 @@ static int synaptics_rmi4_suspend(struct device *dev) synaptics_secure_touch_stop(rmi4_data, true); if (rmi4_data->enable_wakeup_gesture) { - synaptics_rmi4_wakeup_gesture(rmi4_data, true); - enable_irq_wake(rmi4_data->irq); + if (!rmi4_data->suspend) { + /* Set lpm current for bus regulator */ + lpm_uA = rmi4_data->hw_if->board_data->bus_lpm_cur_uA; + if (lpm_uA) { + retval = reg_set_optimum_mode_check( + rmi4_data->bus_reg, lpm_uA); + if (retval < 0) + dev_err(dev, + "Bus Regulator set_opt failed rc=%d\n", + retval); + } + + synaptics_rmi4_wakeup_gesture(rmi4_data, true); + enable_irq_wake(rmi4_data->irq); + } goto exit; } @@ -4577,9 +4700,10 @@ static int synaptics_rmi4_suspend(struct device *dev) if (rmi4_data->ts_pinctrl) { retval = pinctrl_select_state(rmi4_data->ts_pinctrl, rmi4_data->pinctrl_state_suspend); - if (retval < 0) + if (retval < 0) { dev_err(dev, "Cannot get idle pinctrl state\n"); goto err_pinctrl; + } } exit: mutex_lock(&exp_data.mutex); @@ -4590,10 +4714,10 @@ exit: } mutex_unlock(&exp_data.mutex); - if (!rmi4_data->suspend) { + if (!rmi4_data->suspend && !rmi4_data->enable_wakeup_gesture && + !rmi4_data->hw_if->board_data->dont_disable_regs) synaptics_rmi4_enable_reg(rmi4_data, false); - synaptics_rmi4_get_reg(rmi4_data, false); - } + rmi4_data->suspend = true; return 0; @@ -4619,17 +4743,30 @@ static int synaptics_rmi4_resume(struct device *dev) synaptics_secure_touch_stop(rmi4_data, true); if (rmi4_data->enable_wakeup_gesture) { - synaptics_rmi4_wakeup_gesture(rmi4_data, false); - disable_irq_wake(rmi4_data->irq); + if (rmi4_data->suspend) { + /* Set active current for the bus regulator */ + if (rmi4_data->hw_if->board_data->bus_lpm_cur_uA) { + retval = reg_set_optimum_mode_check( + rmi4_data->bus_reg, + I2C_ACTIVE_LOAD_UA); + if (retval < 0) + dev_err(dev, + "Pwr regulator set_opt failed rc=%d\n", + retval); + } + + + 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_get_reg(rmi4_data, true); + if (rmi4_data->suspend && + !rmi4_data->hw_if->board_data->dont_disable_regs) synaptics_rmi4_enable_reg(rmi4_data, true); - } synaptics_rmi4_sleep_enable(rmi4_data, false); synaptics_rmi4_irq_enable(rmi4_data, true, false); @@ -4641,12 +4778,14 @@ static int synaptics_rmi4_resume(struct device *dev) } exit: -#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__); + #ifdef FB_READY_RESET + if (rmi4_data->hw_if->board_data->i2c_addr != SDW2500_I2C_ADDR) { + 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); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h index 7d92791afb25e50ea238e813b9aef35eeb305154..7a5b3b5abb473a0b77a016bc9b4a8d83590322ff 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h @@ -371,6 +371,7 @@ struct synaptics_rmi4_data { bool fb_ready; bool f11_wakeup_gesture; bool f12_wakeup_gesture; + bool wakeup_gesture_en; bool enable_wakeup_gesture; bool wedge_sensor; bool report_pressure; diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c index f4854a93a44602bd381311ae127766b433137928..b3afc714b8124da7e27365fd3a520967de5f7a5f 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c @@ -43,10 +43,9 @@ #include "synaptics_dsx_core.h" #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 @@ -54,7 +53,7 @@ #define FB_READY_TIMEOUT_S 30 #endif #endif -*/ + #define FORCE_UPDATE false #define DO_LOCKDOWN false @@ -3418,6 +3417,7 @@ static int fwu_start_reflash(void) enum flash_area flash_area; const struct firmware *fw_entry = NULL; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + const unsigned char *image_name; if (rmi4_data->sensor_sleep) { dev_err(rmi4_data->pdev->dev.parent, @@ -3433,9 +3433,14 @@ static int fwu_start_reflash(void) pr_notice("%s: Start of reflash process\n", __func__); if (fwu->image == NULL) { + if (rmi4_data->hw_if->board_data->fw_name) + image_name = rmi4_data->hw_if->board_data->fw_name; + else + image_name = FW_IMAGE_NAME; + retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN, - FW_IMAGE_NAME, sizeof(FW_IMAGE_NAME), - sizeof(FW_IMAGE_NAME)); + image_name, strlen(image_name), + strlen(image_name)); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to copy image file name\n", diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c index 563ce16885b32ca50ae64493d65a16fbbc45dfa2..95ea222663a45a46f38ee47025f692235b2e1b4d 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c @@ -5,7 +5,8 @@ * * Copyright (C) 2012 Alexandra Chin * Copyright (C) 2012 Scott Lin - * Copyright (C) 2016, The Linux Foundation. All rights reserved. + * Copyright (C) 2016, 2018 The Linux Foundation. All rights reserved. + * * 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 @@ -81,6 +82,12 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) bdata->resume_in_workqueue = of_property_read_bool(np, "synaptics,resume-in-workqueue"); + bdata->wakeup_gesture_en = of_property_read_bool(np, + "synaptics,wakeup-gestures-en"); + + bdata->dont_disable_regs = of_property_read_bool(np, + "synaptics,do-not-disable-regulators"); + retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name); if (retval < 0) bdata->pwr_reg_name = NULL; @@ -181,6 +188,10 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) bdata->max_y_for_2d = -1; } + retval = of_property_read_u32(np, "synaptics,bus-lpm-cur-uA", + &value); + bdata->bus_lpm_cur_uA = retval < 0 ? 0 : value; + prop = of_find_property(np, "synaptics,swap-axes", NULL); bdata->swap_axes = prop > 0 ? true : false; @@ -205,6 +216,12 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) bdata->ub_i2c_addr = -1; } + retval = of_property_read_string(np, "synaptics,fw-name", &name); + if (retval < 0) + bdata->fw_name = NULL; + else + bdata->fw_name = name; + prop = of_find_property(np, "synaptics,cap-button-codes", NULL); if (prop && prop->length) { bdata->cap_button_map->map = devm_kzalloc(dev, diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 1bf9906b5a3fc189276c39d065a2cc58b36ddbd3..75810fa97db5c9897ce6f9a5b8d8e64bb9b503b1 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -456,6 +456,14 @@ static int tsc2007_probe(struct i2c_client *client, tsc2007_stop(ts); + /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) { + dev_err(&client->dev, + "Failed to setup chip: %d\n", err); + return err; /* usually, chip does not respond */ + } + err = input_register_device(input_dev); if (err) { dev_err(&client->dev, diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index e8ba7db084b5c9dc0e90519a634dfe5b7dce01e1..7e0a6cf0541a70d82a0bb897483e361bc3f510a6 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -3381,6 +3381,7 @@ static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova, mutex_unlock(&domain->api_lock); domain_flush_tlb_pde(domain); + domain_flush_complete(domain); return unmap_size; } diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c index ff22d71bea1231c2bea8e75dc9d46c218accc6ec..ac9675ea6dfb8a2370c28f4348e4ae6e3d3bf020 100644 --- a/drivers/iommu/dma-mapping-fast.c +++ b/drivers/iommu/dma-mapping-fast.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016,2019, The Linux Foundation. All rights reserved. * * 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 @@ -397,11 +397,21 @@ static void *fast_smmu_alloc(struct device *dev, size_t size, av8l_fast_iopte *ptep; unsigned long flags; struct sg_mapping_iter miter; - unsigned int count = ALIGN(size, SZ_4K) >> PAGE_SHIFT; + size_t count = ALIGN(size, SZ_4K) >> PAGE_SHIFT; int prot = IOMMU_READ | IOMMU_WRITE; /* TODO: extract from attrs */ pgprot_t remap_prot = pgprot_writecombine(PAGE_KERNEL); struct page **pages; + /* + * sg_alloc_table_from_pages accepts unsigned int value for count + * so check count doesn't exceed UINT_MAX. + */ + + if (count > UINT_MAX) { + dev_err(dev, "count: %zx exceeds UNIT_MAX\n", count); + return NULL; + } + *handle = DMA_ERROR_CODE; pages = __fast_smmu_alloc_pages(count, gfp); diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 4c8fcab840fa2aa153a518ddde66244baca72d8d..27495a62b5dd6ba648ab2284007d39cd448b659b 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2016,10 +2016,12 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, uint64_t tmp; if (!sg_res) { + unsigned int pgoff = sg->offset & ~PAGE_MASK; + sg_res = aligned_nrpages(sg->offset, sg->length); - sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset; + sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + pgoff; sg->dma_length = sg->length; - pteval = page_to_phys(sg_page(sg)) | prot; + pteval = (sg_phys(sg) - pgoff) | prot; phys_pfn = pteval >> VTD_PAGE_SHIFT; } @@ -3326,7 +3328,7 @@ static int intel_nontranslate_map_sg(struct device *hddev, for_each_sg(sglist, sg, nelems, i) { BUG_ON(!sg_page(sg)); - sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset; + sg->dma_address = sg_phys(sg); sg->dma_length = sg->length; } return nelems; diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 9a0aba0d8d592c324518298ad2f078e902b388cd..3c9e5cd435d11b6fa11902ccb11b6523f54c4fb7 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017,2019, The Linux Foundation. All rights reserved. * * 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 @@ -1288,19 +1288,21 @@ static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf, { struct iommu_debug_device *ddev = file->private_data; char c[2]; + size_t buflen = sizeof(c); if (*offset) return 0; c[0] = ddev->domain ? '1' : '0'; c[1] = '\n'; - if (copy_to_user(ubuf, &c, 2)) { + buflen = min(count, buflen); + if (copy_to_user(ubuf, &c, buflen)) { pr_err("copy_to_user failed\n"); return -EFAULT; } *offset = 1; /* non-zero means we're done */ - return 2; + return buflen; } static const struct file_operations iommu_debug_attach_fops = { @@ -1375,7 +1377,7 @@ static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf, snprintf(buf, 100, "%pa\n", &phys); } - buflen = strlen(buf); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index f6b17e6af2fb261f84eafd974d652a76716dcb95..c9e54a0b4bd1f5f146177f485930cf9bc291fc97 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -118,7 +118,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, break; /* found a free slot */ } adjust_limit_pfn: - limit_pfn = curr_iova->pfn_lo - 1; + limit_pfn = curr_iova->pfn_lo ? (curr_iova->pfn_lo - 1) : 0; move_left: prev = curr; curr = rb_prev(curr); diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index bbbaf5de65d2cda705949998e4e3a62ce813496e..8d332a36e5600955c32a5da69d2a2201f064bdad 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -175,7 +175,8 @@ static const struct irq_domain_ops routable_irq_domain_ops = { static int __init crossbar_of_init(struct device_node *node) { - int i, size, max = 0, reserved = 0, entry; + int i, size, reserved = 0; + u32 max = 0, entry, reg_size; const __be32 *irqsr; int ret = -ENOMEM; @@ -252,9 +253,9 @@ static int __init crossbar_of_init(struct device_node *node) if (!cb->register_offsets) goto err_irq_map; - of_property_read_u32(node, "ti,reg-size", &size); + of_property_read_u32(node, "ti,reg-size", ®_size); - switch (size) { + switch (reg_size) { case 1: cb->write = crossbar_writeb; break; @@ -280,7 +281,7 @@ static int __init crossbar_of_init(struct device_node *node) continue; cb->register_offsets[i] = reserved; - reserved += size; + reserved += reg_size; } of_property_read_u32(node, "ti,irqs-safe-map", &cb->safe_map); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 7324511d28d26a632c3f6df26860b5163854ad6c..33c27f8ffd67ab6fcf020552fa20ebe4b13b8944 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -675,7 +675,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq) MPIDR_TO_SGI_AFFINITY(cluster_id, 1) | tlist << ICC_SGI1R_TARGET_LIST_SHIFT); - pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); + pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); gic_write_sgi1r(val); } @@ -690,7 +690,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) * Ensure that stores to Normal memory are visible to the * other CPUs before issuing the IPI. */ - smp_wmb(); + wmb(); for_each_cpu_mask(cpu, *mask) { u64 cluster_id = cpu_logical_map(cpu) & ~0xffUL; diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 823f6985b2603198ff7b7ea7c8869db6032ba168..dd7e38ac29bdd8fd9c8a58e34ed471e1a731bde5 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -1032,6 +1032,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) sizeof(avmb1_carddef)))) return -EFAULT; cdef.cardtype = AVM_CARDTYPE_B1; + cdef.cardnr = 0; } else { if ((retval = copy_from_user(&cdef, data, sizeof(avmb1_extcarddef)))) diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c index d91dd580e9781bc73704d3ad41c009265e227320..37aaea88a6adc05ab599bea9af566d41be3c100d 100644 --- a/drivers/isdn/hardware/eicon/diva.c +++ b/drivers/isdn/hardware/eicon/diva.c @@ -387,10 +387,10 @@ void divasa_xdi_driver_unload(void) ** Receive and process command from user mode utility */ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *mptr, divas_xdi_copy_from_user_fn_t cp_fn) { - diva_xdi_um_cfg_cmd_t msg; + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = NULL; diva_os_spin_lock_magic_t old_irql; struct list_head *tmp; @@ -400,21 +400,21 @@ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, length, sizeof(diva_xdi_um_cfg_cmd_t))) return NULL; } - if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { + if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) { DBG_ERR(("A: A(?) open, write error")) return NULL; } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); list_for_each(tmp, &adapter_queue) { a = list_entry(tmp, diva_os_xdi_adapter_t, link); - if (a->controller == (int)msg.adapter) + if (a->controller == (int)msg->adapter) break; a = NULL; } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); if (!a) { - DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter)) + DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter)) } return (a); @@ -436,8 +436,10 @@ void diva_xdi_close_adapter(void *adapter, void *os_handle) int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn) + int length, void *mptr, + divas_xdi_copy_from_user_fn_t cp_fn) { + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; void *data; @@ -458,7 +460,13 @@ diva_xdi_write(void *adapter, void *os_handle, const void __user *src, return (-2); } - length = (*cp_fn) (os_handle, data, src, length); + if (msg) { + *(diva_xdi_um_cfg_cmd_t *)data = *msg; + length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg), + src + sizeof(*msg), length - sizeof(*msg)); + } else { + length = (*cp_fn) (os_handle, data, src, length); + } if (length > 0) { if ((*(a->interface.cmd_proc)) (a, (diva_xdi_um_cfg_cmd_t *) data, length)) { diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h index e979085d1b891ff50497337849cd8a5157ffa57e..a0a607c0c32e219b45014f5bb22b64fb61752547 100644 --- a/drivers/isdn/hardware/eicon/diva.h +++ b/drivers/isdn/hardware/eicon/diva.h @@ -19,10 +19,11 @@ int diva_xdi_read(void *adapter, void *os_handle, void __user *dst, int max_length, divas_xdi_copy_to_user_fn_t cp_fn); int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn); + int length, void *msg, + divas_xdi_copy_from_user_fn_t cp_fn); void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *msg, divas_xdi_copy_from_user_fn_t cp_fn); void diva_xdi_close_adapter(void *adapter, void *os_handle); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index a2e0ed6c9a4d367db910d9493974bcd116a369e1..91bd2ba0bdd889ae5aecefa4b3c3e02ef1b3ce2f 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -591,19 +591,22 @@ static int divas_release(struct inode *inode, struct file *file) static ssize_t divas_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); - } - if (!file->private_data) { - return (-ENODEV); + if (!file->private_data) + return (-ENODEV); + ret = diva_xdi_write(file->private_data, file, + buf, count, &msg, xdi_copy_from_user); + } else { + ret = diva_xdi_write(file->private_data, file, + buf, count, NULL, xdi_copy_from_user); } - ret = diva_xdi_write(file->private_data, file, - buf, count, xdi_copy_from_user); switch (ret) { case -1: /* Message should be removed from rx mailbox first */ ret = -EBUSY; @@ -622,11 +625,12 @@ static ssize_t divas_write(struct file *file, const char __user *buf, static ssize_t divas_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); } if (!file->private_data) { diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index e4c43a17b333f1ecaed85cbe50133274600cb092..8088c34336aa82adb1a6167fb79078b6d1dbb2fc 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1655,13 +1655,7 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) } else return -EINVAL; case IIOCDBGVAR: - if (arg) { - if (copy_to_user(argp, &dev, sizeof(ulong))) - return -EFAULT; - return 0; - } else - return -EINVAL; - break; + return -EINVAL; default: if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index bf3fbd00a091a166d1e6411d0d84a8ea1355405a..64b586458d3dbecaf887cc18e70e5ff2234aa9b1 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -828,7 +828,6 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count) isdn_net_local *lp; struct ippp_struct *is; int proto; - unsigned char protobuf[4]; is = file->private_data; @@ -842,24 +841,28 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count) if (!lp) printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n"); else { - /* - * Don't reset huptimer for - * LCP packets. (Echo requests). - */ - if (copy_from_user(protobuf, buf, 4)) - return -EFAULT; - proto = PPP_PROTOCOL(protobuf); - if (proto != PPP_LCP) - lp->huptimer = 0; + if (lp->isdn_device < 0 || lp->isdn_channel < 0) { + unsigned char protobuf[4]; + /* + * Don't reset huptimer for + * LCP packets. (Echo requests). + */ + if (copy_from_user(protobuf, buf, 4)) + return -EFAULT; + + proto = PPP_PROTOCOL(protobuf); + if (proto != PPP_LCP) + lp->huptimer = 0; - if (lp->isdn_device < 0 || lp->isdn_channel < 0) return 0; + } if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { unsigned short hl; struct sk_buff *skb; + unsigned char *cpy_buf; /* * we need to reserve enough space in front of * sk_buff. old call to dev_alloc_skb only reserved @@ -872,11 +875,21 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count) return count; } skb_reserve(skb, hl); - if (copy_from_user(skb_put(skb, count), buf, count)) + cpy_buf = skb_put(skb, count); + if (copy_from_user(cpy_buf, buf, count)) { kfree_skb(skb); return -EFAULT; } + + /* + * Don't reset huptimer for + * LCP packets. (Echo requests). + */ + proto = PPP_PROTOCOL(cpy_buf); + if (proto != PPP_LCP) + lp->huptimer = 0; + if (is->debug & 0x40) { printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot); diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 9cb4b621fbc3cffe0bceb770bde7dbdac292dd95..b92a19a594a108f6ba71126fa05c76ed47b49e01 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -72,7 +72,7 @@ send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) if (sk->sk_state != MISDN_BOUND) continue; if (!cskb) - cskb = skb_copy(skb, GFP_KERNEL); + cskb = skb_copy(skb, GFP_ATOMIC); if (!cskb) { printk(KERN_WARNING "%s no skb\n", __func__); break; diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c20146a74b96662cab4e72f6d880948b54d51871..7bb01ac5d9ab53ef5844609c88fc9f52589096d9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -299,6 +299,15 @@ config LEDS_PCA963X LED driver chip accessed via the I2C bus. Supported devices include PCA9633 and PCA9634 +config LEDS_PCA9956B + tristate "LED Support for PCA9956B I2C chips" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for LEDs connected to PCA9956B + LED driver chips accessed via the I2C bus. Supported + devices include PCA9956B. + config LEDS_WM831X_STATUS tristate "LED support for status LEDs on WM831x PMICs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index b2e1d5bad5c9a17ae10297892f5e34767ea107f6..dc71d9ce3c332977085bc25d54ae3178b2245100 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o +obj-$(CONFIG_LEDS_PCA9956B) += leds-pca9956b.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index e8b1120f486d6de7289f77e378b0e2ad14e3712d..eef3e64ca0a87251df918ebb763a7139b79785da 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -88,21 +88,23 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, down_read(&led_cdev->trigger_lock); if (!led_cdev->trigger) - len += sprintf(buf+len, "[none] "); + len += scnprintf(buf+len, PAGE_SIZE - len, "[none] "); else - len += sprintf(buf+len, "none "); + len += scnprintf(buf+len, PAGE_SIZE - len, "none "); list_for_each_entry(trig, &trigger_list, next_trig) { if (led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name)) - len += sprintf(buf+len, "[%s] ", trig->name); + len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ", + trig->name); else - len += sprintf(buf+len, "%s ", trig->name); + len += scnprintf(buf+len, PAGE_SIZE - len, "%s ", + trig->name); } up_read(&led_cdev->trigger_lock); up_read(&triggers_list_lock); - len += sprintf(len+buf, "\n"); + len += scnprintf(len+buf, PAGE_SIZE - len, "\n"); return len; } EXPORT_SYMBOL_GPL(led_trigger_show); diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index c3a08b60535bc31048d1246c1d5ef01dd5c12c6b..760deffa9ad3043b7847671ad8867971115e507b 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -281,7 +281,7 @@ static int pca955x_probe(struct i2c_client *client, "slave address 0x%02x\n", id->name, chip->bits, client->addr); - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; if (pdata) { diff --git a/drivers/leds/leds-pca9956b.c b/drivers/leds/leds-pca9956b.c new file mode 100644 index 0000000000000000000000000000000000000000..f612c9a9469be0294fdf4e8ca7e057b36ddfe03a --- /dev/null +++ b/drivers/leds/leds-pca9956b.c @@ -0,0 +1,534 @@ +/* + * leds-pca9956b.c - NXP PCA9956B LED segment driver + * + * Copyright (C) 2017 NXP Semiconductors + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "leds-pca9956b.h" + +#define PCA9956B_LED_NUM 24 +#define MAX_DEVICES 32 + +#define DRIVER_NAME "nxp-ledseg" +#define DRIVER_VERSION "17.11.28" + +struct pca9956b_chip { + struct i2c_client *client; + struct mutex lock; + struct pca9956b_led *leds; +}; + +struct pca9956b_led { + struct led_classdev led_cdev; + struct pca9956b_chip *chip; + int led_num; + char name[32]; +}; + +static struct device *pca9956b_dev; + +/* + * Read one byte from given register address. + */ +static int pca9956b_read_reg(struct pca9956b_chip *chip, int reg, uint8_t *val) +{ + int ret = i2c_smbus_read_byte_data(chip->client, reg); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed reading register\n"); + return ret; + } + + *val = (uint8_t)ret; + return 0; +} + +/* + * Write one byte to the given register address. + */ +static int pca9956b_write_reg(struct pca9956b_chip *chip, int reg, uint8_t val) +{ + int ret = i2c_smbus_write_byte_data(chip->client, reg, val); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed writing register\n"); + return ret; + } + + return 0; +} + +/* + * Read string from device tree property and write it to the register. + */ +static int pca9956b_readWrite_reg(struct pca9956b_chip *chip, + char *readStr, int writeRegAddr) +{ + struct device_node *np = chip->client->dev.of_node; + uint32_t reg_value; + int ret; + + ret = of_property_read_u32(np, readStr, ®_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to read %s\n", + __func__, readStr); + return ret; + } + + mutex_lock(&chip->lock); + + ret = pca9956b_write_reg(chip, writeRegAddr, (uint8_t)reg_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to write %s , value = 0x%x\n", + __func__, readStr, reg_value); + mutex_unlock(&chip->lock); + return ret; + } + + mutex_unlock(&chip->lock); + + return ret; +} + +/* + * Store one byte to given register address. + */ +static ssize_t pca9956b_storeReg(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + unsigned int ret, reg_value, reg_addr; + + ret = sscanf(buf, "%x %x", ®_addr, ®_value); + if (ret == 0) { + dev_err(&chip->client->dev, + "[%s] fail to pca9956b out.\n", + __func__); + return count; + } + + if (reg_addr < PCA9956B_MODE1 || reg_addr > PCA9956B_IREFALL) { + dev_err(&chip->client->dev, + "[%s] Out of range. Reg = 0x%x\n", + __func__, reg_addr); + return count; + } + + mutex_lock(&chip->lock); + + ret = pca9956b_write_reg(chip, reg_addr, (uint8_t)reg_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Operation [0x%x , %d] is failed.\n", + __func__, reg_addr, reg_value); + + mutex_unlock(&chip->lock); + + return count; +} + +/* + * Show all registers + */ +static ssize_t pca9956b_showReg(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + uint8_t reg_value = 0; + int ret, i; + char *bufp = buf; + + mutex_lock(&chip->lock); + + for (i = PCA9956B_MODE1; i < PCA9956B_IREFALL; i++) { + ret = pca9956b_read_reg(chip, i, ®_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Reading reg[0x%x] is failed.\n", + __func__, i); + + bufp += snprintf(bufp, PAGE_SIZE, "Addr[0x%x] = 0x%x\n", i, reg_value); + } + + mutex_unlock(&chip->lock); + + return strlen(buf); +} + +static DEVICE_ATTR(reg, 0664, + pca9956b_showReg, pca9956b_storeReg); + +/* + * Show error register. + */ +static ssize_t pca9956_showErr(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + uint8_t reg_value = 0; + int ret, i; + char *bufp = buf; + + mutex_lock(&chip->lock); + + for (i = PCA9956B_EFLAG0 ; i <= PCA9956B_EFLAG4 ; i++) { + ret = pca9956b_read_reg(chip, i, ®_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Reading [0x%x] is failed.\n", + __func__, i); + + bufp += snprintf(bufp, PAGE_SIZE, "PCA9956B_EFLAG[%d] = 0x%x\n", + i - PCA9956B_EFLAG0, reg_value); + } + + mutex_unlock(&chip->lock); + + return strlen(buf); +} +static DEVICE_ATTR(err, 0664, + pca9956_showErr, NULL); + +static struct attribute *attrs[] = { + &dev_attr_err.attr, + &dev_attr_reg.attr, + NULL, /* Need to NULL terminate the list of attributes */ +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +/* + * Individual PWM set function + */ +static void pca9956b_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct pca9956b_led *pca9956b; + struct pca9956b_chip *chip; + int ret; + + pca9956b = container_of(led_cdev, struct pca9956b_led, led_cdev); + chip = pca9956b->chip; + + mutex_lock(&chip->lock); + ret = pca9956b_write_reg(chip, + PCA9956B_PWM0 + pca9956b->led_num, + value); + if (ret != 0) + dev_err(&chip->client->dev, "[%s] is failed = %d.\n", + __func__, ret); + + mutex_unlock(&chip->lock); +} + +/* + * Individual PWM get function + */ +static enum led_brightness pca9956b_brightness_get( + struct led_classdev *led_cdev) +{ + struct pca9956b_led *pca9956b; + struct pca9956b_chip *chip; + int ret; + uint8_t reg_value; + + pca9956b = container_of(led_cdev, struct pca9956b_led, led_cdev); + chip = pca9956b->chip; + + mutex_lock(&chip->lock); + ret = pca9956b_read_reg(chip, PCA9956B_PWM0 + pca9956b->led_num, + ®_value); + if (ret != 0) + dev_err(&chip->client->dev, "[%s] is failed = %d.\n", + __func__, ret); + + mutex_unlock(&chip->lock); + + return reg_value; +} + +static int pca9956b_registerClassDevice(struct i2c_client *client, + struct pca9956b_chip *chip) +{ + int i, err; + struct pca9956b_led *led; + struct led_platform_data *pdata; + + pdata = dev_get_platdata(&client->dev); + if (pdata) { + if (pdata->num_leds != PCA9956B_LED_NUM) { + dev_err(&client->dev, + "board info claims %d LEDs on a %d-bit chip\n", + pdata->num_leds, PCA9956B_LED_NUM); + return -ENODEV; + } + } + + for (i = 0 ; i < PCA9956B_LED_NUM ; i++) { + led = &chip->leds[i]; + led->led_num = i; + + /* Platform data can specify LED names and default triggers */ + if (pdata) { + if (pdata->leds[i].name) + snprintf(led->name, + sizeof(led->name), "pca9956b:%s", + pdata->leds[i].name); + if (pdata->leds[i].default_trigger) + led->led_cdev.default_trigger = + pdata->leds[i].default_trigger; + } else { + snprintf(led->name, sizeof(led->name), + "pca9956b:%d", i); + } + + led->led_cdev.name = led->name; + led->led_cdev.brightness_set = pca9956b_brightness_set; + led->led_cdev.brightness_get = pca9956b_brightness_get; + led->chip = chip; + led->led_num = i; + + err = led_classdev_register(&client->dev, + &led->led_cdev); + if (err < 0) + goto exit; + + } + return 0; +exit: + while (i--) + led_classdev_unregister(&chip->leds[i].led_cdev); + + return err; +} + +/* + * Read properties and write it to register. + */ +static int pca9956b_setup(struct pca9956b_chip *chip) +{ + struct device_node *np = chip->client->dev.of_node; + int ret; + uint32_t reg_value; + + ret = of_property_read_u32(np, "pca9956b,support_initialize", + ®_value); + if (ret < 0) { + pr_err("[%s]: " + "Unable to pca9956b,support_initialize\n", + __func__); + return ret; + } + + if (0 == reg_value) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,mode1", + PCA9956B_MODE1); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,mode2", + PCA9956B_MODE2); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout0", + PCA9956B_LEDOUT0); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout1", + PCA9956B_LEDOUT1); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout2", + PCA9956B_LEDOUT2); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout3", + PCA9956B_LEDOUT3); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout4", + PCA9956B_LEDOUT4); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout5", + PCA9956B_LEDOUT5); + if (ret < 0) + return ret; + + /* set default IREF to all IREF */ + { + int reg_addr; + + ret = of_property_read_u32(np, "pca9956b,defaultiref", + ®_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to read pca9956b,defaultiref\n", + __func__); + return ret; + } + mutex_lock(&chip->lock); + + for (reg_addr = PCA9956B_IREF0; reg_addr <= PCA9956B_IREF23; reg_addr++) { + ret = pca9956b_write_reg(chip, reg_addr, (uint8_t)reg_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to write reg0x%x[0x%x]\n", + __func__, reg_addr, reg_value); + mutex_unlock(&chip->lock); + return ret; + } + } + mutex_unlock(&chip->lock); + } + + /* set IREF0 ~ IREF23 if required */ + + return ret; +} + + +static int pca9956b_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pca9956b_chip *chip; + struct pca9956b_led *led; + int ret; + int i; + + pr_info(DRIVER_NAME": "" (I2C) "DRIVER_VERSION"\n"); + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); + return -EIO; + } + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->leds = devm_kzalloc(&client->dev, sizeof(*led)*PCA9956B_LED_NUM, + GFP_KERNEL); + if (!chip->leds) { + devm_kfree(&client->dev, chip); + return -ENOMEM; + } + + i2c_set_clientdata(client, chip); + + mutex_init(&chip->lock); + chip->client = client; + + /* LED device class registration */ + ret = pca9956b_registerClassDevice(client, chip); + if (ret < 0) + goto exit; + + /* Configuration setup */ + ret = pca9956b_setup(chip); + if (ret < 0) + goto err_setup; + + pca9956b_dev = &client->dev; + + ret = sysfs_create_group(&pca9956b_dev->kobj, &attr_group); + if (ret) { + dev_err(&client->dev, + "Failed to create sysfs group for pca9956b\n"); + goto err_setup; + } + + return 0; + +err_setup: + for (i = 0; i < PCA9956B_LED_NUM; i++) + led_classdev_unregister(&chip->leds[i].led_cdev); +exit: + mutex_destroy(&chip->lock); + devm_kfree(&client->dev, chip->leds); + devm_kfree(&client->dev, chip); + return ret; +} + +static int pca9956b_remove(struct i2c_client *client) +{ + struct pca9956b_chip *dev = i2c_get_clientdata(client); + int i; + + for (i = 0; i < PCA9956B_LED_NUM; i++) + led_classdev_unregister(&dev->leds[i].led_cdev); + + sysfs_remove_group(&pca9956b_dev->kobj, &attr_group); + + mutex_destroy(&dev->lock); + devm_kfree(&client->dev, dev->leds); + devm_kfree(&client->dev, dev); + return 0; +} + +static struct of_device_id pca9956b_dt_ids[] = { + { .compatible = "nxp,pca9956b",}, +}; + +static const struct i2c_device_id pca9956b_id[] = { + {DRIVER_NAME"-i2c", 0, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pca9956b_id); + +static struct i2c_driver pca9956b_driver = { + .driver = { + .name = DRIVER_NAME"-i2c", + .of_match_table = of_match_ptr(pca9956b_dt_ids), + }, + .probe = pca9956b_probe, + .remove = pca9956b_remove, + .id_table = pca9956b_id, +}; + +static int __init pca9956b_init(void) +{ + return i2c_add_driver(&pca9956b_driver); +} + +static void __exit pca9956b_exit(void) +{ + i2c_del_driver(&pca9956b_driver); +} +module_init(pca9956b_init); +module_exit(pca9956b_exit); +MODULE_AUTHOR("NXP Semiconductors"); +MODULE_DESCRIPTION("PCA9956B : 24-channel constant current LED driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/leds/leds-pca9956b.h b/drivers/leds/leds-pca9956b.h new file mode 100644 index 0000000000000000000000000000000000000000..3ff309684801263c20470838cbf366da79e67620 --- /dev/null +++ b/drivers/leds/leds-pca9956b.h @@ -0,0 +1,111 @@ +/* + * leds-pca9956b.h - NXP PCA9956B LED segment driver + * + * Copyright (C) 2017 NXP Semiconductors + * + * 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. + */ + +#ifndef PCA9956B_H + +/* Register address */ +enum { + PCA9956B_MODE1 = 0x00, /* AIF, SLEEP, SUBn, ALLCALL */ + PCA9956B_MODE2, /* OVERTEMP, ERROR, DMBLNK, CLRERR, OCH */ + PCA9956B_LEDOUT0, /* LED driver output state */ + PCA9956B_LEDOUT1, + PCA9956B_LEDOUT2, + PCA9956B_LEDOUT3, + PCA9956B_LEDOUT4, + PCA9956B_LEDOUT5, + PCA9956B_GRPPWM, /* DMBLINK set 0, then GRPPWM controls + global brightness */ + PCA9956B_GRPFREQ, /* DMBLINK set 1, then GRPFREQ controls + global blinking period */ + + /* 10 : 0x0A */ + PCA9956B_PWM0, /* Brightness control */ + PCA9956B_PWM1, + PCA9956B_PWM2, + PCA9956B_PWM3, + PCA9956B_PWM4, + PCA9956B_PWM5, + PCA9956B_PWM6, + PCA9956B_PWM7, + PCA9956B_PWM8, + PCA9956B_PWM9, + + /* 20 : 0x14 */ + PCA9956B_PWM10, + PCA9956B_PWM11, + PCA9956B_PWM12, + PCA9956B_PWM13, + PCA9956B_PWM14, + PCA9956B_PWM15, + PCA9956B_PWM16, + PCA9956B_PWM17, + PCA9956B_PWM18, + PCA9956B_PWM19, + + /* 30 : 0x1E */ + PCA9956B_PWM20, + PCA9956B_PWM21, + PCA9956B_PWM22, + PCA9956B_PWM23, + PCA9956B_IREF0, /* Output current control */ + PCA9956B_IREF1, + PCA9956B_IREF2, + PCA9956B_IREF3, + PCA9956B_IREF4, + PCA9956B_IREF5, + + /* 40 : 0x28 */ + PCA9956B_IREF6, + PCA9956B_IREF7, + PCA9956B_IREF8, + PCA9956B_IREF9, + PCA9956B_IREF10, + PCA9956B_IREF11, + PCA9956B_IREF12, + PCA9956B_IREF13, + PCA9956B_IREF14, + PCA9956B_IREF15, + + /* 50 : 0x32 */ + PCA9956B_IREF16, + PCA9956B_IREF17, + PCA9956B_IREF18, + PCA9956B_IREF19, + PCA9956B_IREF20, + PCA9956B_IREF21, + PCA9956B_IREF22, + PCA9956B_IREF23, + PCA9956B_OFFSET, /* led turn-on delay */ + PCA9956B_SUBADR1, /* I2C bus subaddress */ + + /* 60 : 0x3C */ + PCA9956B_SUBADR2, + PCA9956B_SUBADR3, + PCA9956B_ALLCALLADR, /* Allows all the PCA9956Bs on the bus to be + programmed at the same time */ + PCA9956B_PWMALL, /* brightness control for all LEDn outputs */ + PCA9956B_IREFALL, /* output current value for all LED outputs */ + PCA9956B_EFLAG0, /* LED error detection */ + PCA9956B_EFLAG1, + PCA9956B_EFLAG2, + PCA9956B_EFLAG3, + PCA9956B_EFLAG4, + + /* 70 : 0x46 */ + PCA9956B_EFLAG5, +}; + +#endif /* PCA9956B_H */ diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c index ec4b4e7d9409ea5f78e3e0bf4f3e0b16e6a32db7..785fe5130672ffd4c6b8920a2fec44d373141117 100644 --- a/drivers/leds/leds-qpnp-flash.c +++ b/drivers/leds/leds-qpnp-flash.c @@ -1307,7 +1307,7 @@ static void qpnp_flash_led_work(struct work_struct *work) int max_curr_avail_ma = 0; int total_curr_ma = 0; int i; - u8 val; + u8 val = 0; /* Global lock is to synchronize between the flash leds and torch */ mutex_lock(&led->flash_led_lock); @@ -1319,8 +1319,30 @@ static void qpnp_flash_led_work(struct work_struct *work) goto turn_off; if (led->open_fault) { - dev_err(&led->spmi_dev->dev, "Open fault detected\n"); - goto unlock_mutex; + if (flash_node->type == FLASH) { + dev_dbg(&led->spmi_dev->dev, "Open fault detected\n"); + goto unlock_mutex; + } + /* + * Checking LED fault status again if open_fault has been + * detected previously. Update open_fault status then the + * flash leds could be controlled again if the hardware + * status is recovered. + */ + rc = spmi_ext_register_readl(led->spmi_dev->ctrl, + led->spmi_dev->sid, + FLASH_LED_FAULT_STATUS(led->base), &val, 1); + if (rc) { + dev_err(&led->spmi_dev->dev, + "Failed to read out fault status register\n"); + goto unlock_mutex; + } + + led->open_fault = (val & FLASH_LED_OPEN_FAULT_DETECTED); + if (led->open_fault) { + dev_err(&led->spmi_dev->dev, "Open fault detected\n"); + goto unlock_mutex; + } } if (!flash_node->flash_on && flash_node->num_regulators > 0) { @@ -1804,7 +1826,7 @@ turn_off: goto exit_flash_led_work; } - led->open_fault |= (val & FLASH_LED_OPEN_FAULT_DETECTED); + led->open_fault = (val & FLASH_LED_OPEN_FAULT_DETECTED); } rc = qpnp_led_masked_write(led->spmi_dev, diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index dee88e59f0d34be1359661368799d8546668eda7..d7b90ed7c7172b97227b682ae4ab465b597c87ca 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -527,8 +527,9 @@ init_pmu(void) int timeout; struct adb_request req; - out_8(&via[B], via[B] | TREQ); /* negate TREQ */ - out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ + /* Negate TREQ. Set TACK to input and TREQ to output. */ + out_8(&via[B], in_8(&via[B]) | TREQ); + out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); timeout = 100000; @@ -1450,8 +1451,8 @@ pmu_sr_intr(void) struct adb_request *req; int bite = 0; - if (via[B] & TREQ) { - printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); + if (in_8(&via[B]) & TREQ) { + printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B])); out_8(&via[IFR], SR_INT); return NULL; } diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 8eeab72b93e2c4fcf6573e6a63d768f40f8e5320..d6427a75611a964e09423552047b4c096c3b5a13 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -285,8 +285,10 @@ do { \ break; \ \ mutex_unlock(&(ca)->set->bucket_lock); \ - if (kthread_should_stop()) \ + if (kthread_should_stop()) { \ + set_current_state(TASK_RUNNING); \ return 0; \ + } \ \ try_to_freeze(); \ schedule(); \ @@ -406,7 +408,8 @@ long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait) finish_wait(&ca->set->bucket_wait, &w); out: - wake_up_process(ca->alloc_thread); + if (ca->alloc_thread) + wake_up_process(ca->alloc_thread); trace_bcache_alloc(ca, reserve); @@ -513,15 +516,21 @@ struct open_bucket { /* * We keep multiple buckets open for writes, and try to segregate different - * write streams for better cache utilization: first we look for a bucket where - * the last write to it was sequential with the current write, and failing that - * we look for a bucket that was last used by the same task. + * write streams for better cache utilization: first we try to segregate flash + * only volume write streams from cached devices, secondly we look for a bucket + * where the last write to it was sequential with the current write, and + * failing that we look for a bucket that was last used by the same task. * * The ideas is if you've got multiple tasks pulling data into the cache at the * same time, you'll get better cache utilization if you try to segregate their * data and preserve locality. * - * For example, say you've starting Firefox at the same time you're copying a + * For example, dirty sectors of flash only volume is not reclaimable, if their + * dirty sectors mixed with dirty sectors of cached device, such buckets will + * be marked as dirty and won't be reclaimed, though the dirty data of cached + * device have been written back to backend device. + * + * And say you've starting Firefox at the same time you're copying a * bunch of files. Firefox will likely end up being fairly hot and stay in the * cache awhile, but the data you copied might not be; if you wrote all that * data to the same buckets it'd get invalidated at the same time. @@ -538,7 +547,10 @@ static struct open_bucket *pick_data_bucket(struct cache_set *c, struct open_bucket *ret, *ret_task = NULL; list_for_each_entry_reverse(ret, &c->data_buckets, list) - if (!bkey_cmp(&ret->key, search)) + if (UUID_FLASH_ONLY(&c->uuids[KEY_INODE(&ret->key)]) != + UUID_FLASH_ONLY(&c->uuids[KEY_INODE(search)])) + continue; + else if (!bkey_cmp(&ret->key, search)) goto found; else if (ret->last_write_point == write_point) ret_task = ret; diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 04f7bc28ef832b6dded6d10e810ddbfbfada4fca..b4812b1b9df4d4b914754da73b741801fe1ff6fe 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -348,6 +348,7 @@ struct cached_dev { /* Limit number of writeback bios in flight */ struct semaphore in_flight; struct task_struct *writeback_thread; + struct workqueue_struct *writeback_write_wq; struct keybuf writeback_keys; @@ -921,7 +922,7 @@ void bcache_write_super(struct cache_set *); int bch_flash_dev_create(struct cache_set *c, uint64_t size); -int bch_cached_dev_attach(struct cached_dev *, struct cache_set *); +int bch_cached_dev_attach(struct cached_dev *, struct cache_set *, uint8_t *); void bch_cached_dev_detach(struct cached_dev *); void bch_cached_dev_run(struct cached_dev *); void bcache_device_stop(struct bcache_device *); diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 43829d9493f7065c4943b0fe4d9ceaa7315e466f..5a8c4017be6629540bc183d3275233efdb118d74 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -808,7 +808,10 @@ int bch_btree_cache_alloc(struct cache_set *c) c->shrink.scan_objects = bch_mca_scan; c->shrink.seeks = 4; c->shrink.batch = c->btree_pages * 2; - register_shrinker(&c->shrink); + + if (register_shrinker(&c->shrink)) + pr_warn("bcache: %s: could not register shrinker", + __func__); return 0; } @@ -1866,14 +1869,17 @@ void bch_initial_gc_finish(struct cache_set *c) */ for_each_cache(ca, c, i) { for_each_bucket(b, ca) { - if (fifo_full(&ca->free[RESERVE_PRIO])) + if (fifo_full(&ca->free[RESERVE_PRIO]) && + fifo_full(&ca->free[RESERVE_BTREE])) break; if (bch_can_invalidate_bucket(ca, b) && !GC_MARK(b)) { __bch_invalidate_one_bucket(ca, b); - fifo_push(&ca->free[RESERVE_PRIO], - b - ca->buckets); + if (!fifo_push(&ca->free[RESERVE_PRIO], + b - ca->buckets)) + fifo_push(&ca->free[RESERVE_BTREE], + b - ca->buckets); } } } diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 62e6e98186b5cd536d75a9bec14a2c374102abbe..ac8f1ac3feda891c7e2d610e01824426de77fb8f 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -464,6 +464,7 @@ struct search { unsigned recoverable:1; unsigned write:1; unsigned read_dirty_data:1; + unsigned cache_missed:1; unsigned long start_time; @@ -630,11 +631,11 @@ static void do_bio_hook(struct search *s, struct bio *orig_bio) static void search_free(struct closure *cl) { struct search *s = container_of(cl, struct search, cl); - bio_complete(s); if (s->iop.bio) bio_put(s->iop.bio); + bio_complete(s); closure_debug_destroy(cl); mempool_free(s, s->d->c->search); } @@ -651,6 +652,7 @@ static inline struct search *search_alloc(struct bio *bio, s->orig_bio = bio; s->cache_miss = NULL; + s->cache_missed = 0; s->d = d; s->recoverable = 1; s->write = (bio->bi_rw & REQ_WRITE) != 0; @@ -706,7 +708,14 @@ static void cached_dev_read_error(struct closure *cl) struct search *s = container_of(cl, struct search, cl); struct bio *bio = &s->bio.bio; - if (s->recoverable) { + /* + * If read request hit dirty data (s->read_dirty_data is true), + * then recovery a failed read request from cached device may + * get a stale data back. So read failure recovery is only + * permitted when read request hit clean data in cache device, + * or when cache read race happened. + */ + if (s->recoverable && !s->read_dirty_data) { /* Retry from the backing device: */ trace_bcache_read_retry(s->orig_bio); @@ -767,7 +776,7 @@ static void cached_dev_read_done_bh(struct closure *cl) struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); bch_mark_cache_accounting(s->iop.c, s->d, - !s->cache_miss, s->iop.bypass); + !s->cache_missed, s->iop.bypass); trace_bcache_read(s->orig_bio, !s->cache_miss, s->iop.bypass); if (s->iop.error) @@ -786,6 +795,8 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); struct bio *miss, *cache_bio; + s->cache_missed = 1; + if (s->cache_miss || s->iop.bypass) { miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split); ret = miss == bio ? MAP_DONE : MAP_CONTINUE; diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index a7a03a21d78aad38943c47174dec0bbf71d779a3..e41760e7095b6ef7c25ba36c1242a1c03997e686 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -921,6 +921,12 @@ static void cached_dev_detach_finish(struct work_struct *w) mutex_lock(&bch_register_lock); + cancel_delayed_work_sync(&dc->writeback_rate_update); + if (!IS_ERR_OR_NULL(dc->writeback_thread)) { + kthread_stop(dc->writeback_thread); + dc->writeback_thread = NULL; + } + memset(&dc->sb.set_uuid, 0, 16); SET_BDEV_STATE(&dc->sb, BDEV_STATE_NONE); @@ -961,7 +967,8 @@ void bch_cached_dev_detach(struct cached_dev *dc) cached_dev_put(dc); } -int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) +int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, + uint8_t *set_uuid) { uint32_t rtime = cpu_to_le32(get_seconds()); struct uuid_entry *u; @@ -969,7 +976,8 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) bdevname(dc->bdev, buf); - if (memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16)) + if ((set_uuid && memcmp(set_uuid, c->sb.set_uuid, 16)) || + (!set_uuid && memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16))) return -ENOENT; if (dc->disk.c) { @@ -1054,7 +1062,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) } if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) { - bch_sectors_dirty_init(dc); + bch_sectors_dirty_init(&dc->disk); atomic_set(&dc->has_dirty, 1); atomic_inc(&dc->count); bch_writeback_queue(dc); @@ -1087,6 +1095,8 @@ static void cached_dev_free(struct closure *cl) cancel_delayed_work_sync(&dc->writeback_rate_update); if (!IS_ERR_OR_NULL(dc->writeback_thread)) kthread_stop(dc->writeback_thread); + if (dc->writeback_write_wq) + destroy_workqueue(dc->writeback_write_wq); mutex_lock(&bch_register_lock); @@ -1201,7 +1211,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page, list_add(&dc->list, &uncached_devices); list_for_each_entry(c, &bch_cache_sets, list) - bch_cached_dev_attach(dc, c); + bch_cached_dev_attach(dc, c, NULL); if (BDEV_STATE(&dc->sb) == BDEV_STATE_NONE || BDEV_STATE(&dc->sb) == BDEV_STATE_STALE) @@ -1258,6 +1268,7 @@ static int flash_dev_run(struct cache_set *c, struct uuid_entry *u) goto err; bcache_device_attach(d, c, u - c->uuids); + bch_sectors_dirty_init(d); bch_flash_dev_request_init(d); add_disk(d->disk); @@ -1720,7 +1731,7 @@ static void run_cache_set(struct cache_set *c) bcache_write_super(c); list_for_each_entry_safe(dc, t, &uncached_devices, list) - bch_cached_dev_attach(dc, c); + bch_cached_dev_attach(dc, c, NULL); flash_devs_run(c); @@ -1839,6 +1850,7 @@ void bch_cache_release(struct kobject *kobj) static int cache_alloc(struct cache_sb *sb, struct cache *ca) { size_t free; + size_t btree_buckets; struct bucket *b; __module_get(THIS_MODULE); @@ -1848,9 +1860,19 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca) ca->journal.bio.bi_max_vecs = 8; ca->journal.bio.bi_io_vec = ca->journal.bio.bi_inline_vecs; + /* + * when ca->sb.njournal_buckets is not zero, journal exists, + * and in bch_journal_replay(), tree node may split, + * so bucket of RESERVE_BTREE type is needed, + * the worst situation is all journal buckets are valid journal, + * and all the keys need to replay, + * so the number of RESERVE_BTREE type buckets should be as much + * as journal buckets + */ + btree_buckets = ca->sb.njournal_buckets ?: 8; free = roundup_pow_of_two(ca->sb.nbuckets) >> 10; - if (!init_fifo(&ca->free[RESERVE_BTREE], 8, GFP_KERNEL) || + if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets, GFP_KERNEL) || !init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) || !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) || !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) || @@ -1996,6 +2018,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, else err = "device busy"; mutex_unlock(&bch_register_lock); + if (!IS_ERR(bdev)) + bdput(bdev); if (attr == &ksysfs_register_quiet) goto out; } @@ -2115,6 +2139,7 @@ static void bcache_exit(void) if (bcache_major) unregister_blkdev(bcache_major, "bcache"); unregister_reboot_notifier(&reboot); + mutex_destroy(&bch_register_lock); } static int __init bcache_init(void) @@ -2133,14 +2158,15 @@ static int __init bcache_init(void) bcache_major = register_blkdev(0, "bcache"); if (bcache_major < 0) { unregister_reboot_notifier(&reboot); + mutex_destroy(&bch_register_lock); return bcache_major; } if (!(bcache_wq = create_workqueue("bcache")) || !(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) || - sysfs_create_files(bcache_kobj, files) || bch_request_init() || - bch_debug_init(bcache_kobj)) + bch_debug_init(bcache_kobj) || + sysfs_create_files(bcache_kobj, files)) goto err; return 0; diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index b3ff57d61ddea7d053c7b01d5cb1819d2a5a326e..5a5c1f1bd8a5330c388177415d0dc1eb7f87f44c 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -191,7 +191,7 @@ STORE(__cached_dev) { struct cached_dev *dc = container_of(kobj, struct cached_dev, disk.kobj); - unsigned v = size; + ssize_t v; struct cache_set *c; struct kobj_uevent_env *env; @@ -226,7 +226,7 @@ STORE(__cached_dev) bch_cached_dev_run(dc); if (attr == &sysfs_cache_mode) { - ssize_t v = bch_read_string_list(buf, bch_cache_modes + 1); + v = bch_read_string_list(buf, bch_cache_modes + 1); if (v < 0) return v; @@ -263,17 +263,20 @@ STORE(__cached_dev) } if (attr == &sysfs_attach) { - if (bch_parse_uuid(buf, dc->sb.set_uuid) < 16) + uint8_t set_uuid[16]; + + if (bch_parse_uuid(buf, set_uuid) < 16) return -EINVAL; + v = -ENOENT; list_for_each_entry(c, &bch_cache_sets, list) { - v = bch_cached_dev_attach(dc, c); + v = bch_cached_dev_attach(dc, c, set_uuid); if (!v) return size; } pr_err("Can't attach %s: cache set not found", buf); - size = v; + return v; } if (attr == &sysfs_detach && dc->disk.c) diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c index db3ae4c2b2233a4026ebe8a183042eb84d53cdc4..6c18e3ec3e48d016313d5ff65efed378b8e71860 100644 --- a/drivers/md/bcache/util.c +++ b/drivers/md/bcache/util.c @@ -73,24 +73,44 @@ STRTO_H(strtouint, unsigned int) STRTO_H(strtoll, long long) STRTO_H(strtoull, unsigned long long) +/** + * bch_hprint() - formats @v to human readable string for sysfs. + * + * @v - signed 64 bit integer + * @buf - the (at least 8 byte) buffer to format the result into. + * + * Returns the number of bytes used by format. + */ ssize_t bch_hprint(char *buf, int64_t v) { static const char units[] = "?kMGTPEZY"; - char dec[4] = ""; - int u, t = 0; - - for (u = 0; v >= 1024 || v <= -1024; u++) { - t = v & ~(~0 << 10); - v >>= 10; - } - - if (!u) - return sprintf(buf, "%llu", v); - - if (v < 100 && v > -100) - snprintf(dec, sizeof(dec), ".%i", t / 100); - - return sprintf(buf, "%lli%s%c", v, dec, units[u]); + int u = 0, t; + + uint64_t q; + + if (v < 0) + q = -v; + else + q = v; + + /* For as long as the number is more than 3 digits, but at least + * once, shift right / divide by 1024. Keep the remainder for + * a digit after the decimal point. + */ + do { + u++; + + t = q & ~(~0 << 10); + q >>= 10; + } while (q >= 1000); + + if (v < 0) + /* '-', up to 3 digits, '.', 1 digit, 1 character, null; + * yields 8 bytes. + */ + return sprintf(buf, "-%llu.%i%c", q, t * 10 / 1024, units[u]); + else + return sprintf(buf, "%llu.%i%c", q, t * 10 / 1024, units[u]); } ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[], diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 540256a0df4fd9ce47d94889a15df6889bbe7a89..fe19e5841bfcaee25348b1413121c5ddbaefe9ac 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -21,7 +21,8 @@ static void __update_writeback_rate(struct cached_dev *dc) { struct cache_set *c = dc->disk.c; - uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size; + uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size - + bcache_flash_devs_sectors_dirty(c); uint64_t cache_dirty_target = div_u64(cache_sectors * dc->writeback_percent, 100); @@ -190,7 +191,7 @@ static void write_dirty(struct closure *cl) closure_bio_submit(&io->bio, cl, &io->dc->disk); - continue_at(cl, write_dirty_finish, system_wq); + continue_at(cl, write_dirty_finish, io->dc->writeback_write_wq); } static void read_dirty_endio(struct bio *bio, int error) @@ -210,7 +211,7 @@ static void read_dirty_submit(struct closure *cl) closure_bio_submit(&io->bio, cl, &io->dc->disk); - continue_at(cl, write_dirty, system_wq); + continue_at(cl, write_dirty, io->dc->writeback_write_wq); } static void read_dirty(struct cached_dev *dc) @@ -424,19 +425,28 @@ static int bch_writeback_thread(void *arg) while (!kthread_should_stop()) { down_write(&dc->writeback_lock); - if (!atomic_read(&dc->has_dirty) || - (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) && - !dc->writeback_running)) { + set_current_state(TASK_INTERRUPTIBLE); + /* + * If the bache device is detaching, skip here and continue + * to perform writeback. Otherwise, if no dirty data on cache, + * or there is dirty data on cache but writeback is disabled, + * the writeback thread should sleep here and wait for others + * to wake up it. + */ + if (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) && + (!atomic_read(&dc->has_dirty) || !dc->writeback_running)) { up_write(&dc->writeback_lock); - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) + if (kthread_should_stop()) { + set_current_state(TASK_RUNNING); return 0; + } try_to_freeze(); schedule(); continue; } + set_current_state(TASK_RUNNING); searched_full_index = refill_dirty(dc); @@ -446,6 +456,16 @@ static int bch_writeback_thread(void *arg) cached_dev_put(dc); SET_BDEV_STATE(&dc->sb, BDEV_STATE_CLEAN); bch_write_bdev_super(dc, NULL); + /* + * If bcache device is detaching via sysfs interface, + * writeback thread should stop after there is no dirty + * data on cache. BCACHE_DEV_DETACHING flag is set in + * bch_cached_dev_detach(). + */ + if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) { + up_write(&dc->writeback_lock); + break; + } } up_write(&dc->writeback_lock); @@ -488,17 +508,17 @@ static int sectors_dirty_init_fn(struct btree_op *_op, struct btree *b, return MAP_CONTINUE; } -void bch_sectors_dirty_init(struct cached_dev *dc) +void bch_sectors_dirty_init(struct bcache_device *d) { struct sectors_dirty_init op; bch_btree_op_init(&op.op, -1); - op.inode = dc->disk.id; + op.inode = d->id; - bch_btree_map_keys(&op.op, dc->disk.c, &KEY(op.inode, 0, 0), + bch_btree_map_keys(&op.op, d->c, &KEY(op.inode, 0, 0), sectors_dirty_init_fn, 0); - dc->disk.sectors_dirty_last = bcache_dev_sectors_dirty(&dc->disk); + d->sectors_dirty_last = bcache_dev_sectors_dirty(d); } void bch_cached_dev_writeback_init(struct cached_dev *dc) @@ -522,6 +542,11 @@ void bch_cached_dev_writeback_init(struct cached_dev *dc) int bch_cached_dev_writeback_start(struct cached_dev *dc) { + dc->writeback_write_wq = alloc_workqueue("bcache_writeback_wq", + WQ_MEM_RECLAIM, 0); + if (!dc->writeback_write_wq) + return -ENOMEM; + dc->writeback_thread = kthread_create(bch_writeback_thread, dc, "bcache_writeback"); if (IS_ERR(dc->writeback_thread)) diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h index 073a042aed243b2660f6b70a380d0647c709aa65..daec4fd782ea0ade84b8da0b7a1378933c407d88 100644 --- a/drivers/md/bcache/writeback.h +++ b/drivers/md/bcache/writeback.h @@ -14,6 +14,25 @@ static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d) return ret; } +static inline uint64_t bcache_flash_devs_sectors_dirty(struct cache_set *c) +{ + uint64_t i, ret = 0; + + mutex_lock(&bch_register_lock); + + for (i = 0; i < c->nr_uuids; i++) { + struct bcache_device *d = c->devices[i]; + + if (!d || !UUID_FLASH_ONLY(&c->uuids[i])) + continue; + ret += bcache_dev_sectors_dirty(d); + } + + mutex_unlock(&bch_register_lock); + + return ret; +} + static inline unsigned offset_to_stripe(struct bcache_device *d, uint64_t offset) { @@ -85,7 +104,7 @@ static inline void bch_writeback_add(struct cached_dev *dc) void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int); -void bch_sectors_dirty_init(struct cached_dev *dc); +void bch_sectors_dirty_init(struct bcache_device *); void bch_cached_dev_writeback_init(struct cached_dev *); int bch_cached_dev_writeback_start(struct cached_dev *); diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index cced062cab4b72bfab796434eb8f696c3a3502cd..cb5c9d8ea139e66512e41b44537687f7f77d1fb3 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1802,6 +1802,11 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks, long pages; struct bitmap_page *new_bp; + if (bitmap->storage.file && !init) { + pr_info("md: cannot resize file-based bitmap\n"); + return -EINVAL; + } + if (chunksize == 0) { /* If there is enough space, leave the chunk size unchanged, * else increase by factor of two until there is enough space. diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index cb250a86d635c84b0853ec5c1109eea18385182b..97b09fef2b3d1e62cfc85344670cb7ef0a122105 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -729,9 +729,21 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) dev = name_to_dev_t(target_device); if (!dev) { - DMERR("no dev found for %s", target_device); - handle_error(); - return -EINVAL; + const unsigned int timeout_ms = DM_VERITY_WAIT_DEV_TIMEOUT_MS; + unsigned int wait_time_ms = 0; + + DMERR("android_verity_ctr: retry %s\n", target_device); + while (driver_probe_done() != 0 || + (dev = name_to_dev_t(target_device)) == 0) { + msleep(100); + wait_time_ms += 100; + if (wait_time_ms > timeout_ms) { + DMERR("android_verity_ctr: retry timeout(%dms)\n", timeout_ms); + DMERR("no dev found for %s", target_device); + handle_error(); + return -EINVAL; + } + } } if (is_eng()) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 9c5a0b4d544620b303b42dfb60197dd50b16c738..e5235c8148120a77fb52fe127c84e4205aa62bd0 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -14,6 +14,7 @@ #include #include #include +#include #define DM_MSG_PREFIX "bufio" @@ -47,14 +48,6 @@ */ #define DM_BUFIO_INLINE_VECS 16 -/* - * Buffer hash - */ -#define DM_BUFIO_HASH_BITS 20 -#define DM_BUFIO_HASH(block) \ - ((((block) >> DM_BUFIO_HASH_BITS) ^ (block)) & \ - ((1 << DM_BUFIO_HASH_BITS) - 1)) - /* * Don't try to use kmem_cache_alloc for blocks larger than this. * For explanation, see alloc_buffer_data below. @@ -106,7 +99,7 @@ struct dm_bufio_client { unsigned minimum_buffers; - struct hlist_head *cache_hash; + struct rb_root buffer_tree; wait_queue_head_t free_buffer_wait; int async_write_error; @@ -135,7 +128,7 @@ enum data_mode { }; struct dm_buffer { - struct hlist_node hash_list; + struct rb_node node; struct list_head lru_list; sector_t block; void *data; @@ -253,6 +246,53 @@ static LIST_HEAD(dm_bufio_all_clients); */ static DEFINE_MUTEX(dm_bufio_clients_lock); +/*---------------------------------------------------------------- + * A red/black tree acts as an index for all the buffers. + *--------------------------------------------------------------*/ +static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block) +{ + struct rb_node *n = c->buffer_tree.rb_node; + struct dm_buffer *b; + + while (n) { + b = container_of(n, struct dm_buffer, node); + + if (b->block == block) + return b; + + n = (b->block < block) ? n->rb_left : n->rb_right; + } + + return NULL; +} + +static void __insert(struct dm_bufio_client *c, struct dm_buffer *b) +{ + struct rb_node **new = &c->buffer_tree.rb_node, *parent = NULL; + struct dm_buffer *found; + + while (*new) { + found = container_of(*new, struct dm_buffer, node); + + if (found->block == b->block) { + BUG_ON(found != b); + return; + } + + parent = *new; + new = (found->block < b->block) ? + &((*new)->rb_left) : &((*new)->rb_right); + } + + rb_link_node(&b->node, parent, new); + rb_insert_color(&b->node, &c->buffer_tree); +} + +static void __remove(struct dm_bufio_client *c, struct dm_buffer *b) +{ + rb_erase(&b->node, &c->buffer_tree); +} + /*----------------------------------------------------------------*/ static void adjust_total_allocated(enum data_mode data_mode, long diff) @@ -435,7 +475,7 @@ static void __link_buffer(struct dm_buffer *b, sector_t block, int dirty) b->block = block; b->list_mode = dirty; list_add(&b->lru_list, &c->lru[dirty]); - hlist_add_head(&b->hash_list, &c->cache_hash[DM_BUFIO_HASH(block)]); + __insert(b->c, b); b->last_accessed = jiffies; } @@ -449,7 +489,7 @@ static void __unlink_buffer(struct dm_buffer *b) BUG_ON(!c->n_buffers[b->list_mode]); c->n_buffers[b->list_mode]--; - hlist_del(&b->hash_list); + __remove(b->c, b); list_del(&b->lru_list); } @@ -761,12 +801,14 @@ enum new_flag { static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf) { struct dm_buffer *b; + bool tried_noio_alloc = false; /* * dm-bufio is resistant to allocation failures (it just keeps * one buffer reserved in cases all the allocations fail). * So set flags to not try too hard: - * GFP_NOIO: don't recurse into the I/O layer + * GFP_NOWAIT: don't wait; if we need to sleep we'll release our + * mutex and wait ourselves. * __GFP_NORETRY: don't retry and rather return failure * __GFP_NOMEMALLOC: don't use emergency reserves * __GFP_NOWARN: don't print a warning in case of failure @@ -776,7 +818,7 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client */ while (1) { if (dm_bufio_cache_size_latch != 1) { - b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); if (b) return b; } @@ -784,6 +826,15 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client if (nf == NF_PREFETCH) return NULL; + if (dm_bufio_cache_size_latch != 1 && !tried_noio_alloc) { + dm_bufio_unlock(c); + b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + dm_bufio_lock(c); + if (b) + return b; + tried_noio_alloc = true; + } + if (!list_empty(&c->reserved_buffers)) { b = list_entry(c->reserved_buffers.next, struct dm_buffer, lru_list); @@ -876,7 +927,8 @@ static void __get_memory_limit(struct dm_bufio_client *c, buffers = c->minimum_buffers; *limit_buffers = buffers; - *threshold_buffers = buffers * DM_BUFIO_WRITEBACK_PERCENT / 100; + *threshold_buffers = mult_frac(buffers, + DM_BUFIO_WRITEBACK_PERCENT, 100); } /* @@ -907,23 +959,6 @@ static void __check_watermark(struct dm_bufio_client *c, __write_dirty_buffers_async(c, 1, write_list); } -/* - * Find a buffer in the hash. - */ -static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block) -{ - struct dm_buffer *b; - - hlist_for_each_entry(b, &c->cache_hash[DM_BUFIO_HASH(block)], - hash_list) { - dm_bufio_cond_resched(); - if (b->block == block) - return b; - } - - return NULL; -} - /*---------------------------------------------------------------- * Getting a buffer *--------------------------------------------------------------*/ @@ -1553,11 +1588,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign r = -ENOMEM; goto bad_client; } - c->cache_hash = vmalloc(sizeof(struct hlist_head) << DM_BUFIO_HASH_BITS); - if (!c->cache_hash) { - r = -ENOMEM; - goto bad_hash; - } + c->buffer_tree = RB_ROOT; c->bdev = bdev; c->block_size = block_size; @@ -1576,9 +1607,6 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign c->n_buffers[i] = 0; } - for (i = 0; i < 1 << DM_BUFIO_HASH_BITS; i++) - INIT_HLIST_HEAD(&c->cache_hash[i]); - mutex_init(&c->lock); INIT_LIST_HEAD(&c->reserved_buffers); c->need_reserved_buffers = reserved_buffers; @@ -1652,8 +1680,6 @@ bad_cache: } dm_io_client_destroy(c->dm_io); bad_dm_io: - vfree(c->cache_hash); -bad_hash: kfree(c); bad_client: return ERR_PTR(r); @@ -1680,9 +1706,7 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c) mutex_unlock(&dm_bufio_clients_lock); - for (i = 0; i < 1 << DM_BUFIO_HASH_BITS; i++) - BUG_ON(!hlist_empty(&c->cache_hash[i])); - + BUG_ON(!RB_EMPTY_ROOT(&c->buffer_tree)); BUG_ON(c->need_reserved_buffers); while (!list_empty(&c->reserved_buffers)) { @@ -1700,7 +1724,6 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c) BUG_ON(c->n_buffers[i]); dm_io_client_destroy(c->dm_io); - vfree(c->cache_hash); kfree(c); } EXPORT_SYMBOL_GPL(dm_bufio_client_destroy); @@ -1764,19 +1787,15 @@ static int __init dm_bufio_init(void) memset(&dm_bufio_caches, 0, sizeof dm_bufio_caches); memset(&dm_bufio_cache_names, 0, sizeof dm_bufio_cache_names); - mem = (__u64)((totalram_pages - totalhigh_pages) * - DM_BUFIO_MEMORY_PERCENT / 100) << PAGE_SHIFT; + mem = (__u64)mult_frac(totalram_pages - totalhigh_pages, + DM_BUFIO_MEMORY_PERCENT, 100) << PAGE_SHIFT; if (mem > ULONG_MAX) mem = ULONG_MAX; #ifdef CONFIG_MMU - /* - * Get the size of vmalloc space the same way as VMALLOC_TOTAL - * in fs/proc/internal.h - */ - if (mem > (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100) - mem = (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100; + if (mem > mult_frac(VMALLOC_TOTAL, DM_BUFIO_VMALLOC_PERCENT, 100)) + mem = mult_frac(VMALLOC_TOTAL, DM_BUFIO_VMALLOC_PERCENT, 100); #endif dm_bufio_default_cache_size = mem; diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 1e64e9c50d85f0aa1d33dbf5dfc34338db27160e..aeb9ee6082d983cf665b739ac956739bae5a9255 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -324,7 +324,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd) disk_super->version = cpu_to_le32(MAX_CACHE_VERSION); memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); - disk_super->policy_hint_size = 0; + disk_super->policy_hint_size = cpu_to_le32(0); __copy_sm_root(cmd, disk_super); @@ -635,6 +635,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd, disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]); disk_super->policy_version[1] = cpu_to_le32(cmd->policy_version[1]); disk_super->policy_version[2] = cpu_to_le32(cmd->policy_version[2]); + disk_super->policy_hint_size = cpu_to_le32(cmd->policy_hint_size); disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits); disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 74adcd2c967ec8680d0cfd5c9d876c93074dbe10..01d7b5785b8e51cc8f8efa0c78a9306be9be0e2f 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -299,6 +299,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, else if (rw & REQ_WRITE_SAME) special_cmd_max_sectors = q->limits.max_write_same_sectors; if ((rw & (REQ_DISCARD | REQ_WRITE_SAME)) && special_cmd_max_sectors == 0) { + atomic_inc(&io->count); dec_count(io, region, -EOPNOTSUPP); return; } diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 3a7cade5e27d828ffa2df3b9254f9064ec078c84..77833b65e01e84ddc6b65f3e8360f97ca4d079a0 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -454,6 +454,8 @@ static int run_complete_job(struct kcopyd_job *job) if (atomic_dec_and_test(&kc->nr_jobs)) wake_up(&kc->destroyq); + cond_resched(); + return 0; } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 9642b379eb829c6e8243168e477ed8d4f86fdc28..a1097ab232e3d928d40a10c0957f0a357a5eea0f 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -524,14 +524,14 @@ static int adjoin(struct dm_table *table, struct dm_target *ti) * On the other hand, dm-switch needs to process bulk data using messages and * excessive use of GFP_NOIO could cause trouble. */ -static char **realloc_argv(unsigned *array_size, char **old_argv) +static char **realloc_argv(unsigned *size, char **old_argv) { char **argv; unsigned new_size; gfp_t gfp; - if (*array_size) { - new_size = *array_size * 2; + if (*size) { + new_size = *size * 2; gfp = GFP_KERNEL; } else { new_size = 8; @@ -539,8 +539,8 @@ static char **realloc_argv(unsigned *array_size, char **old_argv) } argv = kmalloc(new_size * sizeof(*argv), gfp); if (argv) { - memcpy(argv, old_argv, *array_size * sizeof(*argv)); - *array_size = new_size; + memcpy(argv, old_argv, *size * sizeof(*argv)); + *size = new_size; } kfree(old_argv); diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 07fd9ca52372c4733ff1dd7499fb089be469575f..d8eb8655925b0e29210981414c0e51b85933b16a 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -81,10 +81,14 @@ #define SECTOR_TO_BLOCK_SHIFT 3 /* + * For btree insert: * 3 for btree insert + * 2 for btree lookup used within space map + * For btree remove: + * 2 for shadow spine + + * 4 for rebalance 3 child node */ -#define THIN_MAX_CONCURRENT_LOCKS 5 +#define THIN_MAX_CONCURRENT_LOCKS 6 /* This should be plenty */ #define SPACE_MAP_ROOT_SIZE 128 @@ -186,6 +190,12 @@ struct dm_pool_metadata { sector_t data_block_size; bool read_only:1; + /* + * We reserve a section of the metadata for commit overhead. + * All reported space does *not* include this. + */ + dm_block_t metadata_reserve; + /* * Set if a transaction has to be aborted but the attempt to roll back * to the previous (good) transaction failed. The only pool metadata @@ -820,6 +830,20 @@ static int __commit_transaction(struct dm_pool_metadata *pmd) return dm_tm_commit(pmd->tm, sblock); } +static void __set_metadata_reserve(struct dm_pool_metadata *pmd) +{ + int r; + dm_block_t total; + dm_block_t max_blocks = 4096; /* 16M */ + + r = dm_sm_get_nr_blocks(pmd->metadata_sm, &total); + if (r) { + DMERR("could not get size of metadata device"); + pmd->metadata_reserve = max_blocks; + } else + pmd->metadata_reserve = min(max_blocks, div_u64(total, 10)); +} + struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, sector_t data_block_size, bool format_device) @@ -854,6 +878,8 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, return ERR_PTR(r); } + __set_metadata_reserve(pmd); + return pmd; } @@ -1621,6 +1647,13 @@ int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, down_read(&pmd->root_lock); if (!pmd->fail_io) r = dm_sm_get_nr_free(pmd->metadata_sm, result); + + if (!r) { + if (*result < pmd->metadata_reserve) + *result = 0; + else + *result -= pmd->metadata_reserve; + } up_read(&pmd->root_lock); return r; @@ -1742,8 +1775,11 @@ int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_cou int r = -EINVAL; down_write(&pmd->root_lock); - if (!pmd->fail_io) + if (!pmd->fail_io) { r = __resize_space_map(pmd->metadata_sm, new_count); + if (!r) + __set_metadata_reserve(pmd); + } up_write(&pmd->root_lock); return r; diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 9dfe2bb713c50df776b36d6252f44167d3965724..68c7102a64c869ae5c900ee0eb7b3d630e0d3c5d 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -140,7 +140,13 @@ struct dm_thin_new_mapping; enum pool_mode { PM_WRITE, /* metadata may be changed */ PM_OUT_OF_DATA_SPACE, /* metadata may be changed, though data may not be allocated */ + + /* + * Like READ_ONLY, except may switch back to WRITE on metadata resize. Reported as READ_ONLY. + */ + PM_OUT_OF_METADATA_SPACE, PM_READ_ONLY, /* metadata may not be changed */ + PM_FAIL, /* all I/O fails */ }; @@ -992,7 +998,37 @@ static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); -static void check_for_space(struct pool *pool) +static void requeue_bios(struct pool *pool); + +static bool is_read_only_pool_mode(enum pool_mode mode) +{ + return (mode == PM_OUT_OF_METADATA_SPACE || mode == PM_READ_ONLY); +} + +static bool is_read_only(struct pool *pool) +{ + return is_read_only_pool_mode(get_pool_mode(pool)); +} + +static void check_for_metadata_space(struct pool *pool) +{ + int r; + const char *ooms_reason = NULL; + dm_block_t nr_free; + + r = dm_pool_get_free_metadata_block_count(pool->pmd, &nr_free); + if (r) + ooms_reason = "Could not get free metadata blocks"; + else if (!nr_free) + ooms_reason = "No free metadata blocks"; + + if (ooms_reason && !is_read_only(pool)) { + DMERR("%s", ooms_reason); + set_pool_mode(pool, PM_OUT_OF_METADATA_SPACE); + } +} + +static void check_for_data_space(struct pool *pool) { int r; dm_block_t nr_free; @@ -1004,8 +1040,10 @@ static void check_for_space(struct pool *pool) if (r) return; - if (nr_free) + if (nr_free) { set_pool_mode(pool, PM_WRITE); + requeue_bios(pool); + } } /* @@ -1016,14 +1054,16 @@ static int commit(struct pool *pool) { int r; - if (get_pool_mode(pool) >= PM_READ_ONLY) + if (get_pool_mode(pool) >= PM_OUT_OF_METADATA_SPACE) return -EINVAL; r = dm_pool_commit_metadata(pool->pmd); if (r) metadata_operation_failed(pool, "dm_pool_commit_metadata", r); - else - check_for_space(pool); + else { + check_for_metadata_space(pool); + check_for_data_space(pool); + } return r; } @@ -1082,10 +1122,26 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) r = dm_pool_alloc_data_block(pool->pmd, result); if (r) { - metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); + if (r == -ENOSPC) + set_pool_mode(pool, PM_OUT_OF_DATA_SPACE); + else + metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); + return r; + } + + r = dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks); + if (r) { + metadata_operation_failed(pool, "dm_pool_get_free_metadata_block_count", r); return r; } + if (!free_blocks) { + /* Let's commit before we use up the metadata reserve. */ + r = commit(pool); + if (r) + return r; + } + return 0; } @@ -1117,6 +1173,7 @@ static int should_error_unserviceable_bio(struct pool *pool) case PM_OUT_OF_DATA_SPACE: return pool->pf.error_if_no_space ? -ENOSPC : 0; + case PM_OUT_OF_METADATA_SPACE: case PM_READ_ONLY: case PM_FAIL: return -EIO; @@ -1816,8 +1873,9 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) error_retry_list(pool); break; + case PM_OUT_OF_METADATA_SPACE: case PM_READ_ONLY: - if (old_mode != new_mode) + if (!is_read_only_pool_mode(old_mode)) notify_of_pool_mode_change(pool, "read-only"); dm_pool_metadata_read_only(pool->pmd); pool->process_bio = process_bio_read_only; @@ -2720,6 +2778,10 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit) DMINFO("%s: growing the metadata device from %llu to %llu blocks", dm_device_name(pool->pool_md), sb_metadata_dev_size, metadata_dev_size); + + if (get_pool_mode(pool) == PM_OUT_OF_METADATA_SPACE) + set_pool_mode(pool, PM_WRITE); + r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size); if (r) { metadata_operation_failed(pool, "dm_pool_resize_metadata_dev", r); @@ -2967,7 +3029,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv) struct pool_c *pt = ti->private; struct pool *pool = pt->pool; - if (get_pool_mode(pool) >= PM_READ_ONLY) { + if (get_pool_mode(pool) >= PM_OUT_OF_METADATA_SPACE) { DMERR("%s: unable to service pool target messages in READ_ONLY or FAIL mode", dm_device_name(pool->pool_md)); return -EINVAL; @@ -3040,6 +3102,7 @@ static void pool_status(struct dm_target *ti, status_type_t type, dm_block_t nr_blocks_data; dm_block_t nr_blocks_metadata; dm_block_t held_root; + enum pool_mode mode; char buf[BDEVNAME_SIZE]; char buf2[BDEVNAME_SIZE]; struct pool_c *pt = ti->private; @@ -3110,9 +3173,10 @@ static void pool_status(struct dm_target *ti, status_type_t type, else DMEMIT("- "); - if (pool->pf.mode == PM_OUT_OF_DATA_SPACE) + mode = get_pool_mode(pool); + if (mode == PM_OUT_OF_DATA_SPACE) DMEMIT("out_of_data_space "); - else if (pool->pf.mode == PM_READ_ONLY) + else if (is_read_only_pool_mode(mode)) DMEMIT("ro "); else DMEMIT("rw "); diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index db8d6d01f4299a665c51311646359c64a6485471..b04a9bf7e1d49fcd12a31de4ce212a448aa61321 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -19,6 +19,7 @@ #include #include +#include #define DM_MSG_PREFIX "verity" @@ -32,6 +33,7 @@ #define DM_VERITY_OPT_LOGGING "ignore_corruption" #define DM_VERITY_OPT_RESTART "restart_on_corruption" #define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks" +#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once" #define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC) @@ -394,6 +396,18 @@ static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io, return 0; } +/* + * Moves the bio iter one data block forward. + */ +static inline void verity_bv_skip_block(struct dm_verity *v, + struct dm_verity_io *io, + struct bvec_iter *iter) +{ + struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size); + + bio_advance_iter(bio, iter, 1 << v->data_dev_block_bits); +} + /* * Verify one "dm_verity_io" structure. */ @@ -406,9 +420,16 @@ static int verity_verify_io(struct dm_verity_io *io) for (b = 0; b < io->n_blocks; b++) { int r; + sector_t cur_block = io->block + b; struct shash_desc *desc = verity_io_hash_desc(v, io); - r = verity_hash_for_block(v, io, io->block + b, + if (v->validated_blocks && + likely(test_bit(cur_block, v->validated_blocks))) { + verity_bv_skip_block(v, io, &io->iter); + continue; + } + + r = verity_hash_for_block(v, io, cur_block, verity_io_want_digest(v, io), &is_zero); if (unlikely(r < 0)) @@ -441,13 +462,16 @@ static int verity_verify_io(struct dm_verity_io *io) return r; if (likely(memcmp(verity_io_real_digest(v, io), - verity_io_want_digest(v, io), v->digest_size) == 0)) + verity_io_want_digest(v, io), v->digest_size) == 0)) { + if (v->validated_blocks) + set_bit(cur_block, v->validated_blocks); continue; + } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, - io->block + b, NULL, &start) == 0) + cur_block, NULL, &start) == 0) continue; else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA, - io->block + b)) + cur_block)) return -EIO; } @@ -642,6 +666,8 @@ void verity_status(struct dm_target *ti, status_type_t type, args += DM_VERITY_OPTS_FEC; if (v->zero_digest) args++; + if (v->validated_blocks) + args++; if (!args) return; DMEMIT(" %u", args); @@ -660,6 +686,8 @@ void verity_status(struct dm_target *ti, status_type_t type, } if (v->zero_digest) DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES); + if (v->validated_blocks) + DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE); sz = verity_fec_status_table(v, sz, result, maxlen); break; } @@ -730,6 +758,7 @@ void verity_dtr(struct dm_target *ti) if (v->bufio) dm_bufio_client_destroy(v->bufio); + vfree(v->validated_blocks); kfree(v->salt); kfree(v->root_digest); kfree(v->zero_digest); @@ -751,6 +780,26 @@ void verity_dtr(struct dm_target *ti) } EXPORT_SYMBOL_GPL(verity_dtr); +static int verity_alloc_most_once(struct dm_verity *v) +{ + struct dm_target *ti = v->ti; + + /* the bitset can only handle INT_MAX blocks */ + if (v->data_blocks > INT_MAX) { + ti->error = "device too large to use check_at_most_once"; + return -E2BIG; + } + + v->validated_blocks = vzalloc(BITS_TO_LONGS(v->data_blocks) * + sizeof(unsigned long)); + if (!v->validated_blocks) { + ti->error = "failed to allocate bitset for check_at_most_once"; + return -ENOMEM; + } + + return 0; +} + static int verity_alloc_zero_digest(struct dm_verity *v) { int r = -ENOMEM; @@ -820,6 +869,12 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v) } continue; + } else if (!strcasecmp(arg_name, DM_VERITY_OPT_AT_MOST_ONCE)) { + r = verity_alloc_most_once(v); + if (r) + return r; + continue; + } else if (verity_is_fec_opt_arg(arg_name)) { r = verity_fec_parse_opt_args(as, v, &argc, arg_name); if (r) @@ -1090,7 +1145,7 @@ EXPORT_SYMBOL_GPL(verity_ctr); static struct target_type verity_target = { .name = "verity", - .version = {1, 3, 0}, + .version = {1, 4, 0}, .module = THIS_MODULE, .ctr = verity_ctr, .dtr = verity_dtr, diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h index 47a96a56794bcacad658294c28e9719088b6bd46..79f992bae75410961d963ba75e1c358aab1940aa 100644 --- a/drivers/md/dm-verity.h +++ b/drivers/md/dm-verity.h @@ -16,6 +16,7 @@ #include #include +#define DM_VERITY_WAIT_DEV_TIMEOUT_MS (2000) #define DM_VERITY_MAX_LEVELS 63 enum verity_mode { @@ -63,6 +64,7 @@ struct dm_verity { sector_t hash_level_block[DM_VERITY_MAX_LEVELS]; struct dm_verity_fec *fec; /* forward error correction */ + unsigned long *validated_blocks; /* bitset blocks validated */ }; struct dm_verity_io { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 256b515101a8b29a673c0a4c2440685e7f7d9523..245731994ceed2dce42056490e523dd533aca6c8 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -3034,11 +3034,15 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj) md = container_of(kobj, struct mapped_device, kobj_holder.kobj); - if (test_bit(DMF_FREEING, &md->flags) || - dm_deleting_md(md)) - return NULL; - + spin_lock(&_minor_lock); + if (test_bit(DMF_FREEING, &md->flags) || dm_deleting_md(md)) { + md = NULL; + goto out; + } dm_get(md); +out: + spin_unlock(&_minor_lock); + return md; } diff --git a/drivers/md/md.c b/drivers/md/md.c index f88f912f0296f4a65bb4830646eebc0d633fb668..ba201db6afce503da623b203cc5c86b56878d766 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5676,6 +5676,9 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev) char b[BDEVNAME_SIZE]; struct md_rdev *rdev; + if (!mddev->pers) + return -ENODEV; + rdev = find_rdev(mddev, dev); if (!rdev) return -ENXIO; diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index 360c22d4464767fb4982e42d07741541900c408b..f2a8e4c69d9fbc8487eccdc4dfb33ac46ea9753d 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -572,23 +572,8 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key) pn->keys[1] = rn->keys[0]; memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64)); - /* - * rejig the spine. This is ugly, since it knows too - * much about the spine - */ - if (s->nodes[0] != new_parent) { - unlock_block(s->info, s->nodes[0]); - s->nodes[0] = new_parent; - } - if (key < le64_to_cpu(rn->keys[0])) { - unlock_block(s->info, right); - s->nodes[1] = left; - } else { - unlock_block(s->info, left); - s->nodes[1] = right; - } - s->count = 2; - + unlock_block(s->info, left); + unlock_block(s->info, right); return 0; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 63e57254ff62f5bf39c7bbeae0f3342217f31a6b..3064a6e3ad98c7151ca60d22cbbf9890af2b80a7 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1722,6 +1722,17 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) struct md_rdev *repl = conf->mirrors[conf->raid_disks + number].rdev; freeze_array(conf, 0); + if (atomic_read(&repl->nr_pending)) { + /* It means that some queued IO of retry_list + * hold repl. Thus, we cannot set replacement + * as NULL, avoiding rdev NULL pointer + * dereference in sync_request_write and + * handle_write_finished. + */ + err = -EBUSY; + unfreeze_array(conf); + goto abort; + } clear_bit(Replacement, &repl->flags); p->rdev = repl; conf->mirrors[conf->raid_disks + number].rdev = NULL; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1b49827757b5f3574000457abc63bdebdfdc55ca..d09e227a72139d72acdfd8ce8f86386be3eb2168 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1514,11 +1514,24 @@ retry_write: mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); + + cb = blk_check_plugged(raid10_unplug, mddev, + sizeof(*plug)); + if (cb) + plug = container_of(cb, struct raid10_plug_cb, + cb); + else + plug = NULL; spin_lock_irqsave(&conf->device_lock, flags); - bio_list_add(&conf->pending_bio_list, mbio); - conf->pending_count++; + if (plug) { + bio_list_add(&plug->pending, mbio); + plug->pending_cnt++; + } else { + bio_list_add(&conf->pending_bio_list, mbio); + conf->pending_count++; + } spin_unlock_irqrestore(&conf->device_lock, flags); - if (!mddev_check_plugged(mddev)) + if (!plug) md_wakeup_thread(mddev->thread); } } @@ -2741,7 +2754,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) for (m = 0; m < conf->copies; m++) { int dev = r10_bio->devs[m].devnum; rdev = conf->mirrors[dev].rdev; - if (r10_bio->devs[m].bio == NULL) + if (r10_bio->devs[m].bio == NULL || + r10_bio->devs[m].bio->bi_end_io == NULL) continue; if (test_bit(BIO_UPTODATE, &r10_bio->devs[m].bio->bi_flags)) { @@ -2757,7 +2771,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) md_error(conf->mddev, rdev); } rdev = conf->mirrors[dev].replacement; - if (r10_bio->devs[m].repl_bio == NULL) + if (r10_bio->devs[m].repl_bio == NULL || + r10_bio->devs[m].repl_bio->bi_end_io == NULL) continue; if (test_bit(BIO_UPTODATE, &r10_bio->devs[m].repl_bio->bi_flags)) { @@ -3704,6 +3719,7 @@ static int run(struct mddev *mddev) if (blk_queue_discard(bdev_get_queue(rdev->bdev))) discard_supported = true; + first = 0; } if (mddev->queue) { @@ -3754,6 +3770,13 @@ static int run(struct mddev *mddev) disk->rdev->saved_raid_disk < 0) conf->fullsync = 1; } + + if (disk->replacement && + !test_bit(In_sync, &disk->replacement->flags) && + disk->replacement->saved_raid_disk < 0) { + conf->fullsync = 1; + } + disk->recovery_disabled = mddev->recovery_disabled - 1; } @@ -4119,6 +4142,7 @@ static int raid10_start_reshape(struct mddev *mddev) diff = 0; if (first || diff < min_offset_diff) min_offset_diff = diff; + first = 0; } } @@ -4399,11 +4423,12 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, allow_barrier(conf); } + raise_barrier(conf, 0); read_more: /* Now schedule reads for blocks from sector_nr to last */ r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO); r10_bio->state = 0; - raise_barrier(conf, sectors_done != 0); + raise_barrier(conf, 1); atomic_set(&r10_bio->remaining, 0); r10_bio->mddev = mddev; r10_bio->sector = sector_nr; @@ -4508,6 +4533,8 @@ bio_full: if (sector_nr <= last) goto read_more; + lower_barrier(conf); + /* Now that we have done the whole section we can * update reshape_progress */ diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 094f36064ff015e3c47a1670c1fd543124a050ee..9f442b9418e5822b21e7cc4c70ed41cf3859e1b1 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1454,8 +1454,11 @@ static void ops_complete_reconstruct(void *stripe_head_ref) struct r5dev *dev = &sh->dev[i]; if (dev->written || i == pd_idx || i == qd_idx) { - if (!discard && !test_bit(R5_SkipCopy, &dev->flags)) + if (!discard && !test_bit(R5_SkipCopy, &dev->flags)) { set_bit(R5_UPTODATE, &dev->flags); + if (test_bit(STRIPE_EXPAND_READY, &sh->state)) + set_bit(R5_Expanded, &dev->flags); + } if (fua) set_bit(R5_WantFUA, &dev->flags); if (sync) @@ -3700,6 +3703,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) s->failed++; if (rdev && !test_bit(Faulty, &rdev->flags)) do_recovery = 1; + else if (!rdev) { + rdev = rcu_dereference( + conf->disks[i].replacement); + if (rdev && !test_bit(Faulty, &rdev->flags)) + do_recovery = 1; + } } } if (test_bit(STRIPE_SYNCING, &sh->state)) { diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c index bfe831c10b1c46ccabf4efd41a49a8550b04ab70..b95a631f23f9ab3f34d7f323997afbfe9b30d542 100644 --- a/drivers/media/common/siano/smsendian.c +++ b/drivers/media/common/siano/smsendian.c @@ -35,7 +35,7 @@ void smsendian_handle_tx_message(void *buffer) switch (msg->x_msg_header.msg_type) { case MSG_SMS_DATA_DOWNLOAD_REQ: { - msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]); + msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0])); break; } @@ -44,7 +44,7 @@ void smsendian_handle_tx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -64,7 +64,7 @@ void smsendian_handle_rx_message(void *buffer) { struct sms_version_res *ver = (struct sms_version_res *) msg; - ver->chip_model = le16_to_cpu(ver->chip_model); + ver->chip_model = le16_to_cpu((__force __le16)ver->chip_model); break; } @@ -81,7 +81,7 @@ void smsendian_handle_rx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -95,9 +95,9 @@ void smsendian_handle_message_header(void *msg) #ifdef __BIG_ENDIAN struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg; - phdr->msg_type = le16_to_cpu(phdr->msg_type); - phdr->msg_length = le16_to_cpu(phdr->msg_length); - phdr->msg_flags = le16_to_cpu(phdr->msg_flags); + phdr->msg_type = le16_to_cpu((__force __le16)phdr->msg_type); + phdr->msg_length = le16_to_cpu((__force __le16)phdr->msg_length); + phdr->msg_flags = le16_to_cpu((__force __le16)phdr->msg_flags); #endif /* __BIG_ENDIAN */ } EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 0aac3096728ee1faafa49a2ca8ad0986d18b0158..051bdfac6a1d24679d1460589217ee9bef37129a 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -749,6 +749,29 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * b goto exit; } + /* + * It may need some time for the CAM to settle down, or there might + * be a race condition between the CAM, writing HC and our last + * check for DA. This happens, if the CAM asserts DA, just after + * checking DA before we are setting HC. In this case it might be + * a bug in the CAM to keep the FR bit, the lower layer/HW + * communication requires a longer timeout or the CAM needs more + * time internally. But this happens in reality! + * We need to read the status from the HW again and do the same + * we did for the previous check for DA + */ + status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (status < 0) + goto exit; + + if (status & (STATUSREG_DA | STATUSREG_RE)) { + if (status & STATUSREG_DA) + dvb_ca_en50221_thread_wakeup(ca); + + status = -EAGAIN; + goto exit; + } + /* send the amount of data */ if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) goto exit; diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 61b9415088c8a3eb4c101399966d4bdac6cd13a3..e5b559fea8f3e333c57ef3a98f9ff33fa3162596 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -224,8 +224,20 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) wake_up_interruptible (&events->wait_queue); } +static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv, + struct dvb_fe_events *events) +{ + int ret; + + up(&fepriv->sem); + ret = events->eventw != events->eventr; + down(&fepriv->sem); + + return ret; +} + static int dvb_frontend_get_event(struct dvb_frontend *fe, - struct dvb_frontend_event *event, int flags) + struct dvb_frontend_event *event, int flags) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; @@ -243,13 +255,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, if (flags & O_NONBLOCK) return -EWOULDBLOCK; - up(&fepriv->sem); - - ret = wait_event_interruptible (events->wait_queue, - events->eventw != events->eventr); - - if (down_interruptible (&fepriv->sem)) - return -ERESTARTSYS; + ret = wait_event_interruptible(events->wait_queue, + dvb_frontend_test_event(fepriv, events)); if (ret < 0) return ret; diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index e0aaea1016e46f37d250c7951c27b83a64bfee21..6627235fa27249f2383fcd419a0a784aa7215d3c 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -5,7 +5,7 @@ * Copyright (C) 2003 Oliver Endriss * Copyright (C) 2004 Andrew de Quincey * - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved. * * based on code originally found in av7110.c & dvb_ci.c: * Copyright (C) 1999-2003 Ralph Metzler @@ -235,9 +235,11 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, */ smp_store_release(&rbuf->pwrite, 0); } - status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); - if (status) - return len - todo; + + if (copy_from_user(rbuf->data + rbuf->pwrite, buf, todo)) { + smp_store_release(&rbuf->pwrite, oldpwrite); + return -EFAULT; + } /* smp_store_release() for write pointer update, see above */ smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size); diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 64a759c017d4dbfde5def3724bf0126ed228ed62..09fde4e51210f7a4ca2525d420019068d61c0ee8 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -14,6 +14,8 @@ * GNU General Public License for more details. */ +#include + #include "si2168_priv.h" static const struct dvb_frontend_ops si2168_ops; @@ -380,6 +382,7 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; + udelay(100); memcpy(cmd.args, "\x85", 1); cmd.wlen = 1; cmd.rlen = 1; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index e453a3ffe7d1b638ed3c5bf776dbe35eaa7304de..d96582b684c4628de3d91fff127740e2dcf657fd 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -420,11 +420,13 @@ static void cx25840_initialize(struct i2c_client *client) INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); + if (q) { + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + } /* 6. */ cx25840_write(client, 0x115, 0x8c); @@ -465,8 +467,13 @@ static void cx23885_initialize(struct i2c_client *client) { DEFINE_WAIT(wait); struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u32 clk_freq = 0; struct workqueue_struct *q; + /* cx23885 sets hostdata to clk_freq pointer */ + if (v4l2_get_subdev_hostdata(&state->sd)) + clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd)); + /* * Come out of digital power down * The CX23888, at least, needs this, otherwise registers aside from @@ -502,8 +509,13 @@ static void cx23885_initialize(struct i2c_client *client) * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz * 572.73 MHz before post divide */ - /* HVR1850 or 50MHz xtal */ - cx25840_write(client, 0x2, 0x71); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25Mhz xtal */ + ; /* nothing to do */ + } else { + /* HVR1850 or 50MHz xtal */ + cx25840_write(client, 0x2, 0x71); + } cx25840_write4(client, 0x11c, 0x01d1744c); cx25840_write4(client, 0x118, 0x00000416); cx25840_write4(client, 0x404, 0x0010253e); @@ -546,9 +558,15 @@ static void cx23885_initialize(struct i2c_client *client) /* HVR1850 */ switch (state->id) { case CX23888_AV: - /* 888/HVR1250 specific */ - cx25840_write4(client, 0x10c, 0x13333333); - cx25840_write4(client, 0x108, 0x00000515); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25MHz xtal */ + cx25840_write4(client, 0x10c, 0x01b6db7b); + cx25840_write4(client, 0x108, 0x00000512); + } else { + /* 888/HVR1250 or 50MHz xtal */ + cx25840_write4(client, 0x10c, 0x13333333); + cx25840_write4(client, 0x108, 0x00000515); + } break; default: cx25840_write4(client, 0x10c, 0x002be2c9); @@ -575,7 +593,7 @@ static void cx23885_initialize(struct i2c_client *client) * 368.64 MHz before post divide * 122.88 MHz / 0xa = 12.288 MHz */ - /* HVR1850 or 50MHz xtal */ + /* HVR1850 or 50MHz xtal or 25MHz xtal */ cx25840_write4(client, 0x114, 0x017dbf48); cx25840_write4(client, 0x110, 0x000a030e); break; @@ -631,11 +649,13 @@ static void cx23885_initialize(struct i2c_client *client) INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); + if (q) { + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + } /* Call the cx23888 specific std setup func, we no longer rely on * the generic cx24840 func. @@ -746,11 +766,13 @@ static void cx231xx_initialize(struct i2c_client *client) INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); + if (q) { + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + } cx25840_std_setup(client); diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index 629a5cdadd3ad8c3673296ce488c054147cc7843..fa635894fb0fc54a0d68c95376d5674fa196782c 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -421,6 +421,7 @@ static int s5k6aa_set_ahb_address(struct i2c_client *client) /** * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration + * @s5k6aa: pointer to &struct s5k6aa describing the device * * Configure the internal ISP PLL for the required output frequency. * Locking: called with s5k6aa.lock mutex held. @@ -669,6 +670,7 @@ static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa) /** * s5k6aa_configure_video_bus - configure the video output interface + * @s5k6aa: pointer to &struct s5k6aa describing the device * @bus_type: video bus type: parallel or MIPI-CSI * @nlanes: number of MIPI lanes to be used (MIPI-CSI only) * @@ -724,6 +726,8 @@ static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout, /** * s5k6aa_set_prev_config - write user preview register set + * @s5k6aa: pointer to &struct s5k6aa describing the device + * @preset: s5kaa preset to be applied * * Configure output resolution and color fromat, pixel clock * frequency range, device frame rate type and frame period range. @@ -777,6 +781,7 @@ static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa, /** * s5k6aa_initialize_isp - basic ISP MCU initialization + * @sd: pointer to V4L2 sub-device descriptor * * Configure AHB addresses for registers read/write; configure PLLs for * required output pixel clock. The ISP power supply needs to be already diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index b49254e4ea0af09779860f8f69ccddcaa4164d02..6a2f204b902f1b8db46211060da6acb9c27a6dd3 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -939,7 +939,7 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (rval) goto out; - for (i = 0; i < 1000; i++) { + for (i = 1000; i > 0; i--) { rval = smiapp_read( sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s); @@ -950,11 +950,10 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) break; - if (--i == 0) { - rval = -ETIMEDOUT; - goto out; - } - + } + if (!i) { + rval = -ETIMEDOUT; + goto out; } for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index ab01598ec83fefb759587b87ae905f8a8c3174f5..d8be90cd6e56ce3def690b8fd9b81fbb015b826a 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -1016,7 +1016,7 @@ static int ov6650_probe(struct i2c_client *client, priv->code = V4L2_MBUS_FMT_YUYV8_2X8; priv->colorspace = V4L2_COLORSPACE_JPEG; - priv->clk = v4l2_clk_get(&client->dev, "mclk"); + priv->clk = v4l2_clk_get(&client->dev, NULL); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); goto eclkget; diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 970a04e1e56e694602f4a87261079646c517875f..a085027664741ebbc9883bfb74dd9f7e5d387a90 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -834,7 +834,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, * set COM8 */ if (priv->band_filter) { - ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); + ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF); if (!ret) ret = ov772x_mask_set(client, BDBASE, 0xff, 256 - priv->band_filter); diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c index 11765835d7b2977ec3317863f05f2560b25eff1c..866e6c8323f4154cc13ec41fafaa0e4f5d35ccd8 100644 --- a/drivers/media/pci/bt8xx/bt878.c +++ b/drivers/media/pci/bt8xx/bt878.c @@ -425,8 +425,7 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) bt878_num); if (bt878_num >= BT878_MAX) { printk(KERN_ERR "bt878: Too many devices inserted\n"); - result = -ENOMEM; - goto fail0; + return -ENOMEM; } if (pci_enable_device(dev)) return -EIO; diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c index d407244fd1bce3339b3fdbc13ea3e4801114f19a..bd0f5b1951884063d5c447d1498fdf9d9f98c588 100644 --- a/drivers/media/pci/bt8xx/dvb-bt8xx.c +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c @@ -680,6 +680,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) /* DST is not a frontend, attaching the ASIC */ if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { pr_err("%s: Could not find a Twinhan DST\n", __func__); + kfree(state); break; } /* Attach other DST peripherals if any */ diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 377818887ed22567434318ce8c43cc1010215f69..f74cd5b10ded7563e5165f84a08ace1231046933 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1950,6 +1950,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); if (dev->sd_cx25840) { + /* set host data for clk_freq configuration */ + v4l2_set_subdev_hostdata(dev->sd_cx25840, + &dev->clk_freq); + dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; v4l2_subdev_call(dev->sd_cx25840, core, load_fw); } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 3bd386c371f74ab260b00cac9dcfaa9eadecc962..01966969ca682c4d2cf7e79a94321cd4e0cca0bf 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -870,6 +870,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if (cx23885_boards[dev->board].clk_freq > 0) dev->clk_freq = cx23885_boards[dev->board].clk_freq; + if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE && + dev->pci->subsystem_device == 0x7137) { + /* Hauppauge ImpactVCBe device ID 0x7137 is populated + * with an 888, and a 25Mhz crystal, instead of the + * usual third overtone 50Mhz. The default clock rate must + * be overridden so the cx25840 is properly configured + */ + dev->clk_freq = 25000000; + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); cx23885_irq_add(dev, 0x001f00); diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index e81173c41e5aaee45fa9168ebb243b486c39b7b7..34335ced002e9c03e4aa6f0eaf9c4215cb75f065 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -871,6 +871,10 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->nr = ++cx25821_devcount; sprintf(dev->name, "cx25821[%d]", dev->nr); + if (dev->nr >= ARRAY_SIZE(card)) { + CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card)); + return -ENODEV; + } if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); @@ -887,9 +891,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->channels[i].sram_channels = &cx25821_sram_channels[i]; } - if (dev->nr > 1) - CX25821_INFO("dev->nr > 1!"); - /* board config */ dev->board = 1; /* card[dev->nr]; */ dev->_max_num_decoders = MAX_DECODERS; diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index 86763203d61dba58d19c0eaba9ab87bb7de237c6..021c46da794de192ed164cd419db6974bc49b25c 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -430,7 +430,8 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) __func__, fw->size); if (fw->size != fwlength) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); + printk(KERN_ERR "saa7164: firmware incorrect size %zu != %u\n", + fw->size, fwlength); ret = -ENOMEM; goto out; } diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c index 300bd3c9473876fb7b2751da7ab91532397621c2..0992bb0e207e994ebcdca1355c78e1b448a3c9aa 100644 --- a/drivers/media/pci/ttpci/av7110_hw.c +++ b/drivers/media/pci/ttpci/av7110_hw.c @@ -56,11 +56,11 @@ by Nathan Laredo */ int av7110_debiwrite(struct av7110 *av7110, u32 config, - int addr, u32 val, int count) + int addr, u32 val, unsigned int count) { struct saa7146_dev *dev = av7110->dev; - if (count <= 0 || count > 32764) { + if (count > 32764) { printk("%s: invalid count %d\n", __func__, count); return -1; } @@ -78,12 +78,12 @@ int av7110_debiwrite(struct av7110 *av7110, u32 config, return 0; } -u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count) +u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count) { struct saa7146_dev *dev = av7110->dev; u32 result = 0; - if (count > 32764 || count <= 0) { + if (count > 32764) { printk("%s: invalid count %d\n", __func__, count); return 0; } diff --git a/drivers/media/pci/ttpci/av7110_hw.h b/drivers/media/pci/ttpci/av7110_hw.h index 1634aba5cb84693bfde178dba08f5dc32ab3ab91..ccb1480594068f4058ac8c774cbc888ea16818be 100644 --- a/drivers/media/pci/ttpci/av7110_hw.h +++ b/drivers/media/pci/ttpci/av7110_hw.h @@ -377,14 +377,14 @@ extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, /* DEBI (saa7146 data extension bus interface) access */ extern int av7110_debiwrite(struct av7110 *av7110, u32 config, - int addr, u32 val, int count); + int addr, u32 val, unsigned int count); extern u32 av7110_debiread(struct av7110 *av7110, u32 config, - int addr, int count); + int addr, unsigned int count); /* DEBI during interrupt */ /* single word writes */ -static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) { av7110_debiwrite(av7110, config, addr, val, count); } @@ -397,7 +397,7 @@ static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, av7110_debiwrite(av7110, config, addr, 0, count); } -static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) { u32 res; @@ -408,7 +408,7 @@ static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, i } /* DEBI outside interrupts, only for count <= 4! */ -static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) { unsigned long flags; @@ -417,7 +417,7 @@ static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, i spin_unlock_irqrestore(&av7110->debilock, flags); } -static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) { unsigned long flags; u32 res; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index b4c9f1d089684f316215803018541a47d0f4270b..fc1716f087771a9ded619989acefa9ffda8af450 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -846,9 +846,7 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb, if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) || (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) || - (frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) || (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) || - (frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) || (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M)) swap(addr->cb, addr->cr); diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index 76b6b4d146169824593170c08f79a89a2b18c06f..322677f2cbb042b505b202ed5cdb5e28b8cd0bab 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -389,12 +389,17 @@ static void __isp_video_try_fmt(struct fimc_isp *isp, struct v4l2_pix_format_mplane *pixm, const struct fimc_fmt **fmt) { - *fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2); + const struct fimc_fmt *__fmt; + + __fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2); + + if (fmt) + *fmt = __fmt; pixm->colorspace = V4L2_COLORSPACE_SRGB; pixm->field = V4L2_FIELD_NONE; - pixm->num_planes = (*fmt)->memplanes; - pixm->pixelformat = (*fmt)->fourcc; + pixm->num_planes = __fmt->memplanes; + pixm->pixelformat = __fmt->fourcc; /* * TODO: double check with the docmentation these width/height * constraints are correct. diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index 3f8a3c61ade01724ade4989b6ceccff159f27006..961874afc155b946c4dc9be3c91c8749cf07e5a5 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -56,7 +56,6 @@ source "drivers/media/platform/msm/camera_v2/Kconfig" endif # MSMB_CAMERA endif -source "drivers/media/platform/msm/ais/Kconfig" source "drivers/media/platform/msm/dvb/Kconfig" source "drivers/media/platform/msm/broadcast/Kconfig" source "drivers/media/platform/msm/sde/Kconfig" diff --git a/drivers/media/platform/msm/ais/Kconfig b/drivers/media/platform/msm/ais/Kconfig deleted file mode 100644 index 8e02155251d97bb6d710321e2c946fcd13c01fd8..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/Kconfig +++ /dev/null @@ -1,85 +0,0 @@ -menuconfig MSM_AIS - bool "QTI MSM Automotive Imaging Subsystem" - depends on ARCH_MSM && VIDEO_V4L2 && I2C - ---help--- - Say Y here to enable msm AIS - -config MSM_AIS_DEBUG - bool "QTI MSM AIS debugging with printk" - depends on MSM_AIS - default n - ---help--- - Enable printk() debug for msm AIS. - Enabling ais debug will affect performance. - This feature is only applicable to - Automotive platforms. - -config MSM_AIS_CAMERA_SENSOR - bool "QTI MSM camera sensor support" - depends on MSM_AIS - select NEW_LEDS - select LEDS_CLASS - ---help--- - This flag enables support for Camera Sensor. - The sensor driver is capable of providing real time - data for camera support. The driver support V4L2 - subdev APIs. - -config MSM_AIS_CPP - bool "QTI MSM Camera Post Processing Engine support" - depends on MSM_AIS - ---help--- - Enable support for Camera Post-processing Engine - The Post processing engine is capable of scaling - and cropping image. The driver support V4L2 subdev - APIs. - -config MSM_AIS_EEPROM - bool "QTI MSM Camera ROM Interface for Calibration support" - depends on MSM_AIS - ---help--- - Enable support for ROM Interface for Calibration - Provides interface for reading the Calibration data - and also provides support for writing data in case of FLASH ROM. - Currently supports I2C, CCI and SPI protocol - -config MSM_AIS_JPEG - bool "QTI MSM Jpeg Encoder Engine support" - depends on MSM_AIS - ---help--- - Enable support for Jpeg Encoder/Decoder - Engine for 8974. - This module serves as the common driver - for the JPEG 1.0 encoder and decoder. - -config MSM_AIS_FD - bool "QTI MSM FD face detection engine support" - depends on MSM_AIS - ---help--- - Enables support for the MSM FD face detection engine. - MSM Face Detection library - enables the Face detection - hardware block. - -config MSM_AIS_JPEGDMA - bool "QTI MSM Jpeg dma" - depends on MSM_AIS - select V4L2_MEM2MEM_DEV - ---help--- - Enable support for Jpeg dma engine. - The jpeg DMA engine is a hardware enabled - jpeg decode. - This feature is currently not supported on - Automotive platforms. - -config MSM_AIS_SEC_CCI_TA_NAME - string "Name of TA to handle Secure CCI transactions" - depends on MSM_AIS_CCI - default "seccamdemo64" - -config MSM_AIS_SEC_CCI_DEBUG - bool "QTI MSM Secure CCI Relay Debug" - depends on MSM_AIS_CCI - ---help--- - Enables simulation of secure camera for Secure CCI Realy - debugging. diff --git a/drivers/media/platform/msm/ais/Makefile b/drivers/media/platform/msm/ais/Makefile deleted file mode 100644 index b09636a724132a9939881b2e3a5db312a0d15296..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/sensor -ccflags-y += -Idrivers/media/platform/msm/ais/codecs -ccflags-y += -Idrivers/media/platform/msm/ais/isps -ccflags-y += -Idrivers/media/platform/msm/ais/pproc -ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2 -ccflags-y += -Idrivers/media/platform/msm/ais/camera -ccflags-y += -Idrivers/media/platform/msm/ais/jpeg_10 -ccflags-y += -Idrivers/media/platform/msm/ais/jpeg_dma -ccflags-y += -Idrivers/media/platform/msm/ais/fd -ccflags-y += -Idrivers/media/platform/msm/ais/common - -obj-$(CONFIG_MSM_AIS) += common/ -obj-$(CONFIG_MSM_AIS) += msm.o -obj-$(CONFIG_MSM_AIS) += camera/ -obj-$(CONFIG_MSM_AIS) += msm_vb2/ -obj-$(CONFIG_MSM_AIS) += sensor/ -obj-$(CONFIG_MSM_AIS) += pproc/ -obj-$(CONFIG_MSM_AIS) += isp/ -obj-$(CONFIG_MSM_AIS) += ispif/ -obj-$(CONFIG_MSM_AIS_JPEG) += jpeg_10/ -obj-$(CONFIG_MSM_AIS_JPEGDMA) += jpeg_dma/ -obj-$(CONFIG_MSM_AIS) += msm_buf_mgr/ -obj-$(CONFIG_MSM_AIS_FD) += fd/ diff --git a/drivers/media/platform/msm/ais/camera/Makefile b/drivers/media/platform/msm/ais/camera/Makefile deleted file mode 100644 index e465a034b9e5b7eb8186c9494bad0c417e808017..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/camera/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2 -obj-$(CONFIG_MSM_AIS) += camera.o diff --git a/drivers/media/platform/msm/ais/common/Makefile b/drivers/media/platform/msm/ais/common/Makefile deleted file mode 100644 index e1fa3f2ea8481b21121779a42c7331991f52cb4a..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais/ -obj-$(CONFIG_MSM_AIS) += msm_camera_io_util.o cam_smmu_api.o cam_hw_ops.o cam_soc_api.o diff --git a/drivers/media/platform/msm/ais/common/cam_hw_ops.c b/drivers/media/platform/msm/ais/common/cam_hw_ops.c deleted file mode 100644 index 073778c9edcca4210c5bdc02e4c97b75ea05985c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/cam_hw_ops.c +++ /dev/null @@ -1,338 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "CAM-AHB %s:%d " fmt, __func__, __LINE__ -#define TRUE 1 -#include -#include -#include -#include -#include -#include -#include "cam_hw_ops.h" - -#ifdef CONFIG_CAM_AHB_DBG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -struct cam_ahb_client { - enum cam_ahb_clk_vote vote; -}; - -struct cam_bus_vector { - const char *name; -}; - -struct cam_ahb_client_data { - struct msm_bus_scale_pdata *pbus_data; - u32 ahb_client; - u32 ahb_clk_state; - struct msm_bus_vectors *paths; - struct msm_bus_paths *usecases; - struct cam_bus_vector *vectors; - u32 *votes; - u32 cnt; - u32 probe_done; - struct cam_ahb_client clients[CAM_AHB_CLIENT_MAX]; - struct mutex lock; -}; - -static struct cam_ahb_client_data data; - -int get_vector_index(char *name) -{ - int i = 0, rc = -1; - - for (i = 0; i < data.cnt; i++) { - if (strcmp(name, data.vectors[i].name) == 0) - return i; - } - - return rc; -} - -int cam_ahb_clk_init(struct platform_device *pdev) -{ - int i = 0, cnt = 0, rc = 0, index = 0; - struct device_node *of_node; - - if (!pdev) { - pr_err("invalid pdev argument\n"); - return -EINVAL; - } - - of_node = pdev->dev.of_node; - data.cnt = of_property_count_strings(of_node, "bus-vectors"); - if (data.cnt == 0) { - pr_err("no vectors strings found in device tree, count=%d", - data.cnt); - return 0; - } - - cnt = of_property_count_u32_elems(of_node, "qcom,bus-votes"); - if (cnt == 0) { - pr_err("no vector values found in device tree, count=%d", cnt); - return 0; - } - - if (data.cnt != cnt) { - pr_err("vector mismatch num of strings=%u, num of values %d\n", - data.cnt, cnt); - return -EINVAL; - } - - CDBG("number of bus vectors: %d\n", data.cnt); - - data.vectors = devm_kzalloc(&pdev->dev, - sizeof(struct cam_bus_vector) * cnt, - GFP_KERNEL); - if (!data.vectors) - return -ENOMEM; - - for (i = 0; i < data.cnt; i++) { - rc = of_property_read_string_index(of_node, "bus-vectors", - i, &(data.vectors[i].name)); - CDBG("dbg: names[%d] = %s\n", i, data.vectors[i].name); - if (rc < 0) { - pr_err("failed\n"); - rc = -EINVAL; - goto err1; - } - } - - data.paths = devm_kzalloc(&pdev->dev, - sizeof(struct msm_bus_vectors) * cnt, - GFP_KERNEL); - if (!data.paths) { - rc = -ENOMEM; - goto err1; - } - - data.usecases = devm_kzalloc(&pdev->dev, - sizeof(struct msm_bus_paths) * cnt, - GFP_KERNEL); - if (!data.usecases) { - rc = -ENOMEM; - goto err2; - } - - data.pbus_data = devm_kzalloc(&pdev->dev, - sizeof(struct msm_bus_scale_pdata), - GFP_KERNEL); - if (!data.pbus_data) { - rc = -ENOMEM; - goto err3; - } - - data.votes = devm_kzalloc(&pdev->dev, sizeof(u32) * cnt, - GFP_KERNEL); - if (!data.votes) { - rc = -ENOMEM; - goto err4; - } - - rc = of_property_read_u32_array(of_node, "qcom,bus-votes", - data.votes, cnt); - - for (i = 0; i < data.cnt; i++) { - data.paths[i] = (struct msm_bus_vectors) { - MSM_BUS_MASTER_AMPSS_M0, - MSM_BUS_SLAVE_CAMERA_CFG, - 0, - data.votes[i] - }; - data.usecases[i] = (struct msm_bus_paths) { - .num_paths = 1, - .vectors = &data.paths[i], - }; - CDBG("dbg: votes[%d] = %u\n", i, data.votes[i]); - } - - *data.pbus_data = (struct msm_bus_scale_pdata) { - .name = "msm_camera_ahb", - .num_usecases = data.cnt, - .usecase = data.usecases, - }; - - data.ahb_client = - msm_bus_scale_register_client(data.pbus_data); - if (!data.ahb_client) { - pr_err("ahb vote registering failed\n"); - rc = -EINVAL; - goto err5; - } - - index = get_vector_index("suspend"); - if (index < 0) { - pr_err("svs vector not supported\n"); - rc = -EINVAL; - goto err6; - } - - /* request for svs in init */ - msm_bus_scale_client_update_request(data.ahb_client, - index); - data.ahb_clk_state = CAM_AHB_SUSPEND_VOTE; - data.probe_done = TRUE; - mutex_init(&data.lock); - - CDBG("dbg, done registering ahb votes\n"); - CDBG("dbg, clk state :%u, probe :%d\n", - data.ahb_clk_state, data.probe_done); - return rc; - -err6: - msm_bus_scale_unregister_client(data.ahb_client); -err5: - devm_kfree(&pdev->dev, data.votes); - data.votes = NULL; -err4: - devm_kfree(&pdev->dev, data.pbus_data); - data.pbus_data = NULL; -err3: - devm_kfree(&pdev->dev, data.usecases); - data.usecases = NULL; -err2: - devm_kfree(&pdev->dev, data.paths); - data.paths = NULL; -err1: - devm_kfree(&pdev->dev, data.vectors); - data.vectors = NULL; - return rc; -} -EXPORT_SYMBOL(cam_ahb_clk_init); - -int cam_consolidate_ahb_vote(enum cam_ahb_clk_client id, - enum cam_ahb_clk_vote vote) -{ - int i = 0; - u32 max = 0; - - CDBG("dbg: id :%u, vote : 0x%x\n", id, vote); - mutex_lock(&data.lock); - data.clients[id].vote = vote; - - if (vote == data.ahb_clk_state) { - CDBG("dbg: already at desired vote\n"); - mutex_unlock(&data.lock); - return 0; - } - - for (i = 0; i < CAM_AHB_CLIENT_MAX; i++) { - if (data.clients[i].vote > max) - max = data.clients[i].vote; - } - - CDBG("dbg: max vote : %u\n", max); - if (max >= 0) { - if (max != data.ahb_clk_state) { - msm_bus_scale_client_update_request(data.ahb_client, - max); - data.ahb_clk_state = max; - CDBG("dbg: state : %u, vector : %d\n", - data.ahb_clk_state, max); - } - } else { - pr_err("err: no bus vector found\n"); - mutex_unlock(&data.lock); - return -EINVAL; - } - mutex_unlock(&data.lock); - return 0; -} - -static int cam_ahb_get_voltage_level(unsigned int corner) -{ - switch (corner) { - case RPM_REGULATOR_CORNER_NONE: - return CAM_AHB_SUSPEND_VOTE; - - case RPM_REGULATOR_CORNER_SVS_KRAIT: - case RPM_REGULATOR_CORNER_SVS_SOC: - return CAM_AHB_SVS_VOTE; - - case RPM_REGULATOR_CORNER_NORMAL: - return CAM_AHB_NOMINAL_VOTE; - - case RPM_REGULATOR_CORNER_SUPER_TURBO: - return CAM_AHB_TURBO_VOTE; - - case RPM_REGULATOR_CORNER_TURBO: - case RPM_REGULATOR_CORNER_RETENTION: - default: - return -EINVAL; - } -} - -int cam_config_ahb_clk(struct device *dev, unsigned long freq, - enum cam_ahb_clk_client id, enum cam_ahb_clk_vote vote) -{ - struct dev_pm_opp *opp; - unsigned int corner; - enum cam_ahb_clk_vote dyn_vote = vote; - int rc = -EINVAL; - - if (id >= CAM_AHB_CLIENT_MAX) { - pr_err("err: invalid argument\n"); - return -EINVAL; - } - - if (data.probe_done != TRUE) { - pr_err("ahb init is not done yet\n"); - return -EINVAL; - } - - CDBG("dbg: id :%u, vote : 0x%x\n", id, vote); - switch (dyn_vote) { - case CAM_AHB_SUSPEND_VOTE: - case CAM_AHB_SVS_VOTE: - case CAM_AHB_NOMINAL_VOTE: - case CAM_AHB_TURBO_VOTE: - break; - case CAM_AHB_DYNAMIC_VOTE: - if (!dev) { - pr_err("device is NULL\n"); - return -EINVAL; - } - opp = dev_pm_opp_find_freq_exact(dev, freq, true); - if (IS_ERR(opp)) { - pr_err("Error on OPP freq :%ld\n", freq); - return -EINVAL; - } - corner = dev_pm_opp_get_voltage(opp); - if (corner == 0) { - pr_err("Bad voltage corner for OPP freq :%ld\n", freq); - return -EINVAL; - } - dyn_vote = cam_ahb_get_voltage_level(corner); - if (dyn_vote < 0) { - pr_err("Bad vote requested\n"); - return -EINVAL; - } - break; - default: - pr_err("err: invalid vote argument\n"); - return -EINVAL; - } - - rc = cam_consolidate_ahb_vote(id, dyn_vote); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - goto end; - } - -end: - return rc; -} -EXPORT_SYMBOL(cam_config_ahb_clk); diff --git a/drivers/media/platform/msm/ais/common/cam_hw_ops.h b/drivers/media/platform/msm/ais/common/cam_hw_ops.h deleted file mode 100644 index 32f93f7b6e0e53dad7480f7ebb9c878a8b2e7723..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/cam_hw_ops.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ -#ifndef _CAM_HW_OPS_H_ -#define _CAM_HW_OPS_H_ - -enum cam_ahb_clk_vote { - /* need to update the voting requests - * according to dtsi entries. - */ - CAM_AHB_SUSPEND_VOTE = 0x0, - CAM_AHB_SVS_VOTE = 0x01, - CAM_AHB_NOMINAL_VOTE = 0x02, - CAM_AHB_TURBO_VOTE = 0x03, - CAM_AHB_DYNAMIC_VOTE = 0xFF, -}; - -enum cam_ahb_clk_client { - CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_CLIENT_CSID, - CAM_AHB_CLIENT_CCI, - CAM_AHB_CLIENT_ISPIF, - CAM_AHB_CLIENT_VFE0, - CAM_AHB_CLIENT_VFE1, - CAM_AHB_CLIENT_CPP, - CAM_AHB_CLIENT_FD, - CAM_AHB_CLIENT_JPEG, - CAM_AHB_CLIENT_MAX -}; - -int cam_config_ahb_clk(struct device *dev, unsigned long freq, - enum cam_ahb_clk_client id, enum cam_ahb_clk_vote vote); -int cam_ahb_clk_init(struct platform_device *pdev); -#endif diff --git a/drivers/media/platform/msm/ais/common/cam_smmu_api.c b/drivers/media/platform/msm/ais/common/cam_smmu_api.c deleted file mode 100644 index 0bfd1caa16e2ffa7cb45df017bf2118f61970581..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/cam_smmu_api.c +++ /dev/null @@ -1,1692 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "CAM-SMMU %s:%d " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cam_smmu_api.h" - -#define SCRATCH_ALLOC_START SZ_128K -#define SCRATCH_ALLOC_END SZ_256M -#define VA_SPACE_END SZ_2G -#define IOMMU_INVALID_DIR -1 -#define BYTE_SIZE 8 -#define COOKIE_NUM_BYTE 2 -#define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE) -#define COOKIE_MASK ((1<> COOKIE_SIZE) & COOKIE_MASK) - -#ifdef CONFIG_CAM_SMMU_DBG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -struct cam_smmu_work_payload { - int idx; - struct iommu_domain *domain; - struct device *dev; - unsigned long iova; - int flags; - void *token; - struct list_head list; -}; - -enum cam_protection_type { - CAM_PROT_INVALID, - CAM_NON_SECURE, - CAM_SECURE, - CAM_PROT_MAX, -}; - -enum cam_iommu_type { - CAM_SMMU_INVALID, - CAM_QSMMU, - CAM_ARM_SMMU, - CAM_SMMU_MAX, -}; - -enum cam_smmu_buf_state { - CAM_SMMU_BUFF_EXIST, - CAM_SMMU_BUFF_NOT_EXIST -}; - -enum cam_smmu_init_dir { - CAM_SMMU_TABLE_INIT, - CAM_SMMU_TABLE_DEINIT, -}; - -struct scratch_mapping { - void *bitmap; - size_t bits; - unsigned int order; - dma_addr_t base; -}; - -struct cam_context_bank_info { - struct device *dev; - struct dma_iommu_mapping *mapping; - dma_addr_t va_start; - size_t va_len; - const char *name; - bool is_secure; - uint8_t scratch_buf_support; - struct scratch_mapping scratch_map; - struct list_head smmu_buf_list; - struct mutex lock; - int handle; - enum cam_smmu_ops_param state; - - void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *, - struct device *, unsigned long, - int, void*); - void *token[CAM_SMMU_CB_MAX]; - int cb_count; -}; - -struct cam_iommu_cb_set { - struct cam_context_bank_info *cb_info; - u32 cb_num; - u32 cb_init_count; - struct work_struct smmu_work; - struct mutex payload_list_lock; - struct list_head payload_list; -}; - -static struct of_device_id msm_cam_smmu_dt_match[] = { - { .compatible = "qcom,msm-cam-smmu", }, - { .compatible = "qcom,msm-cam-smmu-cb", }, - { .compatible = "qcom,qsmmu-cam-cb", }, - {} -}; - -struct cam_dma_buff_info { - struct dma_buf *buf; - struct dma_buf_attachment *attach; - struct sg_table *table; - enum dma_data_direction dir; - int iommu_dir; - int ref_count; - dma_addr_t paddr; - struct list_head list; - int ion_fd; - size_t len; - size_t phys_len; -}; - -static struct cam_iommu_cb_set iommu_cb_set; - -static enum dma_data_direction cam_smmu_translate_dir( - enum cam_smmu_map_dir dir); - -static int cam_smmu_check_handle_unique(int hdl); - -static int cam_smmu_create_iommu_handle(int idx); - -static int cam_smmu_create_add_handle_in_table(char *name, - int *hdl); - -static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, - int ion_fd); - -static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, - dma_addr_t base, size_t size, - int order); - -static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping, - size_t size, - dma_addr_t *iova); - -static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping, - dma_addr_t addr, size_t size); - -static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, - dma_addr_t virt_addr); - -static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, - enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, - size_t *len_ptr); - -static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx, - size_t virt_len, - size_t phys_len, - unsigned int iommu_dir, - dma_addr_t *virt_addr); -static int cam_smmu_unmap_buf_and_remove_from_list( - struct cam_dma_buff_info *mapping_info, int idx); - -static int cam_smmu_free_scratch_buffer_remove_from_list( - struct cam_dma_buff_info *mapping_info, - int idx); - -static void cam_smmu_clean_buffer_list(int idx); - -static void cam_smmu_print_list(int idx); - -static void cam_smmu_print_table(void); - -static int cam_smmu_probe(struct platform_device *pdev); - -static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr); - -static void cam_smmu_page_fault_work(struct work_struct *work) -{ - int j; - int idx; - struct cam_smmu_work_payload *payload; - - mutex_lock(&iommu_cb_set.payload_list_lock); - payload = list_first_entry(&iommu_cb_set.payload_list, - struct cam_smmu_work_payload, - list); - list_del(&payload->list); - mutex_unlock(&iommu_cb_set.payload_list_lock); - - /* Dereference the payload to call the handler */ - idx = payload->idx; - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - cam_smmu_check_vaddr_in_range(idx, (void *)payload->iova); - for (j = 0; j < CAM_SMMU_CB_MAX; j++) { - if ((iommu_cb_set.cb_info[idx].handler[j])) { - iommu_cb_set.cb_info[idx].handler[j]( - payload->domain, - payload->dev, - payload->iova, - payload->flags, - iommu_cb_set.cb_info[idx].token[j]); - } - } - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - kfree(payload); -} - -static void cam_smmu_print_list(int idx) -{ - struct cam_dma_buff_info *mapping; - - pr_err("index = %d ", idx); - list_for_each_entry(mapping, - &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { - pr_err("ion_fd = %d, paddr= 0x%pK, len = %u\n", - mapping->ion_fd, (void *)mapping->paddr, - (unsigned int)mapping->len); - } -} - -static void cam_smmu_print_table(void) -{ - int i; - - for (i = 0; i < iommu_cb_set.cb_num; i++) { - pr_err("i= %d, handle= %d, name_addr=%pK\n", i, - (int)iommu_cb_set.cb_info[i].handle, - (void *)iommu_cb_set.cb_info[i].name); - pr_err("dev = %pK ", iommu_cb_set.cb_info[i].dev); - } -} - - -int cam_smmu_query_vaddr_in_range(int handle, - unsigned long fault_addr, unsigned long *start_addr, - unsigned long *end_addr, int *fd) -{ - int idx, rc = -EINVAL; - struct cam_dma_buff_info *mapping; - unsigned long sa, ea; - - if (!start_addr || !end_addr || !fd) { - pr_err("Invalid params\n"); - return -EINVAL; - } - - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return -EINVAL; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return -EINVAL; - } - - list_for_each_entry(mapping, - &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { - sa = (unsigned long)mapping->paddr; - ea = (unsigned long)mapping->paddr + mapping->len; - - if (sa <= fault_addr && fault_addr < ea) { - *start_addr = sa; - *end_addr = ea; - *fd = mapping->ion_fd; - rc = 0; - break; - } - } - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return rc; -} -EXPORT_SYMBOL(cam_smmu_query_vaddr_in_range); - -static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr) -{ - struct cam_dma_buff_info *mapping; - unsigned long start_addr, end_addr, current_addr; - - current_addr = (unsigned long)vaddr; - list_for_each_entry(mapping, - &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { - start_addr = (unsigned long)mapping->paddr; - end_addr = (unsigned long)mapping->paddr + mapping->len; - - if (start_addr <= current_addr && current_addr < end_addr) { - pr_err("Error: va %pK is valid: range:%pK-%pK, fd = %d cb: %s\n", - vaddr, (void *)start_addr, (void *)end_addr, - mapping->ion_fd, - iommu_cb_set.cb_info[idx].name); - return; - } - CDBG("va %pK is not in this range: %pK-%pK, fd = %d\n", - vaddr, (void *)start_addr, (void *)end_addr, - mapping->ion_fd); - } - pr_err("Cannot find vaddr:%pK in SMMU. %s uses invalid virtual address\n", - vaddr, iommu_cb_set.cb_info[idx].name); -} - -void cam_smmu_reg_client_page_fault_handler(int handle, - void (*client_page_fault_handler)(struct iommu_domain *, - struct device *, unsigned long, - int, void*), void *token) -{ - int idx, i = 0; - - if (!token) { - pr_err("Error: token is NULL\n"); - return; - } - - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return; - } - - if (client_page_fault_handler) { - if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) { - pr_err("%s Should not regiester more handlers\n", - iommu_cb_set.cb_info[idx].name); - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return; - } - iommu_cb_set.cb_info[idx].cb_count++; - for (i = 0; i < iommu_cb_set.cb_info[idx].cb_count; i++) { - if (iommu_cb_set.cb_info[idx].token[i] == NULL) { - iommu_cb_set.cb_info[idx].token[i] = token; - iommu_cb_set.cb_info[idx].handler[i] = - client_page_fault_handler; - break; - } - } - } else { - for (i = 0; i < CAM_SMMU_CB_MAX; i++) { - if (iommu_cb_set.cb_info[idx].token[i] == token) { - iommu_cb_set.cb_info[idx].token[i] = NULL; - iommu_cb_set.cb_info[idx].handler[i] = - NULL; - iommu_cb_set.cb_info[idx].cb_count--; - break; - } - } - if (i == CAM_SMMU_CB_MAX) - pr_err("Error: hdl %x no matching tokens: %s\n", - handle, iommu_cb_set.cb_info[idx].name); - } - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); -} - -static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, - struct device *dev, unsigned long iova, - int flags, void *token) -{ - char *cb_name; - int idx; - struct cam_smmu_work_payload *payload; - - if (!token) { - pr_err("Error: token is NULL\n"); - pr_err("Error: domain = %pK, device = %pK\n", domain, dev); - pr_err("iova = %lX, flags = %d\n", iova, flags); - return 0; - } - - cb_name = (char *)token; - /* check wether it is in the table */ - for (idx = 0; idx < iommu_cb_set.cb_num; idx++) { - if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name)) - break; - } - - if (idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: index is not valid, index = %d, token = %s\n", - idx, cb_name); - return 0; - } - - payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC); - if (!payload) - return 0; - - payload->domain = domain; - payload->dev = dev; - payload->iova = iova; - payload->flags = flags; - payload->token = token; - payload->idx = idx; - - mutex_lock(&iommu_cb_set.payload_list_lock); - list_add_tail(&payload->list, &iommu_cb_set.payload_list); - mutex_unlock(&iommu_cb_set.payload_list_lock); - - schedule_work(&iommu_cb_set.smmu_work); - - return 0; -} - -static int cam_smmu_translate_dir_to_iommu_dir( - enum cam_smmu_map_dir dir) -{ - switch (dir) { - case CAM_SMMU_MAP_READ: - return IOMMU_READ; - case CAM_SMMU_MAP_WRITE: - return IOMMU_WRITE; - case CAM_SMMU_MAP_RW: - return IOMMU_READ|IOMMU_WRITE; - case CAM_SMMU_MAP_INVALID: - default: - pr_err("Error: Direction is invalid. dir = %d\n", dir); - break; - }; - return IOMMU_INVALID_DIR; -} - -static enum dma_data_direction cam_smmu_translate_dir( - enum cam_smmu_map_dir dir) -{ - switch (dir) { - case CAM_SMMU_MAP_READ: - return DMA_FROM_DEVICE; - case CAM_SMMU_MAP_WRITE: - return DMA_TO_DEVICE; - case CAM_SMMU_MAP_RW: - return DMA_BIDIRECTIONAL; - case CAM_SMMU_MAP_INVALID: - default: - pr_err("Error: Direction is invalid. dir = %d\n", (int)dir); - break; - } - return DMA_NONE; -} - -void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops) -{ - unsigned int i; - int j = 0; - - for (i = 0; i < iommu_cb_set.cb_num; i++) { - iommu_cb_set.cb_info[i].handle = HANDLE_INIT; - INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_list); - iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH; - iommu_cb_set.cb_info[i].dev = NULL; - iommu_cb_set.cb_info[i].cb_count = 0; - for (j = 0; j < CAM_SMMU_CB_MAX; j++) { - iommu_cb_set.cb_info[i].token[j] = NULL; - iommu_cb_set.cb_info[i].handler[j] = NULL; - } - if (ops == CAM_SMMU_TABLE_INIT) - mutex_init(&iommu_cb_set.cb_info[i].lock); - else - mutex_destroy(&iommu_cb_set.cb_info[i].lock); - } -} - -static int cam_smmu_check_handle_unique(int hdl) -{ - int i; - - if (hdl == HANDLE_INIT) { - CDBG("iommu handle is init number. Need to try again\n"); - return 1; - } - - for (i = 0; i < iommu_cb_set.cb_num; i++) { - if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT) - continue; - - if (iommu_cb_set.cb_info[i].handle == hdl) { - CDBG("iommu handle %d conflicts\n", (int)hdl); - return 1; - } - } - return 0; -} - -/** - * use low 2 bytes for handle cookie - */ -static int cam_smmu_create_iommu_handle(int idx) -{ - int rand, hdl = 0; - - get_random_bytes(&rand, COOKIE_NUM_BYTE); - hdl = GET_SMMU_HDL(idx, rand); - CDBG("create handle value = %x\n", (int)hdl); - return hdl; -} - -static int cam_smmu_attach_device(int idx) -{ - int rc; - struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; - - /* attach the mapping to device */ - rc = arm_iommu_attach_device(cb->dev, cb->mapping); - if (rc < 0) { - pr_err("Error: ARM IOMMU attach failed. ret = %d\n", rc); - return -ENODEV; - } - return rc; -} - -static int cam_smmu_create_add_handle_in_table(char *name, - int *hdl) -{ - int i; - int handle; - - /* create handle and add in the iommu hardware table */ - for (i = 0; i < iommu_cb_set.cb_num; i++) { - if (!strcmp(iommu_cb_set.cb_info[i].name, name)) { - mutex_lock(&iommu_cb_set.cb_info[i].lock); - if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) { - pr_err("Error: %s already got handle 0x%x\n", - name, - iommu_cb_set.cb_info[i].handle); - mutex_unlock(&iommu_cb_set.cb_info[i].lock); - return -EINVAL; - } - - /* make sure handle is unique */ - do { - handle = cam_smmu_create_iommu_handle(i); - } while (cam_smmu_check_handle_unique(handle)); - - /* put handle in the table */ - iommu_cb_set.cb_info[i].handle = handle; - iommu_cb_set.cb_info[i].cb_count = 0; - *hdl = handle; - CDBG("%s creates handle 0x%x\n", name, handle); - mutex_unlock(&iommu_cb_set.cb_info[i].lock); - return 0; - } - } - - /* if i == iommu_cb_set.cb_num */ - pr_err("Error: Cannot find name %s or all handle exist!\n", - name); - cam_smmu_print_table(); - return -EINVAL; -} - -static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, - dma_addr_t base, size_t size, - int order) -{ - unsigned int count = size >> (PAGE_SHIFT + order); - unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long); - int err = 0; - - if (!count) { - err = -EINVAL; - pr_err("Error: wrong size passed, page count can't be zero"); - goto bail; - } - - scratch_map->bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!scratch_map->bitmap) { - err = -ENOMEM; - goto bail; - } - - scratch_map->base = base; - scratch_map->bits = BITS_PER_BYTE * bitmap_size; - scratch_map->order = order; - -bail: - return err; -} - -static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping, - size_t size, - dma_addr_t *iova) -{ - int rc = 0; - unsigned int order = get_order(size); - unsigned int align = 0; - unsigned int count, start; - - count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) + - (1 << mapping->order) - 1) >> mapping->order; - - /* Transparently, add a guard page to the total count of pages - * to be allocated */ - count++; - - if (order > mapping->order) - align = (1 << (order - mapping->order)) - 1; - - start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0, - count, align); - - if (start > mapping->bits) - rc = -ENOMEM; - - bitmap_set(mapping->bitmap, start, count); - - *iova = mapping->base + (start << (mapping->order + PAGE_SHIFT)); - return rc; -} - -static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping, - dma_addr_t addr, size_t size) -{ - unsigned int start = (addr - mapping->base) >> - (mapping->order + PAGE_SHIFT); - unsigned int count = ((size >> PAGE_SHIFT) + - (1 << mapping->order) - 1) >> mapping->order; - - if (!addr) { - pr_err("Error: Invalid address\n"); - return -EINVAL; - } - - if (start + count > mapping->bits) { - pr_err("Error: Invalid page bits in scratch map\n"); - return -EINVAL; - } - - /* Transparently, add a guard page to the total count of pages - * to be freed */ - count++; - - bitmap_clear(mapping->bitmap, start, count); - - return 0; -} - -static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, - dma_addr_t virt_addr) -{ - struct cam_dma_buff_info *mapping; - - list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, - list) { - if (mapping->paddr == virt_addr) { - CDBG("Found virtual address %lx\n", - (unsigned long)virt_addr); - return mapping; - } - } - - pr_err("Error: Cannot find virtual address %lx by index %d\n", - (unsigned long)virt_addr, idx); - return NULL; -} - -static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, - int ion_fd) -{ - struct cam_dma_buff_info *mapping; - - list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, - list) { - if (mapping->ion_fd == ion_fd) { - CDBG(" find ion_fd %d\n", ion_fd); - return mapping; - } - } - - pr_err("Error: Cannot find fd %d by index %d\n", - ion_fd, idx); - return NULL; -} - -static void cam_smmu_clean_buffer_list(int idx) -{ - int ret; - struct cam_dma_buff_info *mapping_info, *temp; - - list_for_each_entry_safe(mapping_info, temp, - &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { - CDBG("Free mapping address %pK, i = %d, fd = %d\n", - (void *)mapping_info->paddr, idx, - mapping_info->ion_fd); - - if (mapping_info->ion_fd == 0xDEADBEEF) - /* Clean up scratch buffers */ - ret = cam_smmu_free_scratch_buffer_remove_from_list( - mapping_info, idx); - else - /* Clean up regular mapped buffers */ - ret = cam_smmu_unmap_buf_and_remove_from_list( - mapping_info, - idx); - - if (ret < 0) { - pr_err("Buffer delete failed: idx = %d\n", idx); - pr_err("Buffer delete failed: addr = %lx, fd = %d\n", - (unsigned long)mapping_info->paddr, - mapping_info->ion_fd); - /* - * Ignore this error and continue to delete other - * buffers in the list - */ - continue; - } - } -} - -static int cam_smmu_attach(int idx) -{ - int ret; - - if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) { - ret = 0; - } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) { - ret = cam_smmu_attach_device(idx); - if (ret < 0) { - pr_err("Error: ATTACH fail\n"); - return -ENODEV; - } - iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH; - ret = 0; - } else { - pr_err("Error: Not detach/attach\n"); - ret = -EINVAL; - } - return ret; -} - -static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, - enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, - size_t *len_ptr) -{ - int rc = -1; - struct cam_dma_buff_info *mapping_info; - struct dma_buf *buf = NULL; - struct dma_buf_attachment *attach = NULL; - struct sg_table *table = NULL; - - if (!paddr_ptr) { - pr_err("Error: Input pointer invalid\n"); - rc = -EINVAL; - goto err_out; - } - - mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); - if (!mapping_info) { - rc = -ENOSPC; - goto err_out; - } - - /* allocate memory for each buffer information */ - buf = dma_buf_get(ion_fd); - if (IS_ERR_OR_NULL(buf)) { - rc = PTR_ERR(buf); - pr_err("Error: dma get buf failed. fd = %d\n", ion_fd); - goto err_alloc; - } - - attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev); - if (IS_ERR_OR_NULL(attach)) { - rc = PTR_ERR(attach); - pr_err("Error: dma buf attach failed\n"); - goto err_put; - } - - table = dma_buf_map_attachment(attach, dma_dir); - if (IS_ERR_OR_NULL(table)) { - rc = PTR_ERR(table); - pr_err("Error: dma buf map attachment failed\n"); - goto err_detach; - } - - rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, table->sgl, - table->nents, dma_dir, buf); - if (rc != table->nents) { - pr_err("Error: msm_dma_map_sg_lazy failed\n"); - rc = -ENOMEM; - goto err_unmap_sg; - } - - if (table->sgl) { - CDBG("DMA buf: %pK, device: %pK, attach: %pK, table: %pK\n", - (void *)buf, - (void *)iommu_cb_set.cb_info[idx].dev, - (void *)attach, (void *)table); - CDBG("table sgl: %pK, rc: %d, dma_address: 0x%x\n", - (void *)table->sgl, rc, - (unsigned int)table->sgl->dma_address); - } else { - rc = -EINVAL; - pr_err("Error: table sgl is null\n"); - goto err_unmap_sg; - } - - /* fill up mapping_info */ - mapping_info->ion_fd = ion_fd; - mapping_info->buf = buf; - mapping_info->attach = attach; - mapping_info->table = table; - mapping_info->paddr = sg_dma_address(table->sgl); - mapping_info->len = (size_t)sg_dma_len(table->sgl); - mapping_info->dir = dma_dir; - mapping_info->ref_count = 1; - - /* return paddr and len to client */ - *paddr_ptr = sg_dma_address(table->sgl); - *len_ptr = (size_t)sg_dma_len(table->sgl); - - if (!*paddr_ptr || !*len_ptr) { - pr_err("Error: Space Allocation failed!\n"); - rc = -ENOSPC; - goto err_unmap_sg; - } - CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd, - (void *)iommu_cb_set.cb_info[idx].dev, - (void *)*paddr_ptr, (unsigned int)*len_ptr); - - /* add to the list */ - list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); - return 0; - -err_unmap_sg: - dma_buf_unmap_attachment(attach, table, dma_dir); -err_detach: - dma_buf_detach(buf, attach); -err_put: - dma_buf_put(buf); -err_alloc: - kfree(mapping_info); -err_out: - return rc; -} - -static int cam_smmu_unmap_buf_and_remove_from_list( - struct cam_dma_buff_info *mapping_info, - int idx) -{ - if ((!mapping_info->buf) || (!mapping_info->table) || - (!mapping_info->attach)) { - pr_err("Error: Invalid params dev = %pK, table = %pK", - (void *)iommu_cb_set.cb_info[idx].dev, - (void *)mapping_info->table); - pr_err("Error:dma_buf = %pK, attach = %pK\n", - (void *)mapping_info->buf, - (void *)mapping_info->attach); - return -EINVAL; - } - - /* iommu buffer clean up */ - msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, - mapping_info->table->sgl, mapping_info->table->nents, - mapping_info->dir, mapping_info->buf); - dma_buf_unmap_attachment(mapping_info->attach, - mapping_info->table, mapping_info->dir); - dma_buf_detach(mapping_info->buf, mapping_info->attach); - dma_buf_put(mapping_info->buf); - mapping_info->buf = NULL; - - list_del_init(&mapping_info->list); - - /* free one buffer */ - kfree(mapping_info); - return 0; -} - -static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx, - int ion_fd, dma_addr_t *paddr_ptr, - size_t *len_ptr) -{ - struct cam_dma_buff_info *mapping; - - list_for_each_entry(mapping, - &iommu_cb_set.cb_info[idx].smmu_buf_list, - list) { - if (mapping->ion_fd == ion_fd) { - mapping->ref_count++; - *paddr_ptr = mapping->paddr; - *len_ptr = mapping->len; - return CAM_SMMU_BUFF_EXIST; - } - } - return CAM_SMMU_BUFF_NOT_EXIST; -} - -int cam_smmu_get_handle(char *identifier, int *handle_ptr) -{ - int ret = 0; - - if (!identifier) { - pr_err("Error: iommu hardware name is NULL\n"); - return -EFAULT; - } - - if (!handle_ptr) { - pr_err("Error: handle pointer is NULL\n"); - return -EFAULT; - } - - /* create and put handle in the table */ - ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr); - if (ret < 0) { - pr_err("Error: %s get handle fail\n", identifier); - return ret; - } - return ret; -} -EXPORT_SYMBOL(cam_smmu_get_handle); - -int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops) -{ - int ret = 0, idx; - - CDBG("E: ops = %d\n", ops); - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return -EINVAL; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return -EINVAL; - } - - switch (ops) { - case CAM_SMMU_ATTACH: { - ret = cam_smmu_attach(idx); - break; - } - case CAM_SMMU_DETACH: { - ret = 0; - break; - } - case CAM_SMMU_VOTE: - case CAM_SMMU_DEVOTE: - default: - pr_err("Error: idx = %d, ops = %d\n", idx, ops); - ret = -EINVAL; - } - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return ret; -} -EXPORT_SYMBOL(cam_smmu_ops); - -static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx, - size_t virt_len, - size_t phys_len, - unsigned int iommu_dir, - dma_addr_t *virt_addr) -{ - unsigned long nents = virt_len / phys_len; - struct cam_dma_buff_info *mapping_info = NULL; - size_t unmapped; - dma_addr_t iova = 0; - struct scatterlist *sg; - int i = 0; - int rc; - struct iommu_domain *domain = NULL; - struct page *page; - struct sg_table *table = NULL; - - CDBG("%s: nents = %lu, idx = %d, virt_len = %zx\n", - __func__, nents, idx, virt_len); - CDBG("%s: phys_len = %zx, iommu_dir = %d, virt_addr = %pK\n", - __func__, phys_len, iommu_dir, virt_addr); - - /* This table will go inside the 'mapping' structure - * where it will be held until put_scratch_buffer is called - */ - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); - if (!table) { - rc = -ENOMEM; - goto err_table_alloc; - } - - rc = sg_alloc_table(table, nents, GFP_KERNEL); - if (rc < 0) { - rc = -EINVAL; - goto err_sg_alloc; - } - - page = alloc_pages(GFP_KERNEL, get_order(phys_len)); - if (!page) { - rc = -ENOMEM; - goto err_page_alloc; - } - - /* Now we create the sg list */ - for_each_sg(table->sgl, sg, table->nents, i) - sg_set_page(sg, page, phys_len, 0); - - - /* Get the domain from within our cb_set struct and map it*/ - domain = iommu_cb_set.cb_info[idx].mapping->domain; - - rc = cam_smmu_alloc_scratch_va(&iommu_cb_set.cb_info[idx].scratch_map, - virt_len, &iova); - - if (rc < 0) { - pr_err("Could not find valid iova for scratch buffer"); - goto err_iommu_map; - } - - if (iommu_map_sg(domain, - iova, - table->sgl, - table->nents, - iommu_dir) != virt_len) { - pr_err("iommu_map_sg() failed"); - goto err_iommu_map; - } - - /* Now update our mapping information within the cb_set struct */ - mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); - if (!mapping_info) { - rc = -ENOMEM; - goto err_mapping_info; - } - - mapping_info->ion_fd = 0xDEADBEEF; - mapping_info->buf = NULL; - mapping_info->attach = NULL; - mapping_info->table = table; - mapping_info->paddr = iova; - mapping_info->len = virt_len; - mapping_info->iommu_dir = iommu_dir; - mapping_info->ref_count = 1; - mapping_info->phys_len = phys_len; - - CDBG("%s: paddr = %pK, len = %zx, phys_len = %zx", - __func__, (void *)mapping_info->paddr, - mapping_info->len, mapping_info->phys_len); - - list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); - - *virt_addr = (dma_addr_t)iova; - - CDBG("%s: mapped virtual address = %lx\n", __func__, - (unsigned long)*virt_addr); - return 0; - -err_mapping_info: - unmapped = iommu_unmap(domain, iova, virt_len); - if (unmapped != virt_len) - pr_err("Unmapped only %zx instead of %zx", unmapped, virt_len); -err_iommu_map: - __free_pages(sg_page(table->sgl), get_order(phys_len)); -err_page_alloc: - sg_free_table(table); -err_sg_alloc: - kfree(table); -err_table_alloc: - return rc; -} - -static int cam_smmu_free_scratch_buffer_remove_from_list( - struct cam_dma_buff_info *mapping_info, - int idx) -{ - int rc = 0; - size_t unmapped; - struct iommu_domain *domain = - iommu_cb_set.cb_info[idx].mapping->domain; - struct scratch_mapping *scratch_map = - &iommu_cb_set.cb_info[idx].scratch_map; - - if (!mapping_info->table) { - pr_err("Error: Invalid params: dev = %pK, table = %pK, ", - (void *)iommu_cb_set.cb_info[idx].dev, - (void *)mapping_info->table); - return -EINVAL; - } - - /* Clean up the mapping_info struct from the list */ - unmapped = iommu_unmap(domain, mapping_info->paddr, mapping_info->len); - if (unmapped != mapping_info->len) - pr_err("Unmapped only %zx instead of %zx", - unmapped, mapping_info->len); - - rc = cam_smmu_free_scratch_va(scratch_map, - mapping_info->paddr, - mapping_info->len); - if (rc < 0) { - pr_err("Error: Invalid iova while freeing scratch buffer\n"); - rc = -EINVAL; - } - - __free_pages(sg_page(mapping_info->table->sgl), - get_order(mapping_info->phys_len)); - sg_free_table(mapping_info->table); - kfree(mapping_info->table); - list_del_init(&mapping_info->list); - - kfree(mapping_info); - mapping_info = NULL; - - return rc; -} - -int cam_smmu_get_phy_addr_scratch(int handle, - enum cam_smmu_map_dir dir, - dma_addr_t *paddr_ptr, - size_t virt_len, - size_t phys_len) -{ - int idx, rc; - unsigned int iommu_dir; - - if (!paddr_ptr || !virt_len || !phys_len) { - pr_err("Error: Input pointer or lengths invalid\n"); - return -EINVAL; - } - - if (virt_len < phys_len) { - pr_err("Error: virt_len > phys_len"); - return -EINVAL; - } - - iommu_dir = cam_smmu_translate_dir_to_iommu_dir(dir); - if (iommu_dir == IOMMU_INVALID_DIR) { - pr_err("Error: translate direction failed. dir = %d\n", dir); - return -EINVAL; - } - - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return -EINVAL; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - rc = -EINVAL; - goto error; - } - - if (!iommu_cb_set.cb_info[idx].scratch_buf_support) { - pr_err("Error: Context bank does not support scratch bufs\n"); - rc = -EINVAL; - goto error; - } - - CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n", - __func__, handle, idx, dir); - CDBG("%s: virt_len = %zx, phys_len = %zx\n", - __func__, phys_len, virt_len); - - if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { - pr_err("Error: Device %s should call SMMU attach before map buffer\n", - iommu_cb_set.cb_info[idx].name); - rc = -EINVAL; - goto error; - } - - if (!IS_ALIGNED(virt_len, PAGE_SIZE)) { - pr_err("Requested scratch buffer length not page aligned"); - rc = -EINVAL; - goto error; - } - - if (!IS_ALIGNED(virt_len, phys_len)) { - pr_err("Requested virtual length not aligned with physical length"); - rc = -EINVAL; - goto error; - } - - rc = cam_smmu_alloc_scratch_buffer_add_to_list(idx, - virt_len, - phys_len, - iommu_dir, - paddr_ptr); - if (rc < 0) { - pr_err("Error: mapping or add list fail\n"); - goto error; - } - -error: - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return rc; -} - -int cam_smmu_put_phy_addr_scratch(int handle, - dma_addr_t paddr) -{ - int idx; - int rc = -1; - struct cam_dma_buff_info *mapping_info; - - /* find index in the iommu_cb_set.cb_info */ - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return -EINVAL; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - rc = -EINVAL; - goto handle_err; - } - - if (!iommu_cb_set.cb_info[idx].scratch_buf_support) { - pr_err("Error: Context bank does not support scratch buffers"); - rc = -EINVAL; - goto handle_err; - } - - /* Based on virtual address and index, we can find mapping info - * of the scratch buffer - */ - mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr); - if (!mapping_info) { - pr_err("Error: Invalid params\n"); - rc = -EINVAL; - goto handle_err; - } - - /* unmapping one buffer from device */ - rc = cam_smmu_free_scratch_buffer_remove_from_list(mapping_info, idx); - if (rc < 0) { - pr_err("Error: unmap or remove list fail\n"); - goto handle_err; - } - -handle_err: - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return rc; -} - -int cam_smmu_get_phy_addr(int handle, int ion_fd, - enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, - size_t *len_ptr) -{ - int idx, rc; - enum dma_data_direction dma_dir; - enum cam_smmu_buf_state buf_state; - - if (!paddr_ptr || !len_ptr) { - pr_err("Error: Input pointers are invalid\n"); - return -EINVAL; - } - /* clean the content from clients */ - *paddr_ptr = (dma_addr_t)NULL; - *len_ptr = (size_t)0; - - dma_dir = cam_smmu_translate_dir(dir); - if (dma_dir == DMA_NONE) { - pr_err("Error: translate direction failed. dir = %d\n", dir); - return -EINVAL; - } - - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return -EINVAL; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - rc = -EINVAL; - goto get_addr_end; - } - - if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { - pr_err("Error: Device %s should call SMMU attach before map buffer\n", - iommu_cb_set.cb_info[idx].name); - rc = -EINVAL; - goto get_addr_end; - } - - buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); - if (buf_state == CAM_SMMU_BUFF_EXIST) { - CDBG("ion_fd:%d already in the list, give same addr back", - ion_fd); - rc = 0; - goto get_addr_end; - } - rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir, - paddr_ptr, len_ptr); - if (rc < 0) { - pr_err("Error: mapping or add list fail\n"); - goto get_addr_end; - } - -get_addr_end: - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return rc; -} -EXPORT_SYMBOL(cam_smmu_get_phy_addr); - -int cam_smmu_put_phy_addr(int handle, int ion_fd) -{ - int idx, rc; - struct cam_dma_buff_info *mapping_info; - - /* find index in the iommu_cb_set.cb_info */ - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return -EINVAL; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - rc = -EINVAL; - goto put_addr_end; - } - - /* based on ion fd and index, we can find mapping info of buffer */ - mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd); - if (!mapping_info) { - pr_err("Error: Invalid params! idx = %d, fd = %d\n", - idx, ion_fd); - rc = -EINVAL; - goto put_addr_end; - } - - mapping_info->ref_count--; - if (mapping_info->ref_count > 0) { - CDBG("There are still %u buffer(s) with same fd %d", - mapping_info->ref_count, mapping_info->ion_fd); - rc = 0; - goto put_addr_end; - } - - /* unmapping one buffer from device */ - rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx); - if (rc < 0) { - pr_err("Error: unmap or remove list fail\n"); - goto put_addr_end; - } - -put_addr_end: - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return rc; -} -EXPORT_SYMBOL(cam_smmu_put_phy_addr); - -int cam_smmu_destroy_handle(int handle) -{ - int idx; - - idx = GET_SMMU_TABLE_IDX(handle); - if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) { - pr_err("Error: handle or index invalid. idx = %d hdl = %x\n", - idx, handle); - return -EINVAL; - } - - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - if (iommu_cb_set.cb_info[idx].handle != handle) { - pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n", - iommu_cb_set.cb_info[idx].handle, handle); - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return -EINVAL; - } - - if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) { - pr_err("Client %s buffer list is not clean!\n", - iommu_cb_set.cb_info[idx].name); - cam_smmu_print_list(idx); - cam_smmu_clean_buffer_list(idx); - } - - iommu_cb_set.cb_info[idx].cb_count = 0; - iommu_cb_set.cb_info[idx].handle = HANDLE_INIT; - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); - return 0; -} -EXPORT_SYMBOL(cam_smmu_destroy_handle); - -/*This function can only be called after smmu driver probe*/ -int cam_smmu_get_num_of_clients(void) -{ - return iommu_cb_set.cb_num; -} - -static void cam_smmu_release_cb(struct platform_device *pdev) -{ - int i = 0; - - for (i = 0; i < iommu_cb_set.cb_num; i++) { - arm_iommu_detach_device(iommu_cb_set.cb_info[i].dev); - arm_iommu_release_mapping(iommu_cb_set.cb_info[i].mapping); - } - - devm_kfree(&pdev->dev, iommu_cb_set.cb_info); - iommu_cb_set.cb_num = 0; -} - -static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, - struct device *dev) -{ - int rc = 0; - int disable_htw = 1; - - if (!cb || !dev) { - pr_err("Error: invalid input params\n"); - return -EINVAL; - } - - cb->dev = dev; - /* Reserve 256M if scratch buffer support is desired - * and initialize the scratch mapping structure - */ - if (cb->scratch_buf_support) { - cb->va_start = SCRATCH_ALLOC_END; - cb->va_len = VA_SPACE_END - SCRATCH_ALLOC_END; - - rc = cam_smmu_init_scratch_map(&cb->scratch_map, - SCRATCH_ALLOC_START, - SCRATCH_ALLOC_END - SCRATCH_ALLOC_START, - 0); - if (rc < 0) { - pr_err("Error: failed to create scratch map\n"); - rc = -ENODEV; - goto end; - } - } else { - cb->va_start = SZ_128K; - cb->va_len = VA_SPACE_END - SZ_128K; - } - - /* create a virtual mapping */ - cb->mapping = arm_iommu_create_mapping(msm_iommu_get_bus(dev), - cb->va_start, cb->va_len); - if (IS_ERR(cb->mapping)) { - pr_err("Error: create mapping Failed\n"); - rc = -ENODEV; - goto end; - } - - /* - * Set the domain attributes - * disable L2 redirect since it decreases - * performance - */ - if (iommu_domain_set_attr(cb->mapping->domain, - DOMAIN_ATTR_COHERENT_HTW_DISABLE, - &disable_htw)) { - pr_err("Error: couldn't disable coherent HTW\n"); - rc = -ENODEV; - goto err_set_attr; - } - return 0; -err_set_attr: - arm_iommu_release_mapping(cb->mapping); -end: - return rc; -} - -static int cam_alloc_smmu_context_banks(struct device *dev) -{ - struct device_node *domains_child_node = NULL; - - if (!dev) { - pr_err("Error: Invalid device\n"); - return -ENODEV; - } - - iommu_cb_set.cb_num = 0; - - /* traverse thru all the child nodes and increment the cb count */ - for_each_child_of_node(dev->of_node, domains_child_node) { - if (of_device_is_compatible(domains_child_node, - "qcom,msm-cam-smmu-cb")) - iommu_cb_set.cb_num++; - - if (of_device_is_compatible(domains_child_node, - "qcom,qsmmu-cam-cb")) - iommu_cb_set.cb_num++; - } - - if (iommu_cb_set.cb_num == 0) { - pr_err("Error: no context banks present\n"); - return -ENOENT; - } - - /* allocate memory for the context banks */ - iommu_cb_set.cb_info = devm_kzalloc(dev, - iommu_cb_set.cb_num * sizeof(struct cam_context_bank_info), - GFP_KERNEL); - - if (!iommu_cb_set.cb_info) { - pr_err("Error: cannot allocate context banks\n"); - return -ENOMEM; - } - - cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_INIT); - iommu_cb_set.cb_init_count = 0; - - CDBG("no of context banks :%d\n", iommu_cb_set.cb_num); - return 0; -} - -static int cam_populate_smmu_context_banks(struct device *dev, - enum cam_iommu_type type) -{ - int rc = 0; - struct cam_context_bank_info *cb; - struct device *ctx; - - if (!dev) { - pr_err("Error: Invalid device\n"); - return -ENODEV; - } - - /* check the bounds */ - if (iommu_cb_set.cb_init_count >= iommu_cb_set.cb_num) { - pr_err("Error: populate more than allocated cb\n"); - rc = -EBADHANDLE; - goto cb_init_fail; - } - - /* read the context bank from cb set */ - cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count]; - - /* set the name of the context bank */ - rc = of_property_read_string(dev->of_node, "label", &cb->name); - if (rc) { - pr_err("Error: failed to read label from sub device\n"); - goto cb_init_fail; - } - - /* Check if context bank supports scratch buffers */ - if (of_property_read_bool(dev->of_node, "qcom,scratch-buf-support")) - cb->scratch_buf_support = 1; - else - cb->scratch_buf_support = 0; - - /* set the secure/non secure domain type */ - if (of_property_read_bool(dev->of_node, "qcom,secure-context")) - cb->is_secure = CAM_SECURE; - else - cb->is_secure = CAM_NON_SECURE; - - CDBG("cb->name :%s, cb->is_secure :%d, cb->scratch_support :%d\n", - cb->name, cb->is_secure, cb->scratch_buf_support); - - /* set up the iommu mapping for the context bank */ - if (type == CAM_QSMMU) { - ctx = msm_iommu_get_ctx(cb->name); - if (IS_ERR_OR_NULL(ctx)) { - rc = PTR_ERR(ctx); - pr_err("Invalid pointer of ctx : %s rc = %d\n", - cb->name, rc); - return -EINVAL; - } - CDBG("getting QSMMU ctx : %s\n", cb->name); - } else { - ctx = dev; - CDBG("getting Arm SMMU ctx : %s\n", cb->name); - } - rc = cam_smmu_setup_cb(cb, ctx); - if (rc < 0) - pr_err("Error: failed to setup cb : %s\n", cb->name); - - iommu_set_fault_handler(cb->mapping->domain, - cam_smmu_iommu_fault_handler, - (void *)cb->name); - - /* increment count to next bank */ - iommu_cb_set.cb_init_count++; - - CDBG("X: cb init count :%d\n", iommu_cb_set.cb_init_count); - return rc; - -cb_init_fail: - iommu_cb_set.cb_info = NULL; - return rc; -} - -static int cam_smmu_probe(struct platform_device *pdev) -{ - int rc = 0; - struct device *dev = &pdev->dev; - - if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) { - rc = cam_alloc_smmu_context_banks(dev); - if (rc < 0) { - pr_err("Error: allocating context banks\n"); - return -ENOMEM; - } - } - if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-cb")) { - rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU); - if (rc < 0) { - pr_err("Error: populating context banks\n"); - return -ENOMEM; - } - return rc; - } - if (of_device_is_compatible(dev->of_node, "qcom,qsmmu-cam-cb")) { - rc = cam_populate_smmu_context_banks(dev, CAM_QSMMU); - if (rc < 0) { - pr_err("Error: populating context banks\n"); - return -ENOMEM; - } - return rc; - } - - /* probe thru all the subdevices */ - rc = of_platform_populate(pdev->dev.of_node, msm_cam_smmu_dt_match, - NULL, &pdev->dev); - if (rc < 0) - pr_err("Error: populating devices\n"); - - INIT_WORK(&iommu_cb_set.smmu_work, cam_smmu_page_fault_work); - mutex_init(&iommu_cb_set.payload_list_lock); - INIT_LIST_HEAD(&iommu_cb_set.payload_list); - - return rc; -} - -static int cam_smmu_remove(struct platform_device *pdev) -{ - /* release all the context banks and memory allocated */ - cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT); - if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu")) - cam_smmu_release_cb(pdev); - return 0; -} - -static struct platform_driver cam_smmu_driver = { - .probe = cam_smmu_probe, - .remove = cam_smmu_remove, - .driver = { - .name = "msm_cam_smmu", - .owner = THIS_MODULE, - .of_match_table = msm_cam_smmu_dt_match, - }, -}; - -static int __init cam_smmu_init_module(void) -{ - return platform_driver_register(&cam_smmu_driver); -} - -static void __exit cam_smmu_exit_module(void) -{ - platform_driver_unregister(&cam_smmu_driver); -} - -module_init(cam_smmu_init_module); -module_exit(cam_smmu_exit_module); -MODULE_DESCRIPTION("MSM Camera SMMU driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/common/cam_smmu_api.h b/drivers/media/platform/msm/ais/common/cam_smmu_api.h deleted file mode 100644 index 4a13598dc71908c64406301fcc826f4bac1c74fe..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/cam_smmu_api.h +++ /dev/null @@ -1,166 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef _CAM_SMMU_API_H_ -#define _CAM_SMMU_API_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Enum for possible CAM SMMU operations - */ -enum cam_smmu_ops_param { - CAM_SMMU_ATTACH, - CAM_SMMU_DETACH, - CAM_SMMU_VOTE, - CAM_SMMU_DEVOTE, - CAM_SMMU_OPS_INVALID -}; - -enum cam_smmu_map_dir { - CAM_SMMU_MAP_READ, - CAM_SMMU_MAP_WRITE, - CAM_SMMU_MAP_RW, - CAM_SMMU_MAP_INVALID -}; - -/** - * @param identifier: Unique identifier to be used by clients which they - * should get from device tree. CAM SMMU driver will - * not enforce how this string is obtained and will - * only validate this against the list of permitted - * identifiers - * @param handle_ptr: Based on the indentifier, CAM SMMU drivier will - * fill the handle pointed by handle_ptr - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_smmu_get_handle(char *identifier, int *handle_ptr); - -/** - * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) - * @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH - * or CAM_SMMU_DETACH - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); - -/** - * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) - * @param ion_fd: ION handle identifying the memory buffer. - * @phys_addr : Pointer to physical address where mapped address will be - * returned. - * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, - * DMA_TO_DEVICE or DMA_FROM_DEVICE - * @len : Length of buffer mapped returned by CAM SMMU driver. - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_smmu_get_phy_addr(int handle, - int ion_fd, enum cam_smmu_map_dir dir, - dma_addr_t *dma_addr, size_t *len_ptr); - -/** - * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) - * @param ion_fd: ION handle identifying the memory buffer. - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_smmu_put_phy_addr(int handle, int ion_fd); - -/** - * @brief : Allocates a scratch buffer - * - * This function allocates a scratch virtual buffer of length virt_len in the - * device virtual address space mapped to phys_len physically contiguous bytes - * in that device's SMMU. - * - * virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each - * other, otherwise -EINVAL is returned. - * - * -EINVAL will be returned if virt_len is less than phys_len. - * - * Passing a too large phys_len might also cause failure if that much size is - * not available for allocation in a physically contiguous way. - * - * @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) - * @param dir : Direction of mapping which will translate to IOMMU_READ - * IOMMU_WRITE or a bit mask of both. - * @param paddr_ptr: Device virtual address that the client device will be - * able to read from/write to - * @param virt_len : Virtual length of the scratch buffer - * @param phys_len : Physical length of the scratch buffer - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int cam_smmu_get_phy_addr_scratch(int handle, - enum cam_smmu_map_dir dir, - dma_addr_t *paddr_ptr, - size_t virt_len, - size_t phys_len); - -/** - * @brief : Frees a scratch buffer - * - * This function frees a scratch buffer and releases the corresponding SMMU - * mappings. - * - * @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) - * IOMMU_WRITE or a bit mask of both. - * @param paddr_ptr: Device virtual address of client's scratch buffer that - * will be freed. - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int cam_smmu_put_phy_addr_scratch(int handle, - dma_addr_t paddr); - -/** - * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_smmu_destroy_handle(int handle); - -/** - * @return numger of client. Zero in case of error. - */ -int cam_smmu_get_num_of_clients(void); - -/** - * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) - * @return Index of SMMU client. Nagative in case of error. - */ -int cam_smmu_find_index_by_handle(int hdl); - -/** - * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) - * @param client_page_fault_handler: It is triggered in IOMMU page fault - * @param token: It is input param when trigger page fault handler - */ -void cam_smmu_reg_client_page_fault_handler(int handle, - void (*client_page_fault_handler)(struct iommu_domain *, - struct device *, unsigned long, - int, void*), void *token); - -#endif /* _CAM_SMMU_API_H_ */ diff --git a/drivers/media/platform/msm/ais/common/cam_soc_api.c b/drivers/media/platform/msm/ais/common/cam_soc_api.c deleted file mode 100644 index 09d470ed6eb0e851450e3127933bd5a68b0a78d6..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/cam_soc_api.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "CAM-SOC %s:%d " fmt, __func__, __LINE__ -#define NO_SET_RATE -1 -#define INIT_RATE -2 - -#ifdef CONFIG_CAM_SOC_API_DBG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -#include -#include -#include -#include -#include "cam_soc_api.h" - -struct msm_cam_bus_pscale_data { - struct msm_bus_scale_pdata *pdata; - uint32_t bus_client; - uint32_t num_usecases; - uint32_t num_paths; - unsigned int vector_index; - bool dyn_vote; - struct mutex lock; -}; - -struct msm_cam_bus_pscale_data g_cv[CAM_BUS_CLIENT_MAX]; - -/* Get all clocks from DT */ -static int msm_camera_get_clk_info_internal(struct device *dev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, - size_t *num_clk) -{ - int rc = 0; - size_t cnt, tmp; - uint32_t *rates, i = 0; - const char *clk_ctl = NULL; - bool clock_cntl_support = false; - struct device_node *of_node; - - of_node = dev->of_node; - - cnt = of_property_count_strings(of_node, "clock-names"); - if (cnt <= 0) { - pr_err("err: No clocks found in DT=%zu\n", cnt); - return -EINVAL; - } - - tmp = of_property_count_u32_elems(of_node, "qcom,clock-rates"); - if (tmp <= 0) { - pr_err("err: No clk rates device tree, count=%zu", tmp); - return -EINVAL; - } - - if (cnt != tmp) { - pr_err("err: clk name/rates mismatch, strings=%zu, rates=%zu\n", - cnt, tmp); - return -EINVAL; - } - - if (of_property_read_bool(of_node, "qcom,clock-cntl-support")) { - tmp = of_property_count_strings(of_node, - "qcom,clock-control"); - if (tmp <= 0) { - pr_err("err: control strings not found in DT count=%zu", - tmp); - return -EINVAL; - } - if (cnt != tmp) { - pr_err("err: controls mismatch, strings=%zu, ctl=%zu\n", - cnt, tmp); - return -EINVAL; - } - clock_cntl_support = true; - } - - *num_clk = cnt; - - *clk_info = devm_kcalloc(dev, cnt, - sizeof(struct msm_cam_clk_info), GFP_KERNEL); - if (!*clk_info) - return -ENOMEM; - - *clk_ptr = devm_kcalloc(dev, cnt, sizeof(struct clk *), - GFP_KERNEL); - if (!*clk_ptr) { - rc = -ENOMEM; - goto err1; - } - - rates = devm_kcalloc(dev, cnt, sizeof(long), GFP_KERNEL); - if (!rates) { - rc = -ENOMEM; - goto err2; - } - - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, cnt); - if (rc < 0) { - pr_err("err: failed reading clock rates\n"); - rc = -EINVAL; - goto err3; - } - - for (i = 0; i < cnt; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &((*clk_info)[i].clk_name)); - if (rc < 0) { - pr_err("%s reading clock-name failed index %d\n", - __func__, i); - rc = -EINVAL; - goto err3; - } - - CDBG("dbg: clk-name[%d] = %s\n", i, (*clk_info)[i].clk_name); - if (clock_cntl_support) { - rc = of_property_read_string_index(of_node, - "qcom,clock-control", i, &clk_ctl); - if (rc < 0) { - pr_err("%s reading clock-control failed index %d\n", - __func__, i); - rc = -EINVAL; - goto err3; - } - - if (!strcmp(clk_ctl, "NO_SET_RATE")) - (*clk_info)[i].clk_rate = NO_SET_RATE; - else if (!strcmp(clk_ctl, "INIT_RATE")) - (*clk_info)[i].clk_rate = INIT_RATE; - else if (!strcmp(clk_ctl, "SET_RATE")) - (*clk_info)[i].clk_rate = rates[i]; - else { - pr_err("%s: error: clock control has invalid value\n", - __func__); - rc = -EBUSY; - goto err3; - } - } else - (*clk_info)[i].clk_rate = - (rates[i] == 0) ? (long)-1 : rates[i]; - - CDBG("dbg: clk-rate[%d] = rate: %ld\n", - i, (*clk_info)[i].clk_rate); - - (*clk_ptr)[i] = - devm_clk_get(dev, (*clk_info)[i].clk_name); - if (IS_ERR((*clk_ptr)[i])) { - rc = PTR_ERR((*clk_ptr)[i]); - goto err4; - } - CDBG("clk ptr[%d] :%pK\n", i, (*clk_ptr)[i]); - } - - devm_kfree(dev, rates); - return rc; - -err4: - for (--i; i >= 0; i--) - devm_clk_put(dev, (*clk_ptr)[i]); -err3: - devm_kfree(dev, rates); -err2: - devm_kfree(dev, *clk_ptr); -err1: - devm_kfree(dev, *clk_info); - return rc; -} - -/* Get all clocks from DT for I2C devices */ -int msm_camera_i2c_dev_get_clk_info(struct device *dev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, - size_t *num_clk) -{ - int rc = 0; - - if (!dev || !clk_info || !clk_ptr || !num_clk) - return -EINVAL; - - rc = msm_camera_get_clk_info_internal(dev, clk_info, clk_ptr, num_clk); - return rc; -} -EXPORT_SYMBOL(msm_camera_i2c_dev_get_clk_info); - -/* Get all clocks from DT for platform devices */ -int msm_camera_get_clk_info(struct platform_device *pdev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, - size_t *num_clk) -{ - int rc = 0; - - if (!pdev || !&pdev->dev || !clk_info || !clk_ptr || !num_clk) - return -EINVAL; - - rc = msm_camera_get_clk_info_internal(&pdev->dev, - clk_info, clk_ptr, num_clk); - return rc; -} -EXPORT_SYMBOL(msm_camera_get_clk_info); - -/* Get all clocks and multiple rates from DT */ -int msm_camera_get_clk_info_and_rates( - struct platform_device *pdev, - struct msm_cam_clk_info **pclk_info, - struct clk ***pclks, - uint32_t ***pclk_rates, - size_t *num_set, - size_t *num_clk) -{ - int rc = 0, tmp_var, cnt, tmp; - uint32_t i = 0, j = 0; - struct device_node *of_node; - uint32_t **rates; - struct clk **clks; - struct msm_cam_clk_info *clk_info; - - if (!pdev || !pclk_info || !num_clk - || !pclk_rates || !pclks || !num_set) - return -EINVAL; - - of_node = pdev->dev.of_node; - - cnt = of_property_count_strings(of_node, "clock-names"); - if (cnt <= 0) { - pr_err("err: No clocks found in DT=%d\n", cnt); - return -EINVAL; - } - - tmp = of_property_count_u32_elems(of_node, "qcom,clock-rates"); - if (tmp <= 0) { - pr_err("err: No clk rates device tree, count=%d\n", tmp); - return -EINVAL; - } - - if ((tmp % cnt) != 0) { - pr_err("err: clk name/rates mismatch, strings=%d, rates=%d\n", - cnt, tmp); - return -EINVAL; - } - - *num_clk = cnt; - *num_set = (tmp / cnt); - - clk_info = devm_kcalloc(&pdev->dev, cnt, - sizeof(struct msm_cam_clk_info), GFP_KERNEL); - if (!clk_info) - return -ENOMEM; - - clks = devm_kcalloc(&pdev->dev, cnt, sizeof(struct clk *), - GFP_KERNEL); - if (!clks) { - rc = -ENOMEM; - goto err1; - } - - rates = devm_kcalloc(&pdev->dev, *num_set, - sizeof(uint32_t *), GFP_KERNEL); - if (!rates) { - rc = -ENOMEM; - goto err2; - } - - for (i = 0; i < *num_set; i++) { - rates[i] = devm_kcalloc(&pdev->dev, *num_clk, - sizeof(uint32_t), GFP_KERNEL); - if (!rates[i]) { - rc = -ENOMEM; - for (--i; i >= 0; i--) - devm_kfree(&pdev->dev, rates[i]); - goto err3; - } - } - - tmp_var = 0; - for (i = 0; i < *num_set; i++) { - for (j = 0; j < *num_clk; j++) { - rc = of_property_read_u32_index(of_node, - "qcom,clock-rates", tmp_var++, &rates[i][j]); - if (rc < 0) { - pr_err("err: failed reading clock rates\n"); - rc = -EINVAL; - goto err4; - } - CDBG("Clock rate idx %d idx %d value %d\n", - i, j, rates[i][j]); - } - } - for (i = 0; i < *num_clk; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s reading clock-name failed index %d\n", - __func__, i); - rc = -EINVAL; - goto err4; - } - - CDBG("dbg: clk-name[%d] = %s\n", i, clk_info[i].clk_name); - - clks[i] = - devm_clk_get(&pdev->dev, clk_info[i].clk_name); - if (IS_ERR(clks[i])) { - rc = PTR_ERR(clks[i]); - goto err5; - } - CDBG("clk ptr[%d] :%pK\n", i, clks[i]); - } - *pclk_info = clk_info; - *pclks = clks; - *pclk_rates = rates; - - return rc; - -err5: - for (--i; i >= 0; i--) - devm_clk_put(&pdev->dev, clks[i]); -err4: - for (i = 0; i < *num_set; i++) - devm_kfree(&pdev->dev, rates[i]); -err3: - devm_kfree(&pdev->dev, rates); -err2: - devm_kfree(&pdev->dev, clks); -err1: - devm_kfree(&pdev->dev, clk_info); - return rc; -} -EXPORT_SYMBOL(msm_camera_get_clk_info_and_rates); - -/* Enable/Disable all clocks */ -int msm_camera_clk_enable(struct device *dev, - struct msm_cam_clk_info *clk_info, - struct clk **clk_ptr, int num_clk, int enable) -{ - int i; - int rc = 0; - long clk_rate; - - if (enable) { - for (i = 0; i < num_clk; i++) { - CDBG("enable %s\n", clk_info[i].clk_name); - if (clk_info[i].clk_rate > 0) { - clk_rate = clk_round_rate(clk_ptr[i], - clk_info[i].clk_rate); - if (clk_rate < 0) { - pr_err("%s round failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - rc = clk_set_rate(clk_ptr[i], - clk_rate); - if (rc < 0) { - pr_err("%s set failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - - } else if (clk_info[i].clk_rate == INIT_RATE) { - clk_rate = clk_get_rate(clk_ptr[i]); - if (clk_rate == 0) { - clk_rate = - clk_round_rate(clk_ptr[i], 0); - if (clk_rate < 0) { - pr_err("%s round rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - rc = clk_set_rate(clk_ptr[i], - clk_rate); - if (rc < 0) { - pr_err("%s set rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - } - } - rc = clk_prepare_enable(clk_ptr[i]); - if (rc < 0) { - pr_err("%s enable failed\n", - clk_info[i].clk_name); - goto cam_clk_enable_err; - } - if (clk_info[i].delay > 20) { - msleep(clk_info[i].delay); - } else if (clk_info[i].delay) { - usleep_range(clk_info[i].delay * 1000, - (clk_info[i].delay * 1000) + 1000); - } - } - } else { - for (i = num_clk - 1; i >= 0; i--) { - if (clk_ptr[i] != NULL) { - CDBG("%s disable %s\n", __func__, - clk_info[i].clk_name); - clk_disable_unprepare(clk_ptr[i]); - } - } - } - return rc; - -cam_clk_enable_err: -cam_clk_set_err: - for (i--; i >= 0; i--) { - if (clk_ptr[i] != NULL) - clk_disable_unprepare(clk_ptr[i]); - } - return rc; -} -EXPORT_SYMBOL(msm_camera_clk_enable); - -/* Set rate on a specific clock */ -long msm_camera_clk_set_rate(struct device *dev, - struct clk *clk, - long clk_rate) -{ - int rc = 0; - long rate = 0; - - if (!dev || !clk || (clk_rate < 0)) - return -EINVAL; - - CDBG("clk : %pK, enable : %ld\n", clk, clk_rate); - - if (clk_rate > 0) { - rate = clk_round_rate(clk, clk_rate); - if (rate < 0) { - pr_err("round rate failed\n"); - return -EINVAL; - } - - rc = clk_set_rate(clk, rate); - if (rc < 0) { - pr_err("set rate failed\n"); - return -EINVAL; - } - } - - return rate; -} -EXPORT_SYMBOL(msm_camera_clk_set_rate); - -/* release memory allocated for clocks */ -static int msm_camera_put_clk_info_internal(struct device *dev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, int cnt) -{ - int i; - - for (i = cnt - 1; i >= 0; i--) { - if (clk_ptr[i] != NULL) - devm_clk_put(dev, (*clk_ptr)[i]); - - CDBG("clk ptr[%d] :%pK\n", i, (*clk_ptr)[i]); - } - devm_kfree(dev, *clk_info); - devm_kfree(dev, *clk_ptr); - *clk_info = NULL; - *clk_ptr = NULL; - return 0; -} - -/* release memory allocated for clocks for i2c devices */ -int msm_camera_i2c_dev_put_clk_info(struct device *dev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, int cnt) -{ - int rc = 0; - - if (!dev || !clk_info || !clk_ptr) - return -EINVAL; - - rc = msm_camera_put_clk_info_internal(dev, clk_info, clk_ptr, cnt); - return rc; -} -EXPORT_SYMBOL(msm_camera_i2c_dev_put_clk_info); - -/* release memory allocated for clocks for platform devices */ -int msm_camera_put_clk_info(struct platform_device *pdev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, int cnt) -{ - int rc = 0; - - if (!pdev || !&pdev->dev || !clk_info || !clk_ptr) - return -EINVAL; - - rc = msm_camera_put_clk_info_internal(&pdev->dev, - clk_info, clk_ptr, cnt); - return rc; -} -EXPORT_SYMBOL(msm_camera_put_clk_info); - -int msm_camera_put_clk_info_and_rates(struct platform_device *pdev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, uint32_t ***clk_rates, - size_t set, size_t cnt) -{ - int i; - - for (i = set - 1; i >= 0; i--) - devm_kfree(&pdev->dev, (*clk_rates)[i]); - - devm_kfree(&pdev->dev, *clk_rates); - for (i = cnt - 1; i >= 0; i--) { - if (clk_ptr[i] != NULL) - devm_clk_put(&pdev->dev, (*clk_ptr)[i]); - CDBG("clk ptr[%d] :%pK\n", i, (*clk_ptr)[i]); - } - devm_kfree(&pdev->dev, *clk_info); - devm_kfree(&pdev->dev, *clk_ptr); - *clk_info = NULL; - *clk_ptr = NULL; - *clk_rates = NULL; - return 0; -} -EXPORT_SYMBOL(msm_camera_put_clk_info_and_rates); - -/* Get regulators from DT */ -int msm_camera_get_regulator_info(struct platform_device *pdev, - struct msm_cam_regulator **vdd_info, - int *num_reg) -{ - uint32_t cnt; - int i, rc; - struct device_node *of_node; - char prop_name[32]; - struct msm_cam_regulator *tmp_reg; - - if (!pdev || !vdd_info || !num_reg) - return -EINVAL; - - of_node = pdev->dev.of_node; - - if (!of_get_property(of_node, "qcom,vdd-names", NULL)) { - pr_err("err: Regulators property not found\n"); - return -EINVAL; - } - - cnt = of_property_count_strings(of_node, "qcom,vdd-names"); - if (cnt <= 0) { - pr_err("err: no regulators found in device tree, count=%d", - cnt); - return -EINVAL; - } - - tmp_reg = devm_kcalloc(&pdev->dev, cnt, - sizeof(struct msm_cam_regulator), GFP_KERNEL); - if (!tmp_reg) - return -ENOMEM; - - for (i = 0; i < cnt; i++) { - rc = of_property_read_string_index(of_node, - "qcom,vdd-names", i, &tmp_reg[i].name); - if (rc < 0) { - pr_err("Fail to fetch regulators: %d\n", i); - rc = -EINVAL; - goto err1; - } - - CDBG("regulator-names[%d] = %s\n", i, tmp_reg[i].name); - - snprintf(prop_name, 32, "%s-supply", tmp_reg[i].name); - - if (of_get_property(of_node, prop_name, NULL)) { - tmp_reg[i].vdd = - devm_regulator_get(&pdev->dev, tmp_reg[i].name); - if (IS_ERR(tmp_reg[i].vdd)) { - rc = -EINVAL; - pr_err("Fail to get regulator :%d\n", i); - goto err1; - } - } else { - pr_err("Regulator phandle not found :%s\n", - tmp_reg[i].name); - rc = -EINVAL; - goto err1; - } - CDBG("vdd ptr[%d] :%pK\n", i, tmp_reg[i].vdd); - } - - *num_reg = cnt; - *vdd_info = tmp_reg; - - return 0; - -err1: - for (--i; i >= 0; i--) - devm_regulator_put(tmp_reg[i].vdd); - devm_kfree(&pdev->dev, tmp_reg); - return rc; -} -EXPORT_SYMBOL(msm_camera_get_regulator_info); - -/* Enable/Disable regulators */ -int msm_camera_regulator_enable(struct msm_cam_regulator *vdd_info, - int cnt, int enable) -{ - int i; - int rc; - struct msm_cam_regulator *tmp = vdd_info; - - if (!tmp) { - pr_err("Invalid params"); - return -EINVAL; - } - CDBG("cnt : %d\n", cnt); - - for (i = 0; i < cnt; i++) { - if (tmp && !IS_ERR_OR_NULL(tmp->vdd)) { - CDBG("name : %s, enable : %d\n", tmp->name, enable); - if (enable) { - rc = regulator_enable(tmp->vdd); - if (rc < 0) { - pr_err("regulator enable failed %d\n", - i); - goto error; - } - } else { - rc = regulator_disable(tmp->vdd); - if (rc < 0) - pr_err("regulator disable failed %d\n", - i); - } - } - tmp++; - } - - return 0; -error: - for (--i; i > 0; i--) { - --tmp; - if (!IS_ERR_OR_NULL(tmp->vdd)) - regulator_disable(tmp->vdd); - } - return rc; -} -EXPORT_SYMBOL(msm_camera_regulator_enable); - -/* Put regulators regulators */ -void msm_camera_put_regulators(struct platform_device *pdev, - struct msm_cam_regulator **vdd_info, int cnt) -{ - int i; - - if (!vdd_info || !*vdd_info) { - pr_err("Invalid params\n"); - return; - } - - for (i = cnt - 1; i >= 0; i--) { - if (vdd_info[i] && !IS_ERR_OR_NULL(vdd_info[i]->vdd)) - devm_regulator_put(vdd_info[i]->vdd); - CDBG("vdd ptr[%d] :%pK\n", i, vdd_info[i]->vdd); - } - - devm_kfree(&pdev->dev, *vdd_info); - *vdd_info = NULL; -} -EXPORT_SYMBOL(msm_camera_put_regulators); - -struct resource *msm_camera_get_irq(struct platform_device *pdev, - char *irq_name) -{ - if (!pdev || !irq_name) { - pr_err("Invalid params\n"); - return NULL; - } - - CDBG("Get irq for %s\n", irq_name); - return platform_get_resource_byname(pdev, IORESOURCE_IRQ, irq_name); -} -EXPORT_SYMBOL(msm_camera_get_irq); - -int msm_camera_register_irq(struct platform_device *pdev, - struct resource *irq, irq_handler_t handler, - unsigned long irqflags, char *irq_name, void *dev_id) -{ - int rc = 0; - - if (!pdev || !irq || !handler || !irq_name || !dev_id) { - pr_err("Invalid params\n"); - return -EINVAL; - } - - rc = devm_request_irq(&pdev->dev, irq->start, handler, - irqflags, irq_name, dev_id); - if (rc < 0) { - pr_err("irq request fail\n"); - rc = -EINVAL; - } - - CDBG("Registered irq for %s[resource - %pK]\n", irq_name, irq); - - return rc; -} -EXPORT_SYMBOL(msm_camera_register_irq); - -int msm_camera_register_threaded_irq(struct platform_device *pdev, - struct resource *irq, irq_handler_t handler_fn, - irq_handler_t thread_fn, unsigned long irqflags, - const char *irq_name, void *dev_id) -{ - int rc = 0; - - if (!pdev || !irq || !irq_name || !dev_id) { - pr_err("Invalid params\n"); - return -EINVAL; - } - - rc = devm_request_threaded_irq(&pdev->dev, irq->start, handler_fn, - thread_fn, irqflags, irq_name, dev_id); - if (rc < 0) { - pr_err("irq request fail\n"); - rc = -EINVAL; - } - - CDBG("Registered irq for %s[resource - %pK]\n", irq_name, irq); - - return rc; -} -EXPORT_SYMBOL(msm_camera_register_threaded_irq); - -int msm_camera_enable_irq(struct resource *irq, int enable) -{ - if (!irq) { - pr_err("Invalid params\n"); - return -EINVAL; - } - - CDBG("irq Enable %d\n", enable); - if (enable) - enable_irq(irq->start); - else - disable_irq(irq->start); - - return 0; -} -EXPORT_SYMBOL(msm_camera_enable_irq); - -int msm_camera_unregister_irq(struct platform_device *pdev, - struct resource *irq, void *dev_id) -{ - - if (!pdev || !irq || !dev_id) { - pr_err("Invalid params\n"); - return -EINVAL; - } - - CDBG("Un Registering irq for [resource - %pK]\n", irq); - devm_free_irq(&pdev->dev, irq->start, dev_id); - - return 0; -} -EXPORT_SYMBOL(msm_camera_unregister_irq); - -void __iomem *msm_camera_get_reg_base(struct platform_device *pdev, - char *device_name, int reserve_mem) -{ - struct resource *mem; - void *base; - - if (!pdev || !device_name) { - pr_err("Invalid params\n"); - return NULL; - } - - CDBG("device name :%s\n", device_name); - mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, device_name); - if (!mem) { - pr_err("err: mem resource %s not found\n", device_name); - return NULL; - } - - if (reserve_mem) { - CDBG("device:%pK, mem : %pK, size : %d\n", - &pdev->dev, mem, (int)resource_size(mem)); - if (!devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), - device_name)) { - pr_err("err: no valid mem region for device:%s\n", - device_name); - return NULL; - } - } - - base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!base) { - devm_release_mem_region(&pdev->dev, mem->start, - resource_size(mem)); - pr_err("err: ioremap failed: %s\n", device_name); - return NULL; - } - - CDBG("base : %pK\n", base); - return base; -} -EXPORT_SYMBOL(msm_camera_get_reg_base); - -uint32_t msm_camera_get_res_size(struct platform_device *pdev, - char *device_name) -{ - struct resource *mem; - - if (!pdev || !device_name) { - pr_err("Invalid params\n"); - return 0; - } - - CDBG("device name :%s\n", device_name); - mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, device_name); - if (!mem) { - pr_err("err: mem resource %s not found\n", device_name); - return 0; - } - return resource_size(mem); -} -EXPORT_SYMBOL(msm_camera_get_res_size); - - -int msm_camera_put_reg_base(struct platform_device *pdev, - void __iomem *base, char *device_name, int reserve_mem) -{ - struct resource *mem; - - if (!pdev || !base || !device_name) { - pr_err("Invalid params\n"); - return -EINVAL; - } - - CDBG("device name :%s\n", device_name); - mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, device_name); - if (!mem) { - pr_err("err: mem resource %s not found\n", device_name); - return -EINVAL; - } - CDBG("mem : %pK, size : %d\n", mem, (int)resource_size(mem)); - - devm_iounmap(&pdev->dev, base); - if (reserve_mem) - devm_release_mem_region(&pdev->dev, - mem->start, resource_size(mem)); - - return 0; -} -EXPORT_SYMBOL(msm_camera_put_reg_base); - -/* Register the bus client */ -uint32_t msm_camera_register_bus_client(struct platform_device *pdev, - enum cam_bus_client id) -{ - int rc = 0; - uint32_t bus_client, num_usecases, num_paths; - struct msm_bus_scale_pdata *pdata; - struct device_node *of_node; - - CDBG("Register client ID: %d\n", id); - - if (id >= CAM_BUS_CLIENT_MAX || !pdev) { - pr_err("Invalid params"); - return -EINVAL; - } - - of_node = pdev->dev.of_node; - - if (!g_cv[id].pdata) { - rc = of_property_read_u32(of_node, "qcom,msm-bus,num-cases", - &num_usecases); - if (rc) { - pr_err("num-usecases not found\n"); - return -EINVAL; - } - rc = of_property_read_u32(of_node, "qcom,msm-bus,num-paths", - &num_paths); - if (rc) { - pr_err("num-usecases not found\n"); - return -EINVAL; - } - - if (num_paths != 1) { - pr_err("Exceeds number of paths\n"); - return -EINVAL; - } - - if (of_property_read_bool(of_node, - "qcom,msm-bus-vector-dyn-vote")) { - if (num_usecases != 2) { - pr_err("Excess or less vectors\n"); - return -EINVAL; - } - g_cv[id].dyn_vote = true; - } - - pdata = msm_bus_cl_get_pdata(pdev); - if (!pdata) { - pr_err("failed get_pdata client_id :%d\n", id); - return -EINVAL; - } - bus_client = msm_bus_scale_register_client(pdata); - if (!bus_client) { - pr_err("Unable to register bus client :%d\n", id); - return -EINVAL; - } - } else { - pr_err("vector already setup client_id : %d\n", id); - return -EINVAL; - } - - g_cv[id].pdata = pdata; - g_cv[id].bus_client = bus_client; - g_cv[id].vector_index = 0; - g_cv[id].num_usecases = num_usecases; - g_cv[id].num_paths = num_paths; - mutex_init(&g_cv[id].lock); - CDBG("Exit Client ID: %d\n", id); - return 0; -} -EXPORT_SYMBOL(msm_camera_register_bus_client); - -/* Update the bus bandwidth */ -uint32_t msm_camera_update_bus_bw(int id, uint64_t ab, uint64_t ib) -{ - struct msm_bus_paths *path; - struct msm_bus_scale_pdata *pdata; - int idx = 0; - - if (id >= CAM_BUS_CLIENT_MAX) { - pr_err("Invalid params"); - return -EINVAL; - } - if (g_cv[id].num_usecases != 2 || - g_cv[id].num_paths != 1 || - g_cv[id].dyn_vote != true) { - pr_err("dynamic update not allowed\n"); - return -EINVAL; - } - - mutex_lock(&g_cv[id].lock); - idx = g_cv[id].vector_index; - idx = 1 - idx; - g_cv[id].vector_index = idx; - mutex_unlock(&g_cv[id].lock); - - pdata = g_cv[id].pdata; - path = &(pdata->usecase[idx]); - path->vectors[0].ab = ab; - path->vectors[0].ib = ib; - - CDBG("Register client ID : %d [ab : %llx, ib : %llx], update :%d\n", - id, ab, ib, idx); - msm_bus_scale_client_update_request(g_cv[id].bus_client, idx); - - return 0; -} -EXPORT_SYMBOL(msm_camera_update_bus_bw); - -/* Update the bus vector */ -uint32_t msm_camera_update_bus_vector(enum cam_bus_client id, - int vector_index) -{ - if (id >= CAM_BUS_CLIENT_MAX || g_cv[id].dyn_vote == true) { - pr_err("Invalid params"); - return -EINVAL; - } - - if (vector_index < 0 || vector_index > g_cv[id].num_usecases) { - pr_err("Invalid params"); - return -EINVAL; - } - - CDBG("Register client ID : %d vector idx: %d,\n", id, vector_index); - msm_bus_scale_client_update_request(g_cv[id].bus_client, - vector_index); - - return 0; -} -EXPORT_SYMBOL(msm_camera_update_bus_vector); - -/* Unregister the bus client */ -uint32_t msm_camera_unregister_bus_client(enum cam_bus_client id) -{ - if (id >= CAM_BUS_CLIENT_MAX) { - pr_err("Invalid params"); - return -EINVAL; - } - - CDBG("UnRegister client ID: %d\n", id); - - mutex_destroy(&g_cv[id].lock); - msm_bus_scale_unregister_client(g_cv[id].bus_client); - g_cv[id].bus_client = 0; - g_cv[id].num_usecases = 0; - g_cv[id].num_paths = 0; - g_cv[id].vector_index = 0; - g_cv[id].dyn_vote = 0; - - return 0; -} -EXPORT_SYMBOL(msm_camera_unregister_bus_client); diff --git a/drivers/media/platform/msm/ais/common/cam_soc_api.h b/drivers/media/platform/msm/ais/common/cam_soc_api.h deleted file mode 100644 index b9089e874acf3ca4eb1db2e055279eb55c71f7b3..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/cam_soc_api.h +++ /dev/null @@ -1,425 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ -#ifndef _CAM_SOC_API_H_ -#define _CAM_SOC_API_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum cam_bus_client { - CAM_BUS_CLIENT_VFE, - CAM_BUS_CLIENT_CPP, - CAM_BUS_CLIENT_FD, - CAM_BUS_CLIENT_JPEG_ENC0, - CAM_BUS_CLIENT_JPEG_ENC1, - CAM_BUS_CLIENT_JPEG_DEC, - CAM_BUS_CLIENT_JPEG_DMA, - CAM_BUS_CLIENT_MAX -}; - -struct msm_cam_regulator { - const char *name; - struct regulator *vdd; -}; - -/** - * @brief : Gets clock information from dtsi - * - * This function extracts the clocks information for a specific - * platform device - * - * @param pdev : Platform device to get clocks information - * @param clk_info : Pointer to populate clock information array - * @param clk_ptr : Pointer to populate clock resource pointers - * @param num_clk: Pointer to populate the number of clocks - * extracted from dtsi - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int msm_camera_get_clk_info(struct platform_device *pdev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, - size_t *num_clk); - -/** - * @brief : Gets clock information from dtsi - * - * This function extracts the clocks information for a specific - * i2c device - * - * @param dev : i2c device to get clocks information - * @param clk_info : Pointer to populate clock information array - * @param clk_ptr : Pointer to populate clock resource pointers - * @param num_clk: Pointer to populate the number of clocks - * extracted from dtsi - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int msm_camera_i2c_dev_get_clk_info(struct device *dev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, - size_t *num_clk); - -/** - * @brief : Gets clock information and rates from dtsi - * - * This function extracts the clocks information for a specific - * platform device - * - * @param pdev : Platform device to get clocks information - * @param clk_info : Pointer to populate clock information array - * @param clk_ptr : Pointer to populate clock resource pointers - * @param clk_rates : Pointer to populate clock rates - * @param num_set: Pointer to populate the number of sets of rates - * @param num_clk: Pointer to populate the number of clocks - * extracted from dtsi - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int msm_camera_get_clk_info_and_rates( - struct platform_device *pdev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, - uint32_t ***clk_rates, - size_t *num_set, - size_t *num_clk); - -/** - * @brief : Puts clock information - * - * This function releases the memory allocated for the clocks - * - * @param pdev : Pointer to platform device - * @param clk_info : Pointer to release the allocated memory - * @param clk_ptr : Pointer to release the clock resources - * @param cnt : Number of clk resources - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int msm_camera_put_clk_info(struct platform_device *pdev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, int cnt); - -/** - * @brief : Puts clock information - * - * This function releases the memory allocated for the clocks - * - * @param dev : Pointer to i2c device - * @param clk_info : Pointer to release the allocated memory - * @param clk_ptr : Pointer to release the clock resources - * @param cnt : Number of clk resources - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int msm_camera_i2c_dev_put_clk_info(struct device *dev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, int cnt); - -/** - * @brief : Puts clock information - * - * This function releases the memory allocated for the clocks - * - * @param pdev : Pointer to platform device - * @param clk_info : Pointer to release the allocated memory - * @param clk_ptr : Pointer to release the clock resources - * @param clk_ptr : Pointer to release the clock rates - * @param set : Number of sets of clock rates - * @param cnt : Number of clk resources - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int msm_camera_put_clk_info_and_rates(struct platform_device *pdev, - struct msm_cam_clk_info **clk_info, - struct clk ***clk_ptr, uint32_t ***clk_rates, - size_t set, size_t cnt); -/** - * @brief : Enable clocks - * - * This function enables the clocks for a specified device - * - * @param dev : Device to get clocks information - * @param clk_info : Pointer to populate clock information - * @param clk_ptr : Pointer to populate clock information - * @param num_clk: Pointer to populate the number of clocks - * extracted from dtsi - * @param enable : Flag to specify enable/disable - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int msm_camera_clk_enable(struct device *dev, - struct msm_cam_clk_info *clk_info, - struct clk **clk_ptr, - int num_clk, - int enable); -/** - * @brief : Set clock rate - * - * This function sets the rate for a specified clock and - * returns the rounded value - * - * @param dev : Device to get clocks information - * @param clk : Pointer to clock to set rate - * @param clk_rate : Rate to be set - * - * @return Status of operation. Negative in case of error. clk rate otherwise. - */ - -long msm_camera_clk_set_rate(struct device *dev, - struct clk *clk, - long clk_rate); -/** - * @brief : Gets regulator info - * - * This function extracts the regulator information for a specific - * platform device - * - * @param pdev : platform device to get regulator information - * @param vdd_info: Pointer to populate the regulator names - * @param num_reg: Pointer to populate the number of regulators - * extracted from dtsi - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int msm_camera_get_regulator_info(struct platform_device *pdev, - struct msm_cam_regulator **vdd_info, int *num_reg); -/** - * @brief : Enable/Disable the regultors - * - * This function enables/disables the regulators for a specific - * platform device - * - * @param vdd_info: Pointer to list of regulators - * @param cnt: Number of regulators to enable/disable - * @param enable: Flags specifies either enable/disable - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int msm_camera_regulator_enable(struct msm_cam_regulator *vdd_info, - int cnt, int enable); - -/** - * @brief : Release the regulators - * - * This function releases the regulator resources. - * - * @param pdev: Pointer to platform device - * @param vdd_info: Pointer to list of regulators - * @param cnt: Number of regulators to release - */ - -void msm_camera_put_regulators(struct platform_device *pdev, - struct msm_cam_regulator **vdd_info, int cnt); -/** - * @brief : Get the IRQ resource - * - * This function gets the irq resource from dtsi for a specific - * platform device - * - * @param pdev : Platform device to get IRQ - * @param irq_name: Name of the IRQ resource to get from DTSI - * - * @return Pointer to resource if success else null - */ - -struct resource *msm_camera_get_irq(struct platform_device *pdev, - char *irq_name); -/** - * @brief : Register the IRQ - * - * This function registers the irq resource for specified hardware - * - * @param pdev : Platform device to register IRQ resource - * @param irq : IRQ resource - * @param handler : IRQ handler - * @param irqflags : IRQ flags - * @param irq_name: Name of the IRQ - * @param dev : Token of the device - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int msm_camera_register_irq(struct platform_device *pdev, - struct resource *irq, - irq_handler_t handler, - unsigned long irqflags, - char *irq_name, - void *dev); - -/** - * @brief : Register the threaded IRQ - * - * This function registers the irq resource for specified hardware - * - * @param pdev : Platform device to register IRQ resource - * @param irq : IRQ resource - * @param handler_fn : IRQ handler function - * @param thread_fn : thread handler function - * @param irqflags : IRQ flags - * @param irq_name: Name of the IRQ - * @param dev : Token of the device - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int msm_camera_register_threaded_irq(struct platform_device *pdev, - struct resource *irq, - irq_handler_t handler_fn, - irq_handler_t thread_fn, - unsigned long irqflags, - const char *irq_name, - void *dev); - -/** - * @brief : Enable/Disable the IRQ - * - * This function enables or disables a specific IRQ - * - * @param irq : IRQ resource - * @param flag : flag to enable/disable - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int msm_camera_enable_irq(struct resource *irq, int flag); - -/** - * @brief : UnRegister the IRQ - * - * This function Unregisters/Frees the irq resource - * - * @param pdev : Pointer to platform device - * @param irq : IRQ resource - * @param dev : Token of the device - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int msm_camera_unregister_irq(struct platform_device *pdev, - struct resource *irq, void *dev_id); - -/** - * @brief : Gets device register base - * - * This function extracts the device's register base from the dtsi - * for the specified platform device - * - * @param pdev : Platform device to get regulator infor - * @param device_name : Name of the device to fetch the register base - * @param reserve_mem : Flag to decide whether to reserve memory - * region or not. - * - * @return Pointer to resource if success else null - */ - -void __iomem *msm_camera_get_reg_base(struct platform_device *pdev, - char *device_name, int reserve_mem); - -/** - * @brief : Puts device register base - * - * This function releases the memory region for the specified - * resource - * - * @param pdev : Pointer to platform device - * @param base : Pointer to base to unmap - * @param device_name : Device name - * @param reserve_mem : Flag to decide whether to release memory - * region or not. - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -int msm_camera_put_reg_base(struct platform_device *pdev, void __iomem *base, - char *device_name, int reserve_mem); - -/** - * @brief : Register the bus client - * - * This function registers the bus client - * - * @param pdev : Pointer to platform device - * @param id : client identifier - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -uint32_t msm_camera_register_bus_client(struct platform_device *pdev, - enum cam_bus_client id); - -/** - * @brief : Update bus vector - * - * This function votes for the specified vector to the bus - * - * @param id : client identifier - * @param vector_index : vector index to register - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -uint32_t msm_camera_update_bus_vector(enum cam_bus_client id, - int vector_index); - -/** - * @brief : Update the bus bandwidth - * - * This function updates the bandwidth for the specific client - * - * @param client_id : client identifier - * @param ab : Asolute bandwidth - * @param ib : Instantaneous bandwidth - * - * @return non-zero as client id if success else fail - */ - -uint32_t msm_camera_update_bus_bw(int id, uint64_t ab, uint64_t ib); - -/** - * @brief : UnRegister the bus client - * - * This function unregisters the bus client - * - * @param id : client identifier - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ - -uint32_t msm_camera_unregister_bus_client(enum cam_bus_client id); - -/** - * @brief : Gets resource size - * - * This function returns the size of the resource for the - * specified platform device - * - * @param pdev : Platform device to get regulator infor - * @param device_name : Name of the device to fetch the register base - * - * @return size of the resource - */ - -uint32_t msm_camera_get_res_size(struct platform_device *pdev, - char *device_name); - -#endif diff --git a/drivers/media/platform/msm/ais/common/msm_camera_io_util.c b/drivers/media/platform/msm/ais/common/msm_camera_io_util.c deleted file mode 100644 index 49ee72a9f534f60367588b435fbbe434caf82eb4..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/msm_camera_io_util.c +++ /dev/null @@ -1,848 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include "msm_camera_io_util.h" - -#define BUFF_SIZE_128 128 - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -void msm_camera_io_w(u32 data, void __iomem *addr) -{ - CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); - writel_relaxed((data), (addr)); -} - -/* This API is to write a block of data -* to same address -*/ -int32_t msm_camera_io_w_block(const u32 *addr, void __iomem *base, - u32 len) -{ - int i; - - if (!addr || !len || !base) - return -EINVAL; - - for (i = 0; i < len; i++) { - CDBG("%s: len =%d val=%x base =%pK\n", __func__, - len, addr[i], base); - writel_relaxed(addr[i], base); - } - return 0; -} - -/** This API is to write a block of registers -* which is like a 2 dimensional array table with -* register offset and data */ -int32_t msm_camera_io_w_reg_block(const u32 *addr, void __iomem *base, - u32 len) -{ - int i; - - if (!addr || !len || !base) - return -EINVAL; - - for (i = 0; i < len; i = i + 2) { - CDBG("%s: len =%d val=%x base =%pK reg=%x\n", __func__, - len, addr[i + 1], base, addr[i]); - writel_relaxed(addr[i + 1], base + addr[i]); - } - return 0; -} - -void msm_camera_io_w_mb(u32 data, void __iomem *addr) -{ - CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); - /* ensure write is done */ - wmb(); - writel_relaxed((data), (addr)); - /* ensure write is done */ - wmb(); -} - -int32_t msm_camera_io_w_mb_block(const u32 *addr, void __iomem *base, u32 len) -{ - int i; - - if (!addr || !len || !base) - return -EINVAL; - - for (i = 0; i < len; i++) { - /* ensure write is done */ - wmb(); - CDBG("%s: len =%d val=%x base =%pK\n", __func__, - len, addr[i], base); - writel_relaxed(addr[i], base); - } - /* ensure last write is done */ - wmb(); - return 0; -} - -u32 msm_camera_io_r(void __iomem *addr) -{ - uint32_t data = readl_relaxed(addr); - - CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); - return data; -} - -u32 msm_camera_io_r_mb(void __iomem *addr) -{ - uint32_t data; - /* ensure read is done */ - rmb(); - data = readl_relaxed(addr); - /* ensure read is done */ - rmb(); - CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); - return data; -} - -void msm_camera_io_memcpy_toio(void __iomem *dest_addr, - void __iomem *src_addr, u32 len) -{ - int i; - u32 *d = (u32 *) dest_addr; - u32 *s = (u32 *) src_addr; - - for (i = 0; i < len; i++) - writel_relaxed(*s++, d++); -} - -int32_t msm_camera_io_poll_value(void __iomem *addr, u32 wait_data, u32 retry, - unsigned long min_usecs, unsigned long max_usecs) -{ - uint32_t tmp, cnt = 0; - int32_t rc = 0; - - if (!addr) - return -EINVAL; - - tmp = msm_camera_io_r(addr); - while ((tmp != wait_data) && (cnt++ < retry)) { - if (min_usecs > 0 && max_usecs > 0) - usleep_range(min_usecs, max_usecs); - tmp = msm_camera_io_r(addr); - } - if (cnt > retry) { - pr_debug("Poll failed by value\n"); - rc = -EINVAL; - } - return rc; -} - -int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data, - u32 bmask, u32 retry, unsigned long min_usecs, unsigned long max_usecs) -{ - uint32_t tmp, cnt = 0; - int32_t rc = 0; - - if (!addr) - return -EINVAL; - - tmp = msm_camera_io_r(addr); - while (((tmp & bmask) != wait_data) && (cnt++ < retry)) { - if (min_usecs > 0 && max_usecs > 0) - usleep_range(min_usecs, max_usecs); - tmp = msm_camera_io_r(addr); - } - if (cnt > retry) { - pr_debug("Poll failed with mask\n"); - rc = -EINVAL; - } - return rc; -} - -void msm_camera_io_dump(void __iomem *addr, int size, int enable) -{ - char line_str[128], *p_str; - int i; - u32 *p = (u32 *) addr; - u32 data; - - CDBG("%s: addr=%pK size=%d\n", __func__, addr, size); - - if (!p || (size <= 0) || !enable) - return; - - line_str[0] = '\0'; - p_str = line_str; - for (i = 0; i < size/4; i++) { - if (i % 4 == 0) { -#ifdef CONFIG_COMPAT - snprintf(p_str, 20, "%016lx: ", (unsigned long) p); - p_str += 18; -#else - snprintf(p_str, 12, "%08lx: ", (unsigned long) p); - p_str += 10; -#endif - } - data = readl_relaxed(p++); - snprintf(p_str, 12, "%08x ", data); - p_str += 9; - if ((i + 1) % 4 == 0) { - pr_err("%s\n", line_str); - line_str[0] = '\0'; - p_str = line_str; - } - } - if (line_str[0] != '\0') - pr_err("%s\n", line_str); -} - -void msm_camera_io_dump_wstring_base(void __iomem *addr, - struct msm_cam_dump_string_info *dump_data, - int size) -{ - int i, u = sizeof(struct msm_cam_dump_string_info); - - pr_debug("%s: addr=%pK data=%pK size=%d u=%d, cnt=%d\n", __func__, - addr, dump_data, size, u, - (size/u)); - - if (!addr || (size <= 0) || !dump_data) { - pr_err("%s: addr=%pK data=%pK size=%d\n", __func__, - addr, dump_data, size); - return; - } - for (i = 0; i < (size / u); i++) - pr_debug("%s 0x%x\n", (dump_data + i)->print, - readl_relaxed((dump_data + i)->offset + addr)); -} - -void msm_camera_io_memcpy(void __iomem *dest_addr, - void __iomem *src_addr, u32 len) -{ - CDBG("%s: %pK %pK %d\n", __func__, dest_addr, src_addr, len); - msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4); -} - -void msm_camera_io_memcpy_mb(void __iomem *dest_addr, - void __iomem *src_addr, u32 len) -{ - int i; - u32 *d = (u32 *) dest_addr; - u32 *s = (u32 *) src_addr; - /* This is generic function called who needs to register - writes with memory barrier */ - wmb(); - for (i = 0; i < (len / 4); i++) { - msm_camera_io_w(*s++, d++); - /* ensure write is done after every iteration */ - wmb(); - } -} - -int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, - struct msm_cam_clk_info *clk_src_info, int num_clk) -{ - int i; - int rc = 0; - struct clk *mux_clk = NULL; - struct clk *src_clk = NULL; - - for (i = 0; i < num_clk; i++) { - if (clk_src_info[i].clk_name) { - mux_clk = clk_get(dev, clk_info[i].clk_name); - if (IS_ERR(mux_clk)) { - pr_err("%s get failed\n", - clk_info[i].clk_name); - continue; - } - src_clk = clk_get(dev, clk_src_info[i].clk_name); - if (IS_ERR(src_clk)) { - pr_err("%s get failed\n", - clk_src_info[i].clk_name); - continue; - } - clk_set_parent(mux_clk, src_clk); - } - } - return rc; -} - -int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, - struct clk **clk_ptr, int num_clk, int enable) -{ - int i; - int rc = 0; - long clk_rate; - - if (enable) { - for (i = 0; i < num_clk; i++) { - CDBG("%s enable %s\n", __func__, clk_info[i].clk_name); - clk_ptr[i] = clk_get(dev, clk_info[i].clk_name); - if (IS_ERR(clk_ptr[i])) { - pr_err("%s get failed\n", clk_info[i].clk_name); - rc = PTR_ERR(clk_ptr[i]); - goto cam_clk_get_err; - } - if (clk_info[i].clk_rate > 0) { - clk_rate = clk_round_rate(clk_ptr[i], - clk_info[i].clk_rate); - if (clk_rate < 0) { - pr_err("%s round failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - rc = clk_set_rate(clk_ptr[i], - clk_rate); - if (rc < 0) { - pr_err("%s set failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - - } else if (clk_info[i].clk_rate == INIT_RATE) { - clk_rate = clk_get_rate(clk_ptr[i]); - if (clk_rate == 0) { - clk_rate = - clk_round_rate(clk_ptr[i], 0); - if (clk_rate < 0) { - pr_err("%s round rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - rc = clk_set_rate(clk_ptr[i], - clk_rate); - if (rc < 0) { - pr_err("%s set rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - } - } - rc = clk_prepare(clk_ptr[i]); - if (rc < 0) { - pr_err("%s prepare failed\n", - clk_info[i].clk_name); - goto cam_clk_prepare_err; - } - - rc = clk_enable(clk_ptr[i]); - if (rc < 0) { - pr_err("%s enable failed\n", - clk_info[i].clk_name); - goto cam_clk_enable_err; - } - if (clk_info[i].delay > 20) { - msleep(clk_info[i].delay); - } else if (clk_info[i].delay) { - usleep_range(clk_info[i].delay * 1000, - (clk_info[i].delay * 1000) + 1000); - } - } - } else { - for (i = num_clk - 1; i >= 0; i--) { - if (clk_ptr[i] != NULL) { - CDBG("%s disable %s\n", __func__, - clk_info[i].clk_name); - clk_disable(clk_ptr[i]); - clk_unprepare(clk_ptr[i]); - clk_put(clk_ptr[i]); - } - } - } - return rc; - - -cam_clk_enable_err: - clk_unprepare(clk_ptr[i]); -cam_clk_prepare_err: -cam_clk_set_err: - clk_put(clk_ptr[i]); -cam_clk_get_err: - for (i--; i >= 0; i--) { - if (clk_ptr[i] != NULL) { - clk_disable(clk_ptr[i]); - clk_unprepare(clk_ptr[i]); - clk_put(clk_ptr[i]); - } - } - return rc; -} - -int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int config) -{ - int i = 0, j = 0; - int rc = 0; - struct camera_vreg_t *curr_vreg; - - if (num_vreg_seq > num_vreg) { - pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); - return -EINVAL; - } - - if (!num_vreg_seq) - num_vreg_seq = num_vreg; - - if ((cam_vreg == NULL) && num_vreg_seq) { - pr_err("%s:%d cam_vreg NULL\n", __func__, __LINE__); - return -EINVAL; - } - - if (config) { - for (i = 0; i < num_vreg_seq; i++) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - curr_vreg = &cam_vreg[j]; - reg_ptr[j] = regulator_get(dev, - curr_vreg->reg_name); - if (IS_ERR(reg_ptr[j])) { - pr_err("%s: %s get failed\n", - __func__, - curr_vreg->reg_name); - reg_ptr[j] = NULL; - goto vreg_get_fail; - } - if (regulator_count_voltages(reg_ptr[j]) > 0) { - rc = regulator_set_voltage( - reg_ptr[j], - curr_vreg->min_voltage, - curr_vreg->max_voltage); - if (rc < 0) { - pr_err("%s: %s set voltage failed\n", - __func__, - curr_vreg->reg_name); - goto vreg_set_voltage_fail; - } - if (curr_vreg->op_mode >= 0) { - rc = regulator_set_optimum_mode( - reg_ptr[j], - curr_vreg->op_mode); - if (rc < 0) { - pr_err( - "%s:%s set optimum mode fail\n", - __func__, - curr_vreg->reg_name); - goto vreg_set_opt_mode_fail; - } - } - } - } - } else { - for (i = num_vreg_seq-1; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - curr_vreg = &cam_vreg[j]; - if (reg_ptr[j]) { - if (regulator_count_voltages(reg_ptr[j]) > 0) { - if (curr_vreg->op_mode >= 0) { - regulator_set_optimum_mode( - reg_ptr[j], 0); - } - regulator_set_voltage( - reg_ptr[j], 0, curr_vreg-> - max_voltage); - } - regulator_put(reg_ptr[j]); - reg_ptr[j] = NULL; - } - } - } - return 0; - -vreg_unconfig: -if (regulator_count_voltages(reg_ptr[j]) > 0) - regulator_set_optimum_mode(reg_ptr[j], 0); - -vreg_set_opt_mode_fail: -if (regulator_count_voltages(reg_ptr[j]) > 0) - regulator_set_voltage(reg_ptr[j], 0, - curr_vreg->max_voltage); - -vreg_set_voltage_fail: - regulator_put(reg_ptr[j]); - reg_ptr[j] = NULL; - -vreg_get_fail: - for (i--; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - curr_vreg = &cam_vreg[j]; - goto vreg_unconfig; - } - return -ENODEV; -} - -int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int enable) -{ - int i = 0, j = 0, rc = 0; - - if (num_vreg_seq > num_vreg) { - pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); - return -EINVAL; - } - if (!num_vreg_seq) - num_vreg_seq = num_vreg; - - if (enable) { - for (i = 0; i < num_vreg_seq; i++) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - if (IS_ERR(reg_ptr[j])) { - pr_err("%s: %s null regulator\n", - __func__, cam_vreg[j].reg_name); - goto disable_vreg; - } - rc = regulator_enable(reg_ptr[j]); - if (rc < 0) { - pr_err("%s: %s enable failed\n", - __func__, cam_vreg[j].reg_name); - goto disable_vreg; - } - if (cam_vreg[j].delay > 20) - msleep(cam_vreg[j].delay); - else if (cam_vreg[j].delay) - usleep_range(cam_vreg[j].delay * 1000, - (cam_vreg[j].delay * 1000) + 1000); - } - } else { - for (i = num_vreg_seq-1; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - regulator_disable(reg_ptr[j]); - if (cam_vreg[j].delay > 20) - msleep(cam_vreg[j].delay); - else if (cam_vreg[j].delay) - usleep_range(cam_vreg[j].delay * 1000, - (cam_vreg[j].delay * 1000) + 1000); - } - } - return rc; -disable_vreg: - for (i--; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - regulator_disable(reg_ptr[j]); - if (cam_vreg[j].delay > 20) - msleep(cam_vreg[j].delay); - else if (cam_vreg[j].delay) - usleep_range(cam_vreg[j].delay * 1000, - (cam_vreg[j].delay * 1000) + 1000); - } - return rc; -} - -void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, - enum msm_bus_perf_setting perf_setting) -{ - int rc = 0; - - if (!bus_perf_client) { - pr_err("%s: Bus Client NOT Registered!!!\n", __func__); - return; - } - - switch (perf_setting) { - case S_EXIT: - rc = msm_bus_scale_client_update_request(bus_perf_client, 1); - msm_bus_scale_unregister_client(bus_perf_client); - break; - case S_PREVIEW: - rc = msm_bus_scale_client_update_request(bus_perf_client, 1); - break; - case S_VIDEO: - rc = msm_bus_scale_client_update_request(bus_perf_client, 2); - break; - case S_CAPTURE: - rc = msm_bus_scale_client_update_request(bus_perf_client, 3); - break; - case S_ZSL: - rc = msm_bus_scale_client_update_request(bus_perf_client, 4); - break; - case S_LIVESHOT: - rc = msm_bus_scale_client_update_request(bus_perf_client, 5); - break; - case S_DEFAULT: - break; - default: - pr_err("%s: INVALID CASE\n", __func__); - } -} - -int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, - uint8_t gpio_tbl_size, int gpio_en) -{ - int rc = 0, i; - - if (gpio_en) { - for (i = 0; i < gpio_tbl_size; i++) { - gpio_set_value_cansleep(gpio_tbl[i].gpio, - gpio_tbl[i].flags); - usleep_range(gpio_tbl[i].delay, - gpio_tbl[i].delay + 1000); - } - } else { - for (i = gpio_tbl_size - 1; i >= 0; i--) { - if (gpio_tbl[i].flags) - gpio_set_value_cansleep(gpio_tbl[i].gpio, - GPIOF_OUT_INIT_LOW); - } - } - return rc; -} - -int msm_camera_config_single_vreg(struct device *dev, - struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config) -{ - int rc = 0; - const char *vreg_name = NULL; - - if (!dev || !cam_vreg || !reg_ptr) { - pr_err("%s: get failed NULL parameter\n", __func__); - goto vreg_get_fail; - } - if (cam_vreg->type == VREG_TYPE_CUSTOM) { - if (cam_vreg->custom_vreg_name == NULL) { - pr_err("%s : can't find sub reg name", - __func__); - goto vreg_get_fail; - } - vreg_name = cam_vreg->custom_vreg_name; - } else { - if (cam_vreg->reg_name == NULL) { - pr_err("%s : can't find reg name", __func__); - goto vreg_get_fail; - } - vreg_name = cam_vreg->reg_name; - } - - if (config) { - CDBG("%s enable %s\n", __func__, vreg_name); - *reg_ptr = regulator_get(dev, vreg_name); - if (IS_ERR(*reg_ptr)) { - pr_err("%s: %s get failed\n", __func__, vreg_name); - *reg_ptr = NULL; - goto vreg_get_fail; - } - if (regulator_count_voltages(*reg_ptr) > 0) { - CDBG("%s: voltage min=%d, max=%d\n", - __func__, cam_vreg->min_voltage, - cam_vreg->max_voltage); - rc = regulator_set_voltage( - *reg_ptr, cam_vreg->min_voltage, - cam_vreg->max_voltage); - if (rc < 0) { - pr_err("%s: %s set voltage failed\n", - __func__, vreg_name); - goto vreg_set_voltage_fail; - } - if (cam_vreg->op_mode >= 0) { - rc = regulator_set_optimum_mode(*reg_ptr, - cam_vreg->op_mode); - if (rc < 0) { - pr_err( - "%s: %s set optimum mode failed\n", - __func__, vreg_name); - goto vreg_set_opt_mode_fail; - } - } - } - rc = regulator_enable(*reg_ptr); - if (rc < 0) { - pr_err("%s: %s regulator_enable failed\n", __func__, - vreg_name); - goto vreg_unconfig; - } - } else { - CDBG("%s disable %s\n", __func__, vreg_name); - if (*reg_ptr) { - CDBG("%s disable %s\n", __func__, vreg_name); - regulator_disable(*reg_ptr); - if (regulator_count_voltages(*reg_ptr) > 0) { - if (cam_vreg->op_mode >= 0) - regulator_set_optimum_mode(*reg_ptr, 0); - regulator_set_voltage( - *reg_ptr, 0, cam_vreg->max_voltage); - } - regulator_put(*reg_ptr); - *reg_ptr = NULL; - } else { - pr_err("%s can't disable %s\n", __func__, vreg_name); - } - } - return 0; - -vreg_unconfig: -if (regulator_count_voltages(*reg_ptr) > 0) - regulator_set_optimum_mode(*reg_ptr, 0); - -vreg_set_opt_mode_fail: -if (regulator_count_voltages(*reg_ptr) > 0) - regulator_set_voltage(*reg_ptr, 0, cam_vreg->max_voltage); - -vreg_set_voltage_fail: - regulator_put(*reg_ptr); - *reg_ptr = NULL; - -vreg_get_fail: - return -ENODEV; -} - -int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, - int gpio_en) -{ - int rc = 0, i = 0, err = 0; - - if (!gpio_tbl || !size) { - pr_err("%s:%d invalid gpio_tbl %pK / size %d\n", __func__, - __LINE__, gpio_tbl, size); - return -EINVAL; - } - for (i = 0; i < size; i++) { - CDBG("%s:%d i %d, gpio %d dir %ld\n", __func__, __LINE__, i, - gpio_tbl[i].gpio, gpio_tbl[i].flags); - } - if (gpio_en) { - for (i = 0; i < size; i++) { - err = gpio_request_one(gpio_tbl[i].gpio, - gpio_tbl[i].flags, gpio_tbl[i].label); - if (err) { - /* - * After GPIO request fails, contine to - * apply new gpios, outout a error message - * for driver bringup debug - */ - pr_err("%s:%d gpio %d:%s request fails\n", - __func__, __LINE__, - gpio_tbl[i].gpio, gpio_tbl[i].label); - } - } - } else { - gpio_free_array(gpio_tbl, size); - } - return rc; -} - -/* - * msm_camera_get_dt_reg_settings - Get dt reg settings from device-tree. - * @of_node: Pointer to device of_node from dev. - * @dt_prop_name: String of the property to search in of_node from dev. - * @reg_s: Double pointer will be allocated by this function and filled. - * @size: Pointer to fill the length of the available entries. - */ -int msm_camera_get_dt_reg_settings(struct device_node *of_node, - const char *dt_prop_name, uint32_t **reg_s, - unsigned int *size) -{ - int ret; - unsigned int cnt; - - if (!of_node || !dt_prop_name || !size || !reg_s) { - pr_err("%s: Error invalid args %pK:%pK:%pK:%pK\n", - __func__, size, reg_s, of_node, dt_prop_name); - return -EINVAL; - } - if (!of_get_property(of_node, dt_prop_name, &cnt)) { - pr_debug("Missing dt reg settings for %s\n", dt_prop_name); - return -ENOENT; - } - - if (!cnt || (cnt % 8)) { - pr_err("%s: Error invalid number of entries cnt=%d\n", - __func__, cnt); - return -EINVAL; - } - cnt /= 4; - if (cnt != 0) { - *reg_s = kcalloc(cnt, sizeof(uint32_t), - GFP_KERNEL); - if (!*reg_s) - return -ENOMEM; - ret = of_property_read_u32_array(of_node, - dt_prop_name, - *reg_s, - cnt); - if (ret < 0) { - pr_err("%s: No dt reg info read for %s ret=%d\n", - __func__, dt_prop_name, ret); - kfree(*reg_s); - return -ENOENT; - } - *size = cnt; - } else { - pr_err("%s: Error invalid entries\n", __func__); - return -EINVAL; - } - - return ret; -} - -/* - * msm_camera_get_dt_reg_settings - Free dt reg settings memory. - * @reg_s: Double pointer will be allocated by this function and filled. - * @size: Pointer to set the length as invalid. - */ -void msm_camera_put_dt_reg_settings(uint32_t **reg_s, - unsigned int *size) -{ - kfree(*reg_s); - *reg_s = NULL; - *size = 0; -} - -int msm_camera_hw_write_dt_reg_settings(void __iomem *base, - uint32_t *reg_s, - unsigned int size) -{ - int32_t rc = 0; - - if (!reg_s || !base || !size) { - pr_err("%s: Error invalid args\n", __func__); - return -EINVAL; - } - rc = msm_camera_io_w_reg_block((const u32 *) reg_s, - base, size); - if (rc < 0) - pr_err("%s: Failed dt reg setting write\n", __func__); - return rc; -} diff --git a/drivers/media/platform/msm/ais/common/msm_camera_io_util.h b/drivers/media/platform/msm/ais/common/msm_camera_io_util.h deleted file mode 100644 index 338e24d45500ed4fb33d92026441f4753ce3f7be..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/common/msm_camera_io_util.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_CAMERA_IO_UTIL_H -#define __MSM_CAMERA_IO_UTIL_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#define NO_SET_RATE -1 -#define INIT_RATE -2 - -struct msm_gpio_set_tbl { - unsigned gpio; - unsigned long flags; - uint32_t delay; -}; - -struct msm_cam_dump_string_info { - const char *print; - uint32_t offset; -}; - -void msm_camera_io_w(u32 data, void __iomem *addr); -void msm_camera_io_w_mb(u32 data, void __iomem *addr); -u32 msm_camera_io_r(void __iomem *addr); -u32 msm_camera_io_r_mb(void __iomem *addr); -void msm_camera_io_dump(void __iomem *addr, int size, int enable); -void msm_camera_io_memcpy(void __iomem *dest_addr, - void __iomem *src_addr, u32 len); -void msm_camera_io_memcpy_mb(void __iomem *dest_addr, - void __iomem *src_addr, u32 len); -int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, - struct msm_cam_clk_info *clk_src_info, int num_clk); -int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, - struct clk **clk_ptr, int num_clk, int enable); - -int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int config); -int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int enable); - -void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, - enum msm_bus_perf_setting perf_setting); - -int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, - uint8_t gpio_tbl_size, int gpio_en); - -void msm_camera_config_single_gpio(uint16_t gpio, unsigned long flags, - int gpio_en); - -int msm_camera_config_single_vreg(struct device *dev, - struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config); - -int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, - int gpio_en); -void msm_camera_io_dump_wstring_base(void __iomem *addr, - struct msm_cam_dump_string_info *dump_data, - int size); -int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data, - u32 bmask, u32 retry, unsigned long min_usecs, - unsigned long max_usecs); -int32_t msm_camera_io_poll_value(void __iomem *addr, u32 wait_data, u32 retry, - unsigned long min_usecs, unsigned long max_usecs); -int32_t msm_camera_io_w_block(const u32 *addr, void __iomem *base, u32 len); -int32_t msm_camera_io_w_reg_block(const u32 *addr, void __iomem *base, u32 len); -int32_t msm_camera_io_w_mb_block(const u32 *addr, void __iomem *base, u32 len); -int msm_camera_get_dt_reg_settings(struct device_node *of_node, - const char *dt_prop_name, uint32_t **reg_s, - unsigned int *size); -void msm_camera_put_dt_reg_settings(uint32_t **reg_s, - unsigned int *size); -int msm_camera_hw_write_dt_reg_settings(void __iomem *base, - uint32_t *reg_s, - unsigned int size); -#endif diff --git a/drivers/media/platform/msm/ais/fd/Makefile b/drivers/media/platform/msm/ais/fd/Makefile deleted file mode 100644 index 6a5e9edc373655af0250424f4e9c29f22418758d..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/fd/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) -ccflags-y += -Idrivers/media/video/msm -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/pproc/cpp -ccflags-y += -Idrivers/media/platform/msm/ais/msm_buf_mgr/ - -obj-$(CONFIG_MSM_AIS_FD) += msm_fd_dev.o msm_fd_hw.o diff --git a/drivers/media/platform/msm/ais/fd/msm_fd_dev.c b/drivers/media/platform/msm/ais/fd/msm_fd_dev.c deleted file mode 100644 index 5d416e14c8132bf47e450d6c773349cf4b9dffbb..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/fd/msm_fd_dev.c +++ /dev/null @@ -1,1467 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_fd_dev.h" -#include "msm_fd_hw.h" -#include "msm_fd_regs.h" - -#define MSM_FD_DRV_NAME "msm_fd" - -#define MSM_FD_WORD_SIZE_BYTES 4 - -/* Face detection thresholds definitions */ -#define MSM_FD_DEF_THRESHOLD 5 -#define MSM_FD_MAX_THRESHOLD_VALUE 9 - -/* Face angle lookup table */ -#define MSM_FD_DEF_ANGLE_IDX 2 -static int msm_fd_angle[] = {45, 135, 359}; - -/* Face direction lookup table */ -#define MSM_FD_DEF_DIR_IDX 0 -static int msm_fd_dir[] = {0, 90, 270, 180}; - -/* Minimum face size lookup table */ -#define MSM_FD_DEF_MIN_SIZE_IDX 0 -static int msm_fd_min_size[] = {20, 25, 32, 40}; - -/* Face detection size lookup table */ -static struct msm_fd_size fd_size[] = { - { - .width = 320, - .height = 240, - .reg_val = MSM_FD_IMAGE_SIZE_QVGA, - .work_size = (13120 * MSM_FD_WORD_SIZE_BYTES), - }, - { - .width = 427, - .height = 240, - .reg_val = MSM_FD_IMAGE_SIZE_WQVGA, - .work_size = (17744 * MSM_FD_WORD_SIZE_BYTES), - }, - { - .width = 640, - .height = 480, - .reg_val = MSM_FD_IMAGE_SIZE_VGA, - .work_size = (52624 * MSM_FD_WORD_SIZE_BYTES), - }, - { - .width = 854, - .height = 480, - .reg_val = MSM_FD_IMAGE_SIZE_WVGA, - .work_size = (70560 * MSM_FD_WORD_SIZE_BYTES), - }, -}; - -/* - * msm_fd_ctx_from_fh - Get fd context from v4l2 fh. - * @fh: Pointer to v4l2 fh. - */ -static inline struct fd_ctx *msm_fd_ctx_from_fh(struct v4l2_fh *fh) -{ - return container_of(fh, struct fd_ctx, fh); -} - -/* - * msm_fd_get_format_index - Get format index from v4l2 format. - * @f: Pointer to v4l2 format struct. - */ -static int msm_fd_get_format_index(struct v4l2_format *f) -{ - int index; - - for (index = 0; index < ARRAY_SIZE(fd_size); index++) { - if (f->fmt.pix.width <= fd_size[index].width && - f->fmt.pix.height <= fd_size[index].height) - return index; - } - return index - 1; -} - -/* - * msm_fd_get_idx_from_value - Get array index from value. - * @value: Value for which index is needed. - * @array: Array in which index is searched for. - * @array_size: Array size. - */ -static int msm_fd_get_idx_from_value(int value, int *array, int array_size) -{ - int index; - int i; - - index = 0; - for (i = 1; i < array_size; i++) { - if (value == array[i]) { - index = i; - break; - } - if (abs(value - array[i]) < abs(value - array[index])) - index = i; - } - return index; -} - -/* - * msm_fd_fill_format_from_index - Fill v4l2 format struct from size index. - * @f: Pointer of v4l2 struct which will be filled. - * @index: Size index (Format will be filled based on this index). - */ -static int msm_fd_fill_format_from_index(struct v4l2_format *f, int index) -{ - f->fmt.pix.width = fd_size[index].width; - f->fmt.pix.height = fd_size[index].height; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; - if (f->fmt.pix.bytesperline < f->fmt.pix.width) - f->fmt.pix.bytesperline = f->fmt.pix.width; - - f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline, 16); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; - f->fmt.pix.field = V4L2_FIELD_NONE; - - return 0; -} - -/* - * msm_fd_fill_format_from_ctx - Fill v4l2 format struct from fd context. - * @f: Pointer of v4l2 struct which will be filled. - * @c: Pointer to fd context. - */ -static int msm_fd_fill_format_from_ctx(struct v4l2_format *f, struct fd_ctx *c) -{ - if (NULL == c->format.size) - return -EINVAL; - - f->fmt.pix.width = c->format.size->width; - f->fmt.pix.height = c->format.size->height; - f->fmt.pix.pixelformat = c->format.pixelformat; - f->fmt.pix.bytesperline = c->format.bytesperline; - f->fmt.pix.sizeimage = c->format.sizeimage; - f->fmt.pix.field = V4L2_FIELD_NONE; - - return 0; -} - -/* - * msm_fd_queue_setup - vb2_ops queue_setup callback. - * @q: Pointer to vb2 queue struct. - * @fmt: Pointer to v4l2 format struct (NULL is valid argument). - * @num_buffers: Pointer of number of buffers requested. - * @num_planes: Pointer to number of planes requested. - * @sizes: Array containing sizes of planes. - * @alloc_ctxs: Array of allocated contexts for each plane. - */ -static int msm_fd_queue_setup(struct vb2_queue *q, - const struct v4l2_format *fmt, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct fd_ctx *ctx = vb2_get_drv_priv(q); - - *num_planes = 1; - - if (NULL == fmt) - sizes[0] = ctx->format.sizeimage; - else - sizes[0] = fmt->fmt.pix.sizeimage; - - alloc_ctxs[0] = &ctx->mem_pool; - - return 0; -} - -/* - * msm_fd_buf_init - vb2_ops buf_init callback. - * @vb: Pointer to vb2 buffer struct. - */ -int msm_fd_buf_init(struct vb2_buffer *vb) -{ - struct msm_fd_buffer *fd_buffer = - (struct msm_fd_buffer *)vb; - - INIT_LIST_HEAD(&fd_buffer->list); - atomic_set(&fd_buffer->active, 0); - - return 0; -} - -/* - * msm_fd_buf_queue - vb2_ops buf_queue callback. - * @vb: Pointer to vb2 buffer struct. - */ -static void msm_fd_buf_queue(struct vb2_buffer *vb) -{ - struct fd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct msm_fd_buffer *fd_buffer = - (struct msm_fd_buffer *)vb; - - fd_buffer->format = ctx->format; - fd_buffer->settings = ctx->settings; - fd_buffer->work_addr = ctx->work_buf.addr; - msm_fd_hw_add_buffer(ctx->fd_device, fd_buffer); - - if (vb->vb2_queue->streaming) - msm_fd_hw_schedule_and_start(ctx->fd_device); -} - -/* - * msm_fd_start_streaming - vb2_ops start_streaming callback. - * @q: Pointer to vb2 queue struct. - * @count: Number of buffer queued before stream on call. - */ -static int msm_fd_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct fd_ctx *ctx = vb2_get_drv_priv(q); - int ret; - - if (ctx->work_buf.fd == -1) { - dev_err(ctx->fd_device->dev, "Missing working buffer\n"); - return -EINVAL; - } - - ret = msm_fd_hw_get(ctx->fd_device, ctx->settings.speed); - if (ret < 0) { - dev_err(ctx->fd_device->dev, "Can not acquire fd hw\n"); - goto out; - } - - ret = msm_fd_hw_schedule_and_start(ctx->fd_device); - if (ret < 0) - dev_err(ctx->fd_device->dev, "Can not start fd hw\n"); - -out: - return ret; -} - -/* - * msm_fd_stop_streaming - vb2_ops stop_streaming callback. - * @q: Pointer to vb2 queue struct. - */ -static void msm_fd_stop_streaming(struct vb2_queue *q) -{ - struct fd_ctx *ctx = vb2_get_drv_priv(q); - - mutex_lock(&ctx->fd_device->recovery_lock); - msm_fd_hw_remove_buffers_from_queue(ctx->fd_device, q); - msm_fd_hw_put(ctx->fd_device); - mutex_unlock(&ctx->fd_device->recovery_lock); -} - -/* Videobuf2 queue callbacks. */ -static struct vb2_ops msm_fd_vb2_q_ops = { - .queue_setup = msm_fd_queue_setup, - .buf_init = msm_fd_buf_init, - .buf_queue = msm_fd_buf_queue, - .start_streaming = msm_fd_start_streaming, - .stop_streaming = msm_fd_stop_streaming, -}; - -/* - * msm_fd_get_userptr - Map and get buffer handler for user pointer buffer. - * @alloc_ctx: Contexts allocated in buf_setup. - * @vaddr: Virtual addr passed from userpsace (in our case ion fd) - * @size: Size of the buffer - * @write: True if buffer will be used for writing the data. - */ -static void *msm_fd_get_userptr(void *alloc_ctx, - unsigned long vaddr, unsigned long size, int write) -{ - struct msm_fd_mem_pool *pool = alloc_ctx; - struct msm_fd_buf_handle *buf; - int ret; - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - ret = msm_fd_hw_map_buffer(pool, vaddr, buf); - if (ret < 0 || buf->size < size) - goto error; - - return buf; -error: - kzfree(buf); - return ERR_PTR(-ENOMEM); -} - -/* - * msm_fd_put_userptr - Unmap and free buffer handler. - * @buf_priv: Buffer handler allocated get_userptr callback. - */ -static void msm_fd_put_userptr(void *buf_priv) -{ - if (IS_ERR_OR_NULL(buf_priv)) - return; - - msm_fd_hw_unmap_buffer(buf_priv); - - kzfree(buf_priv); -} - -/* Videobuf2 memory callbacks. */ -static struct vb2_mem_ops msm_fd_vb2_mem_ops = { - .get_userptr = msm_fd_get_userptr, - .put_userptr = msm_fd_put_userptr, -}; - -/* - * msm_fd_vbif_error_handler - FD VBIF Error handler - * @handle: FD Device handle - * @error: CPP-VBIF Error code - */ -static int msm_fd_vbif_error_handler(void *handle, uint32_t error) -{ - struct fd_ctx *ctx; - struct msm_fd_device *fd; - struct msm_fd_buffer *active_buf; - int ret; - - if (NULL == handle) { - dev_err(fd->dev, "FD Ctx is null, Cannot recover\n"); - return 0; - } - ctx = (struct fd_ctx *)handle; - fd = (struct msm_fd_device *)ctx->fd_device; - - if (error == CPP_VBIF_ERROR_HANG) { - mutex_lock(&fd->recovery_lock); - dev_err(fd->dev, "Handling FD VBIF Hang\n"); - if (fd->state != MSM_FD_DEVICE_RUNNING) { - dev_err(fd->dev, "FD is not FD_DEVICE_RUNNING, %d\n", - fd->state); - mutex_unlock(&fd->recovery_lock); - return 0; - } - fd->recovery_mode = 1; - - /* Halt and reset */ - msm_fd_hw_put(fd); - msm_fd_hw_get(fd, ctx->settings.speed); - - /* Get active buffer */ - active_buf = msm_fd_hw_get_active_buffer(fd); - - if (active_buf == NULL) { - dev_dbg(fd->dev, "no active buffer, return\n"); - fd->recovery_mode = 0; - mutex_unlock(&fd->recovery_lock); - return 0; - } - - dev_dbg(fd->dev, "Active Buffer present.. Start re-schedule\n"); - - /* Queue the buffer again */ - msm_fd_hw_add_buffer(fd, active_buf); - - /* Schedule and restart */ - ret = msm_fd_hw_schedule_next_buffer(fd); - if (ret) { - dev_err(fd->dev, "Cannot reschedule buffer, recovery failed\n"); - fd->recovery_mode = 0; - mutex_unlock(&fd->recovery_lock); - return ret; - } - dev_dbg(fd->dev, "Restarted FD after VBIF HAng\n"); - mutex_unlock(&fd->recovery_lock); - } - return 0; -} - -/* - * msm_fd_open - Fd device open method. - * @file: Pointer to file struct. - */ -static int msm_fd_open(struct file *file) -{ - struct msm_fd_device *device = video_drvdata(file); - struct video_device *video = video_devdata(file); - struct fd_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->fd_device = device; - - /* Initialize work buffer handler */ - ctx->work_buf.pool = NULL; - ctx->work_buf.fd = -1; - - /* Set ctx defaults */ - ctx->settings.speed = ctx->fd_device->clk_rates_num - 1; - ctx->settings.angle_index = MSM_FD_DEF_ANGLE_IDX; - ctx->settings.direction_index = MSM_FD_DEF_DIR_IDX; - ctx->settings.min_size_index = MSM_FD_DEF_MIN_SIZE_IDX; - ctx->settings.threshold = MSM_FD_DEF_THRESHOLD; - - atomic_set(&ctx->subscribed_for_event, 0); - - v4l2_fh_init(&ctx->fh, video); - - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - - ctx->vb2_q.drv_priv = ctx; - ctx->vb2_q.mem_ops = &msm_fd_vb2_mem_ops; - ctx->vb2_q.ops = &msm_fd_vb2_q_ops; - ctx->vb2_q.buf_struct_size = sizeof(struct msm_fd_buffer); - ctx->vb2_q.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ctx->vb2_q.io_modes = VB2_USERPTR; - ctx->vb2_q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - mutex_init(&ctx->lock); - ret = vb2_queue_init(&ctx->vb2_q); - if (ret < 0) { - dev_err(device->dev, "Error queue init\n"); - goto error_vb2_queue_init; - } - - ctx->mem_pool.fd_device = ctx->fd_device; - ctx->stats = vmalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS); - if (!ctx->stats) { - dev_err(device->dev, "No memory for face statistics\n"); - ret = -ENOMEM; - goto error_stats_vmalloc; - } - - ret = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_FD, - CAM_AHB_SVS_VOTE); - if (ret < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - goto error_ahb_config; - } - - /* Register with CPP VBIF error handler */ - msm_cpp_vbif_register_error_handler((void *)ctx, - VBIF_CLIENT_FD, msm_fd_vbif_error_handler); - - return 0; - -error_ahb_config: - vfree(ctx->stats); -error_stats_vmalloc: - vb2_queue_release(&ctx->vb2_q); -error_vb2_queue_init: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); - return ret; -} - -/* - * msm_fd_release - Fd device release method. - * @file: Pointer to file struct. - */ -static int msm_fd_release(struct file *file) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data); - - /* Un-register with CPP VBIF error handler */ - msm_cpp_vbif_register_error_handler((void *)ctx, - VBIF_CLIENT_FD, NULL); - - mutex_lock(&ctx->lock); - vb2_queue_release(&ctx->vb2_q); - mutex_unlock(&ctx->lock); - - vfree(ctx->stats); - - if (ctx->work_buf.fd != -1) - msm_fd_hw_unmap_buffer(&ctx->work_buf); - - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - - kfree(ctx); - - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_FD, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - - return 0; -} - -/* - * msm_fd_poll - Fd device pool method. - * @file: Pointer to file struct. - * @wait: Pointer to pool table struct. - */ -static unsigned int msm_fd_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data); - unsigned int ret; - - mutex_lock(&ctx->lock); - ret = vb2_poll(&ctx->vb2_q, file, wait); - mutex_unlock(&ctx->lock); - - if (atomic_read(&ctx->subscribed_for_event)) { - poll_wait(file, &ctx->fh.wait, wait); - if (v4l2_event_pending(&ctx->fh)) - ret |= POLLPRI; - } - - return ret; -} - -/* - * msm_fd_private_ioctl - V4l2 private ioctl handler. - * @file: Pointer to file struct. - * @fd: V4l2 device file handle. - * @valid_prio: Priority ioctl valid flag. - * @cmd: Ioctl command. - * @arg: Ioctl argument. - */ -static long msm_fd_private_ioctl(struct file *file, void *fh, - bool valid_prio, unsigned int cmd, void *arg) -{ - struct msm_fd_result *req_result = arg; - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - struct msm_fd_stats *stats; - int stats_idx; - int ret = 0; - int i; - - switch (cmd) { - case VIDIOC_MSM_FD_GET_RESULT: - if (req_result->frame_id == 0) { - dev_err(ctx->fd_device->dev, "Invalid frame id\n"); - return -EINVAL; - } - - stats_idx = req_result->frame_id % MSM_FD_MAX_RESULT_BUFS; - stats = &ctx->stats[stats_idx]; - if (req_result->frame_id != atomic_read(&stats->frame_id)) { - dev_err(ctx->fd_device->dev, "Stats not available\n"); - return -EINVAL; - } - - if (req_result->face_cnt > stats->face_cnt) - req_result->face_cnt = stats->face_cnt; - - for (i = 0; i < req_result->face_cnt; i++) { - ret = copy_to_user((void __user *) - &req_result->face_data[i], - &stats->face_data[i], - sizeof(struct msm_fd_face_data)); - if (ret) { - dev_err(ctx->fd_device->dev, "Copy to user\n"); - return -EFAULT; - } - } - - if (req_result->frame_id != atomic_read(&stats->frame_id)) { - dev_err(ctx->fd_device->dev, "Erroneous buffer\n"); - return -EINVAL; - } - break; - default: - dev_err(ctx->fd_device->dev, "Wrong ioctl type %x\n", cmd); - ret = -ENOTTY; - break; - } - - return ret; -} - -#ifdef CONFIG_COMPAT -/* - * msm_fd_compat_ioctl32 - Compat ioctl handler function. - * @file: Pointer to file struct. - * @cmd: Ioctl command. - * @arg: Ioctl argument. - */ -static long msm_fd_compat_ioctl32(struct file *file, - unsigned int cmd, unsigned long arg) -{ - long ret; - - switch (cmd) { - case VIDIOC_MSM_FD_GET_RESULT32: - { - struct msm_fd_result32 result32; - struct msm_fd_result result; - - if (copy_from_user(&result32, (void __user *)arg, - sizeof(result32))) - return -EFAULT; - - result.frame_id = result32.frame_id; - result.face_cnt = result32.face_cnt; - result.face_data = compat_ptr(result32.face_data); - - ret = msm_fd_private_ioctl(file, file->private_data, - 0, VIDIOC_MSM_FD_GET_RESULT, (void *)&result); - - result32.frame_id = result.frame_id; - result32.face_cnt = result.face_cnt; - - if (copy_to_user((void __user *)arg, &result32, - sizeof(result32))) - return -EFAULT; - - break; - } - default: - ret = -ENOIOCTLCMD; - break; - - } - - return ret; -} -#endif - -/* Fd device file operations callbacks */ -static const struct v4l2_file_operations fd_fops = { - .owner = THIS_MODULE, - .open = msm_fd_open, - .release = msm_fd_release, - .poll = msm_fd_poll, - .unlocked_ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - .compat_ioctl32 = msm_fd_compat_ioctl32, -#endif -}; - -/* - * msm_fd_querycap - V4l2 ioctl query capability handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @cap: Pointer to v4l2_capability struct need to be filled. - */ -static int msm_fd_querycap(struct file *file, - void *fh, struct v4l2_capability *cap) -{ - cap->bus_info[0] = 0; - strlcpy(cap->driver, MSM_FD_DRV_NAME, sizeof(cap->driver)); - strlcpy(cap->card, MSM_FD_DRV_NAME, sizeof(cap->card)); - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT; - - return 0; -} - -/* - * msm_fd_enum_fmt_vid_out - V4l2 ioctl enumerate format handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @f: Pointer to v4l2_fmtdesc struct need to be filled. - */ -static int msm_fd_enum_fmt_vid_out(struct file *file, - void *fh, struct v4l2_fmtdesc *f) -{ - if (f->index > 0) - return -EINVAL; - - f->pixelformat = V4L2_PIX_FMT_GREY; - strlcpy(f->description, "8 Greyscale", - sizeof(f->description)); - - return 0; -} - -/* - * msm_fd_g_fmt - V4l2 ioctl get format handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @f: Pointer to v4l2_format struct need to be filled. - */ -static int msm_fd_g_fmt(struct file *file, void *fh, struct v4l2_format *f) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - return msm_fd_fill_format_from_ctx(f, ctx); -} - -/* - * msm_fd_try_fmt_vid_out - V4l2 ioctl try format handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @f: Pointer to v4l2_format struct. - */ -static int msm_fd_try_fmt_vid_out(struct file *file, - void *fh, struct v4l2_format *f) -{ - int index; - - index = msm_fd_get_format_index(f); - - return msm_fd_fill_format_from_index(f, index); -} - -/* - * msm_fd_s_fmt_vid_out - V4l2 ioctl set format handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @f: Pointer to v4l2_format struct. - */ -static int msm_fd_s_fmt_vid_out(struct file *file, - void *fh, struct v4l2_format *f) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - int index; - - index = msm_fd_get_format_index(f); - - msm_fd_fill_format_from_index(f, index); - - ctx->format.size = &fd_size[index]; - ctx->format.pixelformat = f->fmt.pix.pixelformat; - ctx->format.bytesperline = f->fmt.pix.bytesperline; - ctx->format.sizeimage = f->fmt.pix.sizeimage; - - /* Initialize crop */ - ctx->format.crop.top = 0; - ctx->format.crop.left = 0; - ctx->format.crop.width = fd_size[index].width; - ctx->format.crop.height = fd_size[index].height; - - return 0; -} - -/* - * msm_fd_reqbufs - V4l2 ioctl request buffers handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @req: Pointer to v4l2_requestbuffer struct. - */ -static int msm_fd_reqbufs(struct file *file, - void *fh, struct v4l2_requestbuffers *req) -{ - int ret; - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - mutex_lock(&ctx->lock); - ret = vb2_reqbufs(&ctx->vb2_q, req); - mutex_unlock(&ctx->lock); - return ret; -} - -/* - * msm_fd_qbuf - V4l2 ioctl queue buffer handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @pb: Pointer to v4l2_buffer struct. - */ -static int msm_fd_qbuf(struct file *file, void *fh, - struct v4l2_buffer *pb) -{ - int ret; - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - mutex_lock(&ctx->lock); - ret = vb2_qbuf(&ctx->vb2_q, pb); - mutex_unlock(&ctx->lock); - return ret; - -} - -/* - * msm_fd_dqbuf - V4l2 ioctl dequeue buffer handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @pb: Pointer to v4l2_buffer struct. - */ -static int msm_fd_dqbuf(struct file *file, - void *fh, struct v4l2_buffer *pb) -{ - int ret; - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - mutex_lock(&ctx->lock); - ret = vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK); - mutex_unlock(&ctx->lock); - return ret; -} - -/* - * msm_fd_streamon - V4l2 ioctl stream on handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @buf_type: V4l2 buffer type. - */ -static int msm_fd_streamon(struct file *file, - void *fh, enum v4l2_buf_type buf_type) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - int ret; - - mutex_lock(&ctx->lock); - ret = vb2_streamon(&ctx->vb2_q, buf_type); - mutex_unlock(&ctx->lock); - if (ret < 0) - dev_err(ctx->fd_device->dev, "Stream on fails\n"); - - return ret; -} - -/* - * msm_fd_streamoff - V4l2 ioctl stream off handler. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @buf_type: V4l2 buffer type. - */ -static int msm_fd_streamoff(struct file *file, - void *fh, enum v4l2_buf_type buf_type) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - int ret; - - mutex_lock(&ctx->lock); - ret = vb2_streamoff(&ctx->vb2_q, buf_type); - mutex_unlock(&ctx->lock); - if (ret < 0) - dev_err(ctx->fd_device->dev, "Stream off fails\n"); - - return ret; -} - -/* - * msm_fd_subscribe_event - V4l2 ioctl subscribe for event handler. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_event_subscription containing event information. - */ -static int msm_fd_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - int ret; - - if (sub->type != MSM_EVENT_FD) - return -EINVAL; - - ret = v4l2_event_subscribe(fh, sub, MSM_FD_MAX_RESULT_BUFS, NULL); - if (!ret) - atomic_set(&ctx->subscribed_for_event, 1); - - return ret; -} - -/* - * msm_fd_unsubscribe_event - V4l2 ioctl unsubscribe from event handler. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_event_subscription containing event information. - */ -static int msm_fd_unsubscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - int ret; - - ret = v4l2_event_unsubscribe(fh, sub); - if (!ret) - atomic_set(&ctx->subscribed_for_event, 0); - - return ret; -} - -/* - * msm_fd_guery_ctrl - V4l2 ioctl query control. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_queryctrl struct info need to be filled based on id. - */ -static int msm_fd_guery_ctrl(struct file *file, void *fh, - struct v4l2_queryctrl *a) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - switch (a->id) { - case V4L2_CID_FD_SPEED: - a->type = V4L2_CTRL_TYPE_INTEGER; - a->default_value = ctx->fd_device->clk_rates_num; - a->minimum = 0; - a->maximum = ctx->fd_device->clk_rates_num; - a->step = 1; - strlcpy(a->name, "msm fd face speed idx", - sizeof(a->name)); - break; - case V4L2_CID_FD_FACE_ANGLE: - a->type = V4L2_CTRL_TYPE_INTEGER; - a->default_value = msm_fd_angle[MSM_FD_DEF_ANGLE_IDX]; - a->minimum = msm_fd_angle[0]; - a->maximum = msm_fd_angle[ARRAY_SIZE(msm_fd_angle) - 1]; - a->step = 1; - strlcpy(a->name, "msm fd face angle ctrl", - sizeof(a->name)); - break; - case V4L2_CID_FD_FACE_DIRECTION: - a->type = V4L2_CTRL_TYPE_INTEGER; - a->default_value = msm_fd_dir[MSM_FD_DEF_DIR_IDX]; - a->minimum = msm_fd_dir[0]; - a->maximum = msm_fd_dir[ARRAY_SIZE(msm_fd_dir) - 1]; - a->step = 1; - strlcpy(a->name, "msm fd face direction ctrl", - sizeof(a->name)); - break; - case V4L2_CID_FD_MIN_FACE_SIZE: - a->type = V4L2_CTRL_TYPE_INTEGER; - a->default_value = msm_fd_min_size[MSM_FD_DEF_MIN_SIZE_IDX]; - a->minimum = msm_fd_min_size[0]; - a->maximum = msm_fd_min_size[ARRAY_SIZE(msm_fd_min_size) - 1]; - a->step = 1; - strlcpy(a->name, "msm fd minimum face size (pixels)", - sizeof(a->name)); - break; - case V4L2_CID_FD_DETECTION_THRESHOLD: - a->type = V4L2_CTRL_TYPE_INTEGER; - a->default_value = MSM_FD_DEF_THRESHOLD; - a->minimum = 0; - a->maximum = MSM_FD_MAX_THRESHOLD_VALUE; - a->step = 1; - strlcpy(a->name, "msm fd detection threshold", - sizeof(a->name)); - break; - case V4L2_CID_FD_WORK_MEMORY_SIZE: - a->type = V4L2_CTRL_TYPE_INTEGER; - a->default_value = fd_size[0].work_size; - a->minimum = fd_size[(ARRAY_SIZE(fd_size) - 1)].work_size; - a->maximum = fd_size[0].work_size; - a->step = 1; - strlcpy(a->name, "msm fd working memory size", - sizeof(a->name)); - break; - case V4L2_CID_FD_WORK_MEMORY_FD: - a->type = V4L2_CTRL_TYPE_INTEGER; - a->default_value = -1; - a->minimum = 0; - a->maximum = INT_MAX; - a->step = 1; - strlcpy(a->name, "msm fd ion fd of working memory", - sizeof(a->name)); - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * msm_fd_g_ctrl - V4l2 ioctl get control. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_queryctrl struct need to be filled. - */ -static int msm_fd_g_ctrl(struct file *file, void *fh, struct v4l2_control *a) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - switch (a->id) { - case V4L2_CID_FD_SPEED: - a->value = ctx->settings.speed; - break; - case V4L2_CID_FD_FACE_ANGLE: - a->value = msm_fd_angle[ctx->settings.angle_index]; - break; - case V4L2_CID_FD_FACE_DIRECTION: - a->value = msm_fd_dir[ctx->settings.direction_index]; - break; - case V4L2_CID_FD_MIN_FACE_SIZE: - a->value = msm_fd_min_size[ctx->settings.min_size_index]; - break; - case V4L2_CID_FD_DETECTION_THRESHOLD: - a->value = ctx->settings.threshold; - break; - case V4L2_CID_FD_WORK_MEMORY_SIZE: - if (!ctx->format.size) - return -EINVAL; - - a->value = ctx->format.size->work_size; - break; - case V4L2_CID_FD_WORK_MEMORY_FD: - if (ctx->work_buf.fd == -1) - return -EINVAL; - - a->value = ctx->work_buf.fd; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * msm_fd_s_ctrl - V4l2 ioctl set control. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_queryctrl struct need to be set. - */ -static int msm_fd_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - int idx; - int ret; - - switch (a->id) { - case V4L2_CID_FD_SPEED: - if (a->value > ctx->fd_device->clk_rates_num - 1) - a->value = ctx->fd_device->clk_rates_num - 1; - else if (a->value < 0) - a->value = 0; - - ctx->settings.speed = a->value; - break; - case V4L2_CID_FD_FACE_ANGLE: - idx = msm_fd_get_idx_from_value(a->value, msm_fd_angle, - ARRAY_SIZE(msm_fd_angle)); - - ctx->settings.angle_index = idx; - a->value = msm_fd_angle[ctx->settings.angle_index]; - break; - case V4L2_CID_FD_FACE_DIRECTION: - idx = msm_fd_get_idx_from_value(a->value, msm_fd_dir, - ARRAY_SIZE(msm_fd_dir)); - - ctx->settings.direction_index = idx; - a->value = msm_fd_dir[ctx->settings.direction_index]; - break; - case V4L2_CID_FD_MIN_FACE_SIZE: - idx = msm_fd_get_idx_from_value(a->value, msm_fd_min_size, - ARRAY_SIZE(msm_fd_min_size)); - - ctx->settings.min_size_index = idx; - a->value = msm_fd_min_size[ctx->settings.min_size_index]; - break; - case V4L2_CID_FD_DETECTION_THRESHOLD: - if (a->value > MSM_FD_MAX_THRESHOLD_VALUE) - a->value = MSM_FD_MAX_THRESHOLD_VALUE; - else if (a->value < 0) - a->value = 0; - - ctx->settings.threshold = a->value; - break; - case V4L2_CID_FD_WORK_MEMORY_SIZE: - if (!ctx->format.size) - return -EINVAL; - - if (a->value < ctx->format.size->work_size) - a->value = ctx->format.size->work_size; - break; - case V4L2_CID_FD_WORK_MEMORY_FD: - mutex_lock(&ctx->fd_device->recovery_lock); - if (ctx->work_buf.fd != -1) - msm_fd_hw_unmap_buffer(&ctx->work_buf); - if (a->value >= 0) { - ret = msm_fd_hw_map_buffer(&ctx->mem_pool, - a->value, &ctx->work_buf); - if (ret < 0) { - mutex_unlock(&ctx->fd_device->recovery_lock); - return ret; - } - } - mutex_unlock(&ctx->fd_device->recovery_lock); - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * msm_fd_cropcap - V4l2 ioctl crop capabilities. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_cropcap struct need to be set. - */ -static int msm_fd_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - if (!ctx->format.size) { - dev_err(ctx->fd_device->dev, "Cropcap fails format missing\n"); - return -EINVAL; - } - - a->bounds.top = 0; - a->bounds.left = 0; - a->bounds.width = ctx->format.size->width; - a->bounds.height = ctx->format.size->height; - - a->defrect = ctx->format.crop; - - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -/* - * msm_fd_g_crop - V4l2 ioctl get crop. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_crop struct need to be set. - */ -static int msm_fd_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - - if (!ctx->format.size) { - dev_err(ctx->fd_device->dev, "Get crop, format missing!\n"); - return -EINVAL; - } - - crop->c = ctx->format.crop; - - return 0; -} - -/* - * msm_fd_s_crop - V4l2 ioctl set crop. - * @file: Pointer to file struct. - * @fh: V4l2 File handle. - * @sub: Pointer to v4l2_crop struct need to be set. - */ -static int msm_fd_s_crop(struct file *file, void *fh, - const struct v4l2_crop *crop) -{ - struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - int min_face_size; - - if (!ctx->format.size) { - dev_err(ctx->fd_device->dev, "Get crop, format missing!\n"); - return -EINVAL; - } - - /* First check that crop is valid */ - min_face_size = msm_fd_min_size[ctx->settings.min_size_index]; - - if (crop->c.width < min_face_size || crop->c.height < min_face_size) - return -EINVAL; - - if (crop->c.width + crop->c.left > ctx->format.size->width) - return -EINVAL; - - if (crop->c.height + crop->c.top > ctx->format.size->height) - return -EINVAL; - - ctx->format.crop = crop->c; - - return 0; -} - -/* V4l2 ioctl handlers */ -static const struct v4l2_ioctl_ops fd_ioctl_ops = { - .vidioc_querycap = msm_fd_querycap, - .vidioc_enum_fmt_vid_out = msm_fd_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = msm_fd_g_fmt, - .vidioc_try_fmt_vid_out = msm_fd_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = msm_fd_s_fmt_vid_out, - .vidioc_reqbufs = msm_fd_reqbufs, - .vidioc_qbuf = msm_fd_qbuf, - .vidioc_dqbuf = msm_fd_dqbuf, - .vidioc_streamon = msm_fd_streamon, - .vidioc_streamoff = msm_fd_streamoff, - .vidioc_queryctrl = msm_fd_guery_ctrl, - .vidioc_s_ctrl = msm_fd_s_ctrl, - .vidioc_g_ctrl = msm_fd_g_ctrl, - .vidioc_cropcap = msm_fd_cropcap, - .vidioc_g_crop = msm_fd_g_crop, - .vidioc_s_crop = msm_fd_s_crop, - .vidioc_subscribe_event = msm_fd_subscribe_event, - .vidioc_unsubscribe_event = msm_fd_unsubscribe_event, - .vidioc_default = msm_fd_private_ioctl, -}; - -/* - * msm_fd_fill_results - Read and fill face detection result. - * @fd: Pointer to fd device. - * @face: Pointer of face data which information need to be stored. - * @idx: Face number index need to be filled. - */ -static void msm_fd_fill_results(struct msm_fd_device *fd, - struct msm_fd_face_data *face, int idx) -{ - int half_face_size; - - msm_fd_hw_get_result_angle_pose(fd, idx, &face->angle, &face->pose); - - msm_fd_hw_get_result_conf_size(fd, idx, &face->confidence, - &face->face.width); - face->face.height = face->face.width; - - face->face.left = msm_fd_hw_get_result_x(fd, idx); - face->face.top = msm_fd_hw_get_result_y(fd, idx); - - half_face_size = (face->face.width >> 1); - if (face->face.left > half_face_size) - face->face.left -= half_face_size; - else - face->face.left = 0; - - half_face_size = (face->face.height >> 1); - if (face->face.top > half_face_size) - face->face.top -= half_face_size; - else - face->face.top = 0; -} - -/* - * msm_fd_wq_handler - Fd device workqueue handler. - * @work: Pointer to work struct. - * - * This function is bottom half of fd irq what it does: - * - * - Stop the fd engine. - * - Getter fd result and store in stats buffer. - * - If available schedule next buffer for processing. - * - Sent event to v4l2. - * - Release buffer from v4l2 queue. - */ -static void msm_fd_wq_handler(struct work_struct *work) -{ - struct msm_fd_buffer *active_buf; - struct msm_fd_stats *stats; - struct msm_fd_event *fd_event; - struct msm_fd_device *fd; - struct fd_ctx *ctx; - struct v4l2_event event; - int i; - - fd = container_of(work, struct msm_fd_device, work); - - active_buf = msm_fd_hw_get_active_buffer(fd); - if (!active_buf) { - /* This should never happen, something completely wrong */ - dev_err(fd->dev, "Oops no active buffer empty queue\n"); - return; - } - ctx = vb2_get_drv_priv(active_buf->vb.vb2_queue); - - /* Increment sequence number, 0 means sequence is not valid */ - ctx->sequence++; - if (unlikely(!ctx->sequence)) - ctx->sequence = 1; - - /* Fill face detection statistics */ - stats = &ctx->stats[ctx->sequence % MSM_FD_MAX_RESULT_BUFS]; - - /* First mark stats as invalid */ - atomic_set(&stats->frame_id, 0); - - stats->face_cnt = msm_fd_hw_get_face_count(fd); - for (i = 0; i < stats->face_cnt; i++) - msm_fd_fill_results(fd, &stats->face_data[i], i); - - /* Stats are ready, set correct frame id */ - atomic_set(&stats->frame_id, ctx->sequence); - - /* If Recovery mode is on, we got IRQ after recovery, reset it */ - if (fd->recovery_mode) { - fd->recovery_mode = 0; - dev_dbg(fd->dev, "Got IRQ after Recovery\n"); - } - - /* We have the data from fd hw, we can start next processing */ - msm_fd_hw_schedule_next_buffer(fd); - - /* Return buffer to vb queue */ - active_buf->vb.v4l2_buf.sequence = ctx->fh.sequence; - vb2_buffer_done(&active_buf->vb, VB2_BUF_STATE_DONE); - - /* Sent event */ - memset(&event, 0x00, sizeof(event)); - event.type = MSM_EVENT_FD; - fd_event = (struct msm_fd_event *)event.u.data; - fd_event->face_cnt = stats->face_cnt; - fd_event->buf_index = active_buf->vb.v4l2_buf.index; - fd_event->frame_id = ctx->sequence; - v4l2_event_queue_fh(&ctx->fh, &event); - - /* Release buffer from the device */ - msm_fd_hw_buffer_done(fd, active_buf); -} - -/* - * fd_probe - Fd device probe method. - * @pdev: Pointer fd platform device. - */ -static int fd_probe(struct platform_device *pdev) -{ - struct msm_fd_device *fd; - int ret; - - /* Face detection device struct */ - fd = kzalloc(sizeof(struct msm_fd_device), GFP_KERNEL); - if (!fd) - return -ENOMEM; - - mutex_init(&fd->lock); - spin_lock_init(&fd->slock); - mutex_init(&fd->recovery_lock); - init_completion(&fd->hw_halt_completion); - INIT_LIST_HEAD(&fd->buf_queue); - fd->pdev = pdev; - fd->dev = &pdev->dev; - - /* Get resources */ - ret = msm_fd_hw_get_mem_resources(pdev, fd); - if (ret < 0) { - dev_err(&pdev->dev, "Fail get resources\n"); - ret = -ENODEV; - goto error_mem_resources; - } - - ret = msm_camera_get_regulator_info(pdev, &fd->vdd_info, - &fd->num_reg); - if (ret < 0) { - dev_err(&pdev->dev, "Fail to get regulators\n"); - goto error_get_regulator; - } - ret = msm_camera_get_clk_info_and_rates(pdev, &fd->clk_info, - &fd->clk, &fd->clk_rates, &fd->clk_rates_num, &fd->clk_num); - if (ret < 0) { - dev_err(&pdev->dev, "Fail to get clocks\n"); - goto error_get_clocks; - } - - ret = msm_camera_register_bus_client(pdev, CAM_BUS_CLIENT_FD); - if (ret < 0) { - dev_err(&pdev->dev, "Fail to get bus\n"); - goto error_get_bus; - } - - /* Get face detect hw before read engine revision */ - ret = msm_fd_hw_get(fd, 0); - if (ret < 0) { - dev_err(&pdev->dev, "Fail to get hw\n"); - goto error_hw_get_request_irq; - } - fd->hw_revision = msm_fd_hw_get_revision(fd); - - msm_fd_hw_put(fd); - - ret = msm_fd_hw_request_irq(pdev, fd, msm_fd_wq_handler); - if (ret < 0) { - dev_err(&pdev->dev, "Fail request irq\n"); - goto error_hw_get_request_irq; - } - - /* v4l2 device */ - ret = v4l2_device_register(&pdev->dev, &fd->v4l2_dev); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register v4l2 device\n"); - ret = -ENOENT; - goto error_v4l2_register; - } - - fd->video.fops = &fd_fops; - fd->video.ioctl_ops = &fd_ioctl_ops; - fd->video.minor = -1; - fd->video.release = video_device_release; - fd->video.v4l2_dev = &fd->v4l2_dev; - fd->video.vfl_dir = VFL_DIR_TX; - fd->video.vfl_type = VFL_TYPE_GRABBER; - strlcpy(fd->video.name, MSM_FD_DRV_NAME, sizeof(fd->video.name)); - - ret = video_register_device(&fd->video, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - v4l2_err(&fd->v4l2_dev, "Failed to register video device\n"); - goto error_video_register; - } - - video_set_drvdata(&fd->video, fd); - - platform_set_drvdata(pdev, fd); - - return 0; - -error_video_register: - v4l2_device_unregister(&fd->v4l2_dev); -error_v4l2_register: - msm_fd_hw_release_irq(fd); -error_hw_get_request_irq: - msm_camera_unregister_bus_client(CAM_BUS_CLIENT_FD); -error_get_bus: - msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info, - &fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num); -error_get_clocks: - msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg); -error_get_regulator: - msm_fd_hw_release_mem_resources(fd); -error_mem_resources: - kfree(fd); - return ret; -} - -/* - * fd_device_remove - Fd device remove method. - * @pdev: Pointer fd platform device. - */ -static int fd_device_remove(struct platform_device *pdev) -{ - struct msm_fd_device *fd; - - fd = platform_get_drvdata(pdev); - if (NULL == fd) { - dev_err(&pdev->dev, "Can not get fd drvdata\n"); - return 0; - } - video_unregister_device(&fd->video); - v4l2_device_unregister(&fd->v4l2_dev); - msm_fd_hw_release_irq(fd); - msm_camera_unregister_bus_client(CAM_BUS_CLIENT_FD); - msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info, - &fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num); - msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg); - msm_fd_hw_release_mem_resources(fd); - kfree(fd); - - return 0; -} - -/* Device tree match struct */ -static const struct of_device_id msm_fd_dt_match[] = { - {.compatible = "qcom,face-detection"}, - {} -}; - -/* Fd platform driver definition */ -static struct platform_driver fd_driver = { - .probe = fd_probe, - .remove = fd_device_remove, - .driver = { - .name = MSM_FD_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_fd_dt_match, - }, -}; - -static int __init msm_fd_init_module(void) -{ - return platform_driver_register(&fd_driver); -} - -static void __exit msm_fd_exit_module(void) -{ - platform_driver_unregister(&fd_driver); -} - -module_init(msm_fd_init_module); -module_exit(msm_fd_exit_module); -MODULE_DESCRIPTION("MSM FD driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/fd/msm_fd_dev.h b/drivers/media/platform/msm/ais/fd/msm_fd_dev.h deleted file mode 100644 index a7615a65d2fcf0d7ab9644e92c9aa69d3782a9c6..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/fd/msm_fd_dev.h +++ /dev/null @@ -1,259 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_FD_DEV_H__ -#define __MSM_FD_DEV_H__ - -#include -#include -#include -#include -#include -#include -#include -#include "cam_soc_api.h" -#include "cam_hw_ops.h" -#include "msm_cpp.h" - -/* Maximum number of result buffers */ -#define MSM_FD_MAX_RESULT_BUFS 5 -/* Max number of clocks defined in device tree */ -#define MSM_FD_MAX_CLK_NUM 15 -/* Max number of clock rates defined in device tree */ -#define MSM_FD_MAX_CLK_RATES 5 -/* Max number of faces which can be detected in one hw processing */ -#define MSM_FD_MAX_FACES_DETECTED 32 -/* Max number of regulators defined in device tree */ -#define MSM_FD_MAX_REGULATOR_NUM 3 - -/* - * struct msm_fd_size - Structure contain FD size related values. - * @width: Image width. - * @height: Image height. - * @reg_val: Register value for this size. - * @work_size: Working buffer size in bytes for this size. - */ -struct msm_fd_size { - int width; - int height; - u32 reg_val; - int work_size; -}; - -/* - * struct msm_fd_setings - Structure contain FD settings values. - * @min_size_index: Minimum face size array index. - * @angle_index: Face detection angle array index. - * @direction_index: Face detection direction array index. - * @threshold: Face detection threshold value. - * @speed: Face detection speed value (it should match with clock rate index). - */ -struct msm_fd_setings { - unsigned int min_size_index; - unsigned int angle_index; - unsigned int direction_index; - unsigned int threshold; - unsigned int speed; -}; - -/* - * struct msm_fd_format - Structure contain FD format settings. - * @size: Pointer to fd size struct used for this format. - * @crop: V4l2 crop structure. - * @bytesperline: Bytes per line of input image buffer. - * @sizeimage: Size of input image buffer. - * @pixelformat: Pixel format of input image buffer. - */ -struct msm_fd_format { - struct msm_fd_size *size; - struct v4l2_rect crop; - int bytesperline; - int sizeimage; - u32 pixelformat; -}; - -/* - * struct msm_fd_mem_pool - Structure contain FD memory pool information. - * @fd_device: Pointer to fd device. - * @client: Pointer to ion client. - * @domain_num: Domain number associated with FD hw. - */ -struct msm_fd_mem_pool { - struct msm_fd_device *fd_device; -}; - -/* - * struct msm_fd_buf_handle - Structure contain FD buffer handle information. - * @fd: ion FD from which this buffer is imported. - * @pool: Pointer to FD memory pool struct. - * @handle: Pointer to ion handle. - * @size: Size of the buffer. - * @addr: Adders of FD mmu mapped buffer. This address should be set to FD hw. - */ -struct msm_fd_buf_handle { - int fd; - struct msm_fd_mem_pool *pool; - size_t size; - ion_phys_addr_t addr; -}; - -/* - * struct msm_fd_buffer - Vb2 buffer wrapper structure. - * @vb: Videobuf 2 buffer structure. - * @active: Flag indicating if buffer currently used by FD hw. - * @completion: Completion need to wait on, if buffer is used by FD hw. - * @format: Format information of this buffer. - * @settings: Settings value of this buffer. - * @work_addr: Working buffer address need to be used when for this buffer. - * @list: Buffer is part of FD device processing queue - */ -struct msm_fd_buffer { - struct vb2_buffer vb; - atomic_t active; - struct completion completion; - struct msm_fd_format format; - struct msm_fd_setings settings; - ion_phys_addr_t work_addr; - struct list_head list; -}; - -/* - * struct msm_fd_stats - Structure contains FD result statistic information. - * @frame_id: Frame id for which statistic corresponds to. - * @face_cnt: Number of faces detected and included in face data. - * @face_data: Structure containing detected face data information. - */ -struct msm_fd_stats { - atomic_t frame_id; - u32 face_cnt; - struct msm_fd_face_data face_data[MSM_FD_MAX_FACES_DETECTED]; -}; - -/* - * struct fd_ctx - Structure contains per open file handle context. - * @fd_device: Pointer to fd device. - * @fh: V4l2 file handle. - * @vb2_q: Videobuf 2 queue. - * @sequence: Sequence number for this statistic. - * @format: Current format. - * @settings: Current settings. - * @mem_pool: FD hw memory pool. - * @stats: Pointer to statistic buffers. - * @work_buf: Working memory buffer handle. - */ -struct fd_ctx { - struct msm_fd_device *fd_device; - struct v4l2_fh fh; - struct vb2_queue vb2_q; - unsigned int sequence; - atomic_t subscribed_for_event; - struct msm_fd_format format; - struct msm_fd_setings settings; - struct msm_fd_mem_pool mem_pool; - struct msm_fd_stats *stats; - struct msm_fd_buf_handle work_buf; - struct mutex lock; -}; - -/* - * enum msm_fd_device_state - FD device state. - * @MSM_FD_DEVICE_IDLE: Device is idle, we can start with processing. - * @MSM_FD_DEVICE_RUNNING: Device is running, next processing will be - * scheduled from fd irq. - */ -enum msm_fd_device_state { - MSM_FD_DEVICE_IDLE, - MSM_FD_DEVICE_RUNNING, -}; - -/* - * enum msm_fd_mem_resources - FD device iomem resources. - * @MSM_FD_IOMEM_CORE: Index of fd core registers. - * @MSM_FD_IOMEM_MISC: Index of fd misc registers. - * @MSM_FD_IOMEM_VBIF: Index of fd vbif registers. - * @MSM_FD_IOMEM_LAST: Not valid. - */ -enum msm_fd_mem_resources { - MSM_FD_IOMEM_CORE, - MSM_FD_IOMEM_MISC, - MSM_FD_IOMEM_VBIF, - MSM_FD_IOMEM_LAST -}; - -/* - * struct msm_fd_device - FD device structure. - * @hw_revision: Face detection hw revision. - * @lock: Lock used for reference count. - * @slock: Spinlock used to protect FD device struct. - * @irq_num: Face detection irq number. - * @ref_count: Device reference count. - * @res_mem: Array of memory resources used by FD device. - * @iomem_base: Array of register mappings used by FD device. - * @vdd: Pointer to vdd regulator. - * @clk_num: Number of clocks attached to the device. - * @clk: Array of clock resources used by fd device. - * @clk_rates: Array of clock rates set. - * @bus_vectors: Pointer to bus vectors array. - * @bus_paths: Pointer to bus paths array. - * @bus_scale_data: Memory access bus scale data. - * @bus_client: Memory access bus client. - * @iommu_attached_cnt: Iommu attached devices reference count. - * @iommu_hdl: reference for iommu context. - * @dev: Pointer to device struct. - * @v4l2_dev: V4l2 device. - * @video: Video device. - * @state: FD device state. - * @buf_queue: FD device processing queue. - * @work_queue: Pointer to FD device IRQ bottom half workqueue. - * @work: IRQ bottom half work struct. - * @hw_halt_completion: Completes when face detection hw halt completes. - * @recovery_mode: Indicates if FD is in recovery mode - */ -struct msm_fd_device { - u32 hw_revision; - - struct mutex lock; - spinlock_t slock; - struct mutex recovery_lock; - int ref_count; - - int irq_num; - void __iomem *iomem_base[MSM_FD_IOMEM_LAST]; - struct msm_cam_clk_info *clk_info; - struct msm_cam_regulator *vdd_info; - int num_reg; - struct resource *irq; - - size_t clk_num; - size_t clk_rates_num; - struct clk **clk; - uint32_t **clk_rates; - uint32_t bus_client; - - unsigned int iommu_attached_cnt; - - int iommu_hdl; - struct device *dev; - struct platform_device *pdev; - struct v4l2_device v4l2_dev; - struct video_device video; - - enum msm_fd_device_state state; - struct list_head buf_queue; - struct workqueue_struct *work_queue; - struct work_struct work; - struct completion hw_halt_completion; - int recovery_mode; - uint32_t clk_rate_idx; -}; - -#endif /* __MSM_FD_DEV_H__ */ diff --git a/drivers/media/platform/msm/ais/fd/msm_fd_hw.c b/drivers/media/platform/msm/ais/fd/msm_fd_hw.c deleted file mode 100644 index 6aebc93871a918501cdcbb331b1fde6e8b1f43e8..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/fd/msm_fd_hw.c +++ /dev/null @@ -1,1313 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_fd_dev.h" -#include "msm_fd_hw.h" -#include "msm_fd_regs.h" -#include "cam_smmu_api.h" -#include "msm_camera_io_util.h" - -/* After which revision misc irq for engine is needed */ -#define MSM_FD_MISC_IRQ_FROM_REV 0x10010000 -/* Face detection workqueue name */ -#define MSM_FD_WORQUEUE_NAME "face-detection" -/* Face detection bus client name */ -#define MSM_FD_BUS_CLIENT_NAME "msm_face_detect" -/* Face detection processing timeout in ms */ -#define MSM_FD_PROCESSING_TIMEOUT_MS 150 -/* Face detection halt timeout in ms */ -#define MSM_FD_HALT_TIMEOUT_MS 100 -/* Smmu callback name */ -#define MSM_FD_SMMU_CB_NAME "camera_fd" -/* - * enum msm_fd_reg_setting_entries - FD register setting entries in DT. - * @MSM_FD_REG_ADDR_OFFSET_IDX: Register address offset index. - * @MSM_FD_REG_VALUE_IDX: Register value index. - * @MSM_FD_REG_MASK_IDX: Regester mask index. - * @MSM_FD_REG_LAST_IDX: Index count. - */ -enum msm_fd_dt_reg_setting_index { - MSM_FD_REG_ADDR_OFFSET_IDX, - MSM_FD_REG_VALUE_IDX, - MSM_FD_REG_MASK_IDX, - MSM_FD_REG_LAST_IDX -}; - -/* - * msm_fd_hw_read_reg - Fd read from register. - * @fd: Pointer to fd device. - * @base_idx: Fd memory resource index. - * @reg: Register addr need to be read from. - */ -static inline u32 msm_fd_hw_read_reg(struct msm_fd_device *fd, - enum msm_fd_mem_resources base_idx, u32 reg) -{ - return msm_camera_io_r(fd->iomem_base[base_idx] + reg); -} - -/* - * msm_fd_hw_read_reg - Fd write to register. - * @fd: Pointer to fd device. - * @base_idx: Fd memory resource index. - * @reg: Register addr need to be read from. - e @value: Value to be written. - */ -static inline void msm_fd_hw_write_reg(struct msm_fd_device *fd, - enum msm_fd_mem_resources base_idx, u32 reg, u32 value) -{ - msm_camera_io_w(value, fd->iomem_base[base_idx] + reg); -} - -/* - * msm_fd_hw_reg_clr - Fd clear register bits. - * @fd: Pointer to fd device. - * @base_idx: Fd memory resource index. - * @reg: Register addr need to be read from. - * @clr_bits: Bits need to be clear from register. - */ -static inline void msm_fd_hw_reg_clr(struct msm_fd_device *fd, - enum msm_fd_mem_resources mmio_range, u32 reg, u32 clr_bits) -{ - u32 bits = msm_fd_hw_read_reg(fd, mmio_range, reg); - - msm_fd_hw_write_reg(fd, mmio_range, reg, (bits & ~clr_bits)); -} - -/* - * msm_fd_hw_reg_clr - Fd set register bits. - * @fd: Pointer to fd device. - * @base_idx: Fd memory resource index. - * @reg: Register addr need to be read from. - * @set_bits: Bits need to be set to register. - */ -static inline void msm_fd_hw_reg_set(struct msm_fd_device *fd, - enum msm_fd_mem_resources mmio_range, u32 reg, u32 set_bits) -{ - u32 bits = msm_fd_hw_read_reg(fd, mmio_range, reg); - - msm_fd_hw_write_reg(fd, mmio_range, reg, (bits | set_bits)); -} - -/* - * msm_fd_hw_reg_clr - Fd set size mode register. - * @fd: Pointer to fd device. - * @mode: Size mode to be set. - */ -static inline void msm_fd_hw_set_size_mode(struct msm_fd_device *fd, u32 mode) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_IMAGE_SIZE, mode); -} - -/* - * msm_fd_hw_reg_clr - Fd set crop registers. - * @fd: Pointer to fd device. - * @crop: Pointer to v4l2 crop struct containing the crop information - */ -static inline void msm_fd_hw_set_crop(struct msm_fd_device *fd, - struct v4l2_rect *crop) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_START_X, - (crop->top & MSM_FD_START_X_MASK)); - - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_START_Y, - (crop->left & MSM_FD_START_Y_MASK)); - - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_SIZE_X, - (crop->width & MSM_FD_SIZE_X_MASK)); - - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_SIZE_Y, - (crop->height & MSM_FD_SIZE_Y_MASK)); -} - -/* - * msm_fd_hw_reg_clr - Fd set bytes per line register. - * @fd: Pointer to fd device. - * @b: Bytes per line need to be set. - */ -static inline void msm_fd_hw_set_bytesperline(struct msm_fd_device *fd, u32 b) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_LINE_BYTES, - (b & MSM_FD_LINE_BYTES_MASK)); -} - -/* - * msm_fd_hw_reg_clr - Fd set image address. - * @fd: Pointer to fd device. - * @addr: Input image address need to be set. - */ -static inline void msm_fd_hw_set_image_addr(struct msm_fd_device *fd, u32 addr) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_IMAGE_ADDR, addr); -} - -/* - * msm_fd_hw_set_work_addr - Fd set working buffer address. - * @fd: Pointer to fd device. - * @addr: Working buffer address need to be set. - */ -static inline void msm_fd_hw_set_work_addr(struct msm_fd_device *fd, u32 addr) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_WORK_ADDR, addr); -} - -/* - * msm_fd_hw_set_direction_angle - Fd set face direction and face angle. - * @fd: Pointer to fd device. - * @direction: Face direction need to be set. - * @angle: Face angle need to be set. - */ -static inline void msm_fd_hw_set_direction_angle(struct msm_fd_device *fd, - u32 direction, u32 angle) -{ - u32 reg; - u32 value; - - value = direction | (angle ? 1 << (angle + 1) : 0); - if (value > MSM_FD_CONDT_DIR_MAX) - value = MSM_FD_CONDT_DIR_MAX; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT); - - reg &= ~MSM_FD_CONDT_DIR_MASK; - reg |= (value << MSM_FD_CONDT_DIR_SHIFT); - - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT, reg); -} - -/* - * msm_fd_hw_set_min_face - Fd set minimum face size register. - * @fd: Pointer to fd device. - * @size: Minimum face size need to be set. - */ -static inline void msm_fd_hw_set_min_face(struct msm_fd_device *fd, u32 size) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT); - - reg &= ~MSM_FD_CONDT_MIN_MASK; - reg |= (size << MSM_FD_CONDT_MIN_SHIFT); - - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT, reg); -} - -/* - * msm_fd_hw_set_threshold - Fd set detection threshold register. - * @fd: Pointer to fd device. - * @c: Maximum face count need to be set. - */ -static inline void msm_fd_hw_set_threshold(struct msm_fd_device *fd, u32 thr) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_DHINT, - (thr & MSM_FD_DHINT_MASK)); -} - -/* - * msm_fd_hw_srst - Sw reset control registers. - * @fd: Pointer to fd device. - * - * Before every processing we need to toggle this bit, - * This functions set sw reset control bit to 1/0. - */ -static inline void msm_fd_hw_srst(struct msm_fd_device *fd) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL, - MSM_FD_CONTROL_SRST); - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL, 0); -} - -/* - * msm_fd_hw_get_face_count - Fd read face count register. - * @fd: Pointer to fd device. - */ -int msm_fd_hw_get_face_count(struct msm_fd_device *fd) -{ - u32 reg; - u32 value; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_RESULT_CNT); - - value = reg & MSM_FD_RESULT_CNT_MASK; - if (value > MSM_FD_MAX_FACES_DETECTED) { - dev_warn(fd->dev, "Face count %d out of limit\n", value); - value = MSM_FD_MAX_FACES_DETECTED; - } - - return value; -} - -/* - * msm_fd_hw_run - Starts face detection engine. - * @fd: Pointer to fd device. - * - * Before call this function make sure that control sw reset is perfomed - * (see function msm_fd_hw_srst). - * NOTE: Engine need to be reset before started again. - */ -static inline void msm_fd_hw_run(struct msm_fd_device *fd) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL, - MSM_FD_CONTROL_RUN); -} - -/* - * msm_fd_hw_is_finished - Check if fd hw engine is done with processing. - * @fd: Pointer to fd device. - * - * NOTE: If finish bit is not set, we should not read the result. - */ -static int msm_fd_hw_is_finished(struct msm_fd_device *fd) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL); - - return reg & MSM_FD_CONTROL_FINISH; -} - -/* - * msm_fd_hw_is_runnig - Check if fd hw engine is busy. - * @fd: Pointer to fd device. - */ -static int msm_fd_hw_is_runnig(struct msm_fd_device *fd) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL); - - return reg & MSM_FD_CONTROL_RUN; -} - -/* - * msm_fd_hw_misc_irq_is_core - Check if fd received misc core irq. - * @fd: Pointer to fd device. - */ -static int msm_fd_hw_misc_irq_is_core(struct msm_fd_device *fd) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC, - MSM_FD_MISC_IRQ_STATUS); - - return reg & MSM_FD_MISC_IRQ_STATUS_CORE_IRQ; -} - -/* - * msm_fd_hw_misc_irq_is_halt - Check if fd received misc halt irq. - * @fd: Pointer to fd device. - */ -static int msm_fd_hw_misc_irq_is_halt(struct msm_fd_device *fd) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC, - MSM_FD_MISC_IRQ_STATUS); - - return reg & MSM_FD_MISC_IRQ_STATUS_HALT_REQ; -} - -/* -* msm_fd_hw_misc_clear_all_irq - Clear all misc irq statuses. -* @fd: Pointer to fd device. -*/ -static void msm_fd_hw_misc_clear_all_irq(struct msm_fd_device *fd) -{ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_CLEAR, - MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE); -} - -/* -* msm_fd_hw_misc_irq_enable - Enable fd misc core and halt irq. -* @fd: Pointer to fd device. -*/ -static void msm_fd_hw_misc_irq_enable(struct msm_fd_device *fd) -{ - msm_fd_hw_reg_set(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_MASK, - MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE); -} - -/* -* msm_fd_hw_misc_irq_disable - Disable fd misc core and halt irq. -* @fd: Pointer to fd device. -*/ -static void msm_fd_hw_misc_irq_disable(struct msm_fd_device *fd) -{ - msm_fd_hw_reg_clr(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_MASK, - MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE); -} - -/* - * msm_fd_hw_get_revision - Get hw revision and store in to device. - * @fd: Pointer to fd device. - */ -int msm_fd_hw_get_revision(struct msm_fd_device *fd) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC, - MSM_FD_MISC_HW_VERSION); - - dev_dbg(fd->dev, "Face detection hw revision 0x%x\n", reg); - - return reg; -} - -/* - * msm_fd_hw_get_result_x - Get fd result center x coordinate. - * @fd: Pointer to fd device. - * @idx: Result face index - */ -int msm_fd_hw_get_result_x(struct msm_fd_device *fd, int idx) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, - MSM_FD_RESULT_CENTER_X(idx)); - - return reg; -} - -/* - * msm_fd_hw_get_result_y - Get fd result center y coordinate. - * @fd: Pointer to fd device. - * @idx: Result face index - */ -int msm_fd_hw_get_result_y(struct msm_fd_device *fd, int idx) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, - MSM_FD_RESULT_CENTER_Y(idx)); - - return reg; -} - -/* - * msm_fd_hw_get_result_conf_size - Get fd result confident level and size. - * @fd: Pointer to fd device. - * @idx: Result face index. - * @conf: Pointer to confident value need to be filled. - * @size: Pointer to size value need to be filled. - */ -void msm_fd_hw_get_result_conf_size(struct msm_fd_device *fd, - int idx, u32 *conf, u32 *size) -{ - u32 reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, - MSM_FD_RESULT_CONF_SIZE(idx)); - - *conf = (reg >> MSM_FD_RESULT_CONF_SHIFT) & MSM_FD_RESULT_CONF_MASK; - *size = (reg >> MSM_FD_RESULT_SIZE_SHIFT) & MSM_FD_RESULT_SIZE_MASK; -} - -/* - * msm_fd_hw_get_result_angle_pose - Get fd result angle and pose. - * @fd: Pointer to fd device. - * @idx: Result face index. - * @angle: Pointer to angle value need to be filled. - * @pose: Pointer to pose value need to be filled. - */ -void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx, - u32 *angle, u32 *pose) -{ - u32 reg; - u32 pose_reg; - - reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, - MSM_FD_RESULT_ANGLE_POSE(idx)); - *angle = (reg >> MSM_FD_RESULT_ANGLE_SHIFT) & MSM_FD_RESULT_ANGLE_MASK; - pose_reg = (reg >> MSM_FD_RESULT_POSE_SHIFT) & MSM_FD_RESULT_POSE_MASK; - - switch (pose_reg) { - case MSM_FD_RESULT_POSE_FRONT: - *pose = MSM_FD_POSE_FRONT; - break; - case MSM_FD_RESULT_POSE_RIGHT_DIAGONAL: - *pose = MSM_FD_POSE_RIGHT_DIAGONAL; - break; - case MSM_FD_RESULT_POSE_RIGHT: - *pose = MSM_FD_POSE_RIGHT; - break; - case MSM_FD_RESULT_POSE_LEFT_DIAGONAL: - *pose = MSM_FD_POSE_LEFT_DIAGONAL; - break; - case MSM_FD_RESULT_POSE_LEFT: - *pose = MSM_FD_POSE_LEFT; - break; - default: - dev_err(fd->dev, "Invalid pose from the engine\n"); - *pose = MSM_FD_POSE_FRONT; - break; - } -} - -/* - * msm_fd_hw_misc_irq_supported - Check if misc irq is supported. - * @fd: Pointer to fd device. - */ -static int msm_fd_hw_misc_irq_supported(struct msm_fd_device *fd) -{ - return fd->hw_revision >= MSM_FD_MISC_IRQ_FROM_REV; -} - -/* - * msm_fd_hw_halt - Halt fd core. - * @fd: Pointer to fd device. - */ -static void msm_fd_hw_halt(struct msm_fd_device *fd) -{ - unsigned long time; - - if (msm_fd_hw_misc_irq_supported(fd)) { - init_completion(&fd->hw_halt_completion); - - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_HW_STOP, 1); - - time = wait_for_completion_timeout(&fd->hw_halt_completion, - msecs_to_jiffies(MSM_FD_HALT_TIMEOUT_MS)); - if (!time) - dev_err(fd->dev, "Face detection halt timeout\n"); - - /* Reset sequence after halt */ - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_SW_RESET, - MSM_FD_MISC_SW_RESET_SET); - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL, - MSM_FD_CONTROL_SRST); - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, - MSM_FD_MISC_SW_RESET, 0); - msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL, 0); - } -} - -/* - * msm_fd_core_irq - Face detection core irq handler. - * @irq: Irq number. - * @dev_id: Pointer to fd device. - */ -static irqreturn_t msm_fd_hw_core_irq(int irq, void *dev_id) -{ - struct msm_fd_device *fd = dev_id; - - if (msm_fd_hw_is_finished(fd)) - queue_work(fd->work_queue, &fd->work); - else - dev_err(fd->dev, "Something wrong! FD still running\n"); - - return IRQ_HANDLED; -} - -/* - * msm_fd_hw_misc_irq - Face detection misc irq handler. - * @irq: Irq number. - * @dev_id: Pointer to fd device. - */ -static irqreturn_t msm_fd_hw_misc_irq(int irq, void *dev_id) -{ - struct msm_fd_device *fd = dev_id; - - if (msm_fd_hw_misc_irq_is_core(fd)) - msm_fd_hw_core_irq(irq, dev_id); - - if (msm_fd_hw_misc_irq_is_halt(fd)) - complete_all(&fd->hw_halt_completion); - - msm_fd_hw_misc_clear_all_irq(fd); - - return IRQ_HANDLED; -} - -/* - * msm_fd_hw_request_irq - Configure and enable vbif interface. - * @pdev: Pointer to platform device. - * @fd: Pointer to fd device. - * @work_func: Pointer to work func used for irq bottom half. - */ -int msm_fd_hw_request_irq(struct platform_device *pdev, - struct msm_fd_device *fd, work_func_t work_func) -{ - int ret; - - fd->irq = msm_camera_get_irq(pdev, "fd"); - if (fd->irq_num < 0) { - dev_err(fd->dev, "Can not get fd core irq resource\n"); - ret = -ENODEV; - goto error_irq; - } - - /* If vbif is shared we will need wrapper irq for releasing vbif */ - if (msm_fd_hw_misc_irq_supported(fd)) { - ret = msm_camera_register_irq(pdev, - fd->irq, msm_fd_hw_misc_irq, - IRQF_TRIGGER_RISING, "fd", fd); - if (ret) { - dev_err(fd->dev, "Can not claim wrapper IRQ\n"); - goto error_irq; - } - } else { - ret = msm_camera_register_irq(pdev, - fd->irq, msm_fd_hw_core_irq, - IRQF_TRIGGER_RISING, "fd", fd); - if (ret) { - dev_err(&pdev->dev, "Can not claim core IRQ\n"); - goto error_irq; - } - - } - - fd->work_queue = alloc_workqueue(MSM_FD_WORQUEUE_NAME, - WQ_HIGHPRI | WQ_UNBOUND, 0); - if (!fd->work_queue) { - dev_err(fd->dev, "Can not register workqueue\n"); - ret = -ENOMEM; - goto error_alloc_workqueue; - } - INIT_WORK(&fd->work, work_func); - - return 0; - -error_alloc_workqueue: - msm_camera_unregister_irq(pdev, fd->irq, fd); -error_irq: - return ret; -} - -/* - * msm_fd_hw_release_irq - Free core and wrap irq. - * @fd: Pointer to fd device. - */ -void msm_fd_hw_release_irq(struct msm_fd_device *fd) -{ - if (fd->irq) - msm_camera_unregister_irq(fd->pdev, fd->irq, fd); - - if (fd->work_queue) { - destroy_workqueue(fd->work_queue); - fd->work_queue = NULL; - } -} - -/* - * msm_fd_hw_set_dt_parms_by_name() - read DT params and write to registers. - * @fd: Pointer to fd device. - * @dt_prop_name: Name of the device tree property to read. - * @base_idx: Fd memory resource index. - * - * This function reads register offset and value pairs from dtsi based on - * device tree property name and writes to FD registers. - * - * Return: 0 on success and negative error on failure. - */ -int32_t msm_fd_hw_set_dt_parms_by_name(struct msm_fd_device *fd, - const char *dt_prop_name, - enum msm_fd_mem_resources base_idx) -{ - struct device_node *of_node; - int32_t i = 0 , rc = 0; - uint32_t *dt_reg_settings = NULL; - uint32_t dt_count = 0; - - of_node = fd->dev->of_node; - pr_debug("%s:%d E\n", __func__, __LINE__); - - if (!of_get_property(of_node, dt_prop_name, &dt_count)) { - pr_err("%s: Error property does not exist\n", __func__); - return -ENOENT; - } - if (dt_count % (sizeof(int32_t) * MSM_FD_REG_LAST_IDX)) { - pr_err("%s: Error invalid entries\n", __func__); - return -EINVAL; - } - dt_count /= sizeof(int32_t); - if (dt_count != 0) { - dt_reg_settings = kcalloc(dt_count, - sizeof(uint32_t), - GFP_KERNEL); - - if (!dt_reg_settings) - return -ENOMEM; - - rc = of_property_read_u32_array(of_node, - dt_prop_name, - dt_reg_settings, - dt_count); - if (rc < 0) { - pr_err("%s: No reg info\n", __func__); - kfree(dt_reg_settings); - return -EINVAL; - } - - for (i = 0; i < dt_count; i = i + MSM_FD_REG_LAST_IDX) { - msm_fd_hw_reg_clr(fd, base_idx, - dt_reg_settings[i + MSM_FD_REG_ADDR_OFFSET_IDX], - dt_reg_settings[i + MSM_FD_REG_MASK_IDX]); - msm_fd_hw_reg_set(fd, base_idx, - dt_reg_settings[i + MSM_FD_REG_ADDR_OFFSET_IDX], - dt_reg_settings[i + MSM_FD_REG_VALUE_IDX] & - dt_reg_settings[i + MSM_FD_REG_MASK_IDX]); - pr_debug("%s:%d] %pK %08x\n", __func__, __LINE__, - fd->iomem_base[base_idx] + - dt_reg_settings[i + MSM_FD_REG_ADDR_OFFSET_IDX], - dt_reg_settings[i + MSM_FD_REG_VALUE_IDX] & - dt_reg_settings[i + MSM_FD_REG_MASK_IDX]); - } - kfree(dt_reg_settings); - } - return 0; -} - -/* - * msm_fd_hw_set_dt_parms() - set FD device tree configuration. - * @fd: Pointer to fd device. - * - * This function holds an array of device tree property names and calls - * msm_fd_hw_set_dt_parms_by_name() for each property. - * - * Return: 0 on success and negative error on failure. - */ -int msm_fd_hw_set_dt_parms(struct msm_fd_device *fd) -{ - int rc = 0; - uint8_t dt_prop_cnt = MSM_FD_IOMEM_LAST; - char *dt_prop_name[MSM_FD_IOMEM_LAST] = {"qcom,fd-core-reg-settings", - "qcom,fd-misc-reg-settings", "qcom,fd-vbif-reg-settings"}; - - while (dt_prop_cnt) { - dt_prop_cnt--; - rc = msm_fd_hw_set_dt_parms_by_name(fd, - dt_prop_name[dt_prop_cnt], - dt_prop_cnt); - if (rc == -ENOENT) { - pr_debug("%s: No %s property\n", __func__, - dt_prop_name[dt_prop_cnt]); - rc = 0; - } else if (rc < 0) { - pr_err("%s: %s params set fail\n", __func__, - dt_prop_name[dt_prop_cnt]); - return rc; - } - } - return rc; -} - -/* - * msm_fd_hw_release_mem_resources - Releases memory resources. - * @fd: Pointer to fd device. - */ -void msm_fd_hw_release_mem_resources(struct msm_fd_device *fd) -{ - msm_camera_put_reg_base(fd->pdev, - fd->iomem_base[MSM_FD_IOMEM_MISC], "fd_misc", true); - msm_camera_put_reg_base(fd->pdev, - fd->iomem_base[MSM_FD_IOMEM_CORE], "fd_core", true); - msm_camera_put_reg_base(fd->pdev, - fd->iomem_base[MSM_FD_IOMEM_VBIF], "fd_vbif", false); -} - -/* - * msm_fd_hw_get_mem_resources - Get memory resources. - * @pdev: Pointer to fd platform device. - * @fd: Pointer to fd device. - * - * Get and ioremap platform memory resources. - */ -int msm_fd_hw_get_mem_resources(struct platform_device *pdev, - struct msm_fd_device *fd) -{ - int ret = 0; - - /* Prepare memory resources */ - fd->iomem_base[MSM_FD_IOMEM_CORE] = - msm_camera_get_reg_base(pdev, "fd_core", true); - if (!fd->iomem_base[MSM_FD_IOMEM_CORE]) { - dev_err(fd->dev, "%s can not map fd_core region\n", __func__); - ret = -ENODEV; - goto fd_core_base_failed; - } - - fd->iomem_base[MSM_FD_IOMEM_MISC] = - msm_camera_get_reg_base(pdev, "fd_misc", true); - if (!fd->iomem_base[MSM_FD_IOMEM_MISC]) { - dev_err(fd->dev, "%s can not map fd_misc region\n", __func__); - ret = -ENODEV; - goto fd_misc_base_failed; - } - - fd->iomem_base[MSM_FD_IOMEM_VBIF] = - msm_camera_get_reg_base(pdev, "fd_vbif", false); - if (!fd->iomem_base[MSM_FD_IOMEM_VBIF]) { - dev_err(fd->dev, "%s can not map fd_vbif region\n", __func__); - ret = -ENODEV; - goto fd_vbif_base_failed; - } - - return ret; -fd_vbif_base_failed: - msm_camera_put_reg_base(pdev, - fd->iomem_base[MSM_FD_IOMEM_MISC], "fd_misc", true); -fd_misc_base_failed: - msm_camera_put_reg_base(pdev, - fd->iomem_base[MSM_FD_IOMEM_CORE], "fd_core", true); -fd_core_base_failed: - return ret; -} - -/* - * msm_fd_hw_bus_request - Request bus for memory access. - * @fd: Pointer to fd device. - * @idx: Bus bandwidth array index described in device tree. - */ -static int msm_fd_hw_bus_request(struct msm_fd_device *fd, unsigned int idx) -{ - int ret; - - ret = msm_camera_update_bus_vector(CAM_BUS_CLIENT_FD, idx); - if (ret < 0) { - dev_err(fd->dev, "Fail bus scale update %d\n", ret); - return -EINVAL; - } - - return 0; -} - -/* - * msm_fd_hw_set_clock_rate_idx - Set clock rate based on the index. - * @fd: Pointer to fd device. - * @idx: Clock Array index described in device tree. - */ -static int msm_fd_hw_set_clock_rate_idx(struct msm_fd_device *fd, - unsigned int idx) -{ - int ret; - int i; - - if (idx >= fd->clk_rates_num) { - dev_err(fd->dev, "Invalid clock index %u\n", idx); - return -EINVAL; - } - - for (i = 0; i < fd->clk_num; i++) { - ret = msm_camera_clk_set_rate(&fd->pdev->dev, - fd->clk[i], fd->clk_rates[idx][i]); - if (ret < 0) { - dev_err(fd->dev, "fail set rate on idx[%u][%u]\n", - idx, i); - return -EINVAL; - } - } - - return 0; -} - -/** - * msm_fd_hw_update_settings() - API to set clock rate and bus settings - * @fd: Pointer to fd device. - * @buf: fd buffer - */ -static int msm_fd_hw_update_settings(struct msm_fd_device *fd, - struct msm_fd_buffer *buf) -{ - int ret = 0; - uint32_t clk_rate_idx; - - if (!buf) - return 0; - - clk_rate_idx = buf->settings.speed; - if (fd->clk_rate_idx == clk_rate_idx) - return 0; - - if (fd->bus_client) { - ret = msm_fd_hw_bus_request(fd, clk_rate_idx); - if (ret < 0) { - dev_err(fd->dev, "Fail bus scale update %d\n", ret); - return -EINVAL; - } - } - - ret = msm_fd_hw_set_clock_rate_idx(fd, clk_rate_idx); - if (ret < 0) { - dev_err(fd->dev, "Fail to set clock rate idx\n"); - goto end; - } - dev_dbg(fd->dev, "set clk %d %d", fd->clk_rate_idx, clk_rate_idx); - fd->clk_rate_idx = clk_rate_idx; - -end: - return ret; -} - -/* - * msm_fd_hw_get - Get fd hw for performing any hw operation. - * @fd: Pointer to fd device. - * @clock_rate_idx: Clock rate index. - * - * Prepare fd hw for operation. Have reference count protected by - * fd device mutex. - */ -int msm_fd_hw_get(struct msm_fd_device *fd, unsigned int clock_rate_idx) -{ - int ret; - - mutex_lock(&fd->lock); - - if (fd->ref_count == 0) { - ret = - msm_camera_regulator_enable(fd->vdd_info, - fd->num_reg, true); - if (ret < 0) { - dev_err(fd->dev, "Fail to enable vdd\n"); - goto error; - } - - ret = msm_fd_hw_bus_request(fd, clock_rate_idx); - if (ret < 0) { - dev_err(fd->dev, "Fail bus request\n"); - goto error_bus_request; - } - ret = msm_fd_hw_set_clock_rate_idx(fd, clock_rate_idx); - if (ret < 0) { - dev_err(fd->dev, "Fail to set clock rate idx\n"); - goto error_clocks; - } - ret = msm_camera_clk_enable(&fd->pdev->dev, fd->clk_info, - fd->clk, fd->clk_num, true); - if (ret < 0) { - dev_err(fd->dev, "Fail clk enable request\n"); - goto error_clocks; - } - - if (msm_fd_hw_misc_irq_supported(fd)) - msm_fd_hw_misc_irq_enable(fd); - - ret = msm_fd_hw_set_dt_parms(fd); - if (ret < 0) - goto error_set_dt; - - fd->clk_rate_idx = clock_rate_idx; - } - - fd->ref_count++; - mutex_unlock(&fd->lock); - - return 0; - -error_set_dt: - if (msm_fd_hw_misc_irq_supported(fd)) - msm_fd_hw_misc_irq_disable(fd); - msm_camera_clk_enable(&fd->pdev->dev, fd->clk_info, - fd->clk, fd->clk_num, false); -error_clocks: -error_bus_request: - msm_camera_regulator_enable(fd->vdd_info, fd->num_reg, false); -error: - mutex_unlock(&fd->lock); - return ret; -} - -/* - * msm_fd_hw_get - Put fd hw. - * @fd: Pointer to fd device. - * - * Release fd hw. Have reference count protected by - * fd device mutex. - */ -void msm_fd_hw_put(struct msm_fd_device *fd) -{ - mutex_lock(&fd->lock); - BUG_ON(fd->ref_count == 0); - - if (--fd->ref_count == 0) { - msm_fd_hw_halt(fd); - - if (msm_fd_hw_misc_irq_supported(fd)) - msm_fd_hw_misc_irq_disable(fd); - - /* vector index 0 is 0 ab and 0 ib */ - msm_fd_hw_bus_request(fd, 0); - msm_camera_clk_enable(&fd->pdev->dev, fd->clk_info, - fd->clk, fd->clk_num, false); - msm_camera_regulator_enable(fd->vdd_info, fd->num_reg, false); - } - mutex_unlock(&fd->lock); -} - -/* - * msm_fd_hw_attach_iommu - Attach iommu to face detection engine. - * @fd: Pointer to fd device. - * - * Iommu attach have reference count protected by - * fd device mutex. - */ -static int msm_fd_hw_attach_iommu(struct msm_fd_device *fd) -{ - int ret = -EINVAL; - - mutex_lock(&fd->lock); - - if (fd->iommu_attached_cnt == UINT_MAX) { - dev_err(fd->dev, "Max count reached! can not attach iommu\n"); - goto error; - } - - if (fd->iommu_attached_cnt == 0) { - ret = cam_smmu_get_handle(MSM_FD_SMMU_CB_NAME, &fd->iommu_hdl); - if (ret < 0) { - dev_err(fd->dev, "get handle failed\n"); - ret = -ENOMEM; - goto error; - } - ret = cam_smmu_ops(fd->iommu_hdl, CAM_SMMU_ATTACH); - if (ret < 0) { - dev_err(fd->dev, "Can not attach iommu domain.\n"); - goto error_attach; - } - } - fd->iommu_attached_cnt++; - mutex_unlock(&fd->lock); - - return 0; - -error_attach: - cam_smmu_destroy_handle(fd->iommu_hdl); -error: - mutex_unlock(&fd->lock); - return ret; -} - -/* - * msm_fd_hw_detach_iommu - Detach iommu from face detection engine. - * @fd: Pointer to fd device. - * - * Iommu detach have reference count protected by - * fd device mutex. - */ -static void msm_fd_hw_detach_iommu(struct msm_fd_device *fd) -{ - mutex_lock(&fd->lock); - if (fd->iommu_attached_cnt == 0) { - dev_err(fd->dev, "There is no attached device\n"); - mutex_unlock(&fd->lock); - return; - } - if (--fd->iommu_attached_cnt == 0) { - cam_smmu_ops(fd->iommu_hdl, CAM_SMMU_DETACH); - cam_smmu_destroy_handle(fd->iommu_hdl); - } - mutex_unlock(&fd->lock); -} - -/* - * msm_fd_hw_map_buffer - Map buffer to fd hw mmu. - * @pool: Pointer to fd memory pool. - * @fd: Ion fd. - * @buf: Fd buffer handle, for storing mapped buffer information. - * - * It will map ion fd to fd hw mmu. - */ -int msm_fd_hw_map_buffer(struct msm_fd_mem_pool *pool, int fd, - struct msm_fd_buf_handle *buf) -{ - int ret; - - if (!pool || fd < 0) - return -EINVAL; - - ret = msm_fd_hw_attach_iommu(pool->fd_device); - if (ret < 0) - return -ENOMEM; - - buf->pool = pool; - buf->fd = fd; - ret = cam_smmu_get_phy_addr(pool->fd_device->iommu_hdl, - buf->fd, CAM_SMMU_MAP_RW, - &buf->addr, &buf->size); - if (ret < 0) { - pr_err("Error: cannot get phy addr\n"); - return -ENOMEM; - } - return buf->size; -} - -/* - * msm_fd_hw_unmap_buffer - Unmap buffer from fd hw mmu. - * @buf: Fd buffer handle, for storing mapped buffer information. - */ -void msm_fd_hw_unmap_buffer(struct msm_fd_buf_handle *buf) -{ - if (buf->size) { - cam_smmu_put_phy_addr(buf->pool->fd_device->iommu_hdl, - buf->fd); - msm_fd_hw_detach_iommu(buf->pool->fd_device); - } - - buf->fd = -1; - buf->pool = NULL; -} - -/* - * msm_fd_hw_enable - Configure and enable fd hw. - * @fd: Fd device. - * @buffer: Buffer need to be processed. - * - * Configure and starts fd processing with given buffer. - * NOTE: Fd will not be enabled if engine is in running state. - */ -static int msm_fd_hw_enable(struct msm_fd_device *fd, - struct msm_fd_buffer *buffer) -{ - struct msm_fd_buf_handle *buf_handle = - buffer->vb.planes[0].mem_priv; - - if (msm_fd_hw_is_runnig(fd)) { - dev_err(fd->dev, "Device is busy we can not enable\n"); - return 0; - } - - msm_fd_hw_srst(fd); - msm_fd_hw_set_size_mode(fd, buffer->format.size->reg_val); - msm_fd_hw_set_crop(fd, &buffer->format.crop); - msm_fd_hw_set_bytesperline(fd, buffer->format.bytesperline); - msm_fd_hw_set_image_addr(fd, buf_handle->addr); - msm_fd_hw_set_work_addr(fd, buffer->work_addr); - msm_fd_hw_set_min_face(fd, buffer->settings.min_size_index); - msm_fd_hw_set_threshold(fd, buffer->settings.threshold); - msm_fd_hw_set_direction_angle(fd, buffer->settings.direction_index, - buffer->settings.angle_index); - msm_fd_hw_run(fd); - if (fd->recovery_mode) - dev_err(fd->dev, "Scheduled buffer in recovery mode\n"); - return 1; -} - -/* - * msm_fd_hw_try_enable - Try to enable fd hw. - * @fd: Fd device. - * @buffer: Buffer need to be processed. - * @state: Enable on device state - * - * It will enable fd hw if actual device state is equal with state argument. - */ -static int msm_fd_hw_try_enable(struct msm_fd_device *fd, - struct msm_fd_buffer *buffer, enum msm_fd_device_state state) -{ - int enabled = 0; - - if (state == fd->state) { - - fd->state = MSM_FD_DEVICE_RUNNING; - atomic_set(&buffer->active, 1); - - msm_fd_hw_enable(fd, buffer); - enabled = 1; - } - return enabled; -} - -/* - * msm_fd_hw_next_buffer - Get next buffer from fd device processing queue. - * @fd: Fd device. - */ -static struct msm_fd_buffer *msm_fd_hw_next_buffer(struct msm_fd_device *fd) -{ - struct msm_fd_buffer *buffer = NULL; - - if (!list_empty(&fd->buf_queue)) - buffer = list_first_entry(&fd->buf_queue, - struct msm_fd_buffer, list); - - return buffer; -} - -/* - * msm_fd_hw_add_buffer - Add buffer to fd device processing queue. - * @fd: Fd device. - */ -void msm_fd_hw_add_buffer(struct msm_fd_device *fd, - struct msm_fd_buffer *buffer) -{ - spin_lock(&fd->slock); - - atomic_set(&buffer->active, 0); - init_completion(&buffer->completion); - - INIT_LIST_HEAD(&buffer->list); - list_add_tail(&buffer->list, &fd->buf_queue); - spin_unlock(&fd->slock); -} - -/* - * msm_fd_hw_remove_buffers_from_queue - Removes buffer from - * fd device processing queue. - * @fd: Fd device. - */ -void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd, - struct vb2_queue *vb2_q) -{ - struct msm_fd_buffer *curr_buff; - struct msm_fd_buffer *temp; - struct msm_fd_buffer *active_buffer; - unsigned long time; - - spin_lock(&fd->slock); - - active_buffer = NULL; - list_for_each_entry_safe(curr_buff, temp, &fd->buf_queue, list) { - if (curr_buff->vb.vb2_queue == vb2_q) { - - if (atomic_read(&curr_buff->active)) - active_buffer = curr_buff; - else { - /* Do a Buffer done on all the other buffers */ - vb2_buffer_done(&curr_buff->vb, - VB2_BUF_STATE_DONE); - list_del(&curr_buff->list); - } - } - } - spin_unlock(&fd->slock); - - /* We need to wait active buffer to finish */ - if (active_buffer) { - time = wait_for_completion_timeout(&active_buffer->completion, - msecs_to_jiffies(MSM_FD_PROCESSING_TIMEOUT_MS)); - if (!time) { - /* Do a vb2 buffer done since it timed out */ - vb2_buffer_done(&active_buffer->vb, VB2_BUF_STATE_DONE); - /* Remove active buffer */ - msm_fd_hw_get_active_buffer(fd); - /* Schedule if other buffers are present in device */ - msm_fd_hw_schedule_next_buffer(fd); - } - } -} - -/* - * msm_fd_hw_buffer_done - Mark as done and removes from processing queue. - * @fd: Fd device. - * @buffer: Fd buffer. - */ -int msm_fd_hw_buffer_done(struct msm_fd_device *fd, - struct msm_fd_buffer *buffer) -{ - int ret = 0; - - spin_lock(&fd->slock); - - if (atomic_read(&buffer->active)) { - atomic_set(&buffer->active, 0); - complete_all(&buffer->completion); - } else { - dev_err(fd->dev, "Buffer is not active\n"); - ret = -1; - } - - spin_unlock(&fd->slock); - - return ret; -} - -/* - * msm_fd_hw_get_active_buffer - Get active buffer from fd processing queue. - * @fd: Fd device. - */ -struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd) -{ - struct msm_fd_buffer *buffer = NULL; - - spin_lock(&fd->slock); - if (!list_empty(&fd->buf_queue)) { - buffer = list_first_entry(&fd->buf_queue, - struct msm_fd_buffer, list); - list_del(&buffer->list); - } - spin_unlock(&fd->slock); - - return buffer; -} - -/* - * msm_fd_hw_schedule_and_start - Schedule active buffer and start processing. - * @fd: Fd device. - * - * This can be executed only when device is in idle state. - */ -int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd) -{ - struct msm_fd_buffer *buf; - - spin_lock(&fd->slock); - buf = msm_fd_hw_next_buffer(fd); - if (buf) - msm_fd_hw_try_enable(fd, buf, MSM_FD_DEVICE_IDLE); - - spin_unlock(&fd->slock); - - msm_fd_hw_update_settings(fd, buf); - - return 0; -} - -/* - * msm_fd_hw_schedule_next_buffer - Schedule next buffer and start processing. - * @fd: Fd device. - * - * NOTE: This can be executed only when device is in running state. - */ -int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd) -{ - struct msm_fd_buffer *buf; - int ret; - - spin_lock(&fd->slock); - - /* We can schedule next buffer only in running state */ - if (fd->state != MSM_FD_DEVICE_RUNNING) { - dev_err(fd->dev, "Can not schedule next buffer\n"); - spin_unlock(&fd->slock); - return -EBUSY; - } - - buf = msm_fd_hw_next_buffer(fd); - if (buf) { - ret = msm_fd_hw_try_enable(fd, buf, MSM_FD_DEVICE_RUNNING); - if (0 == ret) { - dev_err(fd->dev, "Ouch can not process next buffer\n"); - spin_unlock(&fd->slock); - return -EBUSY; - } - } else { - fd->state = MSM_FD_DEVICE_IDLE; - if (fd->recovery_mode) - dev_err(fd->dev, "No Buffer in recovery mode.Device Idle\n"); - } - spin_unlock(&fd->slock); - - msm_fd_hw_update_settings(fd, buf); - - return 0; -} diff --git a/drivers/media/platform/msm/ais/fd/msm_fd_hw.h b/drivers/media/platform/msm/ais/fd/msm_fd_hw.h deleted file mode 100644 index c022230d3dc6b6b34d9a9057e4d43032015db1dd..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/fd/msm_fd_hw.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_FD_HW_H__ -#define __MSM_FD_HW_H__ - -#include "msm_fd_dev.h" - -int msm_fd_hw_get_face_count(struct msm_fd_device *fd); - -int msm_fd_hw_get_result_x(struct msm_fd_device *fd, int idx); - -int msm_fd_hw_get_result_y(struct msm_fd_device *fd, int idx); - -void msm_fd_hw_get_result_conf_size(struct msm_fd_device *fd, - int idx, u32 *conf, u32 *size); - -void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx, - u32 *angle, u32 *pose); - -int msm_fd_hw_request_irq(struct platform_device *pdev, - struct msm_fd_device *fd, work_func_t work_func); - -void msm_fd_hw_release_irq(struct msm_fd_device *fd); - -int msm_fd_hw_get_revision(struct msm_fd_device *fd); - -void msm_fd_hw_release_mem_resources(struct msm_fd_device *fd); - -int msm_fd_hw_get_mem_resources(struct platform_device *pdev, - struct msm_fd_device *fd); - -int msm_fd_hw_get_iommu(struct msm_fd_device *fd); - -void msm_fd_hw_put_iommu(struct msm_fd_device *fd); - -int msm_fd_hw_get_regulators(struct msm_fd_device *fd); - -int msm_fd_hw_put_regulators(struct msm_fd_device *fd); - -int msm_fd_hw_get_clocks(struct msm_fd_device *fd); - -int msm_fd_hw_put_clocks(struct msm_fd_device *fd); - -int msm_fd_hw_get_bus(struct msm_fd_device *fd); - -void msm_fd_hw_put_bus(struct msm_fd_device *fd); - -int msm_fd_hw_get(struct msm_fd_device *fd, unsigned int clock_rate_idx); - -void msm_fd_hw_put(struct msm_fd_device *fd); - -int msm_fd_hw_map_buffer(struct msm_fd_mem_pool *pool, int fd, - struct msm_fd_buf_handle *buf); - -void msm_fd_hw_unmap_buffer(struct msm_fd_buf_handle *buf); - -void msm_fd_hw_add_buffer(struct msm_fd_device *fd, - struct msm_fd_buffer *buffer); - -void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd, - struct vb2_queue *vb2_q); - -int msm_fd_hw_buffer_done(struct msm_fd_device *fd, - struct msm_fd_buffer *buffer); - -struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd); - -int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd); - -int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd); - -#endif /* __MSM_FD_HW_H__ */ diff --git a/drivers/media/platform/msm/ais/fd/msm_fd_regs.h b/drivers/media/platform/msm/ais/fd/msm_fd_regs.h deleted file mode 100644 index 69f2af75c4c76653ce500a274c8eea963b2400ae..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/fd/msm_fd_regs.h +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_FD_REGS_H__ -#define __MSM_FD_REGS_H__ - -/* FD core registers */ -#define MSM_FD_CONTROL (0x00) -#define MSM_FD_CONTROL_SRST (1 << 0) -#define MSM_FD_CONTROL_RUN (1 << 1) -#define MSM_FD_CONTROL_FINISH (1 << 2) - -#define MSM_FD_RESULT_CNT (0x04) -#define MSM_FD_RESULT_CNT_MASK (0x3F) - -#define MSM_FD_CONDT (0x08) -#define MSM_FD_CONDT_MIN_MASK (0x03) -#define MSM_FD_CONDT_MIN_SHIFT (0x00) -#define MSM_FD_CONDT_DIR_MAX (0x08) -#define MSM_FD_CONDT_DIR_MASK (0x3C) -#define MSM_FD_CONDT_DIR_SHIFT (0x02) - -#define MSM_FD_START_X (0x0C) -#define MSM_FD_START_X_MASK (0x3FF) - -#define MSM_FD_START_Y (0x10) -#define MSM_FD_START_Y_MASK (0x1FF) - -#define MSM_FD_SIZE_X (0x14) -#define MSM_FD_SIZE_X_MASK (0x3FF) - -#define MSM_FD_SIZE_Y (0x18) -#define MSM_FD_SIZE_Y_MASK (0x1FF) - -#define MSM_FD_DHINT (0x1C) -#define MSM_FD_DHINT_MASK (0xF) - -#define MSM_FD_IMAGE_ADDR (0x24) -#define MSM_FD_IMAGE_ADDR_ALIGN (0x8) - -#define MSM_FD_WORK_ADDR (0x28) -#define MSM_FD_WORK_ADDR_ALIGN (0x8) - -#define MSM_FD_IMAGE_SIZE (0x2C) -#define MSM_FD_IMAGE_SIZE_QVGA (0x0) -#define MSM_FD_IMAGE_SIZE_VGA (0x1) -#define MSM_FD_IMAGE_SIZE_WQVGA (0x2) -#define MSM_FD_IMAGE_SIZE_WVGA (0x3) - -#define MSM_FD_LINE_BYTES (0x30) -#define MSM_FD_LINE_BYTES_MASK (0x1FFF) -#define MSM_FD_LINE_BYTES_ALIGN (0x8) - -#define MSM_FD_RESULT_CENTER_X(x) (0x400 + (0x10 * (x))) - -#define MSM_FD_RESULT_CENTER_Y(x) (0x404 + (0x10 * (x))) - -#define MSM_FD_RESULT_CONF_SIZE(x) (0x408 + (0x10 * (x))) -#define MSM_FD_RESULT_SIZE_MASK (0x1FF) -#define MSM_FD_RESULT_SIZE_SHIFT (0x000) -#define MSM_FD_RESULT_CONF_MASK (0xF) -#define MSM_FD_RESULT_CONF_SHIFT (0x9) - -#define MSM_FD_RESULT_ANGLE_POSE(x) (0x40C + (0x10 * (x))) -#define MSM_FD_RESULT_ANGLE_MASK (0x1FF) -#define MSM_FD_RESULT_ANGLE_SHIFT (0x000) -#define MSM_FD_RESULT_POSE_MASK (0x7) -#define MSM_FD_RESULT_POSE_SHIFT (0x9) -#define MSM_FD_RESULT_POSE_FRONT (0x1) -#define MSM_FD_RESULT_POSE_RIGHT_DIAGONAL (0x2) -#define MSM_FD_RESULT_POSE_RIGHT (0x3) -#define MSM_FD_RESULT_POSE_LEFT_DIAGONAL (0x4) -#define MSM_FD_RESULT_POSE_LEFT (0x5) - -/* FD misc registers */ -#define MSM_FD_MISC_HW_VERSION (0x00) -#define MSM_FD_MISC_CGC_DISABLE (0x04) -#define MSM_FD_HW_STOP (0x08) - -#define MSM_FD_MISC_SW_RESET (0x10) -#define MSM_FD_MISC_SW_RESET_SET (1 << 0) - -#define MSM_FD_MISC_FIFO_STATUS (0x14) -#define MSM_FD_MISC_FIFO_STATUS_RFIFO_DCNT_MAST (0x1F) -#define MSM_FD_MISC_FIFO_STATUS_RFIFO_DCNT_SHIFT (0) -#define MSM_FD_MISC_FIFO_STATUS_RFIFO_FULL (1 << 13) -#define MSM_FD_MISC_FIFO_STATUS_RFIFO_EMPTY (1 << 14) -#define MSM_FD_MISC_FIFO_STATUS_WFIFO_DCNT_MAST (0x1F) -#define MSM_FD_MISC_FIFO_STATUS_WFIFO_DCNT_SHIFT (16) -#define MSM_FD_MISC_FIFO_STATUS_WFIFO_EMPTY (1 << 29) -#define MSM_FD_MISC_FIFO_STATUS_WFIFO_FULL (1 << 30) - -#define MSM_FD_MISC_DATA_ENDIAN (0x18) -#define MSM_FD_MISC_DATA_ENDIAN_BYTE_SWAP_SET (1 << 0) - -#define MSM_FD_MISC_VBIF_REQ_PRIO (0x20) -#define MSM_FD_MISC_VBIF_REQ_PRIO_MASK (0x3) - -#define MSM_FD_MISC_VBIF_PRIO_LEVEL (0x24) -#define MSM_FD_MISC_VBIF_PRIO_LEVEL_MASK (0x3) - -#define MSM_FD_MISC_VBIF_MMU_PDIRECT (0x28) -#define MSM_FD_MISC_VBIF_MMU_PDIRECT_INCREMENT (1 << 0) - -#define MSM_FD_MISC_VBIF_IRQ_CLR (0x30) -#define MSM_FD_MISC_VBIF_IRQ_CLR_ALL (1 << 0) - -#define MSM_FD_MISC_VBIF_DONE_STATUS (0x34) -#define MSM_FD_MISC_VBIF_DONE_STATUS_WRITE (1 << 0) -#define MSM_FD_MISC_VBIF_DONE_STATUS_READ (1 << 1) - -#define MSM_FD_MISC_IRQ_MASK (0x50) -#define MSM_FD_MISC_IRQ_MASK_HALT_REQ (1 << 1) -#define MSM_FD_MISC_IRQ_MASK_CORE_IRQ (1 << 0) - -#define MSM_FD_MISC_IRQ_STATUS (0x54) -#define MSM_FD_MISC_IRQ_STATUS_HALT_REQ (1 << 1) -#define MSM_FD_MISC_IRQ_STATUS_CORE_IRQ (1 << 0) - -#define MSM_FD_MISC_IRQ_CLEAR (0x58) -#define MSM_FD_MISC_IRQ_CLEAR_HALT (1 << 1) -#define MSM_FD_MISC_IRQ_CLEAR_CORE (1 << 0) - -#define MSM_FD_MISC_TEST_BUS_SEL (0x40) -#define MSM_FD_MISC_TEST_BUS_SEL_TEST_MODE_MASK (0xF) -#define MSM_FD_MISC_TEST_BUS_SEL_TEST_MODE_SHIFT (0) -#define MSM_FD_MISC_TEST_BUS_SEL_7_0_MASK (0x3) -#define MSM_FD_MISC_TEST_BUS_SEL_7_0_SHIFT (16) -#define MSM_FD_MISC_TEST_BUS_SEL_15_8_MASK (0x3) -#define MSM_FD_MISC_TEST_BUS_SEL_15_8_SHIFT (18) -#define MSM_FD_MISC_TEST_BUS_SEL_23_16_MASK (0x3) -#define MSM_FD_MISC_TEST_BUS_SEL_23_16_SHIFT (20) -#define MSM_FD_MISC_TEST_BUS_SEL_31_24_MASK (0x3) -#define MSM_FD_MISC_TEST_BUS_SEL_31_24_SHIFT (22) - -#define MSM_FD_MISC_AHB_TEST_EN (0x44) -#define MSM_FD_MISC_AHB_TEST_EN_MASK (0x3) - -#define MSM_FD_MISC_FD2VBIF_INT_TEST_SEL (0x48) -#define MSM_FD_MISC_FD2VBIF_INT_TEST_MASK (0xF) - -#define MSM_FD_MISC_TEST_BUS (0x4C) - -/* FD vbif registers */ -#define MSM_FD_VBIF_CLKON (0x04) -#define MSM_FD_VBIF_QOS_OVERRIDE_EN (0x10) -#define MSM_FD_VBIF_QOS_OVERRIDE_REQPRI (0x18) -#define MSM_FD_VBIF_QOS_OVERRIDE_PRILVL (0x1C) -#define MSM_FD_VBIF_IN_RD_LIM_CONF0 (0xB0) -#define MSM_FD_VBIF_IN_WR_LIM_CONF0 (0xC0) -#define MSM_FD_VBIF_OUT_RD_LIM_CONF0 (0xD0) -#define MSM_FD_VBIF_OUT_WR_LIM_CONF0 (0xD4) -#define MSM_FD_VBIF_DDR_OUT_MAX_BURST (0xD8) -#define MSM_FD_VBIF_ARB_CTL (0xF0) -#define MSM_FD_VBIF_OUT_AXI_AMEMTYPE_CONF0 (0x160) -#define MSM_FD_VBIF_OUT_AXI_AOOO_EN (0x178) -#define MSM_FD_VBIF_OUT_AXI_AOOO (0x17c) -#define MSM_FD_VBIF_ROUND_ROBIN_QOS_ARB (0x124) - -#endif /* __MSM_FD_REGS_H__ */ diff --git a/drivers/media/platform/msm/ais/isp/Makefile b/drivers/media/platform/msm/ais/isp/Makefile deleted file mode 100644 index c7202ee4ffa52821698f93c553853991ed0bb13c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -ccflags-y += -Idrivers/media/platform/msm/ais/common/ -obj-$(CONFIG_MSM_AIS) += msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o -obj-$(CONFIG_MSM_AIS) += msm_isp47.o msm_isp.o diff --git a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c deleted file mode 100644 index 103ef208e86caac6c2d522d2249bab68d3e9598a..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c +++ /dev/null @@ -1,1530 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "msm.h" -#include "msm_buf_mgr.h" -#include "cam_smmu_api.h" -#include "msm_isp_util.h" - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -#define BUF_DEBUG_FULL 0 -#define MAX_LIST_COUNT 100 - -static int msm_buf_check_head_sanity(struct msm_isp_bufq *bufq) -{ - int rc = 0; - struct list_head *prev = NULL; - struct list_head *next = NULL; - - if (!bufq) { - pr_err("%s: Error! Invalid bufq\n", __func__); - return -EINVAL; - } - - prev = bufq->head.prev; - next = bufq->head.next; - - if (!prev) { - pr_err("%s: Error! bufq->head.prev is NULL\n", __func__); - return -EINVAL; - } - - if (!next) { - pr_err("%s: Error! bufq->head.next is NULL\n", __func__); - return -EINVAL; - } - - if (prev->next != &bufq->head) { - pr_err("%s: Error! head prev->next is %pK should be %pK\n", - __func__, prev->next, &bufq->head); - return -EINVAL; - } - - if (next->prev != &bufq->head) { - pr_err("%s: Error! head next->prev is %pK should be %pK\n", - __func__, next->prev, &bufq->head); - return -EINVAL; - } - - return rc; -} - -struct msm_isp_bufq *msm_isp_get_bufq( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle) -{ - struct msm_isp_bufq *bufq = NULL; - uint32_t bufq_index = bufq_handle & 0xFF; - - /* bufq_handle cannot be 0 */ - if ((bufq_handle == 0) || - bufq_index >= BUF_MGR_NUM_BUF_Q || - (bufq_index > buf_mgr->num_buf_q)) - return NULL; - - bufq = &buf_mgr->bufq[bufq_index]; - if (bufq->bufq_handle == bufq_handle) - return bufq; - - return NULL; -} - -static struct msm_isp_buffer *msm_isp_get_buf_ptr( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index) -{ - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return buf_info; - } - - if (bufq->num_bufs <= buf_index) { - pr_err("%s: Invalid buf index\n", __func__); - return buf_info; - } - buf_info = &bufq->bufs[buf_index]; - return buf_info; -} - -static uint32_t msm_isp_get_buf_handle( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t vfe_id, - enum msm_vfe_axi_stream_src output_id) -{ - int i; - uint32_t embedded_stream_id = 0; - - for (i = 0; i < buf_mgr->num_buf_q; i++) { - if (buf_mgr->bufq[i].bufq_handle != 0 && - buf_mgr->bufq[i].vfe_id == vfe_id && - buf_mgr->bufq[i].output_id == output_id) { - pr_err("%s - existing handle for output_id=%d", - __func__, output_id); - return 0; - } - } - - /* put stream id in handle, if its stats, use FFFF */ - if (vfe_id & (1 << 31)) - embedded_stream_id = 0xFFFF; - else - embedded_stream_id = (vfe_id << 4) | output_id; - - for (i = 0; i < buf_mgr->num_buf_q; i++) { - if (buf_mgr->bufq[i].bufq_handle == 0) { - buf_mgr->bufq[i].bufq_handle = 0xA15B0000 | - (embedded_stream_id << 8) | i; - return buf_mgr->bufq[i].bufq_handle; - } - } - return 0; -} - -static int msm_isp_free_bufq_handle(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle) -{ - struct msm_isp_bufq *bufq = - msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) - return -EINVAL; - - /* Set everything except lock to 0 */ - bufq->bufq_handle = 0; - bufq->bufs = 0; - bufq->vfe_id = 0; - bufq->output_id = 0; - bufq->num_bufs = 0; - bufq->buf_type = 0; - INIT_LIST_HEAD(&bufq->head); - - return 0; -} - -static void msm_isp_copy_planes_from_v4l2_buffer( - struct msm_isp_qbuf_buffer *qbuf_buf, - const struct v4l2_buffer *v4l2_buf) -{ - int i; - - qbuf_buf->num_planes = v4l2_buf->length; - for (i = 0; i < qbuf_buf->num_planes; i++) { - qbuf_buf->planes[i].addr = v4l2_buf->m.planes[i].m.userptr; - qbuf_buf->planes[i].offset = v4l2_buf->m.planes[i].data_offset; - qbuf_buf->planes[i].length = v4l2_buf->m.planes[i].length; - } -} - -static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buffer *buf_info, - struct msm_isp_qbuf_buffer *qbuf_buf, - uint32_t output_id) -{ - int i, rc = -1; - int ret; - struct msm_isp_buffer_mapped_info *mapped_info; - uint32_t accu_length = 0; - - for (i = 0; i < qbuf_buf->num_planes; i++) { - mapped_info = &buf_info->mapped_info[i]; - mapped_info->buf_fd = qbuf_buf->planes[i].addr; - ret = cam_smmu_get_phy_addr(buf_mgr->iommu_hdl, - mapped_info->buf_fd, - CAM_SMMU_MAP_RW, - &(mapped_info->paddr), - &(mapped_info->len)); - if (ret) { - rc = -EINVAL; - pr_err_ratelimited("%s: cannot map address", __func__); - goto get_phy_err; - } - - mapped_info->paddr += accu_length; - accu_length += qbuf_buf->planes[i].length; - - CDBG("%s: plane: %d addr:%pK\n", - __func__, i, (void *)mapped_info->paddr); - - } - buf_info->num_planes = qbuf_buf->num_planes; - return 0; -get_phy_err: - i--; - - return rc; -} - -static void msm_isp_unprepare_v4l2_buf( - struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buffer *buf_info, - uint32_t output_id) -{ - int i; - struct msm_isp_buffer_mapped_info *mapped_info; - struct msm_isp_bufq *bufq = NULL; - - if (!buf_mgr || !buf_info) { - pr_err("%s: NULL ptr %pK %pK\n", __func__, - buf_mgr, buf_info); - return; - } - - bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq, output_id %x\n", - __func__, output_id); - return; - } - - for (i = 0; i < buf_info->num_planes; i++) { - mapped_info = &buf_info->mapped_info[i]; - - cam_smmu_put_phy_addr(buf_mgr->iommu_hdl, mapped_info->buf_fd); - } -} - -static int msm_isp_map_buf(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buffer_mapped_info *mapped_info, uint32_t fd) -{ - int rc = 0; - int ret; - - if (!buf_mgr || !mapped_info) { - pr_err_ratelimited("%s: %d] NULL ptr buf_mgr %pK mapped_info %pK\n", - __func__, __LINE__, buf_mgr, mapped_info); - return -EINVAL; - } - ret = cam_smmu_get_phy_addr(buf_mgr->iommu_hdl, - fd, - CAM_SMMU_MAP_RW, - &(mapped_info->paddr), - &(mapped_info->len)); - - if (ret) { - rc = -EINVAL; - pr_err_ratelimited("%s: cannot map address", __func__); - goto smmu_map_error; - } - CDBG("%s: addr:%pK\n", - __func__, (void *)mapped_info->paddr); - - return rc; -smmu_map_error: - cam_smmu_put_phy_addr(buf_mgr->iommu_hdl, - fd); - return rc; -} - -static int msm_isp_unmap_buf(struct msm_isp_buf_mgr *buf_mgr, - uint32_t fd) -{ - if (!buf_mgr) { - pr_err_ratelimited("%s: %d] NULL ptr buf_mgr\n", - __func__, __LINE__); - return -EINVAL; - } - - cam_smmu_put_phy_addr(buf_mgr->iommu_hdl, - fd); - - return 0; -} - -static int msm_isp_buf_prepare(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info, struct vb2_buffer *vb2_buf) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - struct msm_isp_qbuf_buffer buf; - - buf_info = msm_isp_get_buf_ptr(buf_mgr, - info->handle, info->buf_idx); - if (!buf_info) { - pr_err("Invalid buffer prepare\n"); - return rc; - } - - bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", - __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { - rc = buf_info->state; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - - if (buf_info->state != MSM_ISP_BUFFER_STATE_INITIALIZED) { - pr_err("%s: Invalid buffer state: %d bufq %x buf-id %d\n", - __func__, buf_info->state, bufq->bufq_handle, - buf_info->buf_idx); - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - - if (vb2_buf) { - msm_isp_copy_planes_from_v4l2_buffer(&buf, &vb2_buf->v4l2_buf); - buf_info->vb2_buf = vb2_buf; - } else { - buf = info->buffer; - } - - rc = msm_isp_prepare_v4l2_buf(buf_mgr, buf_info, &buf, bufq->output_id); - if (rc < 0) { - pr_err_ratelimited("%s: Prepare buffer error\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; -} - -static int msm_isp_buf_unprepare_all(struct msm_isp_buf_mgr *buf_mgr, - uint32_t buf_handle) -{ - int rc = -1, i; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, buf_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - - for (i = 0; i < bufq->num_bufs; i++) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, i); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED || - buf_info->state == - MSM_ISP_BUFFER_STATE_INITIALIZED) - continue; - - if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->flags)) { - if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) - buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, - bufq->session_id, bufq->stream_id); - } - msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info, bufq->stream_id); - } - return 0; -} - -int msm_isp_flush_queue(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle) -{ - uint32_t rc = 0; - int i = 0; - struct msm_isp_bufq *bufq = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err_ratelimited("%s: Invalid bufq\n", __func__); - return rc; - } - - rc = msm_isp_buf_unprepare_all(buf_mgr, bufq_handle); - - for (i = 0; i < ISP_NUM_BUF_MASK; i++) - bufq->put_buf_mask[i] = 0; - INIT_LIST_HEAD(&bufq->head); - - memset(bufq->bufs, 0x0, bufq->num_bufs*sizeof(bufq->bufs[0])); - for (i = 0; i < bufq->num_bufs; i++) { - bufq->bufs[i].state = MSM_ISP_BUFFER_STATE_INITIALIZED; - bufq->bufs[i].buf_debug.put_state[0] = - MSM_ISP_BUFFER_STATE_PUT_PREPARED; - bufq->bufs[i].buf_debug.put_state[1] = - MSM_ISP_BUFFER_STATE_PUT_PREPARED; - bufq->bufs[i].buf_debug.put_state_last = 0; - bufq->bufs[i].bufq_handle = bufq->bufq_handle; - bufq->bufs[i].buf_idx = i; - INIT_LIST_HEAD(&bufq->bufs[i].list); - } - - return rc; - -} - -static int msm_isp_get_buf_by_index(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct msm_isp_buffer **buf_info) -{ - int rc = -EINVAL; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *temp_buf_info; - uint32_t i = 0; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (buf_index >= bufq->num_bufs) { - pr_err("%s: Invalid buf index: %d max: %d\n", __func__, - buf_index, bufq->num_bufs); - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - - *buf_info = NULL; - for (i = 0; bufq->num_bufs; i++) { - temp_buf_info = &bufq->bufs[i]; - if (temp_buf_info && temp_buf_info->buf_idx == buf_index) { - *buf_info = temp_buf_info; - break; - } - } - - if (*buf_info) { - pr_debug("Found buf in isp buf mgr"); - rc = 0; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; -} - -static int msm_isp_buf_unprepare(struct msm_isp_buf_mgr *buf_mgr, - uint32_t buf_handle, int32_t buf_idx) -{ - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, buf_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return -EINVAL; - } - - buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, buf_idx); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return -EINVAL; - } - if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED || - buf_info->state == MSM_ISP_BUFFER_STATE_INITIALIZED) - return 0; - - if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->flags)) { - if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) - buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, - bufq->session_id, bufq->stream_id); - } - msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info, bufq->stream_id); - - return 0; -} - -static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct msm_isp_buffer **buf_info) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_buffer *temp_buf_info = NULL; - struct msm_isp_bufq *bufq = NULL; - struct vb2_buffer *vb2_buf = NULL; - - if (buf_mgr->open_count == 0) { - pr_err_ratelimited("%s: bug mgr open cnt = 0\n", - __func__); - return 0; - } - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err_ratelimited("%s: Invalid bufq\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (!bufq->bufq_handle) { - pr_err_ratelimited("%s: Invalid bufq handle\n", __func__); - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - - *buf_info = NULL; - - switch (BUF_SRC(bufq->flags)) { - case MSM_ISP_BUFFER_SRC_NATIVE: - list_for_each_entry(temp_buf_info, &bufq->head, list) { - if (temp_buf_info->state == - MSM_ISP_BUFFER_STATE_QUEUED) { - list_del_init(&temp_buf_info->list); - if (msm_buf_check_head_sanity(bufq) < 0) { - spin_unlock_irqrestore( - &bufq->bufq_lock, flags); - WARN(1, "%s buf_handle 0x%x buf_idx %d\n", - __func__, - bufq->bufq_handle, - temp_buf_info->buf_idx); - return -EFAULT; - } - *buf_info = temp_buf_info; - break; - } - } - break; - case MSM_ISP_BUFFER_SRC_HAL: - if (MSM_ISP_INVALID_BUF_INDEX == buf_index) - vb2_buf = buf_mgr->vb2_ops->get_buf( - bufq->session_id, bufq->stream_id); - else - vb2_buf = buf_mgr->vb2_ops->get_buf_by_idx( - bufq->session_id, bufq->stream_id, buf_index); - if (vb2_buf) { - if (vb2_buf->v4l2_buf.index < bufq->num_bufs) { - *buf_info = &bufq->bufs[vb2_buf - ->v4l2_buf.index]; - (*buf_info)->vb2_buf = vb2_buf; - } else { - pr_err("%s: Incorrect buf index %d\n", - __func__, vb2_buf->v4l2_buf.index); - rc = -EINVAL; - } - if ((*buf_info) == NULL) { - buf_mgr->vb2_ops->put_buf(vb2_buf, - bufq->session_id, bufq->stream_id); - pr_err("%s: buf index %d not found!\n", - __func__, vb2_buf->v4l2_buf.index); - rc = -EINVAL; - - } - } else { - CDBG("%s: No HAL Buffer session_id: %d stream_id: %d\n", - __func__, bufq->session_id, bufq->stream_id); - rc = -EINVAL; - } - break; - case MSM_ISP_BUFFER_SRC_SCRATCH: - /* In scratch buf case we have only on buffer in queue. - * We return every time same buffer. */ - *buf_info = list_entry(bufq->head.next, typeof(**buf_info), - list); - break; - default: - pr_err("%s: Incorrect buf source.\n", __func__); - rc = -EINVAL; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - - if (!(*buf_info)) { - rc = -ENOMEM; - } else { - (*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED; - rc = 0; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; -} - -static int msm_isp_put_buf_unsafe(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index) -{ - int rc = -1; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - - switch (buf_info->state) { - case MSM_ISP_BUFFER_STATE_PREPARED: - case MSM_ISP_BUFFER_STATE_DEQUEUED: - if (BUF_SRC(bufq->flags)) { - if (!list_empty(&buf_info->list)) { - WARN(1, "%s: buf %x/%x double add\n", - __func__, bufq_handle, buf_index); - return -EFAULT; - } - list_add_tail(&buf_info->list, &bufq->head); - if (msm_buf_check_head_sanity(bufq) < 0) { - WARN(1, "%s buf_handle 0x%x buf_idx %d\n", - __func__, - bufq->bufq_handle, - buf_info->buf_idx); - return -EFAULT; - } - } else { - buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, - bufq->session_id, bufq->stream_id); - } - buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; - rc = 0; - break; - case MSM_ISP_BUFFER_STATE_DISPATCHED: - buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; - rc = 0; - break; - case MSM_ISP_BUFFER_STATE_QUEUED: - case MSM_ISP_BUFFER_STATE_DIVERTED: - default: - WARN(1, "%s: bufq 0x%x, buf idx 0x%x, incorrect state = %d", - __func__, bufq_handle, buf_index, buf_info->state); - return -EFAULT; - } - - return rc; -} - -static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - - rc = msm_isp_put_buf_unsafe(buf_mgr, bufq_handle, buf_index); - - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - - return rc; -} - -static int msm_isp_update_put_buf_cnt_unsafe( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit) -{ - int rc = -1; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - uint8_t *put_buf_mask = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return rc; - } - - put_buf_mask = &bufq->put_buf_mask[pingpong_bit]; - - if (buf_index >= 0) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return -EFAULT; - } - if (buf_info->state != MSM_ISP_BUFFER_STATE_DEQUEUED) { - pr_err( - "%s: Invalid state, bufq_handle %x output_id %x, state %d\n", - __func__, bufq_handle, - bufq->output_id, buf_info->state); - return -EFAULT; - } - if (buf_info->pingpong_bit != pingpong_bit) { - pr_err("%s: Pingpong bit mismatch\n", __func__); - return -EFAULT; - } - } - - if (bufq->buf_type != ISP_SHARE_BUF || - (*put_buf_mask == 0)) { - if (buf_info) - buf_info->frame_id = frame_id; - } - - if (bufq->buf_type == ISP_SHARE_BUF && - ((*put_buf_mask & (1 << id)) == 0)) { - *put_buf_mask |= (1 << id); - if (*put_buf_mask != ISP_SHARE_BUF_MASK) { - rc = *put_buf_mask; - return 1; - } - *put_buf_mask = 0; - rc = 0; - } else if (bufq->buf_type == ISP_SHARE_BUF && - (*put_buf_mask & (1 << id)) != 0) { - return -ENOTEMPTY; - } - - if (buf_info && - MSM_ISP_BUFFER_SRC_NATIVE == BUF_SRC(bufq->flags)) { - buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; - buf_info->tv = tv; - } - return 0; -} - -static int msm_isp_update_put_buf_cnt(struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit) -{ - int rc = -1; - struct msm_isp_bufq *bufq = NULL; - unsigned long flags; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - rc = msm_isp_update_put_buf_cnt_unsafe(buf_mgr, id, bufq_handle, - buf_index, tv, frame_id, pingpong_bit); - if (-ENOTEMPTY == rc) { - pr_err("%s: Error! Uncleared put_buf_mask for pingpong(%d) from vfe %d bufq 0x%x buf_idx %d\n", - __func__, pingpong_bit, id, bufq_handle, buf_index); - msm_isp_dump_ping_pong_mismatch(); - rc = -EFAULT; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; -} - -static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t output_format) -{ - int rc = 0; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - enum msm_isp_buffer_state state; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return -EINVAL; - } - - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return -EINVAL; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - state = buf_info->state; - - if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->flags)) { - if (state == MSM_ISP_BUFFER_STATE_DEQUEUED) { - buf_info->state = MSM_ISP_BUFFER_STATE_DISPATCHED; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf, - bufq->session_id, bufq->stream_id, - frame_id, tv, output_format); - } else { - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - } - goto done; - } - - /* - * For native buffer put the diverted buffer back to queue since caller - * is not going to send it to CPP, this is error case like - * drop_frame/empty_buffer - */ - if (state == MSM_ISP_BUFFER_STATE_DIVERTED) { - buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; - rc = msm_isp_put_buf_unsafe(buf_mgr, buf_info->bufq_handle, - buf_info->buf_idx); - if (rc < 0) - pr_err("%s: Buf put failed\n", __func__); - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); -done: - return rc; -} - -static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, - uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type, - struct timeval *tv, uint32_t frame_id) -{ - int rc = 0, i; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - unsigned long flags; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return -EINVAL; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - for (i = 0; i < bufq->num_bufs; i++) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, i); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - continue; - } - if ((flush_type == MSM_ISP_BUFFER_FLUSH_DIVERTED) && - (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED)) { - buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; - msm_isp_put_buf_unsafe(buf_mgr, - bufq_handle, buf_info->buf_idx); - } else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL) { - if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { - CDBG("%s: no need to queue Diverted buffer\n", - __func__); - } else if (buf_info->state == - MSM_ISP_BUFFER_STATE_DEQUEUED) { - rc = msm_isp_update_put_buf_cnt_unsafe(buf_mgr, - id, bufq_handle, buf_info->buf_idx, tv, - frame_id, buf_info->pingpong_bit); - if (-ENOTEMPTY == rc) { - rc = 0; - continue; - } - - if (rc == 0) { - buf_info->buf_debug.put_state[ - buf_info->buf_debug. - put_state_last] - = MSM_ISP_BUFFER_STATE_FLUSH; - buf_info->buf_debug.put_state_last ^= 1; - buf_info->state = - MSM_ISP_BUFFER_STATE_PREPARED; - rc = msm_isp_put_buf_unsafe(buf_mgr, - bufq_handle, buf_info->buf_idx); - if (rc == -EFAULT) { - spin_unlock_irqrestore( - &bufq->bufq_lock, - flags); - return rc; - } - } - } - } - } - - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return 0; -} - -static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info) -{ - int rc = 0, buf_state; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, info->handle); - if (!bufq) { - pr_err("%s: Invalid bufq, handle 0x%x, stream id %x num_plane %d\n" - , __func__, info->handle, (info->handle >> 8), - info->buffer.num_planes); - return -EINVAL; - } - - buf_state = msm_isp_buf_prepare(buf_mgr, info, NULL); - if (buf_state < 0) { - pr_err_ratelimited("%s: Buf prepare failed\n", __func__); - return -EINVAL; - } - - if (buf_state == MSM_ISP_BUFFER_STATE_DIVERTED) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, - info->handle, info->buf_idx); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return -EINVAL; - } - if (info->dirty_buf) { - buf_info->buf_debug.put_state[ - buf_info->buf_debug.put_state_last] - = MSM_ISP_BUFFER_STATE_PUT_BUF; - buf_info->buf_debug.put_state_last ^= 1; - buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; - rc = msm_isp_put_buf(buf_mgr, - info->handle, info->buf_idx); - } else { - if (BUF_SRC(bufq->flags)) - pr_err("%s: Invalid native buffer state\n", - __func__); - else { - buf_info->buf_debug.put_state[ - buf_info->buf_debug.put_state_last] = - MSM_ISP_BUFFER_STATE_PUT_BUF; - buf_info->buf_debug.put_state_last ^= 1; - rc = msm_isp_buf_done(buf_mgr, - info->handle, info->buf_idx, - buf_info->tv, buf_info->frame_id, 0); - } - } - } else { - if (MSM_ISP_BUFFER_SRC_HAL != BUF_SRC(bufq->flags)) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, - info->handle, info->buf_idx); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return -EINVAL; - } - - buf_info->buf_debug.put_state[ - buf_info->buf_debug.put_state_last] = - MSM_ISP_BUFFER_STATE_PUT_PREPARED; - buf_info->buf_debug.put_state_last ^= 1; - rc = msm_isp_put_buf(buf_mgr, - info->handle, info->buf_idx); - if (rc < 0) { - pr_err("%s: Buf put failed stream %x\n", - __func__, bufq->stream_id); - return rc; - } - } - } - return 0; -} - -static int msm_isp_buf_dequeue(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info) -{ - struct msm_isp_buffer *buf_info = NULL; - int rc = 0; - - buf_info = msm_isp_get_buf_ptr(buf_mgr, info->handle, info->buf_idx); - if (!buf_info) { - pr_err("Invalid buffer dequeue\n"); - return -EINVAL; - } - - if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { - pr_err("%s: Invalid state %d\n", __func__, buf_info->state); - return -EINVAL; - } - msm_isp_buf_unprepare(buf_mgr, info->handle, info->buf_idx); - - buf_info->state = MSM_ISP_BUFFER_STATE_INITIALIZED; - - return rc; -} - -static int msm_isp_get_bufq_handle(struct msm_isp_buf_mgr *buf_mgr, - uint32_t vfe_id, uint32_t output_id) -{ - int i; - - for (i = 0; i < buf_mgr->num_buf_q; i++) { - if ((buf_mgr->bufq[i].vfe_id == vfe_id) && - (buf_mgr->bufq[i].output_id == output_id)) { - return buf_mgr->bufq[i].bufq_handle; - } - } - pr_err("%s: No match found 0x%x 0x%x\n", __func__, - vfe_id, output_id); - return 0; -} - -static int msm_isp_get_buf_src(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t *buf_src) -{ - struct msm_isp_bufq *bufq = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", - __func__); - return -EINVAL; - } - *buf_src = BUF_SRC(bufq->flags); - - return 0; -} - -static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buf_request *buf_request) -{ - int i; - struct msm_isp_bufq *bufq = NULL; - - CDBG("%s: E\n", __func__); - - if (!buf_request->num_buf || buf_request->num_buf > VB2_MAX_FRAME) { - pr_err("Invalid buffer request\n"); - return -EINVAL; - } - - buf_request->handle = msm_isp_get_buf_handle(buf_mgr, - buf_request->vfe_id, buf_request->output_id); - if (!buf_request->handle) { - pr_err("%s: Invalid buffer handle\n", __func__); - return -EINVAL; - } - - bufq = msm_isp_get_bufq(buf_mgr, buf_request->handle); - if (!bufq) { - pr_err("%s: Invalid bufq output_id %x\n", - __func__, buf_request->output_id); - - return -EINVAL; - } - - bufq->bufs = kzalloc(sizeof(struct msm_isp_buffer) * - buf_request->num_buf, GFP_KERNEL); - if (!bufq->bufs) { - msm_isp_free_bufq_handle(buf_mgr, buf_request->handle); - return -ENOMEM; - } - spin_lock_init(&bufq->bufq_lock); - bufq->bufq_handle = buf_request->handle; - bufq->vfe_id = buf_request->vfe_id; - bufq->flags = buf_request->flags; - bufq->output_id = buf_request->output_id; - bufq->num_bufs = buf_request->num_buf; - bufq->buf_type = buf_request->buf_type; - for (i = 0; i < ISP_NUM_BUF_MASK; i++) - bufq->put_buf_mask[i] = 0; - INIT_LIST_HEAD(&bufq->head); - - for (i = 0; i < buf_request->num_buf; i++) { - bufq->bufs[i].state = MSM_ISP_BUFFER_STATE_INITIALIZED; - bufq->bufs[i].buf_debug.put_state[0] = - MSM_ISP_BUFFER_STATE_PUT_PREPARED; - bufq->bufs[i].buf_debug.put_state[1] = - MSM_ISP_BUFFER_STATE_PUT_PREPARED; - bufq->bufs[i].buf_debug.put_state_last = 0; - bufq->bufs[i].bufq_handle = bufq->bufq_handle; - bufq->bufs[i].buf_idx = i; - INIT_LIST_HEAD(&bufq->bufs[i].list); - } - - return 0; -} - -static int msm_isp_release_bufq(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle) -{ - struct msm_isp_bufq *bufq = NULL; - unsigned long flags; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq release\n"); - return -EINVAL; - } - - msm_isp_buf_unprepare_all(buf_mgr, bufq_handle); - - spin_lock_irqsave(&bufq->bufq_lock, flags); - kfree(bufq->bufs); - msm_isp_free_bufq_handle(buf_mgr, bufq_handle); - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - - return 0; -} - -static void msm_isp_release_all_bufq( - struct msm_isp_buf_mgr *buf_mgr) -{ - struct msm_isp_bufq *bufq = NULL; - unsigned long flags; - int i; - - for (i = 0; i < buf_mgr->num_buf_q; i++) { - bufq = &buf_mgr->bufq[i]; - if (!bufq->bufq_handle) - continue; - - msm_isp_buf_unprepare_all(buf_mgr, bufq->bufq_handle); - - spin_lock_irqsave(&bufq->bufq_lock, flags); - kfree(bufq->bufs); - msm_isp_free_bufq_handle(buf_mgr, bufq->bufq_handle); - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - } -} - - -/** - * msm_isp_buf_put_scratch() - Release scratch buffers - * @buf_mgr: The buffer structure for h/w - * - * Returns 0 on success else error code - */ -static int msm_isp_buf_put_scratch(struct msm_isp_buf_mgr *buf_mgr) -{ - int rc; - - if (!buf_mgr->scratch_buf_addr) - return 0; - - rc = cam_smmu_put_phy_addr_scratch(buf_mgr->iommu_hdl, - buf_mgr->scratch_buf_addr); - if (rc) - pr_err("%s: failed to put scratch buffer to img iommu: %d\n", - __func__, rc); - - - if (!rc) - buf_mgr->scratch_buf_addr = 0; - - return rc; -} - -/** - * msm_isp_buf_get_scratch() - Create scratch buffers - * @buf_mgr: The buffer structure for h/w - * - * Create and map scratch buffers for all IOMMU's under the buffer - * manager. - * - * Returns 0 on success else error code - */ -static int msm_isp_buf_get_scratch(struct msm_isp_buf_mgr *buf_mgr) -{ - int rc; - - if (buf_mgr->scratch_buf_addr || !buf_mgr->scratch_buf_range) - /* already mapped or not supported */ - return 0; - - rc = cam_smmu_get_phy_addr_scratch( - buf_mgr->iommu_hdl, - CAM_SMMU_MAP_RW, - &buf_mgr->scratch_buf_addr, - buf_mgr->scratch_buf_range, - SZ_4K); - if (rc) { - pr_err("%s: failed to map scratch buffer to img iommu: %d\n", - __func__, rc); - return rc; - } - return rc; -} - -int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr, - void *arg) -{ - struct msm_vfe_smmu_attach_cmd *cmd = arg; - int rc = 0; - - pr_debug("%s: cmd->security_mode : %d\n", __func__, cmd->security_mode); - mutex_lock(&buf_mgr->lock); - if (cmd->iommu_attach_mode == IOMMU_ATTACH) { - buf_mgr->secure_enable = cmd->security_mode; - - /* - * Call hypervisor thru scm call to notify secure or - * non-secure mode - */ - if (buf_mgr->attach_ref_cnt == 0) { - rc = cam_smmu_ops(buf_mgr->iommu_hdl, - CAM_SMMU_ATTACH); - if (rc < 0) { - pr_err("%s: img smmu attach error, rc :%d\n", - __func__, rc); - goto err1; - } - } - buf_mgr->attach_ref_cnt++; - rc = msm_isp_buf_get_scratch(buf_mgr); - if (rc) - goto err2; - } else { - if (buf_mgr->attach_ref_cnt > 0) - buf_mgr->attach_ref_cnt--; - else - pr_err("%s: Error! Invalid ref_cnt %d\n", - __func__, buf_mgr->attach_ref_cnt); - - if (buf_mgr->attach_ref_cnt == 0) { - rc = msm_isp_buf_put_scratch(buf_mgr); - rc |= cam_smmu_ops(buf_mgr->iommu_hdl, - CAM_SMMU_DETACH); - if (rc < 0) { - pr_err("%s: img/stats smmu detach error, rc :%d\n", - __func__, rc); - } - } - } - - mutex_unlock(&buf_mgr->lock); - return rc; - -err2: - if (cam_smmu_ops(buf_mgr->iommu_hdl, CAM_SMMU_DETACH)) - pr_err("%s: img smmu detach error\n", __func__); -err1: - mutex_unlock(&buf_mgr->lock); - return rc; -} - - -static int msm_isp_init_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr, - const char *ctx_name) -{ - int rc = -1; - int i = 0; - - mutex_lock(&buf_mgr->lock); - if (buf_mgr->open_count++) { - mutex_unlock(&buf_mgr->lock); - return 0; - } - - CDBG("%s: E\n", __func__); - buf_mgr->attach_ref_cnt = 0; - - buf_mgr->num_buf_q = BUF_MGR_NUM_BUF_Q; - memset(buf_mgr->bufq, 0, sizeof(buf_mgr->bufq)); - - rc = cam_smmu_get_handle("vfe", &buf_mgr->iommu_hdl); - if (rc < 0) { - pr_err("vfe get handle failed\n"); - goto get_handle_error; - } - - for (i = 0; i < BUF_MGR_NUM_BUF_Q; i++) - spin_lock_init(&buf_mgr->bufq[i].bufq_lock); - - buf_mgr->pagefault_debug_disable = 0; - buf_mgr->frameId_mismatch_recovery = 0; - mutex_unlock(&buf_mgr->lock); - return 0; - -get_handle_error: - mutex_unlock(&buf_mgr->lock); - return rc; -} - -static int msm_isp_deinit_isp_buf_mgr( - struct msm_isp_buf_mgr *buf_mgr) -{ - mutex_lock(&buf_mgr->lock); - if (buf_mgr->open_count > 0) - buf_mgr->open_count--; - - if (buf_mgr->open_count) { - mutex_unlock(&buf_mgr->lock); - return 0; - } - msm_isp_release_all_bufq(buf_mgr); - buf_mgr->num_buf_q = 0; - buf_mgr->pagefault_debug_disable = 0; - - msm_isp_buf_put_scratch(buf_mgr); - cam_smmu_ops(buf_mgr->iommu_hdl, CAM_SMMU_DETACH); - cam_smmu_destroy_handle(buf_mgr->iommu_hdl); - - buf_mgr->attach_ref_cnt = 0; - mutex_unlock(&buf_mgr->lock); - return 0; -} - -int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, - unsigned int cmd, void *arg) -{ - int rc = -EINVAL; - - switch (cmd) { - case VIDIOC_MSM_ISP_REQUEST_BUFQ: { - struct msm_isp_buf_request *buf_req = arg; - - rc = buf_mgr->ops->request_bufq(buf_mgr, buf_req); - break; - } - case VIDIOC_MSM_ISP_RELEASE_BUFQ: { - struct msm_isp_buf_request *buf_req = arg; - - rc = buf_mgr->ops->release_bufq(buf_mgr, buf_req->handle); - break; - } - case VIDIOC_MSM_ISP_ENQUEUE_BUF: { - struct msm_isp_qbuf_info *qbuf_info = arg; - - rc = buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info); - break; - } - case VIDIOC_MSM_ISP_DEQUEUE_BUF: { - struct msm_isp_qbuf_info *qbuf_info = arg; - - rc = buf_mgr->ops->dequeue_buf(buf_mgr, qbuf_info); - break; - } - case VIDIOC_MSM_ISP_UNMAP_BUF: { - struct msm_isp_unmap_buf_req *unmap_req = arg; - - rc = buf_mgr->ops->unmap_buf(buf_mgr, unmap_req->fd); - break; - } - } - return rc; -} - -static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr, - unsigned long fault_addr) -{ - struct msm_isp_buffer *bufs = NULL; - uint32_t i = 0, j = 0, k = 0, rc = 0; - char *print_buf = NULL, temp_buf[100]; - uint32_t print_buf_size = 2000; - unsigned long start_addr = 0, end_addr = 0; - int buf_addr_delta = -1; - int temp_delta = 0; - uint32_t debug_output_id = 0; - uint32_t debug_buf_idx = 0; - uint32_t debug_buf_plane = 0; - unsigned long debug_start_addr = 0; - unsigned long debug_end_addr = 0; - uint32_t debug_frame_id = 0; - enum msm_isp_buffer_state debug_state = MSM_ISP_BUFFER_STATE_UNUSED; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - - if (!buf_mgr) { - pr_err_ratelimited("%s: %d] NULL buf_mgr\n", - __func__, __LINE__); - return -EINVAL; - } - - for (i = 0; i < BUF_MGR_NUM_BUF_Q; i++) { - bufq = &buf_mgr->bufq[i]; - - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (!bufq->bufq_handle) { - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - continue; - } - - for (j = 0; j < bufq->num_bufs; j++) { - bufs = &bufq->bufs[j]; - if (!bufs) - continue; - - for (k = 0; k < bufs->num_planes; k++) { - start_addr = bufs-> - mapped_info[k].paddr; - end_addr = bufs->mapped_info[k].paddr + - bufs->mapped_info[k].len - 1; - temp_delta = fault_addr - start_addr; - if (temp_delta < 0) - continue; - - if (buf_addr_delta == -1 || - temp_delta < buf_addr_delta) { - buf_addr_delta = temp_delta; - debug_output_id = bufq->output_id; - debug_buf_idx = j; - debug_buf_plane = k; - debug_start_addr = start_addr; - debug_end_addr = end_addr; - debug_frame_id = bufs->frame_id; - debug_state = bufs->state; - } - } - } - start_addr = 0; - end_addr = 0; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - } - - pr_err("%s: ==== SMMU page fault addr %lx ====\n", __func__, - fault_addr); - pr_err("%s: nearby output id %x, frame_id %d\n", __func__, - debug_output_id, debug_frame_id); - pr_err("%s: nearby buf index %d, plane %d, state %d\n", __func__, - debug_buf_idx, debug_buf_plane, debug_state); - pr_err("%s: buf address %pK -- %pK\n", __func__, - (void *)debug_start_addr, (void *)debug_end_addr); - - if (BUF_DEBUG_FULL) { - print_buf = kzalloc(print_buf_size, GFP_ATOMIC); - if (!print_buf) { - pr_err("%s failed: No memory", __func__); - return -ENOMEM; - } - snprintf(print_buf, print_buf_size, "%s\n", __func__); - for (i = 0; i < BUF_MGR_NUM_BUF_Q; i++) { - if (i % 2 == 0 && i > 0) { - pr_err("%s\n", print_buf); - print_buf[0] = 0; - } - if (buf_mgr->bufq[i].bufq_handle != 0) { - snprintf(temp_buf, sizeof(temp_buf), - "handle %x output %x num_bufs %d\n", - buf_mgr->bufq[i].bufq_handle, - buf_mgr->bufq[i].output_id, - buf_mgr->bufq[i].num_bufs); - strlcat(print_buf, temp_buf, print_buf_size); - for (j = 0; j < buf_mgr->bufq[i].num_bufs; - j++) { - bufs = &buf_mgr->bufq[i].bufs[j]; - if (!bufs) - break; - - for (k = 0; k < bufs->num_planes; k++) { - start_addr = bufs-> - mapped_info[k].paddr; - end_addr = bufs->mapped_info[k]. - paddr + bufs-> - mapped_info[k].len; - snprintf(temp_buf, - sizeof(temp_buf), - " buf %d plane %d start_addr %pK end_addr %pK\n", - j, k, - (void *)start_addr, - (void *)end_addr); - strlcat(print_buf, temp_buf, - print_buf_size); - } - } - start_addr = 0; - end_addr = 0; - } - } - pr_err("%s\n", print_buf); - kfree(print_buf); - } - return rc; -} - -static struct msm_isp_buf_ops isp_buf_ops = { - .request_bufq = msm_isp_request_bufq, - .release_bufq = msm_isp_release_bufq, - .enqueue_buf = msm_isp_buf_enqueue, - .dequeue_buf = msm_isp_buf_dequeue, - .get_bufq_handle = msm_isp_get_bufq_handle, - .get_buf_src = msm_isp_get_buf_src, - .get_buf = msm_isp_get_buf, - .get_buf_by_index = msm_isp_get_buf_by_index, - .map_buf = msm_isp_map_buf, - .unmap_buf = msm_isp_unmap_buf, - .put_buf = msm_isp_put_buf, - .flush_buf = msm_isp_flush_buf, - .buf_done = msm_isp_buf_done, - .buf_mgr_init = msm_isp_init_isp_buf_mgr, - .buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr, - .buf_mgr_debug = msm_isp_buf_mgr_debug, - .get_bufq = msm_isp_get_bufq, - .update_put_buf_cnt = msm_isp_update_put_buf_cnt, -}; - -int msm_isp_create_isp_buf_mgr( - struct msm_isp_buf_mgr *buf_mgr, - struct msm_sd_req_vb2_q *vb2_ops, - struct device *dev, - uint32_t scratch_buf_range) -{ - int rc = 0; - - if (buf_mgr->init_done) - return rc; - - buf_mgr->ops = &isp_buf_ops; - buf_mgr->vb2_ops = vb2_ops; - buf_mgr->open_count = 0; - buf_mgr->pagefault_debug_disable = 0; - buf_mgr->secure_enable = NON_SECURE_MODE; - buf_mgr->attach_state = MSM_ISP_BUF_MGR_DETACH; - buf_mgr->scratch_buf_range = scratch_buf_range; - mutex_init(&buf_mgr->lock); - - return 0; -} diff --git a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.h b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.h deleted file mode 100644 index d8e610541032ee9f4c011bc90aac6020d4de5ceb..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.h +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef _MSM_ISP_BUF_H_ -#define _MSM_ISP_BUF_H_ - -#include -#include "msm_sd.h" - -/** Buffer type could be userspace / HAL. - * Userspase could provide native or scratch buffer. */ -#define BUF_SRC(id) ( \ - (id & ISP_SCRATCH_BUF_BIT) ? MSM_ISP_BUFFER_SRC_SCRATCH : \ - (id & ISP_NATIVE_BUF_BIT) ? MSM_ISP_BUFFER_SRC_NATIVE : \ - MSM_ISP_BUFFER_SRC_HAL) - -/* - * This mask can be set dynamically if there are more than 2 VFE - * and 2 of those are used - */ -#define ISP_SHARE_BUF_MASK 0x3 -#define ISP_NUM_BUF_MASK 2 -#define BUF_MGR_NUM_BUF_Q 28 -#define MAX_IOMMU_CTX 2 - -#define MSM_ISP_INVALID_BUF_INDEX 0xFFFFFFFF - -struct msm_isp_buf_mgr; - -enum msm_isp_buffer_src_t { - MSM_ISP_BUFFER_SRC_HAL, - MSM_ISP_BUFFER_SRC_NATIVE, - MSM_ISP_BUFFER_SRC_SCRATCH, - MSM_ISP_BUFFER_SRC_MAX, -}; - -enum msm_isp_buffer_state { - MSM_ISP_BUFFER_STATE_UNUSED, /* not used */ - MSM_ISP_BUFFER_STATE_INITIALIZED, /* REQBUF done */ - MSM_ISP_BUFFER_STATE_PREPARED, /* BUF mapped */ - MSM_ISP_BUFFER_STATE_QUEUED, /* buf queued */ - MSM_ISP_BUFFER_STATE_DEQUEUED, /* in use in VFE */ - MSM_ISP_BUFFER_STATE_DIVERTED, /* Sent to other hardware*/ - MSM_ISP_BUFFER_STATE_DISPATCHED, /* Sent to HAL*/ -}; - -enum msm_isp_buffer_put_state { - MSM_ISP_BUFFER_STATE_PUT_PREPARED, /* on init */ - MSM_ISP_BUFFER_STATE_PUT_BUF, /* on rotation */ - MSM_ISP_BUFFER_STATE_FLUSH, /* on recovery */ - MSM_ISP_BUFFER_STATE_DROP_REG, /* on drop frame for reg_update */ - MSM_ISP_BUFFER_STATE_DROP_SKIP, /* on drop frame for sw skip */ - MSM_ISP_BUFFER_STATE_RETURN_EMPTY, /* for return empty */ -}; - -enum msm_isp_buffer_flush_t { - MSM_ISP_BUFFER_FLUSH_DIVERTED, - MSM_ISP_BUFFER_FLUSH_ALL, -}; - -enum msm_isp_buf_mgr_state { - MSM_ISP_BUF_MGR_ATTACH, - MSM_ISP_BUF_MGR_DETACH, -}; - -struct msm_isp_buffer_mapped_info { - size_t len; - dma_addr_t paddr; - int buf_fd; -}; - -struct buffer_cmd { - struct list_head list; - struct msm_isp_buffer_mapped_info *mapped_info; -}; - -struct msm_isp_buffer_debug_t { - enum msm_isp_buffer_put_state put_state[2]; - uint8_t put_state_last; -}; - -struct msm_isp_buffer { - /*Common Data structure*/ - int num_planes; - struct msm_isp_buffer_mapped_info mapped_info[VIDEO_MAX_PLANES]; - int buf_idx; - uint32_t bufq_handle; - uint32_t frame_id; - struct timeval *tv; - /* Indicates whether buffer is used as ping ot pong buffer */ - uint32_t pingpong_bit; - - /*Native buffer*/ - struct list_head list; - enum msm_isp_buffer_state state; - - struct msm_isp_buffer_debug_t buf_debug; - - /*Vb2 buffer data*/ - struct vb2_buffer *vb2_buf; -}; - -struct msm_isp_bufq { - uint32_t vfe_id; - enum msm_vfe_axi_stream_src output_id; - uint32_t flags; - uint32_t num_bufs; - uint32_t bufq_handle; - enum msm_isp_buf_type buf_type; - struct msm_isp_buffer *bufs; - spinlock_t bufq_lock; - uint8_t put_buf_mask[ISP_NUM_BUF_MASK]; - /*Native buffer queue*/ - struct list_head head; - /*deprecated params*/ - uint32_t session_id; - uint32_t stream_id; -}; - -struct msm_isp_buf_ops { - int (*request_bufq)(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buf_request *buf_request); - - int (*release_bufq)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle); - - int (*enqueue_buf)(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info); - - int (*dequeue_buf)(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info); - - int (*get_bufq_handle)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t vfe_id, uint32_t output_id); - - int (*get_buf_src)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t *buf_src); - - int (*get_buf)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct msm_isp_buffer **buf_info); - - int (*get_buf_by_index)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct msm_isp_buffer **buf_info); - - int (*map_buf)(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buffer_mapped_info *mapped_info, uint32_t fd); - - int (*unmap_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t fd); - - int (*put_buf)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index); - - int (*flush_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, - uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type, - struct timeval *tv, uint32_t frame_id); - - int (*buf_done)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t output_format); - void (*register_ctx)(struct msm_isp_buf_mgr *buf_mgr, - struct device **iommu_ctx1, struct device **iommu_ctx2, - int num_iommu_ctx1, int num_iommu_ctx2); - int (*buf_mgr_init)(struct msm_isp_buf_mgr *buf_mgr, - const char *ctx_name); - int (*buf_mgr_deinit)(struct msm_isp_buf_mgr *buf_mgr); - int (*buf_mgr_debug)(struct msm_isp_buf_mgr *buf_mgr, - unsigned long fault_addr); - struct msm_isp_bufq * (*get_bufq)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle); - int (*update_put_buf_cnt)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit); -}; - -struct msm_isp_buf_mgr { - int init_done; - uint32_t open_count; - uint32_t pagefault_debug_disable; - uint32_t frameId_mismatch_recovery; - uint16_t num_buf_q; - struct msm_isp_bufq bufq[BUF_MGR_NUM_BUF_Q]; - - struct ion_client *client; - struct msm_isp_buf_ops *ops; - - struct msm_sd_req_vb2_q *vb2_ops; - - /*IOMMU driver*/ - int iommu_hdl; - - /*Add secure mode*/ - int secure_enable; - - int num_iommu_ctx; - int num_iommu_secure_ctx; - int attach_ref_cnt; - enum msm_isp_buf_mgr_state attach_state; - struct device *isp_dev; - struct mutex lock; - /* Scratch buffer */ - dma_addr_t scratch_buf_addr; - uint32_t scratch_buf_range; -}; - -int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr, - struct msm_sd_req_vb2_q *vb2_ops, struct device *dev, - uint32_t scratch_addr_range); - -int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, - unsigned int cmd, void *arg); - -int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr, - void *arg); - -int msm_isp_flush_queue(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle); - -#endif /* _MSM_ISP_BUF_H_ */ diff --git a/drivers/media/platform/msm/ais/isp/msm_isp.c b/drivers/media/platform/msm/ais/isp/msm_isp.c deleted file mode 100644 index 97c0f779cf739e2549e50cb6eafe07ae9eae5e3b..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_isp.c +++ /dev/null @@ -1,658 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_isp.h" -#include "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_isp_stats_util.h" -#include "msm_sd.h" - -static struct msm_sd_req_vb2_q vfe_vb2_ops; -static struct msm_isp_buf_mgr vfe_buf_mgr; -static struct msm_vfe_common_dev_data vfe_common_data; -static struct dual_vfe_resource dualvfe; - -static const struct of_device_id msm_vfe_dt_match[] = { - { - .compatible = "qcom,vfe", - }, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_vfe_dt_match); - -#define MAX_OVERFLOW_COUNTERS 29 -#define OVERFLOW_LENGTH 1024 -#define OVERFLOW_BUFFER_LENGTH 64 -static char stat_line[OVERFLOW_LENGTH]; - -struct msm_isp_statistics stats; -struct msm_isp_ub_info ub_info; - -static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev, - struct msm_isp_bw_req_info *isp_req_hist); - -static char *stats_str[MAX_OVERFLOW_COUNTERS] = { - "imgmaster0_overflow_cnt", - "imgmaster1_overflow_cnt", - "imgmaster2_overflow_cnt", - "imgmaster3_overflow_cnt", - "imgmaster4_overflow_cnt", - "imgmaster5_overflow_cnt", - "imgmaster6_overflow_cnt", - "be_overflow_cnt", - "bg_overflow_cnt", - "bf_overflow_cnt", - "awb_overflow_cnt", - "rs_overflow_cnt", - "cs_overflow_cnt", - "ihist_overflow_cnt", - "skinbhist_overflow_cnt", - "bfscale_overflow_cnt", - "ISP_VFE0_client_info.active", - "ISP_VFE0_client_info.ab", - "ISP_VFE0_client_info.ib", - "ISP_VFE1_client_info.active", - "ISP_VFE1_client_info.ab", - "ISP_VFE1_client_info.ib", - "ISP_CPP_client_info.active", - "ISP_CPP_client_info.ab", - "ISP_CPP_client_info.ib", - "ISP_last_overflow.ab", - "ISP_last_overflow.ib", - "ISP_VFE_CLK_RATE", - "ISP_CPP_CLK_RATE", -}; - -#define MAX_DEPTH_BW_REQ_HISTORY 25 -#define MAX_BW_HISTORY_BUFF_LEN 6144 -#define MAX_BW_HISTORY_LINE_BUFF_LEN 512 - -#define MAX_UB_INFO_BUFF_LEN 1024 -#define MAX_UB_INFO_LINE_BUFF_LEN 256 - -static struct msm_isp_bw_req_info - msm_isp_bw_request_history[MAX_DEPTH_BW_REQ_HISTORY]; -static int msm_isp_bw_request_history_idx; -static char bw_request_history_buff[MAX_BW_HISTORY_BUFF_LEN]; -static char ub_info_buffer[MAX_UB_INFO_BUFF_LEN]; -static spinlock_t req_history_lock; - -static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char, - size_t t_size_t, loff_t *t_loff_t) -{ - int i; - uint64_t *ptr; - char buffer[OVERFLOW_BUFFER_LENGTH] = {0}; - struct vfe_device *vfe_dev = (struct vfe_device *) - t_file->private_data; - struct msm_isp_statistics *stats = vfe_dev->stats; - - memset(stat_line, 0, sizeof(stat_line)); - msm_isp_util_get_bandwidth_stats(vfe_dev, stats); - ptr = (uint64_t *)(stats); - for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) { - strlcat(stat_line, stats_str[i], sizeof(stat_line)); - strlcat(stat_line, " ", sizeof(stat_line)); - snprintf(buffer, sizeof(buffer), "%llu", ptr[i]); - strlcat(stat_line, buffer, sizeof(stat_line)); - strlcat(stat_line, "\r\n", sizeof(stat_line)); - } - return simple_read_from_buffer(t_char, t_size_t, - t_loff_t, stat_line, strlen(stat_line)); -} - -static ssize_t vfe_debugfs_statistics_write(struct file *t_file, - const char *t_char, size_t t_size_t, loff_t *t_loff_t) -{ - struct vfe_device *vfe_dev = (struct vfe_device *) - t_file->private_data; - struct msm_isp_statistics *stats = vfe_dev->stats; - - memset(stats, 0, sizeof(struct msm_isp_statistics)); - - return sizeof(struct msm_isp_statistics); -} - -static int bw_history_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t bw_history_read(struct file *t_file, char *t_char, - size_t t_size_t, loff_t *t_loff_t) -{ - int i; - char *out_buffer = bw_request_history_buff; - char line_buffer[MAX_BW_HISTORY_LINE_BUFF_LEN] = {0}; - struct msm_isp_bw_req_info *isp_req_hist = - (struct msm_isp_bw_req_info *) t_file->private_data; - - memset(out_buffer, 0, MAX_BW_HISTORY_BUFF_LEN); - - snprintf(line_buffer, sizeof(line_buffer), - "Bus bandwidth request history in chronological order:\n"); - strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff)); - - snprintf(line_buffer, sizeof(line_buffer), - "MSM_ISP_MIN_AB = %u, MSM_ISP_MIN_IB = %u\n\n", - MSM_ISP_MIN_AB, MSM_ISP_MIN_IB); - strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff)); - - for (i = 0; i < MAX_DEPTH_BW_REQ_HISTORY; i++) { - snprintf(line_buffer, sizeof(line_buffer), - "idx = %d, client = %u, timestamp = %llu, ab = %llu, ib = %llu\n" - "ISP0.active = %x, ISP0.ab = %llu, ISP0.ib = %llu\n" - "ISP1.active = %x, ISP1.ab = %llu, ISP1.ib = %llu\n" - "CPP.active = %x, CPP.ab = %llu, CPP.ib = %llu\n\n", - i, isp_req_hist[i].client, isp_req_hist[i].timestamp, - isp_req_hist[i].total_ab, isp_req_hist[i].total_ib, - isp_req_hist[i].client_info[0].active, - isp_req_hist[i].client_info[0].ab, - isp_req_hist[i].client_info[0].ib, - isp_req_hist[i].client_info[1].active, - isp_req_hist[i].client_info[1].ab, - isp_req_hist[i].client_info[1].ib, - isp_req_hist[i].client_info[2].active, - isp_req_hist[i].client_info[2].ab, - isp_req_hist[i].client_info[2].ib); - strlcat(out_buffer, line_buffer, - sizeof(bw_request_history_buff)); - } - return simple_read_from_buffer(t_char, t_size_t, - t_loff_t, out_buffer, strlen(out_buffer)); -} - -static ssize_t bw_history_write(struct file *t_file, - const char *t_char, size_t t_size_t, loff_t *t_loff_t) -{ - struct msm_isp_bw_req_info *isp_req_hist = - (struct msm_isp_bw_req_info *) t_file->private_data; - - memset(isp_req_hist, 0, sizeof(msm_isp_bw_request_history)); - msm_isp_bw_request_history_idx = 0; - return sizeof(msm_isp_bw_request_history); -} - -static int ub_info_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t ub_info_read(struct file *t_file, char *t_char, - size_t t_size_t, loff_t *t_loff_t) -{ - int i; - char *out_buffer = ub_info_buffer; - char line_buffer[MAX_UB_INFO_LINE_BUFF_LEN] = {0}; - struct vfe_device *vfe_dev = - (struct vfe_device *) t_file->private_data; - struct msm_isp_ub_info *ub_info = vfe_dev->ub_info; - - memset(out_buffer, 0, MAX_UB_INFO_LINE_BUFF_LEN); - snprintf(line_buffer, sizeof(line_buffer), - "wm_ub_policy_type = %d\n" - "num_wm = %d\n" - "wm_ub = %d\n", - ub_info->policy, ub_info->num_wm, ub_info->wm_ub); - strlcat(out_buffer, line_buffer, - sizeof(ub_info_buffer)); - for (i = 0; i < ub_info->num_wm; i++) { - snprintf(line_buffer, sizeof(line_buffer), - "data[%d] = 0x%x, addr[%d] = 0x%llx\n", - i, ub_info->data[i], i, ub_info->addr[i]); - strlcat(out_buffer, line_buffer, - sizeof(ub_info_buffer)); - } - - return simple_read_from_buffer(t_char, t_size_t, - t_loff_t, out_buffer, strlen(out_buffer)); -} - -static ssize_t ub_info_write(struct file *t_file, - const char *t_char, size_t t_size_t, loff_t *t_loff_t) -{ - struct vfe_device *vfe_dev = - (struct vfe_device *) t_file->private_data; - struct msm_isp_ub_info *ub_info = vfe_dev->ub_info; - - memset(ub_info, 0, sizeof(struct msm_isp_ub_info)); - - return sizeof(struct msm_isp_ub_info); -} - -static const struct file_operations vfe_debugfs_error = { - .open = vfe_debugfs_statistics_open, - .read = vfe_debugfs_statistics_read, - .write = vfe_debugfs_statistics_write, -}; - -static const struct file_operations bw_history_ops = { - .open = bw_history_open, - .read = bw_history_read, - .write = bw_history_write, -}; - -static const struct file_operations ub_info_ops = { - .open = ub_info_open, - .read = ub_info_read, - .write = ub_info_write, -}; - -static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev, - struct msm_isp_bw_req_info *isp_req_hist) -{ - struct dentry *debugfs_base; - char dirname[32] = {0}; - - snprintf(dirname, sizeof(dirname), "msm_isp%d", vfe_dev->pdev->id); - debugfs_base = debugfs_create_dir(dirname, NULL); - if (!debugfs_base) - return -ENOMEM; - if (!debugfs_create_file("stats", S_IRUGO | S_IWUSR, debugfs_base, - vfe_dev, &vfe_debugfs_error)) - return -ENOMEM; - - if (!debugfs_create_file("bw_req_history", S_IRUGO | S_IWUSR, - debugfs_base, isp_req_hist, &bw_history_ops)) - return -ENOMEM; - - if (!debugfs_create_file("ub_info", S_IRUGO | S_IWUSR, - debugfs_base, vfe_dev, &ub_info_ops)) - return -ENOMEM; - - return 0; -} - -void msm_isp_update_req_history(uint32_t client, uint64_t ab, - uint64_t ib, - struct msm_isp_bandwidth_info *client_info, - unsigned long long ts) -{ - int i; - - spin_lock(&req_history_lock); - msm_isp_bw_request_history[msm_isp_bw_request_history_idx].client = - client; - msm_isp_bw_request_history[msm_isp_bw_request_history_idx].timestamp = - ts; - msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab = - ab; - msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib = - ib; - - for (i = 0; i < MAX_ISP_CLIENT; i++) { - msm_isp_bw_request_history[msm_isp_bw_request_history_idx]. - client_info[i].active = client_info[i].active; - msm_isp_bw_request_history[msm_isp_bw_request_history_idx]. - client_info[i].ab = client_info[i].ab; - msm_isp_bw_request_history[msm_isp_bw_request_history_idx]. - client_info[i].ib = client_info[i].ib; - } - - msm_isp_bw_request_history_idx = (msm_isp_bw_request_history_idx + 1) - % MAX_DEPTH_BW_REQ_HISTORY; - spin_unlock(&req_history_lock); -} - -void msm_isp_update_last_overflow_ab_ib(struct vfe_device *vfe_dev) -{ - spin_lock(&req_history_lock); - vfe_dev->msm_isp_last_overflow_ab = - msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab; - vfe_dev->msm_isp_last_overflow_ib = - msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib; - spin_unlock(&req_history_lock); -} - -#ifdef CONFIG_COMPAT -static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg) -{ - long rc; - - if (is_compat_task()) { - struct msm_isp_event_data32 *event_data32; - struct msm_isp_event_data *event_data; - struct v4l2_event isp_event; - struct v4l2_event *isp_event_user; - - memset(&isp_event, 0, sizeof(isp_event)); - rc = v4l2_event_dequeue(vfh, &isp_event, - file->f_flags & O_NONBLOCK); - if (rc) - return rc; - event_data = (struct msm_isp_event_data *) - isp_event.u.data; - isp_event_user = (struct v4l2_event *)arg; - memcpy(isp_event_user, &isp_event, - sizeof(*isp_event_user)); - event_data32 = (struct msm_isp_event_data32 *) - isp_event_user->u.data; - memset(event_data32, 0, - sizeof(struct msm_isp_event_data32)); - event_data32->timestamp.tv_sec = - event_data->timestamp.tv_sec; - event_data32->timestamp.tv_usec = - event_data->timestamp.tv_usec; - event_data32->mono_timestamp.tv_sec = - event_data->mono_timestamp.tv_sec; - event_data32->mono_timestamp.tv_usec = - event_data->mono_timestamp.tv_usec; - event_data32->frame_id = event_data->frame_id; - memcpy(&(event_data32->u), &(event_data->u), - sizeof(event_data32->u)); - } else { - rc = v4l2_event_dequeue(vfh, arg, - file->f_flags & O_NONBLOCK); - } - return rc; -} -#else -static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg) -{ - return v4l2_event_dequeue(vfh, arg, - file->f_flags & O_NONBLOCK); -} -#endif - -static long msm_isp_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; - - switch (cmd) { - case VIDIOC_DQEVENT: { - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return -ENOIOCTLCMD; - return msm_isp_dqevent(file, vfh, arg); - } - break; - case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); - - default: - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); - } -} - -static struct v4l2_subdev_core_ops msm_vfe_v4l2_subdev_core_ops = { - .ioctl = msm_isp_ioctl, - .subscribe_event = msm_isp_subscribe_event, - .unsubscribe_event = msm_isp_unsubscribe_event, -}; - -static struct v4l2_subdev_ops msm_vfe_v4l2_subdev_ops = { - .core = &msm_vfe_v4l2_subdev_core_ops, -}; - -static struct v4l2_subdev_internal_ops msm_vfe_subdev_internal_ops = { - .open = msm_isp_open_node, - .close = msm_isp_close_node, -}; - -static long msm_isp_v4l2_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl); -} - -static struct v4l2_file_operations msm_isp_v4l2_fops = { -#ifdef CONFIG_COMPAT - .compat_ioctl32 = msm_isp_v4l2_fops_ioctl, -#endif - .unlocked_ioctl = msm_isp_v4l2_fops_ioctl -}; - -static int vfe_set_common_data(struct platform_device *pdev) -{ - struct v4l2_subdev *sd = NULL; - struct vfe_device *vfe_dev = NULL; - - sd = (struct v4l2_subdev *)platform_get_drvdata(pdev); - if (!sd) { - pr_err("%s: Error! Cannot find subdev\n", __func__); - return -EPERM; - } - vfe_dev = (struct vfe_device *)v4l2_get_subdevdata(sd); - if (!vfe_dev) { - pr_err("%s: Error! Cannot find vfe_dev\n", __func__); - return -EPERM; - } - - vfe_dev->common_data = (struct msm_vfe_common_dev_data *) - pdev->dev.platform_data; - - vfe_dev->common_data->dual_vfe_res = &dualvfe; - vfe_dev->common_data->dual_vfe_res->axi_data[vfe_dev->pdev->id] = - &vfe_dev->axi_data; - vfe_dev->common_data->dual_vfe_res->stats_data[vfe_dev->pdev->id] = - &vfe_dev->stats_data; - vfe_dev->common_data->dual_vfe_res->vfe_dev[vfe_dev->pdev->id] = - vfe_dev; - return 0; -} - -static int vfe_probe(struct platform_device *pdev) -{ - int rc = 0; - struct device_node *node; - struct platform_device *new_dev = NULL; - uint32_t i = 0; - uint32_t num_hw_sd = 0; - char name[10] = "\0"; - - memset(&vfe_common_data, 0, sizeof(vfe_common_data)); - spin_lock_init(&vfe_common_data.common_dev_data_lock); - - of_property_read_u32(pdev->dev.of_node, - "num_child", &num_hw_sd); - - for (i = 0; i < num_hw_sd; i++) { - node = NULL; - snprintf(name, sizeof(name), "qcom,vfe%d", i); - node = of_find_node_by_name(NULL, name); - if (!node) { - pr_err("%s: Error! Cannot find node in dtsi %s\n", - __func__, name); - break; - } - new_dev = of_find_device_by_node(node); - if (!new_dev) { - pr_err("%s: Failed to find device on bus %s\n", - __func__, node->name); - break; - } - - new_dev->dev.platform_data = - (void *)&vfe_common_data; - rc = vfe_set_common_data(new_dev); - if (rc < 0) - break; - } - - return rc; -} - -int vfe_hw_probe(struct platform_device *pdev) -{ - struct vfe_device *vfe_dev; - /*struct msm_cam_subdev_info sd_info;*/ - const struct of_device_id *match_dev; - int rc = 0; - - vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL); - if (!vfe_dev) { - rc = -ENOMEM; - goto end; - } - vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL); - if (!vfe_dev->stats) { - rc = -ENOMEM; - goto probe_fail1; - } - - vfe_dev->ub_info = kzalloc(sizeof(struct msm_isp_ub_info), GFP_KERNEL); - if (!vfe_dev->ub_info) { - rc = -ENOMEM; - goto probe_fail2; - } - - if (pdev->dev.of_node) { - of_property_read_u32(pdev->dev.of_node, - "cell-index", &pdev->id); - - match_dev = of_match_device(pdev->dev.driver->of_match_table, - &pdev->dev); - if (!match_dev) { - pr_err("%s: No vfe hardware info\n", __func__); - rc = -EINVAL; - goto probe_fail3; - } - vfe_dev->hw_info = - (struct msm_vfe_hardware_info *) match_dev->data; - } else { - vfe_dev->hw_info = (struct msm_vfe_hardware_info *) - platform_get_device_id(pdev)->driver_data; - } - - if (!vfe_dev->hw_info) { - pr_err("%s: No vfe hardware info\n", __func__); - rc = -EINVAL; - goto probe_fail3; - } - ISP_DBG("%s: device id = %d\n", __func__, pdev->id); - - vfe_dev->pdev = pdev; - - rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_platform_data(vfe_dev); - if (rc < 0) { - pr_err("%s: failed to get platform resources\n", __func__); - rc = -ENOMEM; - goto probe_fail3; - } - - INIT_LIST_HEAD(&vfe_dev->tasklet_q); - tasklet_init(&vfe_dev->vfe_tasklet, - msm_isp_do_tasklet, (unsigned long)vfe_dev); - - v4l2_subdev_init(&vfe_dev->subdev.sd, &msm_vfe_v4l2_subdev_ops); - vfe_dev->subdev.sd.internal_ops = - &msm_vfe_subdev_internal_ops; - snprintf(vfe_dev->subdev.sd.name, - ARRAY_SIZE(vfe_dev->subdev.sd.name), - "vfe"); - vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; - v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev); - platform_set_drvdata(pdev, &vfe_dev->subdev.sd); - mutex_init(&vfe_dev->realtime_mutex); - mutex_init(&vfe_dev->core_mutex); - spin_lock_init(&vfe_dev->tasklet_lock); - spin_lock_init(&vfe_dev->shared_data_lock); - spin_lock_init(&vfe_dev->reg_update_lock); - spin_lock_init(&req_history_lock); - media_entity_init(&vfe_dev->subdev.sd.entity, 0, NULL, 0); - vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE; - vfe_dev->subdev.sd.entity.name = pdev->name; - vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2; - rc = msm_sd_register(&vfe_dev->subdev); - if (rc != 0) { - pr_err("%s: msm_sd_register error = %d\n", __func__, rc); - goto probe_fail3; - } - msm_cam_copy_v4l2_subdev_fops(&msm_isp_v4l2_fops); - msm_isp_v4l2_fops.unlocked_ioctl = msm_isp_v4l2_fops_ioctl; -#ifdef CONFIG_COMPAT - msm_isp_v4l2_fops.compat_ioctl32 = - msm_isp_v4l2_fops_ioctl; -#endif - vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_fops; - - vfe_dev->buf_mgr = &vfe_buf_mgr; - v4l2_subdev_notify(&vfe_dev->subdev.sd, - MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops); - rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr, - &vfe_vb2_ops, &pdev->dev, - vfe_dev->hw_info->axi_hw_info->scratch_buf_range); - if (rc < 0) { - pr_err("%s: Unable to create buffer manager\n", __func__); - rc = -EINVAL; - goto probe_fail3; - } - msm_isp_enable_debugfs(vfe_dev, msm_isp_bw_request_history); - vfe_dev->buf_mgr->num_iommu_secure_ctx = - vfe_dev->hw_info->num_iommu_secure_ctx; - vfe_dev->buf_mgr->init_done = 1; - vfe_dev->vfe_open_cnt = 0; - return rc; - -probe_fail3: - kfree(vfe_dev->ub_info); -probe_fail2: - kfree(vfe_dev->stats); -probe_fail1: - kfree(vfe_dev); -end: - return rc; -} - -static struct platform_driver vfe_driver = { - .probe = vfe_probe, - .driver = { - .name = "msm_vfe", - .owner = THIS_MODULE, - .of_match_table = msm_vfe_dt_match, - }, -}; - -static int __init msm_vfe_init_module(void) -{ - return platform_driver_register(&vfe_driver); -} - -static void __exit msm_vfe_exit_module(void) -{ - platform_driver_unregister(&vfe_driver); -} - -late_initcall(msm_vfe_init_module); -module_exit(msm_vfe_exit_module); -MODULE_DESCRIPTION("MSM VFE driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/isp/msm_isp.h b/drivers/media/platform/msm/ais/isp/msm_isp.h deleted file mode 100644 index fa6d070b7c94128dd9ac4542f5ddb9dca10c699d..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_isp.h +++ /dev/null @@ -1,802 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_VFE_H__ -#define __MSM_VFE_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_buf_mgr.h" -#include "cam_hw_ops.h" - -#define VFE40_8974V1_VERSION 0x10000018 -#define VFE40_8974V2_VERSION 0x1001001A -#define VFE40_8974V3_VERSION 0x1001001B -#define VFE40_8x26_VERSION 0x20000013 -#define VFE40_8x26V2_VERSION 0x20010014 -#define VFE40_8916_VERSION 0x10030000 -#define VFE40_8939_VERSION 0x10040000 -#define VFE40_8952_VERSION 0x10060000 -#define VFE40_8976_VERSION 0x10050000 -#define VFE40_8937_VERSION 0x10080000 -#define VFE40_8917_VERSION 0x10080001 -#define VFE40_8953_VERSION 0x10090000 -#define VFE32_8909_VERSION 0x30600 - -#define MAX_IOMMU_CTX 2 -#define MAX_NUM_WM 7 -#define MAX_NUM_RDI 3 -#define MAX_NUM_RDI_MASTER 3 -#define MAX_NUM_COMPOSITE_MASK 4 -#define MAX_NUM_STATS_COMP_MASK 2 -#define MAX_INIT_FRAME_DROP 31 -#define MAX_REG_UPDATE_THRESHOLD 10 -#define ISP_Q2 (1 << 2) - -#define VFE_PING_FLAG 0xFFFFFFFF -#define VFE_PONG_FLAG 0x0 - -#define VFE_MAX_CFG_TIMEOUT 3000 -#define VFE_CLK_INFO_MAX 16 -#define STATS_COMP_BIT_MASK 0x1FF - -#define MSM_ISP_MIN_AB 100000000 -#define MSM_ISP_MIN_IB 100000000 -#define MAX_BUFFERS_IN_HW 2 - -#define MAX_VFE 2 -#define MAX_RECOVERY_THRESHOLD 5 - -struct vfe_device; -struct msm_vfe_axi_stream; -struct msm_vfe_stats_stream; - -#define VFE_SD_HW_MAX VFE_SD_COMMON - -/* Irq operations to perform on the irq mask register */ -enum msm_isp_irq_operation { - /* enable the irq bits in given parameters */ - MSM_ISP_IRQ_ENABLE = 1, - /* disable the irq bits in the given parameters */ - MSM_ISP_IRQ_DISABLE = 2, - /* set the irq bits to the given parameters */ - MSM_ISP_IRQ_SET = 3, -}; - -/* This struct is used to save/track SOF info for some INTF. - * e.g. used in Master-Slave mode */ -struct msm_vfe_sof_info { - uint32_t timestamp_ms; - uint32_t mono_timestamp_ms; - uint32_t frame_id; -}; - -/* Each INTF in Master-Slave mode uses this struct. */ -struct msm_vfe_dual_hw_ms_info { - /* type is Master/Slave */ - enum msm_vfe_dual_hw_ms_type dual_hw_ms_type; - /* sof_info is resource from common_data. If NULL, then this INTF - * sof does not need to be saved */ - struct msm_vfe_sof_info *sof_info; - /* slave_id is index in common_data sof_info array for slaves */ - uint8_t slave_id; -}; - -struct vfe_subscribe_info { - struct v4l2_fh *vfh; - uint32_t active; -}; - -enum msm_isp_pack_fmt { - QCOM, - MIPI, - DPCM6, - DPCM8, - PLAIN8, - PLAIN16, - DPCM10, - MAX_ISP_PACK_FMT, -}; - -enum msm_isp_camif_update_state { - NO_UPDATE, - ENABLE_CAMIF, - DISABLE_CAMIF, - DISABLE_CAMIF_IMMEDIATELY -}; - -struct msm_isp_timestamp { - /* Monotonic clock for v4l2 buffer */ - struct timeval buf_time; - /* Monotonic clock for VT */ - struct timeval vt_time; - /* Wall clock for userspace event */ - struct timeval event_time; -}; - -struct msm_vfe_irq_ops { - void (*read_irq_status_and_clear)(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1); - void (*read_irq_status)(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1); - void (*process_reg_update)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); - void (*process_epoch_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); - void (*process_reset_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1); - void (*process_halt_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1); - void (*process_camif_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); - void (*process_axi_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - uint32_t pingpong_status, - struct msm_isp_timestamp *ts); - void (*process_stats_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - uint32_t pingpong_status, - struct msm_isp_timestamp *ts); - void (*config_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - enum msm_isp_irq_operation); - void (*process_eof_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0); -}; - -struct msm_vfe_axi_ops { - void (*reload_wm)(struct vfe_device *vfe_dev, void __iomem *vfe_base, - uint32_t reload_mask); - void (*enable_wm)(void __iomem *vfe_base, - uint8_t wm_idx, uint8_t enable); - int32_t (*cfg_io_format)(struct vfe_device *vfe_dev, - enum msm_vfe_axi_stream_src stream_src, - uint32_t io_format); - void (*cfg_framedrop)(void __iomem *vfe_base, - struct msm_vfe_axi_stream *stream_info, - uint32_t framedrop_pattern, uint32_t framedrop_period); - void (*clear_framedrop)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*cfg_comp_mask)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*clear_comp_mask)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*clear_irq_mask)(struct vfe_device *vfe_dev); - - void (*cfg_wm_reg)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx); - void (*clear_wm_reg)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); - - void (*cfg_wm_xbar_reg)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx); - void (*clear_wm_xbar_reg)(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); - void (*cfg_ub)(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); - void (*read_wm_ping_pong_addr)(struct vfe_device *vfe_dev); - void (*update_ping_pong_addr)(void __iomem *vfe_base, - uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr, - int32_t buf_size); - uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev); - int (*halt)(struct vfe_device *vfe_dev, uint32_t blocking); - int (*restart)(struct vfe_device *vfe_dev, uint32_t blocking, - uint32_t enable_camif); - void (*update_cgc_override)(struct vfe_device *vfe_dev, - uint8_t wm_idx, uint8_t cgc_override); - uint32_t (*ub_reg_offset)(struct vfe_device *vfe_dev, int idx); - uint32_t (*get_ub_size)(struct vfe_device *vfe_dev); -}; - -struct msm_vfe_core_ops { - void (*reg_update)(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); - long (*reset_hw)(struct vfe_device *vfe_dev, uint32_t first_start, - uint32_t blocking_call); - int (*init_hw)(struct vfe_device *vfe_dev); - void (*init_hw_reg)(struct vfe_device *vfe_dev); - void (*clear_status_reg)(struct vfe_device *vfe_dev); - void (*release_hw)(struct vfe_device *vfe_dev); - void (*cfg_input_mux)(struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg); - int (*start_fetch_eng)(struct vfe_device *vfe_dev, - void *arg); - void (*update_camif_state)(struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state update_state); - void (*cfg_rdi_reg)(struct vfe_device *vfe_dev, - struct msm_vfe_rdi_cfg *rdi_cfg, - enum msm_vfe_input_src input_src); - void (*get_error_mask)(uint32_t *error_mask0, uint32_t *error_mask1); - void (*process_error_status)(struct vfe_device *vfe_dev); - void (*get_overflow_mask)(uint32_t *overflow_mask); - void (*get_irq_mask)(struct vfe_device *vfe_dev, - uint32_t *irq0_mask, uint32_t *irq1_mask); - void (*get_halt_restart_mask)(uint32_t *irq0_mask, - uint32_t *irq1_mask); - void (*get_rdi_wm_mask)(struct vfe_device *vfe_dev, - uint32_t *rdi_wm_mask); - bool (*is_module_cfg_lock_needed)(uint32_t reg_offset); - int (*ahb_clk_cfg)(struct vfe_device *vfe_dev, - struct msm_isp_ahb_clk_cfg *ahb_cfg); - void (*set_halt_restart_mask)(struct vfe_device *vfe_dev); - int (*start_fetch_eng_multi_pass)(struct vfe_device *vfe_dev, - void *arg); -}; -struct msm_vfe_stats_ops { - int (*get_stats_idx)(enum msm_isp_stats_type stats_type); - int (*check_streams)(struct msm_vfe_stats_stream *stream_info); - void (*cfg_framedrop)(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info, - uint32_t framedrop_pattern, uint32_t framedrop_period); - void (*clear_framedrop)(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - void (*cfg_comp_mask)(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t comp_index, - uint8_t enable); - void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - - void (*cfg_wm_reg)(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - void (*clear_wm_reg)(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - - void (*cfg_ub)(struct vfe_device *vfe_dev); - - void (*enable_module)(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable); - - void (*update_ping_pong_addr)(void __iomem *vfe_base, - struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr); - - uint32_t (*get_frame_id)(struct vfe_device *vfe_dev); - uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev); - - void (*update_cgc_override)(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable); - void (*enable_stats_wm)(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable); -}; - -enum msm_isp_hw_client { - ISP_VFE0, - ISP_VFE1, - ISP_CPP, - MAX_ISP_CLIENT, -}; - -struct msm_isp_bandwidth_info { - uint32_t active; - uint64_t ab; - uint64_t ib; -}; - -struct msm_isp_bandwidth_mgr { - uint32_t bus_client; - uint32_t bus_vector_active_idx; - uint32_t use_count; - struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT]; - int (*update_bw)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); - void (*deinit_bw_mgr)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); -}; - -struct msm_vfe_platform_ops { - int (*get_platform_data)(struct vfe_device *vfe_dev); - int (*enable_clks)(struct vfe_device *vfe_dev, int enable); - int (*get_clks)(struct vfe_device *vfe_dev); - void (*put_clks)(struct vfe_device *vfe_dev); - int (*get_clk_rates)(struct vfe_device *vfe_dev, - struct msm_isp_clk_rates *rates); - int (*get_max_clk_rate)(struct vfe_device *vfe_dev, long *rate); - int (*set_clk_rate)(struct vfe_device *vfe_dev, long *rate); - int (*enable_regulators)(struct vfe_device *vfe_dev, int enable); - int (*get_regulators)(struct vfe_device *vfe_dev); - void (*put_regulators)(struct vfe_device *vfe_dev); - int (*init_bw_mgr)(struct vfe_device *vfe_dev, - struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); - int (*update_bw)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); - void (*deinit_bw_mgr)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); -}; - -struct msm_vfe_ops { - struct msm_vfe_irq_ops irq_ops; - struct msm_vfe_axi_ops axi_ops; - struct msm_vfe_core_ops core_ops; - struct msm_vfe_stats_ops stats_ops; - struct msm_vfe_platform_ops platform_ops; -}; - -struct msm_vfe_hardware_info { - int num_iommu_ctx; - /* secure iommu ctx nums */ - int num_iommu_secure_ctx; - int vfe_clk_idx; - int runtime_axi_update; - struct msm_vfe_ops vfe_ops; - struct msm_vfe_axi_hardware_info *axi_hw_info; - struct msm_vfe_stats_hardware_info *stats_hw_info; - uint32_t dmi_reg_offset; - uint32_t min_ab; - uint32_t min_ib; - const char *regulator_names[]; -}; - -struct msm_vfe_axi_hardware_info { - uint8_t num_wm; - uint8_t num_rdi; - uint8_t num_rdi_master; - uint8_t num_comp_mask; - uint32_t min_wm_ub; - uint32_t scratch_buf_range; -}; - -enum msm_vfe_axi_state { - AVAILABLE, - INACTIVE, - ACTIVE, - PAUSED, - START_PENDING, - STOP_PENDING, - PAUSE_PENDING, - RESUME_PENDING, - STARTING, - STOPPING, - PAUSING, - RESUMING, - UPDATING, -}; - -enum msm_vfe_axi_cfg_update_state { - NO_AXI_CFG_UPDATE, - APPLYING_UPDATE_RESUME, - UPDATE_REQUESTED, -}; - -#define VFE_NO_DROP 0xFFFFFFFF -#define VFE_DROP_EVERY_2FRAME 0x55555555 -#define VFE_DROP_EVERY_4FRAME 0x11111111 -#define VFE_DROP_EVERY_8FRAME 0x01010101 -#define VFE_DROP_EVERY_16FRAME 0x00010001 -#define VFE_DROP_EVERY_32FRAME 0x00000001 - -enum msm_vfe_axi_stream_type { - CONTINUOUS_STREAM, - BURST_STREAM, -}; - -struct msm_vfe_frame_request_queue { - struct list_head list; - enum msm_vfe_buff_queue_id buff_queue_id; - uint32_t buf_index; - uint8_t cmd_used; -}; - -#define MSM_VFE_REQUESTQ_SIZE 8 - -struct msm_vfe_axi_stream { - uint32_t frame_id; - enum msm_vfe_axi_state state; - enum msm_vfe_axi_stream_src stream_src; - uint8_t num_planes; - uint8_t wm[MAX_PLANES_PER_STREAM]; - uint32_t output_format;/*Planar/RAW/Misc*/ - struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; - struct msm_vfe_axi_output_plane_cfg - vfe_plane_cfg[MAX_PLANES_PER_STREAM]; - - uint8_t comp_mask_index; - struct msm_isp_buffer *buf[2]; - uint32_t session_id; - uint32_t stream_id; - uint32_t bufq_handle[VFE_BUF_QUEUE_MAX]; - uint8_t controllable_output; - uint8_t undelivered_request_cnt; - uint8_t request_q_idx; - uint32_t request_q_cnt; - struct list_head request_q; - struct msm_vfe_frame_request_queue - request_queue_cmd[MSM_VFE_REQUESTQ_SIZE]; - uint32_t stream_handle; - uint8_t buf_divert; - enum msm_vfe_axi_stream_type stream_type; - uint32_t frame_based; - enum msm_vfe_frame_skip_pattern frame_skip_pattern; - uint32_t current_framedrop_period; /* user requested period*/ - uint32_t requested_framedrop_period; /* requested period*/ - uint32_t activated_framedrop_period; /* active hw period */ - uint32_t num_burst_capture;/*number of frame to capture*/ - uint32_t init_frame_drop; - spinlock_t lock; - - /* Bandwidth calculation info */ - uint32_t max_width; - /* Based on format plane size in Q2. e.g NV12 = 1.5 */ - uint32_t format_factor; - uint32_t bandwidth; - - uint32_t runtime_num_burst_capture; - uint32_t runtime_output_format; - enum msm_stream_memory_input_t memory_input; - struct msm_isp_sw_framskip sw_skip; - uint8_t sw_ping_pong_bit; -}; - -struct msm_vfe_axi_composite_info { - uint32_t stream_handle; - uint32_t stream_composite_mask; -}; - -enum msm_vfe_camif_state { - CAMIF_STOPPED, - CAMIF_ENABLE, - CAMIF_DISABLE, - CAMIF_STOPPING, -}; - -struct msm_vfe_src_info { - uint32_t frame_id; - uint32_t reg_update_frame_id; - uint8_t active; - uint8_t flag; - uint8_t pix_stream_count; - uint8_t raw_stream_count; - enum msm_vfe_inputmux input_mux; - enum ISP_START_PIXEL_PATTERN pixel_pattern; - enum msm_vfe_camif_input camif_input; - uint32_t width; - long pixel_clock; - uint32_t input_format;/*V4L2 pix format with bayer pattern*/ - uint32_t last_updt_frm_id; - uint32_t sof_counter_step; - struct timeval time_stamp; - enum msm_vfe_dual_hw_type dual_hw_type; - struct msm_vfe_dual_hw_ms_info dual_hw_ms_info; - uint32_t eof_id; -}; - -struct msm_vfe_fetch_engine_info { - uint32_t session_id; - uint32_t stream_id; - uint32_t bufq_handle; - uint32_t buf_idx; - uint8_t is_busy; - uint8_t offline_mode; - uint32_t fd; -}; - -enum msm_wm_ub_cfg_type { - MSM_WM_UB_CFG_DEFAULT, - MSM_WM_UB_EQUAL_SLICING, - MSM_WM_UB_CFG_MAX_NUM -}; - -struct msm_vfe_axi_shared_data { - struct msm_vfe_axi_hardware_info *hw_info; - struct msm_vfe_axi_stream stream_info[VFE_AXI_SRC_MAX]; - uint32_t free_wm[MAX_NUM_WM]; - uint32_t wm_image_size[MAX_NUM_WM]; - enum msm_wm_ub_cfg_type wm_ub_cfg_policy; - uint8_t num_used_wm; - uint8_t num_active_stream; - uint8_t num_rdi_stream; - uint8_t num_pix_stream; - uint32_t rdi_wm_mask; - struct msm_vfe_axi_composite_info - composite_info[MAX_NUM_COMPOSITE_MASK]; - uint8_t num_used_composite_mask; - uint32_t stream_update[VFE_SRC_MAX]; - atomic_t axi_cfg_update[VFE_SRC_MAX]; - enum msm_isp_camif_update_state pipeline_update; - struct msm_vfe_src_info src_info[VFE_SRC_MAX]; - uint16_t stream_handle_cnt; - uint32_t event_mask; - uint8_t enable_frameid_recovery; - enum msm_vfe_camif_state camif_state; - uint32_t recovery_count; -}; - -struct msm_vfe_stats_hardware_info { - uint32_t stats_capability_mask; - uint8_t *stats_ping_pong_offset; - uint8_t *stats_wm_index; - uint8_t num_stats_type; - uint8_t num_stats_comp_mask; -}; - -enum msm_vfe_stats_state { - STATS_AVAILABLE, - STATS_INACTIVE, - STATS_ACTIVE, - STATS_START_PENDING, - STATS_STOP_PENDING, - STATS_STARTING, - STATS_STOPPING, -}; - -struct msm_vfe_stats_stream { - uint32_t session_id; - uint32_t stream_id; - uint32_t stream_handle; - uint32_t composite_flag; - enum msm_isp_stats_type stats_type; - enum msm_vfe_stats_state state; - uint32_t framedrop_pattern; - uint32_t framedrop_period; - uint32_t irq_subsample_pattern; - uint32_t init_stats_frame_drop; - struct msm_isp_sw_framskip sw_skip; - - uint32_t buffer_offset; - struct msm_isp_buffer *buf[2]; - uint32_t bufq_handle; -}; - -struct msm_vfe_stats_shared_data { - struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX]; - uint8_t num_active_stream; - atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK]; - uint16_t stream_handle_cnt; - atomic_t stats_update; -}; - -struct msm_vfe_tasklet_queue_cmd { - struct list_head list; - uint32_t vfeInterruptStatus0; - uint32_t vfeInterruptStatus1; - uint32_t vfePingPongStatus; - struct msm_isp_timestamp ts; - uint8_t cmd_used; -}; - -#define MSM_VFE_TASKLETQ_SIZE 200 - -enum msm_vfe_overflow_state { - NO_OVERFLOW, - OVERFLOW_DETECTED, - HALT_ENFORCED, -}; - -struct msm_vfe_error_info { - atomic_t overflow_state; - uint32_t error_mask0; - uint32_t error_mask1; - uint32_t violation_status; - uint32_t camif_status; - uint8_t stream_framedrop_count[BUF_MGR_NUM_BUF_Q]; - uint8_t stats_framedrop_count[MSM_ISP_STATS_MAX]; - uint32_t info_dump_frame_count; - uint32_t error_count; - uint32_t framedrop_flag; -}; - -struct msm_isp_statistics { - int64_t imagemaster0_overflow; - int64_t imagemaster1_overflow; - int64_t imagemaster2_overflow; - int64_t imagemaster3_overflow; - int64_t imagemaster4_overflow; - int64_t imagemaster5_overflow; - int64_t imagemaster6_overflow; - int64_t be_overflow; - int64_t bg_overflow; - int64_t bf_overflow; - int64_t awb_overflow; - int64_t rs_overflow; - int64_t cs_overflow; - int64_t ihist_overflow; - int64_t skinbhist_overflow; - int64_t bfscale_overflow; - - int64_t isp_vfe0_active; - int64_t isp_vfe0_ab; - int64_t isp_vfe0_ib; - - int64_t isp_vfe1_active; - int64_t isp_vfe1_ab; - int64_t isp_vfe1_ib; - - int64_t isp_cpp_active; - int64_t isp_cpp_ab; - int64_t isp_cpp_ib; - - int64_t last_overflow_ab; - int64_t last_overflow_ib; - - int64_t vfe_clk_rate; - int64_t cpp_clk_rate; -}; - -struct msm_isp_bw_req_info { - uint32_t client; - unsigned long long timestamp; - uint64_t total_ab; - uint64_t total_ib; - struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT]; -}; - -#define MSM_ISP_MAX_WM 7 -struct msm_isp_ub_info { - enum msm_wm_ub_cfg_type policy; - uint8_t num_wm; - uint32_t wm_ub; - uint32_t data[MSM_ISP_MAX_WM]; - uint64_t addr[MSM_ISP_MAX_WM]; -}; - -struct msm_vfe_hw_init_parms { - const char *entries; - const char *regs; - const char *settings; -}; - -struct dual_vfe_resource { - struct vfe_device *vfe_dev[MAX_VFE]; - void __iomem *vfe_base[MAX_VFE]; - uint32_t reg_update_mask[MAX_VFE]; - struct msm_vfe_stats_shared_data *stats_data[MAX_VFE]; - struct msm_vfe_axi_shared_data *axi_data[MAX_VFE]; - uint32_t wm_reload_mask[MAX_VFE]; - uint32_t epoch_sync_mask; -}; - -struct master_slave_resource_info { - enum msm_vfe_dual_hw_type dual_hw_type; - struct msm_vfe_sof_info master_sof_info; - uint8_t master_active; - uint32_t sof_delta_threshold; /* Updated by Master */ - uint32_t num_slave; - uint32_t reserved_slave_mask; - uint32_t slave_active_mask; - struct msm_vfe_sof_info slave_sof_info[MS_NUM_SLAVE_MAX]; -}; - -struct msm_vfe_common_dev_data { - spinlock_t common_dev_data_lock; - struct dual_vfe_resource *dual_vfe_res; - struct master_slave_resource_info ms_resource; -}; - -struct msm_vfe_common_subdev { - /* parent reference */ - struct vfe_parent_device *parent; - - /* Media Subdevice */ - struct msm_sd_subdev *subdev; - - /* Buf Mgr */ - struct msm_isp_buf_mgr *buf_mgr; - - /* Common Data */ - struct msm_vfe_common_dev_data *common_data; -}; - -struct vfe_device { - /* Driver private data */ - struct platform_device *pdev; - struct msm_vfe_common_dev_data *common_data; - struct msm_sd_subdev subdev; - struct msm_isp_buf_mgr *buf_mgr; - - /* Resource info */ - struct resource *vfe_irq; - void __iomem *vfe_base; - uint32_t vfe_base_size; - void __iomem *vfe_vbif_base; - uint32_t vfe_vbif_base_size; - struct device *iommu_ctx[MAX_IOMMU_CTX]; - struct msm_cam_regulator *regulator_info; - uint32_t vfe_num_regulators; - struct clk **vfe_clk; - struct msm_cam_clk_info *vfe_clk_info; - uint32_t **vfe_clk_rates; - size_t num_clk; - size_t num_rates; - enum cam_ahb_clk_vote ahb_vote; - - /* Sync variables*/ - struct completion reset_complete; - struct completion halt_complete; - struct completion stream_config_complete; - struct completion stats_config_complete; - struct mutex realtime_mutex; - struct mutex core_mutex; - spinlock_t shared_data_lock; - spinlock_t reg_update_lock; - spinlock_t tasklet_lock; - - /* Tasklet info */ - atomic_t irq_cnt; - uint8_t taskletq_idx; - struct list_head tasklet_q; - struct tasklet_struct vfe_tasklet; - struct msm_vfe_tasklet_queue_cmd - tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; - - /* Data structures */ - struct msm_vfe_hardware_info *hw_info; - struct msm_vfe_axi_shared_data axi_data; - struct msm_vfe_stats_shared_data stats_data; - struct msm_vfe_error_info error_info; - struct msm_vfe_fetch_engine_info fetch_engine_info; - enum msm_vfe_hvx_streaming_cmd hvx_cmd; - - /* State variables */ - uint32_t vfe_hw_version; - int vfe_clk_idx; - uint32_t vfe_open_cnt; - uint8_t vt_enable; - uint32_t vfe_ub_policy; - uint8_t reset_pending; - uint8_t reg_update_requested; - uint8_t reg_updated; - uint32_t is_split; - uint32_t dual_vfe_enable; - unsigned long page_fault_addr; - - /* Debug variables */ - int dump_reg; - struct msm_isp_statistics *stats; - uint64_t msm_isp_last_overflow_ab; - uint64_t msm_isp_last_overflow_ib; - uint64_t msm_isp_vfe_clk_rate; - struct msm_isp_ub_info *ub_info; - uint32_t isp_sof_debug; - uint32_t isp_raw0_debug; - uint32_t isp_raw1_debug; - uint32_t isp_raw2_debug; - - /* irq info */ - uint32_t irq0_mask; - uint32_t irq1_mask; - /* before halt irq info */ - uint32_t recovery_irq0_mask; - uint32_t recovery_irq1_mask; -}; - -struct vfe_parent_device { - struct platform_device *pdev; - uint32_t num_sd; - uint32_t num_hw_sd; - struct platform_device *child_list[VFE_SD_HW_MAX]; - struct msm_vfe_common_subdev *common_sd; -}; - -int vfe_hw_probe(struct platform_device *pdev); -void msm_isp_update_last_overflow_ab_ib(struct vfe_device *vfe_dev); - -#endif diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.h b/drivers/media/platform/msm/ais/isp/msm_isp47.h deleted file mode 100644 index b29fca61ce7c6fe80d1e2f65a1c924d1e04a3ffa..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.h +++ /dev/null @@ -1,202 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_ISP47_H__ -#define __MSM_ISP47_H__ - -#define VFE47_NUM_STATS_COMP 2 -#define VFE47_NUM_STATS_TYPE 9 -/* composite mask order */ -enum msm_vfe47_stats_comp_idx { - STATS_COMP_IDX_HDR_BE = 0, - STATS_COMP_IDX_BG, - STATS_COMP_IDX_BF, - STATS_COMP_IDX_HDR_BHIST, - STATS_COMP_IDX_RS, - STATS_COMP_IDX_CS, - STATS_COMP_IDX_IHIST, - STATS_COMP_IDX_BHIST, - STATS_COMP_IDX_AEC_BG, -}; - -extern struct msm_vfe_hardware_info vfe47_hw_info; - -void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1); -void msm_vfe47_read_irq_status_and_clear(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1); -void msm_vfe47_enable_camif_error(struct vfe_device *vfe_dev, - int enable); -void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); -void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); -void msm_isp47_process_eof_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0); -void msm_vfe47_reg_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); -long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev, - uint32_t first_start, uint32_t blocking_call); -void msm_vfe47_axi_reload_wm(struct vfe_device *vfe_dev, - void __iomem *vfe_base, uint32_t reload_mask); -void msm_vfe47_axi_update_cgc_override(struct vfe_device *vfe_dev, - uint8_t wm_idx, uint8_t enable); -void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); -void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); -void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); -void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); -void msm_vfe47_axi_clear_irq_mask(struct vfe_device *vfe_dev); -void msm_vfe47_cfg_framedrop(void __iomem *vfe_base, - struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, - uint32_t framedrop_period); -void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); -int32_t msm_vfe47_cfg_io_format(struct vfe_device *vfe_dev, - enum msm_vfe_axi_stream_src stream_src, uint32_t io_format); -int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev, - void *arg); -void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg); -void msm_vfe47_cfg_testgen(struct vfe_device *vfe_dev, - struct msm_vfe_testgen_cfg *testgen_cfg); -void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg); -void msm_vfe47_cfg_input_mux(struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg); -void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev, - uint8_t is_stream_on); -void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state update_state); -void msm_vfe47_cfg_rdi_reg( - struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg, - enum msm_vfe_input_src input_src); -void msm_vfe47_axi_cfg_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx); -void msm_vfe47_axi_clear_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); -void msm_vfe47_axi_cfg_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx); -void msm_vfe47_axi_clear_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); -void msm_vfe47_cfg_axi_ub_equal_default( - struct vfe_device *vfe_dev, enum msm_vfe_input_src frame_src); -void msm_vfe47_cfg_axi_ub_equal_slicing( - struct vfe_device *vfe_dev); -void msm_vfe47_cfg_axi_ub(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); -void msm_vfe47_read_wm_ping_pong_addr( - struct vfe_device *vfe_dev); -void msm_vfe47_update_ping_pong_addr( - void __iomem *vfe_base, - uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr, - int32_t buf_size); -int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, - uint32_t blocking); -int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, - uint32_t blocking, uint32_t enable_camif); -uint32_t msm_vfe47_get_wm_mask( - uint32_t irq_status0, uint32_t irq_status1); -uint32_t msm_vfe47_get_comp_mask( - uint32_t irq_status0, uint32_t irq_status1); -uint32_t msm_vfe47_get_pingpong_status( - struct vfe_device *vfe_dev); -int msm_vfe47_get_stats_idx(enum msm_isp_stats_type stats_type); -int msm_vfe47_stats_check_streams( - struct msm_vfe_stats_stream *stream_info); -void msm_vfe47_stats_cfg_comp_mask( - struct vfe_device *vfe_dev, uint32_t stats_mask, - uint8_t request_comp_index, uint8_t enable); -void msm_vfe47_stats_cfg_wm_irq_mask( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); -void msm_vfe47_stats_clear_wm_irq_mask( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); -void msm_vfe47_stats_cfg_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); -void msm_vfe47_stats_clear_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); -void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev); -void msm_vfe47_stats_update_cgc_override(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable); -bool msm_vfe47_is_module_cfg_lock_needed( - uint32_t reg_offset); -void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable); -void msm_vfe47_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr); -uint32_t msm_vfe47_stats_get_wm_mask( - uint32_t irq_status0, uint32_t irq_status1); -uint32_t msm_vfe47_stats_get_comp_mask( - uint32_t irq_status0, uint32_t irq_status1); -uint32_t msm_vfe47_stats_get_frame_id( - struct vfe_device *vfe_dev); -void msm_vfe47_get_error_mask( - uint32_t *error_mask0, uint32_t *error_mask1); -void msm_vfe47_get_overflow_mask(uint32_t *overflow_mask); -void msm_vfe47_get_rdi_wm_mask(struct vfe_device *vfe_dev, - uint32_t *rdi_wm_mask); -void msm_vfe47_get_irq_mask(struct vfe_device *vfe_dev, - uint32_t *irq0_mask, uint32_t *irq1_mask); -void msm_vfe47_restore_irq_mask(struct vfe_device *vfe_dev); -void msm_vfe47_get_halt_restart_mask(uint32_t *irq0_mask, - uint32_t *irq1_mask); -int msm_vfe47_init_hardware(struct vfe_device *vfe_dev); -void msm_vfe47_release_hardware(struct vfe_device *vfe_dev); -void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev); -void msm_vfe47_process_reset_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1); -void msm_vfe47_process_halt_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1); -void msm_vfe47_process_input_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); -void msm_vfe47_process_violation_status( - struct vfe_device *vfe_dev); -void msm_vfe47_process_error_status(struct vfe_device *vfe_dev); -void msm_vfe47_clear_status_reg(struct vfe_device *vfe_dev); -int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev); -int msm_vfe47_enable_regulators(struct vfe_device *vfe_dev, int enable); -int msm_vfe47_get_regulators(struct vfe_device *vfe_dev); -void msm_vfe47_put_regulators(struct vfe_device *vfe_dev); -int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable); -int msm_vfe47_get_clks(struct vfe_device *vfe_dev); -void msm_vfe47_put_clks(struct vfe_device *vfe_dev); -int msm_vfe47_get_clk_rates(struct vfe_device *vfe_dev, - struct msm_isp_clk_rates *rates); -int msm_vfe47_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate); -int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate); -int msm_vfe47_init_bandwidth_mgr(struct vfe_device *vfe_dev, - struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); -void msm_vfe47_deinit_bandwidth_mgr( - struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); -int msm_vfe47_update_bandwidth( - struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr); -void msm_vfe47_config_irq(struct vfe_device *vfe_dev, - uint32_t irq0_mask, uint32_t irq1_mask, - enum msm_isp_irq_operation oper); -#endif /* __MSM_ISP47_H__ */ diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.h deleted file mode 100644 index 0396fc4680f10a09cf6dc7e362fe2a48d35e02dc..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.h +++ /dev/null @@ -1,131 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_ISP_AXI_UTIL_H__ -#define __MSM_ISP_AXI_UTIL_H__ - -#include "msm_isp.h" - -#define HANDLE_TO_IDX(handle) (handle & 0xFF) -#define SRC_TO_INTF(src) \ - ((src < RDI_INTF_0 || src == VFE_AXI_SRC_MAX) ? VFE_PIX_0 : \ - (VFE_RAW_0 + src - RDI_INTF_0)) - -int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_destroy_stream( - struct msm_vfe_axi_shared_data *axi_data, int stream_idx); - -int msm_isp_validate_axi_request( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_reserve_wm( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - -void msm_isp_axi_reserve_comp_mask( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - -int msm_isp_axi_check_stream_state( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd); - -int msm_isp_calculate_framedrop( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); -void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - -int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg); -void msm_isp_get_avtimer_ts(struct msm_isp_timestamp *time_stamp); -int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev, - enum msm_vfe_hw_state hw_state); -int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg); -void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); -int msm_isp_axi_halt(struct vfe_device *vfe_dev, - struct msm_vfe_axi_halt_cmd *halt_cmd); -int msm_isp_axi_reset(struct vfe_device *vfe_dev, - struct msm_vfe_axi_reset_cmd *reset_cmd); -int msm_isp_axi_restart(struct vfe_device *vfe_dev, - struct msm_vfe_axi_restart_cmd *restart_cmd); - -int msm_isp_axi_output_cfg(struct vfe_device *vfe_dev, void *arg); - - -void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); - -void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); - -void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, - enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); - -void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - uint32_t pingpong_status, struct msm_isp_timestamp *ts); - -void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev); - -int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev, - unsigned long fault_addr); - -void msm_isp_increment_frame_id(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); - -int msm_isp_drop_frame(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts, - struct msm_isp_sof_info *sof_info); - -void msm_isp_halt(struct vfe_device *vfe_dev); -void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event); - -void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint32_t pingpong_status, - struct msm_isp_timestamp *ts); - -static inline void msm_isp_cfg_wm_scratch(struct vfe_device *vfe_dev, - int wm, - uint32_t pingpong_bit) -{ - vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( - vfe_dev->vfe_base, wm, - pingpong_bit, vfe_dev->buf_mgr->scratch_buf_addr, 0); -} - -static inline void msm_isp_cfg_stream_scratch(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint32_t pingpong_status) -{ - int i; - uint32_t pingpong_bit; - - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); - for (i = 0; i < stream_info->num_planes; i++) - msm_isp_cfg_wm_scratch(vfe_dev, stream_info->wm[i], - ~pingpong_bit & 0x1); - stream_info->buf[pingpong_bit] = NULL; -} - -int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, - uint32_t buf_idx); -#endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/ais/isp/msm_isp_stats_util.h deleted file mode 100644 index 707901bc62711686dcb20045acba73ecbce32ba7..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_isp_stats_util.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_ISP_STATS_UTIL_H__ -#define __MSM_ISP_STATS_UTIL_H__ - -#include "msm_isp.h" -#define STATS_IDX(idx) (idx & 0xFF) - -void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - uint32_t pingpong_status, struct msm_isp_timestamp *ts); -void msm_isp_stats_stream_update(struct vfe_device *vfe_dev); -int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg); -void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev); -void msm_isp_stats_disable(struct vfe_device *vfe_dev); -int msm_isp_stats_reset(struct vfe_device *vfe_dev); -int msm_isp_stats_restart(struct vfe_device *vfe_dev); -#endif /* __MSM_ISP_STATS_UTIL_H__ */ diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_util.h b/drivers/media/platform/msm/ais/isp/msm_isp_util.h deleted file mode 100644 index b5b0140aa513aba063967008a0cdcd92e88f373d..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/isp/msm_isp_util.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_ISP_UTIL_H__ -#define __MSM_ISP_UTIL_H__ - -#include "msm_isp.h" -#include -#include "msm_camera_io_util.h" - -/* #define CONFIG_MSM_ISP_DBG 1 */ - -#ifdef CONFIG_MSM_ISP_DBG -#define ISP_DBG(fmt, args...) printk(fmt, ##args) -#else -#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -#define ALT_VECTOR_IDX(x) {x = 3 - x; } -#define MAX_ISP_PING_PONG_DUMP_SIZE 20 -struct ping_pong_state { - uint32_t vfe_id; - uint32_t irq_status0; - uint32_t irq_status1; - uint32_t ping_pong_status; - uint32_t core; - struct msm_isp_timestamp ts; -}; -struct dual_vfe_state { - struct ping_pong_state current_vfe_irq; - struct ping_pong_state other_vfe; -}; -struct dump_ping_pong_state { - struct dual_vfe_state arr[MAX_ISP_PING_PONG_DUMP_SIZE]; - uint32_t first; - uint32_t fill_count; - struct vfe_device *vfe_dev; -}; - -void msm_isp_dump_ping_pong_mismatch(void); -void msm_isp_get_status(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1); -void msm_isp_dump_taskelet_debug(void); -uint32_t msm_isp_get_framedrop_period( - enum msm_vfe_frame_skip_pattern frame_skip_pattern); -void msm_isp_reset_burst_count_and_frame_drop( - struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); - -int msm_isp_init_bandwidth_mgr(struct vfe_device *vfe_dev, - enum msm_isp_hw_client client); -int msm_isp_update_bandwidth(enum msm_isp_hw_client client, - uint64_t ab, uint64_t ib); -void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev, - struct msm_isp_statistics *stats); -void msm_isp_util_update_last_overflow_ab_ib(struct vfe_device *vfe_dev); -void msm_isp_util_update_clk_rate(long clock_rate); -void msm_isp_update_req_history(uint32_t client, uint64_t ab, - uint64_t ib, - struct msm_isp_bandwidth_info *client_info, - unsigned long long ts); -void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client); - -int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - -int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - -int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg); -int msm_isp_send_event(struct vfe_device *vfe_dev, - uint32_t type, struct msm_isp_event_data *event_data); -int msm_isp_cal_word_per_line(uint32_t output_format, - uint32_t pixel_per_line); -int msm_isp_get_bit_per_pixel(uint32_t output_format); -enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format); -irqreturn_t msm_isp_process_irq(int irq_num, void *data); -int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); -void msm_isp_do_tasklet(unsigned long data); -void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev); -void msm_isp_process_error_info(struct vfe_device *vfe_dev); -int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); -int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); -long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg); -void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, - struct msm_vfe_fetch_engine_info *fetch_engine_info); -void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format); -void msm_isp_flush_tasklet(struct vfe_device *vfe_dev); -void msm_isp_save_framedrop_values(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); -void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp, - struct vfe_device *vfe_dev); -void msm_isp_process_overflow_irq( - struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1, - uint32_t force_overflow); -#endif /* __MSM_ISP_UTIL_H__ */ diff --git a/drivers/media/platform/msm/ais/ispif/Makefile b/drivers/media/platform/msm/ais/ispif/Makefile deleted file mode 100644 index 4e22b41a0fe166e6c2624c027d83c78c655c8b13..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/ispif/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_ispif.o diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif.c b/drivers/media/platform/msm/ais/ispif/msm_ispif.c deleted file mode 100644 index 1698181c5687d078cf6d5757d7016e541b990706..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif.c +++ /dev/null @@ -1,1807 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_ispif.h" -#include "msm.h" -#include "msm_sd.h" -#include "msm_camera_io_util.h" -#include "cam_hw_ops.h" -#include "cam_soc_api.h" - -#ifdef CONFIG_AIS_MSM_ISPIF_V1 -#include "msm_ispif_hwreg_v1.h" -#elif defined CONFIG_AIS_MSM_ISPIF_V2 -#include "msm_ispif_hwreg_v2.h" -#else -#include "msm_ispif_hwreg_v3.h" -#endif - -#define V4L2_IDENT_ISPIF 50001 -#define MSM_ISPIF_DRV_NAME "msm_ispif" - -#define ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY 0x00 -#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY 0x01 -#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02 - -#define ISPIF_TIMEOUT_SLEEP_US 1000 -#define ISPIF_TIMEOUT_ALL_US 1000000 -#define ISPIF_SOF_DEBUG_COUNT 0 - -#undef CDBG -#ifdef CONFIG_MSM_AIS_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) -#endif - -static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable); -static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); -static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, - unsigned int cmd, void *arg); - -static int msm_ispif_get_clk_info(struct ispif_device *ispif_dev, - struct platform_device *pdev); - - -static void msm_ispif_io_dump_reg(struct ispif_device *ispif) -{ - if (!ispif->enb_dump_reg) - return; - if (!ispif->base) { - pr_err("%s: null pointer for the ispif base\n", __func__); - return; - } - - msm_camera_io_dump(ispif->base, 0x250, 0); -} - - -static inline int msm_ispif_is_intf_valid(uint32_t csid_version, - enum msm_ispif_vfe_intf intf_type) -{ - return ((csid_version <= CSID_VERSION_V22 && intf_type != VFE0) || - (intf_type >= VFE_MAX)) ? false : true; -} - -static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { - {"ispif_ahb_clk", NO_SET_RATE}, - {"camss_top_ahb_clk", NO_SET_RATE}, - {"csi0_ahb_clk", NO_SET_RATE}, - {"csi0_src_clk", NO_SET_RATE}, - {"csi0_phy_clk", NO_SET_RATE}, - {"csi0_clk", NO_SET_RATE}, - {"csi0_pix_clk", NO_SET_RATE}, - {"csi0_rdi_clk", NO_SET_RATE}, - {"csi1_ahb_clk", NO_SET_RATE}, - {"csi1_src_clk", NO_SET_RATE}, - {"csi1_phy_clk", NO_SET_RATE}, - {"csi1_clk", NO_SET_RATE}, - {"csi1_pix_clk", NO_SET_RATE}, - {"csi1_rdi_clk", NO_SET_RATE}, - {"camss_vfe_vfe_clk", NO_SET_RATE}, - {"camss_csi_vfe_clk", NO_SET_RATE}, -}; - -#ifdef CONFIG_COMPAT -struct ispif_cfg_data_ext_32 { - enum ispif_cfg_type_t cfg_type; - compat_caddr_t data; - uint32_t size; -}; - -#define VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT \ - _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct ispif_cfg_data_ext_32) -#endif - -static void msm_ispif_get_pack_mask_from_cfg( - struct msm_ispif_pack_cfg *pack_cfg, - struct msm_ispif_params_entry *entry, - uint32_t *pack_mask) -{ - int i; - uint32_t temp; - - if (WARN_ON(!entry)) - return; - - memset(pack_mask, 0, sizeof(uint32_t) * 2); - for (i = 0; i < entry->num_cids; i++) { - temp = (pack_cfg[entry->cids[i]].pack_mode & 0x3)| - (pack_cfg[entry->cids[i]].even_odd_sel & 0x1) << 2 | - (pack_cfg[entry->cids[i]].pixel_swap_en & 0x1) << 3; - temp = (temp & 0xF) << ((entry->cids[i] % CID8) * 4); - - if (entry->cids[i] > CID7) - pack_mask[1] |= temp; - else - pack_mask[0] |= temp; - CDBG("%s:num %d cid %d mode %d pack_mask %x %x\n", - __func__, entry->num_cids, entry->cids[i], - pack_cfg[entry->cids[i]].pack_mode, - pack_mask[0], pack_mask[1]); - - } -} - -static int msm_ispif_config2(struct ispif_device *ispif, - void *data) -{ - int rc = 0, i = 0; - enum msm_ispif_intftype intftype; - enum msm_ispif_vfe_intf vfe_intf; - uint32_t pack_cfg_mask[2]; - struct msm_ispif_param_data_ext *params = - (struct msm_ispif_param_data_ext *)data; - - if (WARN_ON(!ispif) || WARN_ON(!params)) { - rc = -EINVAL; - return rc; - } - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - - for (i = 0; i < params->num; i++) { - int j; - - if (params->entries[i].num_cids > MAX_CID_CH_v2) - return -EINVAL; - for (j = 0; j < params->entries[i].num_cids; j++) - if (params->entries[i].cids[j] >= CID_MAX) - return -EINVAL; - } - - for (i = 0; i < params->num; i++) { - intftype = params->entries[i].intftype; - vfe_intf = params->entries[i].vfe_intf; - - CDBG("%s, num %d intftype %x, vfe_intf %d, csid %d\n", __func__, - params->num, intftype, vfe_intf, - params->entries[i].csid); - - if ((intftype >= INTF_MAX) || - (vfe_intf >= ispif->vfe_info.num_vfe) || - (ispif->csid_version <= CSID_VERSION_V22 && - (vfe_intf > VFE0))) { - pr_err("%s: VFEID %d and CSID version %d mismatch\n", - __func__, vfe_intf, ispif->csid_version); - return -EINVAL; - } - - msm_ispif_get_pack_mask_from_cfg(params->pack_cfg, - ¶ms->entries[i], pack_cfg_mask); - msm_ispif_cfg_pack_mode(ispif, intftype, vfe_intf, - pack_cfg_mask); - } - return rc; -} - -static long msm_ispif_cmd_ext(struct v4l2_subdev *sd, - void *arg) -{ - long rc = 0; - struct ispif_device *ispif = - (struct ispif_device *)v4l2_get_subdevdata(sd); - struct ispif_cfg_data_ext pcdata; - struct msm_ispif_param_data_ext *params = NULL; -#ifdef CONFIG_COMPAT - struct ispif_cfg_data_ext_32 *pcdata32 = - (struct ispif_cfg_data_ext_32 *)arg; - - if (pcdata32 == NULL) { - pr_err("Invalid params passed from user\n"); - return -EINVAL; - } - pcdata.cfg_type = pcdata32->cfg_type; - pcdata.size = pcdata32->size; - pcdata.data = compat_ptr(pcdata32->data); - -#else - struct ispif_cfg_data_ext *pcdata64 = - (struct ispif_cfg_data_ext *)arg; - - if (pcdata64 == NULL) { - pr_err("Invalid params passed from user\n"); - return -EINVAL; - } - pcdata.cfg_type = pcdata64->cfg_type; - pcdata.size = pcdata64->size; - pcdata.data = pcdata64->data; -#endif - if (pcdata.size != sizeof(struct msm_ispif_param_data_ext)) { - pr_err("%s: payload size mismatch\n", __func__); - return -EINVAL; - } - - params = kzalloc(sizeof(struct msm_ispif_param_data_ext), GFP_KERNEL); - if (!params) - return -ENOMEM; - if (copy_from_user(params, (void __user *)(pcdata.data), - pcdata.size)) { - kfree(params); - return -EFAULT; - } - - mutex_lock(&ispif->mutex); - switch (pcdata.cfg_type) { - case ISPIF_CFG2: - rc = msm_ispif_config2(ispif, params); - msm_ispif_io_dump_reg(ispif); - break; - default: - pr_err("%s: invalid cfg_type\n", __func__); - rc = -EINVAL; - break; - } - mutex_unlock(&ispif->mutex); - kfree(params); - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_ispif_subdev_ioctl_compat(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - if (WARN_ON(!sd)) - return -EINVAL; - - switch (cmd) { - case VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT: - return msm_ispif_cmd_ext(sd, arg); - - default: - return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); - } -} -static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - if (is_compat_task()) - return msm_ispif_subdev_ioctl_compat(sd, cmd, arg); - else - return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); -} -#else -static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); -} -#endif -static void msm_ispif_put_regulator(struct ispif_device *ispif_dev) -{ - int i; - - for (i = 0; i < ispif_dev->ispif_vdd_count; i++) { - regulator_put(ispif_dev->ispif_vdd[i]); - ispif_dev->ispif_vdd[i] = NULL; - } - for (i = 0; i < ispif_dev->vfe_vdd_count; i++) { - regulator_put(ispif_dev->vfe_vdd[i]); - ispif_dev->vfe_vdd[i] = NULL; - } -} - -static inline int __get_vdd(struct platform_device *pdev, - struct regulator **reg, const char *vdd) -{ - int rc = 0; - *reg = regulator_get(&pdev->dev, vdd); - if (IS_ERR_OR_NULL(*reg)) { - rc = PTR_ERR(*reg); - rc = rc ? rc : -EINVAL; - pr_err("%s: Regulator %s get failed %d\n", __func__, vdd, rc); - *reg = NULL; - } - return rc; -} - -static int msm_ispif_get_regulator_info(struct ispif_device *ispif_dev, - struct platform_device *pdev) -{ - int rc; - const char *vdd_name; - struct device_node *of_node; - int i; - int count; - - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, - "qcom,vdd-names"); - if (0 == count) { - pr_err("%s: no regulators found\n", __func__); - return -EINVAL; - } - - if (WARN_ON(count > (ISPIF_VDD_INFO_MAX + ISPIF_VFE_VDD_INFO_MAX))) - return -EINVAL; - ispif_dev->vfe_vdd_count = 0; - ispif_dev->ispif_vdd_count = 0; - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index( - of_node, "qcom,vdd-names", - i, &vdd_name); - if (rc < 0) { - pr_err("%s: read property qcom,ispif-vdd-names at index %d failed\n", - __func__, i); - goto err; - } - if (strnstr(vdd_name, "vfe", strlen(vdd_name))) { - if (WARN_ON(ispif_dev->vfe_vdd_count >= - ISPIF_VFE_VDD_INFO_MAX)) - return -EINVAL; - rc = __get_vdd(pdev, - &ispif_dev->vfe_vdd[ispif_dev->vfe_vdd_count], - vdd_name); - if (0 == rc) - ispif_dev->vfe_vdd_count++; - } else { - if (WARN_ON(ispif_dev->vfe_vdd_count >= - ISPIF_VDD_INFO_MAX)) - return -EINVAL; - rc = __get_vdd(pdev, - &ispif_dev->ispif_vdd - [ispif_dev->ispif_vdd_count], - vdd_name); - if (0 == rc) - ispif_dev->ispif_vdd_count++; - } - if (rc) - goto err; - } - return 0; -err: - for (i = 0; i < ispif_dev->vfe_vdd_count; i++) { - regulator_put(ispif_dev->vfe_vdd[i]); - ispif_dev->vfe_vdd[i] = NULL; - } - for (i = 0; i < ispif_dev->ispif_vdd_count; i++) { - regulator_put(ispif_dev->ispif_vdd[i]); - ispif_dev->ispif_vdd[i] = NULL; - } - ispif_dev->ispif_vdd_count = 0; - ispif_dev->vfe_vdd_count = 0; - return rc; -} - -static int msm_ispif_set_regulators(struct regulator **regs, int count, - uint8_t enable) -{ - int rc = 0; - int i; - - for (i = 0; i < count; i++) { - if (enable) { - rc = regulator_enable(regs[i]); - if (rc) - goto err; - } else { - rc |= regulator_disable(regs[i]); - } - } - if (rc) - pr_err("%s: Regulator disable failed\n", __func__); - return rc; -err: - pr_err("%s: Regulator enable failed\n", __func__); - for (i--; i >= 0; i--) - regulator_disable(regs[i]); - return rc; -} - -static int msm_ispif_reset_hw(struct ispif_device *ispif) -{ - int rc = 0; - long timeout = 0; - struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)]; - - ispif->clk_idx = 0; - - /* Turn ON VFE regulators before enabling the vfe clocks */ - rc = msm_ispif_set_regulators(ispif->vfe_vdd, ispif->vfe_vdd_count, 1); - if (rc < 0) - return rc; - - rc = msm_camera_clk_enable(&ispif->pdev->dev, - ispif->clk_info, ispif->clks, - ispif->num_clk, 1); - if (rc < 0) { - pr_err("%s: cannot enable clock, error = %d\n", - __func__, rc); - rc = msm_camera_clk_enable(&ispif->pdev->dev, - ispif_8626_reset_clk_info, reset_clk1, - ARRAY_SIZE(ispif_8626_reset_clk_info), 1); - if (rc < 0) { - pr_err("%s: cannot enable clock, error = %d", - __func__, rc); - goto reg_disable; - } else { - /* This is set when device is 8x26 */ - ispif->clk_idx = 2; - } - } else { - /* This is set when device is 8974 */ - ispif->clk_idx = 1; - } - - atomic_set(&ispif->reset_trig[VFE0], 1); - /* initiate reset of ISPIF */ - msm_camera_io_w(ISPIF_RST_CMD_MASK, - ispif->base + ISPIF_RST_CMD_ADDR); - - timeout = wait_for_completion_timeout( - &ispif->reset_complete[VFE0], msecs_to_jiffies(500)); - CDBG("%s: VFE0 done\n", __func__); - - if (timeout <= 0) { - rc = -ETIMEDOUT; - pr_err("%s: VFE0 reset wait timeout\n", __func__); - goto clk_disable; - } - - if (ispif->hw_num_isps > 1) { - atomic_set(&ispif->reset_trig[VFE1], 1); - msm_camera_io_w(ISPIF_RST_CMD_1_MASK, - ispif->base + ISPIF_RST_CMD_1_ADDR); - timeout = wait_for_completion_timeout( - &ispif->reset_complete[VFE1], - msecs_to_jiffies(500)); - CDBG("%s: VFE1 done\n", __func__); - if (timeout <= 0) { - pr_err("%s: VFE1 reset wait timeout\n", __func__); - rc = -ETIMEDOUT; - } - } - -clk_disable: - if (ispif->clk_idx == 1) { - rc = rc ? rc : msm_camera_clk_enable(&ispif->pdev->dev, - ispif->clk_info, ispif->clks, - ispif->num_clk, 0); - } - - if (ispif->clk_idx == 2) { - rc = rc ? rc : msm_camera_clk_enable(&ispif->pdev->dev, - ispif_8626_reset_clk_info, reset_clk1, - ARRAY_SIZE(ispif_8626_reset_clk_info), 0); - } -reg_disable: - rc = rc ? rc : msm_ispif_set_regulators(ispif->vfe_vdd, - ispif->vfe_vdd_count, 0); - - return rc; -} - -static int msm_ispif_get_clk_info(struct ispif_device *ispif_dev, - struct platform_device *pdev) -{ - uint32_t num_ahb_clk = 0, non_ahb_clk = 0; - size_t num_clks; - int i, rc; - int j; - struct clk **clks, **temp_clks; - struct msm_cam_clk_info *clk_info, *temp_clk_info; - - struct device_node *of_node; - - of_node = pdev->dev.of_node; - - rc = msm_camera_get_clk_info(pdev, &clk_info, - &clks, &num_clks); - - if (rc) - return rc; - - /* - * reshuffle the clock arrays so that the ahb clocks are - * at the beginning of array - */ - temp_clks = kcalloc(num_clks, sizeof(struct clk *), - GFP_KERNEL); - temp_clk_info = kcalloc(num_clks, sizeof(struct msm_cam_clk_info), - GFP_KERNEL); - if (!temp_clks || !temp_clk_info) { - rc = -ENOMEM; - kfree(temp_clk_info); - kfree(temp_clks); - goto alloc_fail; - } - j = 0; - for (i = 0; i < num_clks; i++) { - if (strnstr(clk_info[i].clk_name, - "ahb", strlen(clk_info[i].clk_name))) { - temp_clk_info[j] = clk_info[i]; - temp_clks[j] = clks[i]; - j++; - num_ahb_clk++; - } - } - for (i = 0; i < num_clks; i++) { - if (!strnstr(clk_info[i].clk_name, - "ahb", strlen(clk_info[i].clk_name))) { - temp_clk_info[j] = clk_info[i]; - temp_clks[j] = clks[i]; - j++; - non_ahb_clk++; - } - } - - for (i = 0; i < num_clks; i++) { - clk_info[i] = temp_clk_info[i]; - clks[i] = temp_clks[i]; - } - kfree(temp_clk_info); - kfree(temp_clks); - - ispif_dev->ahb_clk = clks; - ispif_dev->ahb_clk_info = clk_info; - ispif_dev->num_ahb_clk = num_ahb_clk; - ispif_dev->clk_info = clk_info + num_ahb_clk; - ispif_dev->clks = clks + num_ahb_clk; - ispif_dev->num_clk = non_ahb_clk; - - return 0; -alloc_fail: - msm_camera_put_clk_info(pdev, &clk_info, &clks, num_clks); - return rc; -} - -static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable) -{ - int rc = 0; - - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif->ahb_clk_info, ispif->ahb_clk, - ispif->num_ahb_clk, enable); - if (rc < 0) { - pr_err("%s: cannot enable clock, error = %d", - __func__, rc); - } - - return rc; -} - -static int msm_ispif_reset(struct ispif_device *ispif) -{ - int rc = 0; - int i, vfe_intf; - - if (WARN_ON(!ispif)) - return -EINVAL; - - memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); - memset(ispif->vc_enable, 0, sizeof(ispif->vc_enable)); - for (i = 0; i < ispif->vfe_info.num_vfe; i++) { - - msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT, - ispif->base + ISPIF_VFE_m_CTRL_0(i)); - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i)); - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i)); - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i)); - msm_camera_io_w(0xFFFFFFFF, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_0(i)); - msm_camera_io_w(0xFFFFFFFF, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_1(i)); - msm_camera_io_w(0xFFFFFFFF, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_2(i)); - - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i)); - - msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, - ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); - msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, - ispif->base + ISPIF_VFE_m_INTF_CMD_1(i)); - - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2)); - - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CROP(i, 1)); - } - - msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + - ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); - - for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) { - msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + - ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + - ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + - ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf)); - } - - msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + - ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); - - return rc; -} - -static void msm_ispif_sel_csid_core(struct ispif_device *ispif, - uint8_t intftype, uint8_t csid, uint8_t vfe_intf) -{ - uint32_t data; - - if (WARN_ON(!ispif)) - return; - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return; - } - - data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); - switch (intftype) { - case PIX0: - data &= ~(BIT(1) | BIT(0)); - data |= (uint32_t) csid; - break; - case RDI0: - data &= ~(BIT(5) | BIT(4)); - data |= ((uint32_t) csid) << 4; - break; - case PIX1: - data &= ~(BIT(9) | BIT(8)); - data |= ((uint32_t) csid) << 8; - break; - case RDI1: - data &= ~(BIT(13) | BIT(12)); - data |= ((uint32_t) csid) << 12; - break; - case RDI2: - data &= ~(BIT(21) | BIT(20)); - data |= ((uint32_t) csid) << 20; - break; - } - - msm_camera_io_w_mb(data, ispif->base + - ISPIF_VFE_m_INPUT_SEL(vfe_intf)); -} - -static void msm_ispif_enable_crop(struct ispif_device *ispif, - uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel, - uint16_t end_pixel) -{ - uint32_t data; - - if (WARN_ON(!ispif)) - return; - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return; - } - - data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); - data |= (1 << (intftype + 7)); - if (intftype == PIX0) - data |= 1 << PIX0_LINE_BUF_EN_BIT; - msm_camera_io_w(data, - ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); - - if (intftype == PIX0) - msm_camera_io_w_mb(start_pixel | (end_pixel << 16), - ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0)); - else if (intftype == PIX1) - msm_camera_io_w_mb(start_pixel | (end_pixel << 16), - ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1)); - else { - pr_err("%s: invalid intftype=%d\n", __func__, intftype); - return; - } -} - -static void msm_ispif_enable_intf_cids(struct ispif_device *ispif, - uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable) -{ - uint32_t intf_addr, data, i; - - if (WARN_ON(!ispif)) - return; - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return; - } - - switch (intftype) { - case PIX0: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 0); - break; - case RDI0: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 0); - break; - case PIX1: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 1); - break; - case RDI1: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 1); - break; - case RDI2: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 2); - break; - default: - pr_err("%s: invalid intftype=%d\n", __func__, intftype); - return; - } - - if (enable) - data = (uint32_t) cid_mask; - else - data = (~((uint32_t) cid_mask)) & 0xFFFF; - msm_camera_io_w_mb(data, ispif->base + intf_addr); - - for (i = 0; i < VC_MAX; i++) - ispif->vc_enable[vfe_intf][intftype][i] = - (data & (0xF << (i*4))) ? 1 : 0; - -} - -static int msm_ispif_validate_intf_status(struct ispif_device *ispif, - uint8_t intftype, uint8_t vfe_intf) -{ - int rc = 0; - uint32_t data = 0; - - if (WARN_ON(!ispif)) - return -EINVAL; - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return -EINVAL; - } - - switch (intftype) { - case PIX0: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0)); - break; - case RDI0: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0)); - break; - case PIX1: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1)); - break; - case RDI1: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1)); - break; - case RDI2: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2)); - break; - } - if ((data & 0xf) != 0xf) - rc = -EBUSY; - return rc; -} - -static void msm_ispif_select_clk_mux(struct ispif_device *ispif, - uint8_t intftype, uint8_t csid, uint8_t vfe_intf) -{ - uint32_t data = 0; - - switch (intftype) { - case PIX0: - data = msm_camera_io_r(ispif->clk_mux_base); - data &= ~(0xf << (vfe_intf * 8)); - data |= (csid << (vfe_intf * 8)); - msm_camera_io_w(data, ispif->clk_mux_base); - break; - - case RDI0: - data = msm_camera_io_r(ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - data &= ~(0xf << (vfe_intf * 12)); - data |= (csid << (vfe_intf * 12)); - msm_camera_io_w(data, ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - break; - - case PIX1: - data = msm_camera_io_r(ispif->clk_mux_base); - data &= ~(0xf0 << (vfe_intf * 8)); - data |= (csid << (4 + (vfe_intf * 8))); - msm_camera_io_w(data, ispif->clk_mux_base); - break; - - case RDI1: - data = msm_camera_io_r(ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - data &= ~(0xf << (4 + (vfe_intf * 12))); - data |= (csid << (4 + (vfe_intf * 12))); - msm_camera_io_w(data, ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - break; - - case RDI2: - data = msm_camera_io_r(ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - data &= ~(0xf << (8 + (vfe_intf * 12))); - data |= (csid << (8 + (vfe_intf * 12))); - msm_camera_io_w(data, ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - break; - } - CDBG("%s intftype %d data %x\n", __func__, intftype, data); - /* ensure clk mux is enabled */ - mb(); -} - -static uint16_t msm_ispif_get_cids_mask_from_cfg( - struct msm_ispif_params_entry *entry) -{ - int i; - uint16_t cids_mask = 0; - - if (WARN_ON(!entry)) - return 0; - - for (i = 0; i < entry->num_cids && i < MAX_CID_CH_v2; i++) - cids_mask |= (1 << entry->cids[i]); - - return cids_mask; -} - -static int msm_ispif_config(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int rc = 0, i = 0; - uint16_t cid_mask; - enum msm_ispif_intftype intftype; - enum msm_ispif_vfe_intf vfe_intf; - - if (WARN_ON(!ispif) || WARN_ON(!params)) { - rc = -EINVAL; - return rc; - } - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - - for (i = 0; i < params->num; i++) { - vfe_intf = params->entries[i].vfe_intf; - if (!msm_ispif_is_intf_valid(ispif->csid_version, - vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return -EINVAL; - } - } - - for (i = 0; i < params->num; i++) { - intftype = params->entries[i].intftype; - vfe_intf = params->entries[i].vfe_intf; - - CDBG("%s %d - intftype %x, vfe_intf %d, csid %d\n", __func__, - i, intftype, vfe_intf, params->entries[i].csid); - - if ((intftype >= INTF_MAX) || - (vfe_intf >= ispif->vfe_info.num_vfe) || - (ispif->csid_version <= CSID_VERSION_V22 && - (vfe_intf > VFE0))) { - pr_err("%s: VFEID %d and CSID version %d mismatch\n", - __func__, vfe_intf, ispif->csid_version); - return -EINVAL; - } - - if (ispif->csid_version >= CSID_VERSION_V30) - msm_ispif_select_clk_mux(ispif, intftype, - params->entries[i].csid, vfe_intf); - - rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf); - if (rc) { - pr_err("%s:validate_intf_status failed, rc = %d\n", - __func__, rc); - return rc; - } - - - msm_ispif_sel_csid_core(ispif, intftype, - params->entries[i].csid, vfe_intf); - - cid_mask = msm_ispif_get_cids_mask_from_cfg( - ¶ms->entries[i]); - - msm_ispif_enable_intf_cids(ispif, intftype, - cid_mask, vfe_intf, 1); - - if (params->entries[i].crop_enable) - msm_ispif_enable_crop(ispif, intftype, vfe_intf, - params->entries[i].crop_start_pixel, - params->entries[i].crop_end_pixel); - - CDBG("ISPIF: crop_enable:%d, cid_mask = %d\n", - params->entries[i].crop_enable, cid_mask); - } - - return rc; -} - -static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits, - struct msm_ispif_param_data *params) -{ - uint8_t vc; - int i; - enum msm_ispif_intftype intf_type; - enum msm_ispif_vfe_intf vfe_intf; - - if (WARN_ON(!ispif) || WARN_ON(!params)) - return; - - for (i = 0; i < params->num; i++) { - intf_type = params->entries[i].intftype; - vfe_intf = params->entries[i].vfe_intf; - CDBG("%s: cmd_bits=%d, intf_type=%d : vfe_intf =%d\n", - __func__, cmd_bits, intf_type, vfe_intf); - for (vc = 0; vc < VC_MAX; vc++) { - CDBG("vc_enable[%d]=%d", - vc, ispif->vc_enable[vfe_intf][intf_type][vc]); - if (!ispif->vc_enable[vfe_intf][intf_type][vc]) - continue; - if (intf_type == RDI2) { - /* zero out two bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &= - ~(0x3 << (vc * 2 + 8)); - /* set cmd bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd1 |= - (cmd_bits << (vc * 2 + 8)); - } else { - /* zero 2 bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd &= - ~(0x3 << (vc * 2 + intf_type * 8)); - /* set cmd bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd |= - (cmd_bits << (vc * 2 + intf_type * 8)); - } - } - /* cmd for PIX0, PIX1, RDI0, RDI1 */ - if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) - msm_camera_io_w_mb( - ispif->applied_intf_cmd[vfe_intf].intf_cmd, - ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf)); - - /* cmd for RDI2 */ - if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF) - msm_camera_io_w_mb( - ispif->applied_intf_cmd[vfe_intf].intf_cmd1, - ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf)); - } -} - -static int msm_ispif_stop_immediately(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int rc = 0, i = 0; - - if (WARN_ON(!ispif) || WARN_ON(!params)) { - rc = -EINVAL; - return rc; - } - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - CDBG("%s: params->num= %d\n", - __func__, params->num); - - for (i = 0; i < params->num; i++) { - if (!msm_ispif_is_intf_valid(ispif->csid_version, - params->entries[i].vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - rc = -EINVAL; - return rc; - } - } - - msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params); - - return rc; -} - -static int msm_ispif_start_frame_boundary(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int rc = 0, i = 0; - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - for (i = 0; i < params->num; i++) { - if (!msm_ispif_is_intf_valid(ispif->csid_version, - params->entries[i].vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - rc = -EINVAL; - return rc; - } - } - - msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params); - - return rc; -} - -static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int rc = 0; - - rc = msm_ispif_reset_hw(ispif); - if (!rc) - rc = msm_ispif_reset(ispif); - if (!rc) - rc = msm_ispif_config(ispif, params); - if (!rc) - rc = msm_ispif_start_frame_boundary(ispif, params); - - if (!rc) - pr_info("ISPIF restart Successful\n"); - else - pr_info("ISPIF restart Failed\n"); - - return rc; -} - -static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int i, rc = 0; - uint16_t cid_mask = 0; - uint32_t intf_addr; - enum msm_ispif_vfe_intf vfe_intf; - uint32_t stop_flag = 0; - - if (WARN_ON(!ispif) || WARN_ON(!params)) { - rc = -EINVAL; - return rc; - } - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - - for (i = 0; i < params->num; i++) { - if (!msm_ispif_is_intf_valid(ispif->csid_version, - params->entries[i].vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - rc = -EINVAL; - goto end; - } - } - - msm_ispif_intf_cmd(ispif, - ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY, params); - - for (i = 0; i < params->num; i++) { - cid_mask = - msm_ispif_get_cids_mask_from_cfg(¶ms->entries[i]); - vfe_intf = params->entries[i].vfe_intf; - - switch (params->entries[i].intftype) { - case PIX0: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0); - break; - case RDI0: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0); - break; - case PIX1: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1); - break; - case RDI1: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1); - break; - case RDI2: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2); - break; - default: - pr_err("%s: invalid intftype=%d\n", __func__, - params->entries[i].intftype); - rc = -EPERM; - goto end; - } - - rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag, - (stop_flag & 0xF) == 0xF, - ISPIF_TIMEOUT_SLEEP_US, - ISPIF_TIMEOUT_ALL_US); - if (rc < 0) - pr_err("ISPIF stop frame boundary timeout\n"); - } - -end: - return rc; -} - -static void ispif_process_irq(struct ispif_device *ispif, - struct ispif_irq_status *out, enum msm_ispif_vfe_intf vfe_id) -{ - if (WARN_ON(!ispif) || WARN_ON(!out)) - return; - - if (out[vfe_id].ispifIrqStatus0 & - ISPIF_IRQ_STATUS_PIX_SOF_MASK) { - if (ispif->ispif_sof_debug < ISPIF_SOF_DEBUG_COUNT) - pr_err("%s: PIX0 frame id: %u irqstatus0 0x%x, irqstatus1 0x%x\n", - __func__, - ispif->sof_count[vfe_id].sof_cnt[PIX0], - out[vfe_id].ispifIrqStatus0, - out[vfe_id].ispifIrqStatus1); - ispif->sof_count[vfe_id].sof_cnt[PIX0]++; - ispif->ispif_sof_debug++; - } - if (out[vfe_id].ispifIrqStatus0 & - ISPIF_IRQ_STATUS_RDI0_SOF_MASK) { - if (ispif->ispif_rdi0_debug < ISPIF_SOF_DEBUG_COUNT) - pr_err("%s: RDI0 frame id: %u\n", __func__, - ispif->sof_count[vfe_id].sof_cnt[RDI0]); - ispif->sof_count[vfe_id].sof_cnt[RDI0]++; - ispif->ispif_rdi0_debug++; - } - if (out[vfe_id].ispifIrqStatus1 & - ISPIF_IRQ_STATUS_RDI1_SOF_MASK) { - if (ispif->ispif_rdi1_debug < ISPIF_SOF_DEBUG_COUNT) - pr_err("%s: RDI1 frame id: %u\n", __func__, - ispif->sof_count[vfe_id].sof_cnt[RDI1]); - ispif->sof_count[vfe_id].sof_cnt[RDI1]++; - ispif->ispif_rdi1_debug++; - } - if (out[vfe_id].ispifIrqStatus2 & - ISPIF_IRQ_STATUS_RDI2_SOF_MASK) { - if (ispif->ispif_rdi2_debug < ISPIF_SOF_DEBUG_COUNT) - pr_err("%s: RDI2 frame id: %u\n", __func__, - ispif->sof_count[vfe_id].sof_cnt[RDI2]); - ispif->sof_count[vfe_id].sof_cnt[RDI2]++; - ispif->ispif_rdi2_debug++; - } -} - -static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out, - void *data) -{ - struct ispif_device *ispif = (struct ispif_device *)data; - bool fatal_err = false; - int i = 0; - - if (WARN_ON(!ispif) || WARN_ON(!out)) - return; - - out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_0(VFE0)); - msm_camera_io_w(out[VFE0].ispifIrqStatus0, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE0)); - - out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_1(VFE0)); - msm_camera_io_w(out[VFE0].ispifIrqStatus1, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE0)); - - out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_2(VFE0)); - msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0)); - - if (ispif->vfe_info.num_vfe > 1) { - out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_0(VFE1)); - msm_camera_io_w(out[VFE1].ispifIrqStatus0, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1)); - - out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_1(VFE1)); - msm_camera_io_w(out[VFE1].ispifIrqStatus1, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1)); - - out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_2(VFE1)); - msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1)); - } - msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + - ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); - - if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { - if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) { - if (atomic_dec_and_test(&ispif->reset_trig[VFE0])) - complete(&ispif->reset_complete[VFE0]); - } - - if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE0 pix0 overflow.\n", - __func__); - fatal_err = true; - } - - if (out[VFE0].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE0 rdi0 overflow.\n", - __func__); - fatal_err = true; - } - - if (out[VFE0].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE0 rdi1 overflow.\n", - __func__); - fatal_err = true; - } - - if (out[VFE0].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE0 rdi2 overflow.\n", - __func__); - fatal_err = true; - } - - ispif_process_irq(ispif, out, VFE0); - } - if (ispif->hw_num_isps > 1) { - if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) { - if (atomic_dec_and_test(&ispif->reset_trig[VFE1])) - complete(&ispif->reset_complete[VFE1]); - } - - if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE1 pix0 overflow.\n", - __func__); - fatal_err = true; - } - - if (out[VFE1].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE1 rdi0 overflow.\n", - __func__); - fatal_err = true; - } - - if (out[VFE1].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE1 rdi1 overflow.\n", - __func__); - fatal_err = true; - } - - if (out[VFE1].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) { - pr_err_ratelimited("%s: VFE1 rdi2 overflow.\n", - __func__); - fatal_err = true; - } - - ispif_process_irq(ispif, out, VFE1); - } - - if (fatal_err == true) { - pr_err_ratelimited("%s: fatal error, stop ispif immediately\n", - __func__); - for (i = 0; i < ispif->vfe_info.num_vfe; i++) { - msm_camera_io_w(0x0, - ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i)); - msm_camera_io_w(0x0, - ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i)); - msm_camera_io_w(0x0, - ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i)); - msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, - ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); - msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, - ispif->base + ISPIF_VFE_m_INTF_CMD_1(i)); - } - } -} - -static irqreturn_t msm_io_ispif_irq(int irq_num, void *data) -{ - struct ispif_irq_status irq[VFE_MAX]; - - msm_ispif_read_irq_status(irq, data); - return IRQ_HANDLED; -} - - -static int msm_ispif_set_vfe_info(struct ispif_device *ispif, - struct msm_ispif_vfe_info *vfe_info) -{ - if (!vfe_info || (vfe_info->num_vfe == 0) || - (vfe_info->num_vfe > ispif->hw_num_isps)) { - pr_err("Invalid VFE info: %pK %d\n", vfe_info, - (vfe_info ? vfe_info->num_vfe : 0)); - return -EINVAL; - } - - memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info)); - - return 0; -} - - -static int msm_ispif_init(struct ispif_device *ispif, - uint32_t csid_version) -{ - int rc = 0; - - if (WARN_ON(!ispif)) { - rc = -EINVAL; - return rc; - } - - if (ispif->ispif_state == ISPIF_POWER_UP) { - pr_err("%s: ispif already initted state = %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - - /* can we set to zero? */ - ispif->applied_intf_cmd[VFE0].intf_cmd = 0xFFFFFFFF; - ispif->applied_intf_cmd[VFE0].intf_cmd1 = 0xFFFFFFFF; - ispif->applied_intf_cmd[VFE1].intf_cmd = 0xFFFFFFFF; - ispif->applied_intf_cmd[VFE1].intf_cmd1 = 0xFFFFFFFF; - memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); - memset(ispif->vc_enable, 0, sizeof(ispif->vc_enable)); - - ispif->csid_version = csid_version; - CDBG("%s: CSID_VERSION= %d\n ", __func__, csid_version); - if (ispif->csid_version >= CSID_VERSION_V30 && !ispif->clk_mux_base) { - ispif->clk_mux_base = msm_camera_get_reg_base(ispif->pdev, - "csi_clk_mux", 1); - if (!ispif->clk_mux_base) - return -ENOMEM; - } - - rc = cam_config_ahb_clk(NULL, 0, - CAM_AHB_CLIENT_ISPIF, CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - rc = msm_ispif_reset_hw(ispif); - if (rc) - goto error_ahb; - - rc = msm_ispif_reset(ispif); - if (rc) - goto error_ahb; - ispif->ispif_state = ISPIF_POWER_UP; - return 0; - -error_ahb: - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - return rc; -} - -static void msm_ispif_release(struct ispif_device *ispif) -{ - if (WARN_ON(!ispif)) - return; - - msm_ispif_reset(ispif); - msm_ispif_reset_hw(ispif); - - msm_camera_enable_irq(ispif->irq, 0); - - ispif->ispif_state = ISPIF_POWER_DOWN; - - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); -} - -static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) -{ - long rc = 0; - struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg; - struct ispif_device *ispif = - (struct ispif_device *)v4l2_get_subdevdata(sd); - - if (WARN_ON(!sd) || WARN_ON(!pcdata)) { - rc = -EINVAL; - return rc; - } - - mutex_lock(&ispif->mutex); - CDBG("%s cfg_type = %d\n", __func__, pcdata->cfg_type); - switch (pcdata->cfg_type) { - case ISPIF_ENABLE_REG_DUMP: - ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */ - break; - case ISPIF_INIT: - rc = msm_ispif_init(ispif, ispif->csid_version); - if (rc) { - pr_err("%s: %d Init failed\n", __func__, __LINE__); - break; - } - msm_ispif_io_dump_reg(ispif); - break; - - case ISPIF_RESET: - case ISPIF_RELEASE: - msm_ispif_reset(ispif); - msm_ispif_reset_hw(ispif); - break; - case ISPIF_CFG: - rc = msm_ispif_config(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_START_FRAME_BOUNDARY: - rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_RESTART_FRAME_BOUNDARY: - rc = msm_ispif_restart_frame_boundary(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_STOP_FRAME_BOUNDARY: - rc = msm_ispif_stop_frame_boundary(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_STOP: - rc = msm_ispif_stop_immediately(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_SET_VFE_INFO: - rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info); - break; - default: - pr_err("%s: invalid cfg_type\n", __func__); - rc = -EINVAL; - break; - } - mutex_unlock(&ispif->mutex); - return rc; -} -static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops; - -static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct ispif_device *ispif = - (struct ispif_device *)v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_MSM_ISPIF_CFG: - return msm_ispif_cmd(sd, arg); - case VIDIOC_MSM_ISPIF_CFG_EXT: - return msm_ispif_cmd_ext(sd, arg); - case MSM_SD_NOTIFY_FREEZE: { - ispif->ispif_sof_debug = 0; - ispif->ispif_rdi0_debug = 0; - ispif->ispif_rdi1_debug = 0; - ispif->ispif_rdi2_debug = 0; - return 0; - } - case MSM_SD_UNNOTIFY_FREEZE: - return 0; - case MSM_SD_SHUTDOWN: - return 0; - default: - pr_err_ratelimited("%s: invalid cmd 0x%x received\n", - __func__, cmd); - return -ENOIOCTLCMD; - } -} - -static long msm_ispif_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - - return msm_ispif_subdev_ioctl(sd, cmd, arg); -} - -static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_ispif_subdev_do_ioctl); -} - -static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct ispif_device *ispif = v4l2_get_subdevdata(sd); - int rc = 0; - - CDBG("ISPIF: ispif_open_node"); - mutex_lock(&ispif->mutex); - if (0 == ispif->open_cnt) { - /* enable regulator and clocks on first open */ - rc = msm_ispif_set_regulators(ispif->ispif_vdd, - ispif->ispif_vdd_count, 1); - if (rc) - goto unlock; - - rc = msm_ispif_clk_ahb_enable(ispif, 1); - if (rc) - goto ahb_clk_enable_fail; - - rc = msm_camera_enable_irq(ispif->irq, 1); - if (rc) - goto irq_enable_fail; - } - /* mem remap is done in init when the clock is on */ - ispif->open_cnt++; - mutex_unlock(&ispif->mutex); - return rc; -irq_enable_fail: - msm_ispif_clk_ahb_enable(ispif, 0); -ahb_clk_enable_fail: - msm_ispif_set_regulators(ispif->ispif_vdd, ispif->ispif_vdd_count, 0); -unlock: - mutex_unlock(&ispif->mutex); - return rc; -} - -static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - int rc = 0; - struct ispif_device *ispif = v4l2_get_subdevdata(sd); - - CDBG("ISPIF: ispif_close_node"); - if (!ispif) { - pr_err("%s: invalid input\n", __func__); - return -EINVAL; - } - mutex_lock(&ispif->mutex); - if (ispif->open_cnt == 0) { - pr_err("%s: Invalid close\n", __func__); - rc = -ENODEV; - goto end; - } - ispif->open_cnt--; - if (ispif->open_cnt == 0) { - msm_ispif_release(ispif); - /* disable clocks and regulator on last close */ - msm_ispif_clk_ahb_enable(ispif, 0); - msm_ispif_set_regulators(ispif->ispif_vdd, - ispif->ispif_vdd_count, 0); - } -end: - mutex_unlock(&ispif->mutex); - return rc; -} - -static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = { - .ioctl = &msm_ispif_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_ispif_subdev_ops = { - .core = &msm_ispif_subdev_core_ops, -}; - -static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops = { - .open = ispif_open_node, - .close = ispif_close_node, -}; - -static int ispif_probe(struct platform_device *pdev) -{ - int rc; - struct ispif_device *ispif; - - ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL); - if (!ispif) - return -ENOMEM; - - if (pdev->dev.of_node) { - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - rc = of_property_read_u32((&pdev->dev)->of_node, - "qcom,num-isps", &ispif->hw_num_isps); - if (rc) - /* backward compatibility */ - ispif->hw_num_isps = 1; - /* not an error condition */ - rc = 0; - } - - rc = msm_ispif_get_regulator_info(ispif, pdev); - if (rc < 0) - goto regulator_fail; - - rc = msm_ispif_get_clk_info(ispif, pdev); - if (rc < 0) { - pr_err("%s: msm_isp_get_clk_info() failed", __func__); - rc = -EFAULT; - goto get_clk_fail; - } - mutex_init(&ispif->mutex); - ispif->base = msm_camera_get_reg_base(pdev, "ispif", 1); - if (!ispif->base) { - rc = -ENOMEM; - goto reg_base_fail; - } - - ispif->irq = msm_camera_get_irq(pdev, "ispif"); - if (!ispif->irq) { - rc = -ENODEV; - goto get_irq_fail; - } - rc = msm_camera_register_irq(pdev, ispif->irq, msm_io_ispif_irq, - IRQF_TRIGGER_RISING, "ispif", ispif); - if (rc) { - rc = -ENODEV; - goto get_irq_fail; - } - rc = msm_camera_enable_irq(ispif->irq, 0); - if (rc) - goto sd_reg_fail; - - ispif->pdev = pdev; - - v4l2_subdev_init(&ispif->msm_sd.sd, &msm_ispif_subdev_ops); - ispif->msm_sd.sd.internal_ops = &msm_ispif_internal_ops; - ispif->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - snprintf(ispif->msm_sd.sd.name, - ARRAY_SIZE(ispif->msm_sd.sd.name), MSM_ISPIF_DRV_NAME); - v4l2_set_subdevdata(&ispif->msm_sd.sd, ispif); - - platform_set_drvdata(pdev, &ispif->msm_sd.sd); - - media_entity_init(&ispif->msm_sd.sd.entity, 0, NULL, 0); - ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF; - ispif->msm_sd.sd.entity.name = pdev->name; - ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1; - rc = msm_sd_register(&ispif->msm_sd); - if (rc) { - pr_err("%s: msm_sd_register error = %d\n", __func__, rc); - goto sd_reg_fail; - } - msm_cam_copy_v4l2_subdev_fops(&msm_ispif_v4l2_subdev_fops); - msm_ispif_v4l2_subdev_fops.unlocked_ioctl = - msm_ispif_subdev_fops_ioctl; -#ifdef CONFIG_COMPAT - msm_ispif_v4l2_subdev_fops.compat_ioctl32 = msm_ispif_subdev_fops_ioctl; -#endif - ispif->msm_sd.sd.devnode->fops = &msm_ispif_v4l2_subdev_fops; - ispif->ispif_state = ISPIF_POWER_DOWN; - ispif->open_cnt = 0; - init_completion(&ispif->reset_complete[VFE0]); - init_completion(&ispif->reset_complete[VFE1]); - atomic_set(&ispif->reset_trig[VFE0], 0); - atomic_set(&ispif->reset_trig[VFE1], 0); - - ispif->csid_version = CSID_VERSION_V35; - memset(&ispif->vfe_info, 0, sizeof(struct msm_ispif_vfe_info)); - ispif->vfe_info.num_vfe = 2; - - return 0; - -sd_reg_fail: - msm_camera_unregister_irq(pdev, ispif->irq, ispif); -get_irq_fail: - msm_camera_put_reg_base(pdev, ispif->base, "ispif", 1); -reg_base_fail: - msm_camera_put_clk_info(pdev, &ispif->ahb_clk_info, - &ispif->ahb_clk, - ispif->num_ahb_clk + ispif->num_clk); -get_clk_fail: - msm_ispif_put_regulator(ispif); -regulator_fail: - mutex_destroy(&ispif->mutex); - kfree(ispif); - return rc; -} - -static const struct of_device_id msm_ispif_dt_match[] = { - {.compatible = "qcom,ispif"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_ispif_dt_match); - -static struct platform_driver ispif_driver = { - .probe = ispif_probe, - .driver = { - .name = MSM_ISPIF_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_ispif_dt_match, - }, -}; - -static int __init msm_ispif_init_module(void) -{ - return platform_driver_register(&ispif_driver); -} - -static void __exit msm_ispif_exit_module(void) -{ - platform_driver_unregister(&ispif_driver); -} - -module_init(msm_ispif_init_module); -module_exit(msm_ispif_exit_module); -MODULE_DESCRIPTION("MSM ISP Interface driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif.h b/drivers/media/platform/msm/ais/ispif/msm_ispif.h deleted file mode 100644 index 00ec48254ddb535c7b151a23e90636ce891638af..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_ISPIF_H -#define MSM_ISPIF_H - -#include -#include -#include -#include -#include "msm_sd.h" - -/* Maximum number of voltage supply for ispif and vfe */ -#define ISPIF_VDD_INFO_MAX 2 -#define ISPIF_VFE_VDD_INFO_MAX 2 - -#define ISPIF_CLK_INFO_MAX 27 - -struct ispif_irq_status { - uint32_t ispifIrqStatus0; - uint32_t ispifIrqStatus1; - uint32_t ispifIrqStatus2; -}; - -enum msm_ispif_state_t { - ISPIF_POWER_UP, - ISPIF_POWER_DOWN, -}; -struct ispif_sof_count { - uint32_t sof_cnt[INTF_MAX]; -}; - -struct ispif_intf_cmd { - uint32_t intf_cmd; - uint32_t intf_cmd1; -}; - -struct ispif_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct resource *irq; - void __iomem *base; - void __iomem *clk_mux_base; - struct mutex mutex; - uint8_t start_ack_pending; - uint32_t csid_version; - int enb_dump_reg; - uint32_t open_cnt; - struct ispif_sof_count sof_count[VFE_MAX]; - struct ispif_intf_cmd applied_intf_cmd[VFE_MAX]; - uint8_t vc_enable[VFE_MAX][INTF_MAX][VC_MAX]; - enum msm_ispif_state_t ispif_state; - struct msm_ispif_vfe_info vfe_info; - struct clk **ahb_clk; - struct msm_cam_clk_info *ahb_clk_info; - struct clk **clks; - struct msm_cam_clk_info *clk_info; - struct completion reset_complete[VFE_MAX]; - atomic_t reset_trig[VFE_MAX]; - uint32_t hw_num_isps; - uint32_t num_ahb_clk; - uint32_t num_clk; - uint32_t clk_idx; - uint32_t ispif_sof_debug; - uint32_t ispif_rdi0_debug; - uint32_t ispif_rdi1_debug; - uint32_t ispif_rdi2_debug; - struct regulator *ispif_vdd[ISPIF_VDD_INFO_MAX]; - int ispif_vdd_count; - struct regulator *vfe_vdd[ISPIF_VFE_VDD_INFO_MAX]; - int vfe_vdd_count; -}; -#endif diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v1.h deleted file mode 100644 index f791e283a979ceb3aeea884611887198b9b8f067..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v1.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_ISPIF_HWREG_V1_H__ -#define __MSM_ISPIF_HWREG_V1_H__ - -/* common registers */ -#define ISPIF_RST_CMD_ADDR 0x0000 -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124 -#define PIX0_LINE_BUF_EN_BIT 0 - -#define ISPIF_VFE(m) (0x0) - -#define ISPIF_VFE_m_CTRL_0(m) (0x0008 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x0100 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x010C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x0118 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x0108 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x0114 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x0120 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x0104 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x0110 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x011C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INPUT_SEL(m) (0x000C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_0(m) (0x0004 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_1(m) (0x0030 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x0010 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + \ - ((n > 0) ? (0x20) : 0) \ - + 8*(n)) -#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x0290 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x001C + ISPIF_VFE(m) + \ - ((n > 0) ? (0x24) : 0) \ - + 0xc*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x0020 + ISPIF_VFE(m) + \ - ((n > 0) ? (0x24) : 0) \ - + 0xc*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x0024 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + \ - ((n > 0) ? (0x34) : 0) \ - + 8*(n)) - -/* Defines for compatibility with newer ISPIF versions */ -#define ISPIF_RST_CMD_1_ADDR (0x0000) -#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x0000 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x0000 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x0000 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x0000 + ISPIF_VFE(m)) - - - -/* CSID CLK MUX SEL REGISTERS */ -#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 - -/* ISPIF RESET BITS */ -#define VFE_CLK_DOMAIN_RST BIT(31) -#define RDI_CLK_DOMAIN_RST BIT(30) -#define PIX_CLK_DOMAIN_RST BIT(29) -#define AHB_CLK_DOMAIN_RST BIT(28) -#define RDI_1_CLK_DOMAIN_RST BIT(27) -#define PIX_1_CLK_DOMAIN_RST BIT(26) -#define RDI_2_CLK_DOMAIN_RST BIT(25) -#define RDI_2_MISR_RST_STB BIT(20) -#define RDI_2_VFE_RST_STB BIT(19) -#define RDI_2_CSID_RST_STB BIT(18) -#define RDI_1_MISR_RST_STB BIT(14) -#define RDI_1_VFE_RST_STB BIT(13) -#define RDI_1_CSID_RST_STB BIT(12) -#define PIX_1_VFE_RST_STB BIT(10) -#define PIX_1_CSID_RST_STB BIT(9) -#define RDI_0_MISR_RST_STB BIT(8) -#define RDI_0_VFE_RST_STB BIT(7) -#define RDI_0_CSID_RST_STB BIT(6) -#define PIX_0_MISR_RST_STB BIT(5) -#define PIX_0_VFE_RST_STB BIT(4) -#define PIX_0_CSID_RST_STB BIT(3) -#define SW_REG_RST_STB BIT(2) -#define MISC_LOGIC_RST_STB BIT(1) -#define STROBED_RST_EN BIT(0) - -#define ISPIF_RST_CMD_MASK 0xFE1C77FF -#define ISPIF_RST_CMD_1_MASK 0xFFFFFFFF /* undefined */ - -#define ISPIF_RST_CMD_MASK_RESTART 0x00001FF9 -#define ISPIF_RST_CMD_1_MASK_RESTART 0x00001FF9 /* undefined */ - -/* irq_mask_0 */ -#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) -#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) -#define RESET_DONE_IRQ BIT(27) -/* irq_mask_1 */ -#define PIX_INTF_1_OVERFLOW_IRQ BIT(12) -#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) -/* irq_mask_2 */ -#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) - -#define ISPIF_IRQ_STATUS_MASK 0x0A493249 -#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 -#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 - -#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x000249 -#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x000249 - -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001 - -#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA - -/* ISPIF RDI pack mode not supported */ -static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, - uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) -{ -} -#endif /* __MSM_ISPIF_HWREG_V1_H__ */ diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v2.h deleted file mode 100644 index c91feb341e1aa2c3a7c10c45d145bd447e958e73..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v2.h +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_ISPIF_HWREG_V2_H__ -#define __MSM_ISPIF_HWREG_V2_H__ - -/* common registers */ -#define ISPIF_RST_CMD_ADDR 0x008 -#define ISPIF_RST_CMD_1_ADDR 0x00C -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C -#define PIX0_LINE_BUF_EN_BIT 6 - -#define ISPIF_VFE(m) ((m) * 0x200) - -#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x278 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x288 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x28C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x290 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x298 + ISPIF_VFE(m) + 8*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x29C + ISPIF_VFE(m) + 8*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m)) - -/* CSID CLK MUX SEL REGISTERS */ -#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 - -/* ISPIF RESET BITS */ -#define VFE_CLK_DOMAIN_RST BIT(31) -#define PIX_1_CLK_DOMAIN_RST BIT(30) -#define PIX_CLK_DOMAIN_RST BIT(29) -#define RDI_2_CLK_DOMAIN_RST BIT(28) -#define RDI_1_CLK_DOMAIN_RST BIT(27) -#define RDI_CLK_DOMAIN_RST BIT(26) -#define AHB_CLK_DOMAIN_RST BIT(25) -#define RDI_2_VFE_RST_STB BIT(12) -#define RDI_2_CSID_RST_STB BIT(11) -#define RDI_1_VFE_RST_STB BIT(10) -#define RDI_1_CSID_RST_STB BIT(9) -#define RDI_0_VFE_RST_STB BIT(8) -#define RDI_0_CSID_RST_STB BIT(7) -#define PIX_1_VFE_RST_STB BIT(6) -#define PIX_1_CSID_RST_STB BIT(5) -#define PIX_0_VFE_RST_STB BIT(4) -#define PIX_0_CSID_RST_STB BIT(3) -#define SW_REG_RST_STB BIT(2) -#define MISC_LOGIC_RST_STB BIT(1) -#define STROBED_RST_EN BIT(0) - -#define ISPIF_RST_CMD_MASK 0xFE0F1FFF -#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9 - -#define ISPIF_RST_CMD_MASK_RESTART 0x00001FF9 -#define ISPIF_RST_CMD_1_MASK_RESTART 0x00001FF9 - -#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) -#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) -#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) -#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) -#define RESET_DONE_IRQ BIT(27) - -#define ISPIF_IRQ_STATUS_MASK 0x0A493249 -#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 -#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 - -#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249 -#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249 - -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1 - -#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA - -/* ISPIF RDI pack mode not supported */ -static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, - uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) -{ -} -#endif /* __MSM_ISPIF_HWREG_V2_H__ */ diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v3.h b/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v3.h deleted file mode 100644 index a15505f60878632e3dc7e62161c8de02d8eab74b..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif_hwreg_v3.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_ISPIF_HWREG_V3_H__ -#define __MSM_ISPIF_HWREG_V3_H__ - -/* common registers */ -#define ISPIF_RST_CMD_ADDR 0x008 -#define ISPIF_RST_CMD_1_ADDR 0x00C -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C -#define PIX0_LINE_BUF_EN_BIT 6 - -#define ISPIF_VFE(m) ((m) * 0x200) - -#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_CTRL_1(m) (0x204 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_PACK_0(m, n) (0x270 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_PACK_1(m, n) (0x27C + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x288 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x290 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x294 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x298 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x29C + ISPIF_VFE(m) + 8*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x2A0 + ISPIF_VFE(m) + 8*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m)) - -/* CSID CLK MUX SEL REGISTERS */ -#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 - -/* ISPIF RESET BITS */ -#define VFE_CLK_DOMAIN_RST BIT(31) -#define PIX_1_CLK_DOMAIN_RST BIT(30) -#define PIX_CLK_DOMAIN_RST BIT(29) -#define RDI_2_CLK_DOMAIN_RST BIT(28) -#define RDI_1_CLK_DOMAIN_RST BIT(27) -#define RDI_CLK_DOMAIN_RST BIT(26) -#define AHB_CLK_DOMAIN_RST BIT(25) -#define RDI_2_VFE_RST_STB BIT(12) -#define RDI_2_CSID_RST_STB BIT(11) -#define RDI_1_VFE_RST_STB BIT(10) -#define RDI_1_CSID_RST_STB BIT(9) -#define RDI_0_VFE_RST_STB BIT(8) -#define RDI_0_CSID_RST_STB BIT(7) -#define PIX_1_VFE_RST_STB BIT(6) -#define PIX_1_CSID_RST_STB BIT(5) -#define PIX_0_VFE_RST_STB BIT(4) -#define PIX_0_CSID_RST_STB BIT(3) -#define SW_REG_RST_STB BIT(2) -#define MISC_LOGIC_RST_STB BIT(1) -#define STROBED_RST_EN BIT(0) - -#define ISPIF_RST_CMD_MASK 0xFE7F1FFF -#define ISPIF_RST_CMD_1_MASK 0xFC7F1FF9 - -#define ISPIF_RST_CMD_MASK_RESTART 0x7F1FF9 -#define ISPIF_RST_CMD_1_MASK_RESTART 0x7F1FF9 - -#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) -#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) -#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) -#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) -#define RESET_DONE_IRQ BIT(27) - -#define ISPIF_IRQ_STATUS_MASK 0x0A493249 -#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 -#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 - -#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249 -#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249 - -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1 - -#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA - -/* ISPIF RDI pack mode support */ -static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, - uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) -{ - uint32_t pack_addr[2]; - - BUG_ON(!ispif); - - switch (intftype) { - case RDI0: - pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 0); - pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 0); - break; - case RDI1: - pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 1); - pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 1); - break; - case RDI2: - pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 2); - pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 2); - break; - default: - pr_debug("%s: pack_mode not supported on intftype=%d\n", - __func__, intftype); - return; - } - pr_debug("%s: intftype %d pack_mask %x: 0x%x, %x:0x%x\n", - __func__, intftype, pack_addr[0], - pack_cfg_mask[0], pack_addr[1], - pack_cfg_mask[1]); - msm_camera_io_w_mb(pack_cfg_mask[0], ispif->base + pack_addr[0]); - msm_camera_io_w_mb(pack_cfg_mask[1], ispif->base + pack_addr[1]); -} -#endif /* __MSM_ISPIF_HWREG_V3_H__ */ diff --git a/drivers/media/platform/msm/ais/jpeg_10/Makefile b/drivers/media/platform/msm/ais/jpeg_10/Makefile deleted file mode 100644 index fe2e00a8012baf6022b6857e6fa4787373b6eb1e..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) - -ccflags-y += -Idrivers/media/platform/msm/ais/jpeg_10 -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -ccflags-y += -Idrivers/media/platform/msm/ais/common - -obj-$(CONFIG_MSM_AIS_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_common.h b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_common.h deleted file mode 100644 index 9db73005e13c60210cae6ee304dbdb97b9442897..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_common.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_JPEG_COMMON_H -#define MSM_JPEG_COMMON_H - -#define JPEG_DBG(fmt, args...) pr_debug(fmt, ##args) - -#define JPEG_PR_ERR pr_err -#define JPEG_DBG_HIGH pr_debug - -#define JPEG_BUS_VOTED(pgmn_dev) (pgmn_dev->jpeg_bus_vote = 1) -#define JPEG_BUS_UNVOTED(pgmn_dev) (pgmn_dev->jpeg_bus_vote = 0) - -enum JPEG_MODE { - JPEG_MODE_DISABLE, - JPEG_MODE_OFFLINE, - JPEG_MODE_REALTIME, - JPEG_MODE_REALTIME_ROTATION -}; - -enum JPEG_ROTATION { - JPEG_ROTATION_0, - JPEG_ROTATION_90, - JPEG_ROTATION_180, - JPEG_ROTATION_270 -}; - -#endif /* MSM_JPEG_COMMON_H */ diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_core.c b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_core.c deleted file mode 100644 index 9e5394bdfe357b5d7b27b6200058c10301efbe57..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_core.c +++ /dev/null @@ -1,384 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include "msm_jpeg_hw.h" -#include "msm_jpeg_core.h" -#include "msm_jpeg_platform.h" -#include "msm_jpeg_common.h" - -int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, - void *base, int size) { - unsigned long flags; - int rc = 0; - int tm = 500; /*500ms*/ - - JPEG_DBG("%s:%d] reset", __func__, __LINE__); - memset(&pgmn_dev->fe_pingpong_buf, 0, - sizeof(pgmn_dev->fe_pingpong_buf)); - pgmn_dev->fe_pingpong_buf.is_fe = 1; - memset(&pgmn_dev->we_pingpong_buf, 0, - sizeof(pgmn_dev->we_pingpong_buf)); - spin_lock_irqsave(&pgmn_dev->reset_lock, flags); - pgmn_dev->reset_done_ack = 0; - if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) - msm_jpeg_hw_reset(base, size); - else - msm_jpeg_hw_reset_dma(base, size); - - spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); - rc = wait_event_timeout( - pgmn_dev->reset_wait, - pgmn_dev->reset_done_ack, - msecs_to_jiffies(tm)); - - if (!pgmn_dev->reset_done_ack) { - JPEG_DBG("%s: reset ACK failed %d", __func__, rc); - return -EBUSY; - } - - JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc); - spin_lock_irqsave(&pgmn_dev->reset_lock, flags); - pgmn_dev->reset_done_ack = 0; - pgmn_dev->state = MSM_JPEG_RESET; - spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); - - return 0; -} - -void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev) -{ - int i = 0; - - for (i = 0; i < 2; i++) { - if (pgmn_dev->we_pingpong_buf.buf_status[i] && - pgmn_dev->release_buf) - msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, - pgmn_dev->we_pingpong_buf.buf[i].ion_fd); - pgmn_dev->we_pingpong_buf.buf_status[i] = 0; - } -} - -void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev) -{ - init_waitqueue_head(&pgmn_dev->reset_wait); - spin_lock_init(&pgmn_dev->reset_lock); -} - -int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev) -{ - msm_jpeg_hw_fe_start(pgmn_dev->base); - return 0; -} - -/* fetch engine */ -int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf) -{ - int rc = 0; - - if (0 == buf->cbcr_len) - buf->cbcr_buffer_addr = 0x0; - - JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__, - (int) buf->y_buffer_addr, buf->y_len, - (int) buf->cbcr_buffer_addr, buf->cbcr_len); - - if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) { - rc = msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf, - buf, pgmn_dev->base); - if (rc < 0) - return rc; - msm_jpeg_hw_fe_mmu_prefetch(buf, pgmn_dev->base, - pgmn_dev->decode_flag); - } else { - rc = msm_jpegdma_hw_pingpong_update( - &pgmn_dev->fe_pingpong_buf, buf, pgmn_dev->base); - if (rc < 0) - return rc; - msm_jpegdma_hw_fe_mmu_prefetch(buf, pgmn_dev->base); - } - - return rc; -} - -void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf); -} - -/* write engine */ -int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf) { - - JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__, - (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr, - buf->y_len); - - pgmn_dev->we_pingpong_buf.buf[0] = *buf; - pgmn_dev->we_pingpong_buf.buf_status[0] = 1; - - if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) { - msm_jpeg_hw_we_buffer_update( - &pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base); - msm_jpeg_hw_we_mmu_prefetch(buf, pgmn_dev->base, - pgmn_dev->decode_flag); - } else { - msm_jpegdma_hw_we_buffer_update( - &pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base); - msm_jpegdma_hw_we_mmu_prefetch(buf, pgmn_dev->base); - } - - return 0; -} - -int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_hw_buf *buf) -{ - int i = 0; - - for (i = 0; i < 2; i++) { - if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr - == buf->y_buffer_addr) - pgmn_dev->we_pingpong_buf.buf_status[i] = 0; - } - return 0; -} - -void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - - return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf); -} - -void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - struct msm_jpeg_hw_buf *buf_p; - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - - buf_p = msm_jpeg_hw_pingpong_active_buffer( - &pgmn_dev->we_pingpong_buf); - if (buf_p && !pgmn_dev->decode_flag) { - buf_p->framedone_len = - msm_jpeg_hw_encode_output_size(pgmn_dev->base); - JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__, - buf_p->framedone_len); - } - - return buf_p; -} - -void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - /* @todo return the status back to msm_jpeg_core_reset */ - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - return NULL; -} - -void *msm_jpeg_core_err_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - JPEG_PR_ERR("%s: Error %x\n", __func__, jpeg_irq_status); - return NULL; -} - -static int (*msm_jpeg_irq_handler)(int, void *, void *); - -void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev, - int jpeg_irq_status) -{ - void *data = NULL; - - data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, - pgmn_dev, data); - data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE, - pgmn_dev, data); -} - -irqreturn_t msm_jpeg_core_irq(int irq_num, void *context) -{ - void *data = NULL; - unsigned long flags; - int jpeg_irq_status; - struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context; - - JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num); - - jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base); - - JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__, - jpeg_irq_status); - - /* For reset and framedone IRQs, clear all bits */ - if (pgmn_dev->state == MSM_JPEG_IDLE) { - JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", - __func__, __LINE__, pgmn_dev->state); - JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, - __LINE__); - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - return IRQ_HANDLED; - } else if (jpeg_irq_status & 0x10000000) { - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - } else if (jpeg_irq_status & 0x1) { - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - if (pgmn_dev->decode_flag) - msm_jpeg_decode_status(pgmn_dev->base); - } else { - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - jpeg_irq_status, pgmn_dev->base); - } - - if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) { - /* send fe ping pong irq */ - JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__); - data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, - context, data); - data = msm_jpeg_core_framedone_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler( - MSM_JPEG_HW_MASK_COMP_FRAMEDONE, - context, data); - pgmn_dev->state = MSM_JPEG_INIT; - } - if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) { - data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status, - pgmn_dev); - spin_lock_irqsave(&pgmn_dev->reset_lock, flags); - pgmn_dev->reset_done_ack = 1; - spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); - wake_up(&pgmn_dev->reset_wait); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler( - MSM_JPEG_HW_MASK_COMP_RESET_ACK, - context, data); - } - - /* Unexpected/unintended HW interrupt */ - if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) { - if (pgmn_dev->state != MSM_JPEG_EXECUTING) { - /* Clear all the bits and ignore the IRQ */ - JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", - __func__, __LINE__, pgmn_dev->state); - JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, - __LINE__); - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - return IRQ_HANDLED; - } - if (pgmn_dev->decode_flag) - msm_jpeg_decode_status(pgmn_dev->base); - msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status); - data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev); - if (msm_jpeg_irq_handler) { - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR, - context, data); - } - } - - return IRQ_HANDLED; -} - -irqreturn_t msm_jpegdma_core_irq(int irq_num, void *context) -{ - void *data = NULL; - unsigned long flags; - int jpeg_irq_status; - struct msm_jpeg_device *pgmn_dev = context; - - JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num); - - jpeg_irq_status = msm_jpegdma_hw_irq_get_status(pgmn_dev->base); - - JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__, - jpeg_irq_status); - - /* For reset and framedone IRQs, clear all bits */ - if (pgmn_dev->state == MSM_JPEG_IDLE) { - JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", - __func__, __LINE__, pgmn_dev->state); - JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, - __LINE__); - msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK, - JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base); - return IRQ_HANDLED; - } else if (jpeg_irq_status & 0x00000400) { - msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK, - JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base); - } else if (jpeg_irq_status & 0x1) { - msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK, - JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base); - } else { - msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK, - jpeg_irq_status, pgmn_dev->base); - } - - if (msm_jpegdma_hw_irq_is_frame_done(jpeg_irq_status)) { - /* send fe ping pong irq */ - JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__); - data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, - context, data); - data = msm_jpeg_core_framedone_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler( - MSM_JPEG_HW_MASK_COMP_FRAMEDONE, - context, data); - pgmn_dev->state = MSM_JPEG_INIT; - } - if (msm_jpegdma_hw_irq_is_reset_ack(jpeg_irq_status)) { - data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status, - pgmn_dev); - spin_lock_irqsave(&pgmn_dev->reset_lock, flags); - pgmn_dev->reset_done_ack = 1; - spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); - wake_up(&pgmn_dev->reset_wait); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler( - MSM_JPEG_HW_MASK_COMP_RESET_ACK, - context, data); - } - - return IRQ_HANDLED; -} - -void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)) -{ - msm_jpeg_irq_handler = irq_handler; -} - -void msm_jpeg_core_irq_remove(void) -{ - msm_jpeg_irq_handler = NULL; -} diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_core.h b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_core.h deleted file mode 100644 index 994c110e56b65c0b055561b81068c877c00d536a..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_core.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_JPEG_CORE_H -#define MSM_JPEG_CORE_H - -#include -#include "msm_jpeg_hw.h" -#include "msm_jpeg_sync.h" - -#define msm_jpeg_core_buf msm_jpeg_hw_buf - -irqreturn_t msm_jpeg_core_irq(int irq_num, void *context); -irqreturn_t msm_jpegdma_core_irq(int irq_num, void *context); -void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)); -void msm_jpeg_core_irq_remove(void); - -int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf); -int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf); -int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_hw_buf *buf); - -int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, - void *base, int size); -int msm_jpeg_core_fe_start(struct msm_jpeg_device *); - -void msm_jpeg_core_release(struct msm_jpeg_device *); -void msm_jpeg_core_init(struct msm_jpeg_device *); -#endif /* MSM_JPEG_CORE_H */ diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_dev.c deleted file mode 100644 index a0a6ffd0e69a48b23f5ef0edaae76546d3a92900..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_dev.c +++ /dev/null @@ -1,344 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_jpeg_sync.h" -#include "msm_jpeg_common.h" - -#define MSM_JPEG_NAME "jpeg" -#define DEV_NAME_LEN 10 - -static int msm_jpeg_open(struct inode *inode, struct file *filp) -{ - int rc = 0; - - struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev, - struct msm_jpeg_device, cdev); - filp->private_data = pgmn_dev; - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - - rc = __msm_jpeg_open(pgmn_dev); - - JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, - filp->f_path.dentry->d_name.name, pgmn_dev->open_count); - - return rc; -} - -static int msm_jpeg_release(struct inode *inode, struct file *filp) -{ - int rc; - - struct msm_jpeg_device *pgmn_dev = filp->private_data; - - JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__); - - rc = __msm_jpeg_release(pgmn_dev); - - JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, - filp->f_path.dentry->d_name.name, pgmn_dev->open_count); - return rc; -} -#ifdef CONFIG_COMPAT -static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = filp->private_data; - - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__, - __LINE__, _IOC_NR(cmd), pgmn_dev, - (unsigned long)arg); - - rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - return rc; -} -#endif -static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = filp->private_data; - - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__, - __LINE__, _IOC_NR(cmd), pgmn_dev, - (unsigned long)arg); - - rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - return rc; -} - -static const struct file_operations msm_jpeg_fops = { - .owner = THIS_MODULE, - .open = msm_jpeg_open, - .release = msm_jpeg_release, - .unlocked_ioctl = msm_jpeg_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = msm_jpeg_compat_ioctl, -#endif -}; - - -int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *)jpeg_sd->host_priv; - - JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%pK\n", - __func__, __LINE__, (unsigned long)jpeg_sd, - pgmn_dev); - rc = __msm_jpeg_open(pgmn_dev); - JPEG_DBG("%s:%d: rc=%d\n", - __func__, __LINE__, rc); - return rc; -} - -static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - long rc; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *)sd->host_priv; - - JPEG_DBG("%s: cmd=%d\n", __func__, cmd); - - JPEG_DBG("%s: pgmn_dev 0x%pK", __func__, pgmn_dev); - - JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__); - - rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg); - pr_debug("%s: X\n", __func__); - return rc; -} - -void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *)jpeg_sd->host_priv; - JPEG_DBG("%s:pgmn_dev=0x%pK", __func__, pgmn_dev); - rc = __msm_jpeg_release(pgmn_dev); - JPEG_DBG("%s:rc=%d", __func__, rc); -} - -static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = { - .ioctl = msm_jpeg_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = { - .core = &msm_jpeg_subdev_core_ops, -}; - -struct msm_jpeg_priv_data { - enum msm_jpeg_core_type core_type; -}; - -static const struct msm_jpeg_priv_data msm_jpeg_priv_data_jpg = { - .core_type = MSM_JPEG_CORE_CODEC -}; -static const struct msm_jpeg_priv_data msm_jpeg_priv_data_dma = { - .core_type = MSM_JPEG_CORE_DMA -}; - -static const struct of_device_id msm_jpeg_dt_match[] = { - {.compatible = "qcom,jpeg", .data = &msm_jpeg_priv_data_jpg}, - {.compatible = "qcom,jpeg_dma", .data = &msm_jpeg_priv_data_dma}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match); - -static int msm_jpeg_init_dev(struct platform_device *pdev) -{ - int rc = -1; - struct device *dev; - struct msm_jpeg_device *msm_jpeg_device_p; - const struct of_device_id *device_id; - const struct msm_jpeg_priv_data *priv_data; - char devname[DEV_NAME_LEN]; - - msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); - if (!msm_jpeg_device_p) { - JPEG_PR_ERR("%s: no mem\n", __func__); - return -EFAULT; - } - - msm_jpeg_device_p->pdev = pdev; - - device_id = of_match_device(msm_jpeg_dt_match, &pdev->dev); - if (!device_id) { - JPEG_PR_ERR("%s: device_id is NULL\n", __func__); - goto fail; - } - - priv_data = device_id->data; - msm_jpeg_device_p->core_type = priv_data->core_type; - - if (pdev->dev.of_node) - of_property_read_u32((&pdev->dev)->of_node, "cell-index", - &pdev->id); - - snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id); - - rc = __msm_jpeg_init(msm_jpeg_device_p); - if (rc < -1) { - JPEG_PR_ERR("%s: initialization failed\n", __func__); - goto fail; - } - - v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops); - v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p); - JPEG_DBG("%s: msm_jpeg_device_p 0x%lx", __func__, - (unsigned long)msm_jpeg_device_p); - - rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1, - devname); - if (rc < 0) { - JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__); - goto fail_1; - } - - if (!msm_jpeg_device_p->msm_jpeg_class) { - msm_jpeg_device_p->msm_jpeg_class = - class_create(THIS_MODULE, devname); - if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) { - rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class); - JPEG_PR_ERR("%s: create device class failed\n", - __func__); - goto fail_2; - } - } - - dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL, - MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno), - MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL, - "%s%d", MSM_JPEG_NAME, pdev->id); - if (IS_ERR(dev)) { - JPEG_PR_ERR("%s: error creating device\n", __func__); - rc = -ENODEV; - goto fail_3; - } - - cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops); - msm_jpeg_device_p->cdev.owner = THIS_MODULE; - msm_jpeg_device_p->cdev.ops = - (const struct file_operations *) &msm_jpeg_fops; - rc = cdev_add(&msm_jpeg_device_p->cdev, - msm_jpeg_device_p->msm_jpeg_devno, 1); - if (rc < 0) { - JPEG_PR_ERR("%s: error adding cdev\n", __func__); - rc = -ENODEV; - goto fail_4; - } - - platform_set_drvdata(pdev, &msm_jpeg_device_p); - - JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id); - - return rc; - -fail_4: - device_destroy(msm_jpeg_device_p->msm_jpeg_class, - msm_jpeg_device_p->msm_jpeg_devno); - -fail_3: - class_destroy(msm_jpeg_device_p->msm_jpeg_class); - -fail_2: - unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); - -fail_1: - __msm_jpeg_exit(msm_jpeg_device_p); - return rc; - -fail: - kfree(msm_jpeg_device_p); - return rc; - -} - -static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p) -{ - cdev_del(&msm_jpeg_device_p->cdev); - device_destroy(msm_jpeg_device_p->msm_jpeg_class, - msm_jpeg_device_p->msm_jpeg_devno); - class_destroy(msm_jpeg_device_p->msm_jpeg_class); - unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); - cam_smmu_destroy_handle(msm_jpeg_device_p->iommu_hdl); - - __msm_jpeg_exit(msm_jpeg_device_p); -} - -static int __msm_jpeg_probe(struct platform_device *pdev) -{ - return msm_jpeg_init_dev(pdev); -} - -static int __msm_jpeg_remove(struct platform_device *pdev) -{ - struct msm_jpeg_device *msm_jpegd_device_p; - - msm_jpegd_device_p = platform_get_drvdata(pdev); - if (msm_jpegd_device_p) - msm_jpeg_exit(msm_jpegd_device_p); - - return 0; -} - -static struct platform_driver msm_jpeg_driver = { - .probe = __msm_jpeg_probe, - .remove = __msm_jpeg_remove, - .driver = { - .name = "msm_jpeg", - .owner = THIS_MODULE, - .of_match_table = msm_jpeg_dt_match, - }, -}; - -static int __init msm_jpeg_driver_init(void) -{ - int rc; - - rc = platform_driver_register(&msm_jpeg_driver); - return rc; -} - -static void __exit msm_jpeg_driver_exit(void) -{ - platform_driver_unregister(&msm_jpeg_driver); -} - -MODULE_DESCRIPTION("msm jpeg jpeg driver"); - -module_init(msm_jpeg_driver_init); -module_exit(msm_jpeg_driver_exit); diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw.c deleted file mode 100644 index 0b6cf168e468c81fddfde97a80151ddbff286563..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw.c +++ /dev/null @@ -1,928 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include "msm_jpeg_hw.h" -#include "msm_jpeg_common.h" -#include "msm_camera_io_util.h" - -#include - -int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, - struct msm_jpeg_hw_buf *buf, void *base) -{ - int buf_free_index = -1; - - if (!pingpong_hw->buf_status[0]) { - buf_free_index = 0; - } else if (!pingpong_hw->buf_status[1]) { - buf_free_index = 1; - } else { - JPEG_PR_ERR("%s:%d: pingpong buffer busy\n", - __func__, __LINE__); - return -EBUSY; - } - - pingpong_hw->buf[buf_free_index] = *buf; - pingpong_hw->buf_status[buf_free_index] = 1; - - if (pingpong_hw->is_fe) { - /* it is fe */ - msm_jpeg_hw_fe_buffer_update( - &pingpong_hw->buf[buf_free_index], buf_free_index, - base); - } else { - /* it is we */ - msm_jpeg_hw_we_buffer_update( - &pingpong_hw->buf[buf_free_index], buf_free_index, - base); - } - return 0; -} - -int msm_jpegdma_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, - struct msm_jpeg_hw_buf *buf, void *base) -{ - int buf_free_index = -1; - - if (!pingpong_hw->buf_status[0]) { - buf_free_index = 0; - } else if (!pingpong_hw->buf_status[1]) { - buf_free_index = 1; - } else { - JPEG_PR_ERR("%s:%d: pingpong buffer busy\n", - __func__, __LINE__); - return -EBUSY; - } - - pingpong_hw->buf[buf_free_index] = *buf; - pingpong_hw->buf_status[buf_free_index] = 1; - - if (pingpong_hw->is_fe) { - /* it is fe */ - msm_jpegdma_hw_fe_buffer_update( - &pingpong_hw->buf[buf_free_index], buf_free_index, - base); - } else { - /* it is we */ - msm_jpegdma_hw_we_buffer_update( - &pingpong_hw->buf[buf_free_index], buf_free_index, - base); - } - return 0; -} -void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw) -{ - struct msm_jpeg_hw_buf *buf_p = NULL; - - if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) { - buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; - pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0; - } - - pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index; - - return (void *) buf_p; -} - -void *msm_jpeg_hw_pingpong_active_buffer( - struct msm_jpeg_hw_pingpong *pingpong_hw) -{ - struct msm_jpeg_hw_buf *buf_p = NULL; - - if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) - buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; - - return (void *) buf_p; -} - -struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR, - JPEG_IRQ_STATUS_BMSK, {0} }, -}; - -int msm_jpeg_hw_irq_get_status(void *base) -{ - uint32_t n_irq_status = 0; - - n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base); - return n_irq_status; -} - -struct msm_jpeg_hw_cmd hw_cmd_irq_get_dmastatus[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEGDMA_IRQ_STATUS_ADDR, - JPEGDMA_IRQ_STATUS_BMSK, {0} }, -}; - -int msm_jpegdma_hw_irq_get_status(void *base) -{ - uint32_t n_irq_status = 0; - - n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_dmastatus[0], base); - return n_irq_status; -} - -struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_READ, 1, - JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR, - JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } , -}; - -long msm_jpeg_hw_encode_output_size(void *base) -{ - uint32_t encode_output_size = 0; - - encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0], - base); - - return encode_output_size; -} - -void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base) -{ - struct msm_jpeg_hw_cmd cmd_irq_clear; - - cmd_irq_clear.type = MSM_JPEG_HW_CMD_TYPE_WRITE; - cmd_irq_clear.n = 1; - cmd_irq_clear.offset = JPEG_IRQ_CLEAR_ADDR; - cmd_irq_clear.mask = mask; - cmd_irq_clear.data = data; - JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data); - msm_jpeg_hw_write(&cmd_irq_clear, base); -} - -void msm_jpegdma_hw_irq_clear(uint32_t mask, uint32_t data, void *base) -{ - struct msm_jpeg_hw_cmd cmd_irq_clear; - - cmd_irq_clear.type = MSM_JPEG_HW_CMD_TYPE_WRITE; - cmd_irq_clear.n = 1; - cmd_irq_clear.offset = JPEGDMA_IRQ_CLEAR_ADDR; - cmd_irq_clear.mask = mask; - cmd_irq_clear.data = data; - JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data); - msm_jpeg_hw_write(&cmd_irq_clear, base); -} - -struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, - JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR, - JPEG_PLN0_RD_OFFSET_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR, - JPEG_PLN0_RD_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR, - JPEG_PLN1_RD_OFFSET_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR, - JPEG_PLN1_RD_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_OFFSET_ADDR, - JPEG_PLN1_RD_OFFSET_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_PNTR_ADDR, - JPEG_PLN2_RD_PNTR_BMSK, {0} }, -}; - -void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - if (pingpong_index == 0) { - hw_cmd_p = &hw_cmd_fe_ping_update[0]; - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->y_buffer_addr; - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->cbcr_buffer_addr; - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->pln2_addr; - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); - } -} - -struct msm_jpeg_hw_cmd hw_dma_cmd_fe_ping_update[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR, - JPEGDMA_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_CMD_ADDR, - JPEGDMA_CMD_BMSK, {JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_FE_0_RD_PNTR, - JPEG_PLN0_RD_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_FE_1_RD_PNTR, - JPEG_PLN1_RD_PNTR_BMSK, {0} }, -}; - -void msm_jpegdma_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - if (pingpong_index != 0) - return; - - hw_cmd_p = &hw_dma_cmd_fe_ping_update[0]; - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->y_buffer_addr; - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->cbcr_buffer_addr; - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); -} - -struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, - JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} }, -}; - -void msm_jpeg_hw_fe_start(void *base) -{ - msm_jpeg_hw_write(&hw_cmd_fe_start[0], base); -} - -struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, -}; - -void msm_jpeg_decode_status(void *base) -{ - uint32_t data; - - data = msm_camera_io_r(base + JPEG_DECODE_MCUS_DECODED_STATUS); - JPEG_DBG_HIGH("Decode MCUs decode status %u", data); - data = msm_camera_io_r(base + JPEG_DECODE_BITS_CONSUMED_STATUS); - JPEG_DBG_HIGH("Decode bits consumed status %u", data); - data = msm_camera_io_r(base + JPEG_DECODE_PRED_Y_STATE); - JPEG_DBG_HIGH("Decode prediction Y state %u", data); - data = msm_camera_io_r(base + JPEG_DECODE_PRED_C_STATE); - JPEG_DBG_HIGH("Decode prediction C state %u", data); - data = msm_camera_io_r(base + JPEG_DECODE_RSM_STATE); - JPEG_DBG_HIGH("Decode prediction RSM state %u", data); -} - - -void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - if (pingpong_index == 0) { - hw_cmd_p = &hw_cmd_we_ping_update[0]; - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->y_buffer_addr; - JPEG_DBG_HIGH("%s Output pln0 buffer address is %x\n", __func__, - p_input->y_buffer_addr); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->cbcr_buffer_addr; - JPEG_DBG_HIGH("%s Output pln1 buffer address is %x\n", __func__, - p_input->cbcr_buffer_addr); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->pln2_addr; - JPEG_DBG_HIGH("%s Output pln2 buffer address is %x\n", __func__, - p_input->pln2_addr); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - } -} - -struct msm_jpeg_hw_cmd hw_dma_cmd_we_ping_update[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_CMD_ADDR, - JPEGDMA_CMD_BMSK, {JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_WE_0_WR_PNTR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_WE_1_WR_PNTR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, -}; -void msm_jpegdma_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - if (pingpong_index != 0) - return; - - hw_cmd_p = &hw_dma_cmd_we_ping_update[0]; - msm_jpeg_hw_write(hw_cmd_p++, base); - - /* ensure write is done */ - wmb(); - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->y_buffer_addr; - JPEG_DBG_HIGH("%s Output we 0 buffer address is %x\n", __func__, - p_input->y_buffer_addr); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = p_input->cbcr_buffer_addr; - JPEG_DBG_HIGH("%s Output we 1 buffer address is %x\n", __func__, - p_input->cbcr_buffer_addr); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); -} - -struct msm_jpeg_hw_cmd hw_cmd_fe_mmu_prefetch[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S0_MMU_PF_ADDR_MIN, - MSM_JPEG_S0_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S0_MMU_PF_ADDR_MAX, - MSM_JPEG_S0_MMU_PF_ADDR_MAX_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MIN, - MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MAX, - MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MIN, - MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MAX, - MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK, {0} }, -}; - -/* - * msm_jpeg_hw_fe_mmu_prefetch() - writes fe min/max addrs for each plane to - * MMU prefetch registers. - * @buf: Pointer to jpeg hw buffer. - * @base: Pointer to base address. - * @decode_flag: Jpeg decode flag. - * - * This function writes fe min/max address for each plane to MMU prefetch - * registers, MMU prefetch hardware will only prefetch address translations - * within this min/max boundary. - * - * Return: None. - */ -void msm_jpeg_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base, - uint8_t decode_flag) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - hw_cmd_p = &hw_cmd_fe_mmu_prefetch[0]; - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - - JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n", - __func__, __LINE__, tmp_hw_cmd.data); - - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - if (buf->y_len) - tmp_hw_cmd.data += buf->y_len - 1; - - JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n", - __func__, __LINE__, tmp_hw_cmd.data, buf->y_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - if (!decode_flag) { - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->cbcr_buffer_addr; - - JPEG_DBG("%s:%d: MIN cbcr_buf_addr %08x\n", - __func__, __LINE__, tmp_hw_cmd.data); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->cbcr_buffer_addr; - if (buf->cbcr_len) - tmp_hw_cmd.data += buf->cbcr_len - 1; - - JPEG_DBG("%s:%d: MAX cbcr_buf_addr %08x, cbcr_len %d\n" - , __func__, __LINE__, tmp_hw_cmd.data, buf->cbcr_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->pln2_addr; - - JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x\n", - __func__, __LINE__, tmp_hw_cmd.data); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->pln2_addr; - if (buf->pln2_len) - tmp_hw_cmd.data += buf->pln2_len - 1; - - JPEG_DBG("%s:%d: MAX pln2_buf_addr %08x, pln2_len %d\n" - , __func__, __LINE__, tmp_hw_cmd.data, buf->pln2_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - } - /* ensure write is done */ - wmb(); -} - -struct msm_jpeg_hw_cmd hw_cmd_we_mmu_prefetch[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MIN, - MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MAX, - MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MIN, - MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MAX, - MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S3_MMU_PF_ADDR_MIN, - MSM_JPEG_S3_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S3_MMU_PF_ADDR_MAX, - MSM_JPEG_S3_MMU_PF_ADDR_MAX_BMSK, {0} }, -}; - -/* - * msm_jpeg_hw_we_mmu_prefetch() - write we min/max addrs for each plane to - * MMU prefetch registers. - * @buf: Pointer to jpeg hw buffer. - * @base: Pointer to base address. - * @decode_flag: Jpeg decode flag. - * - * This function writes we min/max address for each plane to MMU prefetch - * registers, MMU prefetch hardware will only prefetch address translations - * within this min/max boundary. - * - * Return: None. - */ -void msm_jpeg_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base, - uint8_t decode_flag) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - hw_cmd_p = &hw_cmd_we_mmu_prefetch[0]; - - /* ensure write is done */ - wmb(); - if (decode_flag) { - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - - JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n", - __func__, __LINE__, tmp_hw_cmd.data); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - if (buf->y_len) - tmp_hw_cmd.data += buf->y_len - 1; - - JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n", - __func__, __LINE__, tmp_hw_cmd.data, buf->y_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->cbcr_buffer_addr; - - JPEG_DBG("%s:%d: MIN cbcr_buf_addr %08x\n", - __func__, __LINE__, tmp_hw_cmd.data); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->cbcr_buffer_addr; - if (buf->cbcr_len) - tmp_hw_cmd.data += buf->cbcr_len - 1; - - JPEG_DBG("%s:%d: MAX cbcr_buf_addr %08x, cbcr_len %d\n" - , __func__, __LINE__, tmp_hw_cmd.data, buf->cbcr_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->pln2_addr; - - JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x\n", - __func__, __LINE__, tmp_hw_cmd.data); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->pln2_addr; - if (buf->pln2_len) - tmp_hw_cmd.data += buf->pln2_len - 1; - - JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x, pln2_len %d\n" - , __func__, __LINE__, tmp_hw_cmd.data, buf->pln2_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - } else { - hw_cmd_p += 4; - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - - JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n", - __func__, __LINE__, tmp_hw_cmd.data); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - if (buf->y_len) - tmp_hw_cmd.data += buf->y_len - 1; - - JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n", - __func__, __LINE__, tmp_hw_cmd.data, buf->y_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - } - /* ensure write is done */ - wmb(); -} - -struct msm_jpeg_hw_cmd hw_dma_cmd_fe_mmu_prefetch[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN, - MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX, - MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX_BMSK, {0} }, -}; - -/* - * msm_jpegdma_hw_fe_mmu_prefetch() - write DMA fe min/max addrs to - * MMU prefetch registers. - * @buf: Pointer to jpeg hw buffer. - * @base: Pointer to base address. - * - * This function writes DMA fe min/max address for each plane to MMU prefetch - * registers, MMU prefetch hardware will only prefetch address translations - * with in this min/max boundary. - * - * Return: None. - */ -void msm_jpegdma_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - hw_cmd_p = &hw_dma_cmd_fe_mmu_prefetch[0]; - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - - JPEG_DBG("%s:%d: MIN DMA addr %08x , reg offset %08x\n", - __func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset); - - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - if (buf->y_len) - tmp_hw_cmd.data += buf->y_len - 1; - - JPEG_DBG("%s:%d: MAX DMA addr %08x , reg offset %08x , length %d\n", - __func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset, - buf->y_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); -} - -struct msm_jpeg_hw_cmd hw_dma_cmd_we_mmu_prefetch[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN, - MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX, - MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX_BMSK, {0} }, -}; - -/* - * msm_jpegdma_hw_we_mmu_prefetch() - write DMA we min/max addrs to - * MMU prefetch registers. - * @buf: Pointer to jpeg hw buffer. - * @base: Pointer to base address. - * - * This function writes DMA we min/max address for each plane to MMU prefetch - * registers, MMU prefetch hardware will only prefetch address translations - * with in this min/max boundary. - * - * Return: None. - */ -void msm_jpegdma_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - struct msm_jpeg_hw_cmd tmp_hw_cmd; - - hw_cmd_p = &hw_dma_cmd_we_mmu_prefetch[0]; - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - - JPEG_DBG("%s:%d: MIN DMA addr %08x , reg offset %08x\n", - __func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset); - - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(&tmp_hw_cmd, base); - - tmp_hw_cmd = *hw_cmd_p++; - tmp_hw_cmd.data = buf->y_buffer_addr; - if (buf->y_len) - tmp_hw_cmd.data += buf->y_len - 1; - - JPEG_DBG("%s:%d: MAX DMA addr %08x , reg offset %08x , length %d\n", - __func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset, - buf->y_len); - - msm_jpeg_hw_write(&tmp_hw_cmd, base); - /* ensure write is done */ - wmb(); -} - -struct msm_jpeg_hw_cmd hw_cmd_reset[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR, - JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} }, -}; - -void msm_jpeg_hw_reset(void *base, int size) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - - hw_cmd_p = &hw_cmd_reset[0]; - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p, base); - /* ensure write is done */ - wmb(); -} -struct msm_jpeg_hw_cmd hw_cmd_reset_dma[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR, - JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_DISABLE_ALL} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_CLEAR_ADDR, - JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_CLEAR_ALL} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR, - JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_ALLSOURCES_ENABLE} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_RESET_CMD_ADDR, - JPEGDMA_RESET_CMD_BMSK, {JPEGDMA_RESET_DEFAULT} }, -}; - -void msm_jpeg_hw_reset_dma(void *base, int size) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - - hw_cmd_p = &hw_cmd_reset_dma[0]; - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - /* ensure write is done */ - wmb(); - msm_jpeg_hw_write(hw_cmd_p, base); - /* ensure write is done */ - wmb(); -} - -uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p, - void *jpeg_region_base) -{ - uint32_t *paddr; - uint32_t data; - - paddr = jpeg_region_base + hw_cmd_p->offset; - - data = msm_camera_io_r(paddr); - data &= hw_cmd_p->mask; - - return data; -} - -void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p, - void *jpeg_region_base) -{ - uint32_t *paddr; - uint32_t old_data, new_data; - - paddr = jpeg_region_base + hw_cmd_p->offset; - - if (hw_cmd_p->mask == 0xffffffff) { - old_data = 0; - } else { - old_data = msm_camera_io_r(paddr); - old_data &= ~hw_cmd_p->mask; - } - - new_data = hw_cmd_p->data & hw_cmd_p->mask; - new_data |= old_data; - JPEG_DBG("%s:%d] %pK %08x\n", __func__, __LINE__, - paddr, new_data); - msm_camera_io_w(new_data, paddr); -} - -int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us, - void *base) -{ - int tm = hw_cmd_p->n; - uint32_t data; - uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask; - - data = msm_jpeg_hw_read(hw_cmd_p, base); - if (data != wait_data) { - while (tm) { - udelay(m_us); - data = msm_jpeg_hw_read(hw_cmd_p, base); - if (data == wait_data) - break; - tm--; - } - } - hw_cmd_p->data = data; - return tm; -} - -void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us) -{ - int tm = hw_cmd_p->n; - - while (tm) { - udelay(m_us); - tm--; - } -} - -int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, - uint32_t max_size, void *base) -{ - int is_copy_to_user = 0; - uint32_t data; - - while (m_cmds--) { - if (hw_cmd_p->offset >= max_size) { - JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, - __LINE__, hw_cmd_p->offset, max_size); - return -EFAULT; - } - if (hw_cmd_p->offset & 0x3) { - JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__, - __LINE__, hw_cmd_p->offset); - return -EFAULT; - } - - switch (hw_cmd_p->type) { - case MSM_JPEG_HW_CMD_TYPE_READ: - hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base); - is_copy_to_user = 1; - break; - - case MSM_JPEG_HW_CMD_TYPE_WRITE: - msm_jpeg_hw_write(hw_cmd_p, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_WRITE_OR: - data = msm_jpeg_hw_read(hw_cmd_p, base); - hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) | - data; - msm_jpeg_hw_write(hw_cmd_p, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_UWAIT: - msm_jpeg_hw_wait(hw_cmd_p, 1, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_MWAIT: - msm_jpeg_hw_wait(hw_cmd_p, 1000, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_UDELAY: - msm_jpeg_hw_delay(hw_cmd_p, 1); - break; - - case MSM_JPEG_HW_CMD_TYPE_MDELAY: - msm_jpeg_hw_delay(hw_cmd_p, 1000); - break; - - default: - JPEG_PR_ERR("wrong hw command type\n"); - break; - } - - hw_cmd_p++; - } - return is_copy_to_user; -} - -void msm_jpeg_io_dump(void *base, int size) -{ - char line_str[128], *p_str; - void __iomem *addr = (void __iomem *)base; - int i; - u32 *p = (u32 *) addr; - u32 data; - - JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size); - line_str[0] = '\0'; - p_str = line_str; - for (i = 0; i < size/4; i++) { - if (i % 4 == 0) { - snprintf(p_str, 12, "%08lx: ", (unsigned long)p); - p_str += 10; - } - data = msm_camera_io_r(p++); - snprintf(p_str, 12, "%08x ", data); - p_str += 9; - if ((i + 1) % 4 == 0) { - JPEG_DBG_HIGH("%s\n", line_str); - line_str[0] = '\0'; - p_str = line_str; - } - } - if (line_str[0] != '\0') - JPEG_DBG_HIGH("%s\n", line_str); -} - diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw.h deleted file mode 100644 index 43ced6389746c2286fc8c7ddb4fc06d382659891..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw.h +++ /dev/null @@ -1,142 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_JPEG_HW_H -#define MSM_JPEG_HW_H - -#include -#include "msm_jpeg_hw_reg.h" -#include - -struct msm_jpeg_hw_buf { - struct msm_jpeg_buf vbuf; - struct file *file; - uint32_t framedone_len; - uint32_t y_buffer_addr; - uint32_t y_len; - uint32_t cbcr_buffer_addr; - uint32_t cbcr_len; - uint32_t num_of_mcu_rows; - int ion_fd; - uint32_t pln2_addr; - uint32_t pln2_len; -}; - -struct msm_jpeg_hw_pingpong { - uint8_t is_fe; /* 1: fe; 0: we */ - struct msm_jpeg_hw_buf buf[2]; - int buf_status[2]; - int buf_active_index; -}; - -int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, - struct msm_jpeg_hw_buf *buf, void *); -int msm_jpegdma_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, - struct msm_jpeg_hw_buf *buf, void *); -void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw); -void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong - *pingpong_hw); - -void msm_jpeg_hw_irq_clear(uint32_t, uint32_t, void *); -void msm_jpegdma_hw_irq_clear(uint32_t, uint32_t, void *); -int msm_jpeg_hw_irq_get_status(void *); -int msm_jpegdma_hw_irq_get_status(void *); -long msm_jpeg_hw_encode_output_size(void *); -#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \ - MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK -#define MSM_JPEG_HW_MASK_COMP_FE \ - MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK -#define MSM_JPEG_HW_MASK_COMP_WE \ - (MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \ - MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK) -#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \ - MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK -#define MSM_JPEG_HW_MASK_COMP_ERR \ - (MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \ - MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK) - -#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE) -#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE) -#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE) -#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK) -#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR) - - -#define MSM_JPEGDMA_HW_MASK_COMP_FRAMEDONE \ - MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_MASK -#define MSM_JPEGDMA_HW_MASK_COMP_FE \ - MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_MASK -#define MSM_JPEGDMA_HW_MASK_COMP_WE \ - (MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_MASK) -#define MSM_JPEGDMA_HW_MASK_COMP_RESET_ACK \ - MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_MASK - - -#define msm_jpegdma_hw_irq_is_frame_done(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_FRAMEDONE) -#define msm_jpegdma_hw_irq_is_fe_pingpong(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_FE) -#define msm_jpegdma_hw_irq_is_we_pingpong(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_WE) -#define msm_jpegdma_hw_irq_is_reset_ack(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_RESET_ACK) - - -void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *); -void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *); -void msm_jpegdma_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *); -void msm_jpegdma_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *); - - -void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime); - -void msm_jpeg_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *, - uint8_t decode_flag); -void msm_jpeg_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *, - uint8_t decode_flag); -void msm_jpegdma_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *); -void msm_jpegdma_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *); - -void msm_jpeg_hw_fe_start(void *); -void msm_jpeg_hw_clk_cfg(void); - -void msm_jpeg_hw_reset(void *base, int size); -void msm_jpeg_hw_irq_cfg(void); - -uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *, void *); -void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *); -int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *); -void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int); -int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t , - uint32_t , void *); -void msm_jpeg_hw_region_dump(int size); -void msm_jpeg_io_dump(void *base, int size); -void msm_jpeg_decode_status(void *base); -void msm_jpeg_hw_reset_dma(void *base, int size); - -#endif /* MSM_JPEG_HW_H */ diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw_reg.h deleted file mode 100644 index 68510b52c2fec0ae3f76409eb4363fd69c8e48b7..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_hw_reg.h +++ /dev/null @@ -1,210 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_JPEG_HW_REG_H -#define MSM_JPEG_HW_REG_H - -#define JPEG_REG_BASE 0 - -#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018 -#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF -#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF - -#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 -#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 - -#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010 -#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001 - -#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004 -#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002 - -#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008 -#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003 - -#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010 -#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004 - -#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020 -#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005 - -#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000 -#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a - -#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800 -#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b - -#define MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26) -#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29) - -#define JPEG_OFFLINE_CMD_START 0x00000001 - -#define JPEG_RESET_DEFAULT 0x00032093 - -#define JPEG_IRQ_DISABLE_ALL 0x00000000 -#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF - -#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038) -#define JPEG_PLN0_RD_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C -#define JPEG_PLN0_RD_OFFSET_BMSK 0xFFFFFFFF - -#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044) -#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048 -#define JPEG_PLN1_RD_OFFSET_BMSK 0xFFFFFFFF - -#define JPEG_PLN2_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000050) -#define JPEG_PLN2_RD_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN2_RD_OFFSET_ADDR 0x00000054 -#define JPEG_PLN2_RD_OFFSET_BMSK 0xFFFFFFFF - -#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010) -#define JPEG_CMD_BMSK 0xFFFFFFFF -#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700 - -#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc) -#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0) -#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4) -#define JPEG_PLN2_WR_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018) -#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF -#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF - -#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c) -#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF - -#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008) -#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF - -#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020) -#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S0_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000310) -#define MSM_JPEG_S0_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S0_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000314) -#define MSM_JPEG_S0_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S1_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x0000031C) -#define MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S1_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000320) -#define MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S2_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000328) -#define MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S2_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x0000032C) -#define MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S3_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000334) -#define MSM_JPEG_S3_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF - -#define MSM_JPEG_S3_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000338) -#define MSM_JPEG_S3_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF - -#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180) -#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF - -#define JPEG_DECODE_MCUS_DECODED_STATUS (JPEG_REG_BASE + 0x00000258) -#define JPEG_DECODE_BITS_CONSUMED_STATUS (JPEG_REG_BASE + 0x0000025C) -#define JPEG_DECODE_PRED_Y_STATE (JPEG_REG_BASE + 0x00000260) -#define JPEG_DECODE_PRED_C_STATE (JPEG_REG_BASE + 0x00000264) -#define JPEG_DECODE_RSM_STATE (JPEG_REG_BASE + 0x00000268) - -#define JPEG_HW_VERSION (JPEG_REG_BASE + 0x00000000) - -#define VBIF_BASE_ADDRESS 0xFDA60000 -#define VBIF_REGION_SIZE 0xC30 -#define JPEG_VBIF_CLKON 0x4 -#define JPEG_VBIF_IN_RD_LIM_CONF0 0xB0 -#define JPEG_VBIF_IN_RD_LIM_CONF1 0xB4 -#define JPEG_VBIF_IN_RD_LIM_CONF2 0xB8 -#define JPEG_VBIF_IN_WR_LIM_CONF0 0xC0 -#define JPEG_VBIF_IN_WR_LIM_CONF1 0xC4 -#define JPEG_VBIF_IN_WR_LIM_CONF2 0xC8 -#define JPEG_VBIF_OUT_RD_LIM_CONF0 0xD0 -#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4 -#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8 -#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC -#define JPEG_VBIF_ARB_CTL 0xF0 -#define JPEG_VBIF_OUT_AXI_AOOO_EN 0x178 -#define JPEG_VBIF_OUT_AXI_AOOO 0x17c -#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB 0x124 -#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 -#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 - -#define JPEGDMA_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x0000000C) -#define JPEGDMA_IRQ_MASK_BMSK 0xFFFFFFFF -#define JPEGDMA_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF - -#define JPEGDMA_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x00000014) -#define JPEGDMA_IRQ_CLEAR_BMSK 0xFFFFFFFF - -#define JPEGDMA_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008) -#define JPEGDMA_RESET_CMD_BMSK 0xFFFFFFFF - -#define JPEGDMA_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000010) -#define JPEGDMA_IRQ_STATUS_BMSK 0xFFFFFFFF -#define JPEGDMA_RESET_DEFAULT 0x00032083 - - -#define JPEGDMA_CMD_ADDR (JPEG_REG_BASE + 0x0000001C) -#define JPEGDMA_CMD_BMSK (0xFFFFFFFF) -#define JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES 0x030 -#define JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES 0x300 - -#define JPEGDMA_IRQ_DISABLE_ALL 0x00000000 -#define JPEGDMA_IRQ_CLEAR_ALL 0x00001FFF -#define MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 -#define MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 -#define MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000006 -#define MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001 -#define MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_MASK 0x00000060 -#define MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_SHIFT 0x00000005 -#define MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_MASK 0x00000400 -#define MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a - -#define MSM_JPEGDMA_FE_0_RD_PNTR (JPEG_REG_BASE + 0x00000034) -#define MSM_JPEGDMA_FE_1_RD_PNTR (JPEG_REG_BASE + 0x00000078) -#define MSM_JPEGDMA_WE_0_WR_PNTR (JPEG_REG_BASE + 0x000000BC) -#define MSM_JPEGDMA_WE_1_WR_PNTR (JPEG_REG_BASE + 0x000000EC) - -#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000190) -#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF - -#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000198) -#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF - -#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x000001A4) -#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF - -#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x000001AC) -#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF - -#endif /* MSM_JPEG_HW_REG_H */ diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_platform.c deleted file mode 100644 index 1e741680f162c87d746334436cc5789922dfed4e..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_platform.c +++ /dev/null @@ -1,513 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_camera_io_util.h" -#include "msm_jpeg_platform.h" -#include "msm_jpeg_sync.h" -#include "msm_jpeg_common.h" -#include "msm_jpeg_hw.h" - -#define JPEG_DT_PROP_CNT 2 - - -int msm_jpeg_get_clock_index(struct msm_jpeg_device *pgmn_dev, - const char *clk_name) -{ - uint32_t i = 0; - - for (i = 0; i < pgmn_dev->num_clk; i++) { - if (!strcmp(clk_name, pgmn_dev->jpeg_clk_info[i].clk_name)) - return i; - } - return -EINVAL; -} - -int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, - long clk_rate) -{ - int rc = 0; - uint32_t msm_jpeg_idx; - - /* retrieve clock index from list of clocks */ - msm_jpeg_idx = msm_jpeg_get_clock_index(pgmn_dev, - "core_clk"); - if (msm_jpeg_idx < 0) { - JPEG_PR_ERR("%s:Fail to get clock index\n", __func__); - return -EINVAL; - } - - /* set the rate */ - msm_camera_clk_set_rate(&pgmn_dev->pdev->dev, - pgmn_dev->jpeg_clk[msm_jpeg_idx], clk_rate); - - return rc; -} - -void msm_jpeg_platform_p2v(int iommu_hdl, int fd) -{ - cam_smmu_put_phy_addr(iommu_hdl, fd); -} - -uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, - uint32_t len, int iommu_hdl) -{ - dma_addr_t paddr; - size_t size; - int rc; - - rc = cam_smmu_get_phy_addr(pgmn_dev->iommu_hdl, fd, CAM_SMMU_MAP_RW, - &paddr, &size); - JPEG_DBG("%s:%d] addr 0x%x size %zu", __func__, __LINE__, - (uint32_t)paddr, size); - - if (rc < 0) { - JPEG_PR_ERR("%s: fd %d got phy addr error %d\n", __func__, fd, - rc); - goto err_get_phy; - } - - /* validate user input */ - if (len > size) { - JPEG_PR_ERR("%s: invalid offset + len\n", __func__); - goto err_size; - } - - return paddr; -err_size: - cam_smmu_put_phy_addr(pgmn_dev->iommu_hdl, fd); -err_get_phy: - return 0; -} - -static void set_vbif_params(struct msm_jpeg_device *pgmn_dev, - void *jpeg_vbif_base) -{ - msm_camera_io_w(0x1, - jpeg_vbif_base + JPEG_VBIF_CLKON); - - if (pgmn_dev->hw_version != JPEG_8994) { - msm_camera_io_w(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF0); - msm_camera_io_w(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF1); - msm_camera_io_w(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF2); - msm_camera_io_w(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF0); - msm_camera_io_w(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF1); - msm_camera_io_w(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2); - msm_camera_io_w(0x00001010, - jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0); - msm_camera_io_w(0x00000110, - jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0); - msm_camera_io_w(0x00000707, - jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST); - msm_camera_io_w(0x00000FFF, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN); - msm_camera_io_w(0x0FFF0FFF, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO); - msm_camera_io_w(0x2222, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1); - } - - msm_camera_io_w(0x7, - jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST); - msm_camera_io_w(0x00000030, - jpeg_vbif_base + JPEG_VBIF_ARB_CTL); - - /* FE and WE QOS configuration need to be set when - QOS RR arbitration is enabled */ - if (pgmn_dev->hw_version != JPEG_8974_V1) - msm_camera_io_w(0x00000003, - jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); - else - msm_camera_io_w(0x00000001, - jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); - - msm_camera_io_w(0x22222222, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0); - -} - -/* - * msm_jpeg_set_init_dt_parms() - get device tree config and write to registers. - * @pgmn_dev: Pointer to jpeg device. - * @dt_prop_name: Device tree property name. - * @base: Base address. - * - * This function reads register offsets and values from dtsi based on - * device tree property name and writes to jpeg registers. - * - * Return: 0 on success and negative error on failure. - */ -static int32_t msm_jpeg_set_init_dt_parms(struct msm_jpeg_device *pgmn_dev, - const char *dt_prop_name, - void *base) -{ - struct device_node *of_node; - int32_t i = 0 , rc = 0; - uint32_t *dt_reg_settings = NULL; - uint32_t dt_count = 0; - - of_node = pgmn_dev->pdev->dev.of_node; - JPEG_DBG("%s:%d E\n", __func__, __LINE__); - - if (!of_get_property(of_node, dt_prop_name, - &dt_count)) { - JPEG_DBG("%s: Error property does not exist\n", - __func__); - return -ENOENT; - } - if (dt_count % 8) { - JPEG_PR_ERR("%s: Error invalid entries\n", - __func__); - return -EINVAL; - } - dt_count /= 4; - if (dt_count != 0) { - dt_reg_settings = kcalloc(dt_count, sizeof(uint32_t), - GFP_KERNEL); - if (!dt_reg_settings) { - JPEG_PR_ERR("%s:%d No memory\n", - __func__, __LINE__); - return -ENOMEM; - } - rc = of_property_read_u32_array(of_node, - dt_prop_name, - dt_reg_settings, - dt_count); - if (rc < 0) { - JPEG_PR_ERR("%s: No reg info\n", - __func__); - kfree(dt_reg_settings); - return -EINVAL; - } - for (i = 0; i < dt_count; i = i + 2) { - JPEG_DBG("%s:%d] %pK %08x\n", - __func__, __LINE__, - base + dt_reg_settings[i], - dt_reg_settings[i + 1]); - msm_camera_io_w(dt_reg_settings[i + 1], - base + dt_reg_settings[i]); - } - kfree(dt_reg_settings); - } - return 0; -} - -static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev) -{ - int rc; - - rc = cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_ATTACH); - if (rc < 0) { - JPEG_PR_ERR("%s: Device attach failed\n", __func__); - return -ENODEV; - } - JPEG_DBG("%s:%d] handle %d attach\n", - __func__, __LINE__, pgmn_dev->iommu_hdl); - return 0; -} - -static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] handle %d detach\n", - __func__, __LINE__, pgmn_dev->iommu_hdl); - cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_DETACH); - return 0; -} - - -int msm_jpeg_platform_init(irqreturn_t (*handler)(int, void *), - void *context) -{ - int rc = -1; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *) context; - struct platform_device *pdev = pgmn_dev->pdev; - - pgmn_dev->state = MSM_JPEG_IDLE; - - /* enable all regulators */ - rc = msm_camera_regulator_enable(pgmn_dev->jpeg_vdd, - pgmn_dev->num_reg, true); - if (rc < 0) { - JPEG_PR_ERR("%s: failed to enable regulators\n", __func__); - goto err_reg_enable; - } - - /* enable all clocks */ - rc = msm_camera_clk_enable(&pgmn_dev->pdev->dev, - pgmn_dev->jpeg_clk_info, pgmn_dev->jpeg_clk, - pgmn_dev->num_clk, true); - if (rc < 0) { - JPEG_PR_ERR("%s: clk enable failed\n", __func__); - goto err_clk_enable; - } - - /* attach the smmu context banks */ - rc = msm_jpeg_attach_iommu(pgmn_dev); - if (rc < 0) { - JPEG_PR_ERR("%s: iommu attach failed\n", __func__); - goto err_fail_iommu; - } - rc = msm_jpeg_set_init_dt_parms(pgmn_dev, "qcom,vbif-reg-settings", - pgmn_dev->vbif_base); - if (rc == -ENOENT) { - JPEG_DBG("%s: No qcom,vbif-reg-settings property\n", __func__); - set_vbif_params(pgmn_dev, pgmn_dev->vbif_base); - } else if (rc < 0) { - JPEG_PR_ERR("%s: vbif params set fail\n", __func__); - goto err_fail_set_vbif; - } - - /* register the interrupt handler */ - rc = msm_camera_register_irq(pgmn_dev->pdev, - pgmn_dev->jpeg_irq_res, handler, IRQF_TRIGGER_RISING, - "jpeg", context); - if (rc < 0) { - JPEG_PR_ERR("%s: irq request fail\n", __func__); - goto err_reg_irq_fail; - } - - pgmn_dev->hw_version = msm_camera_io_r(pgmn_dev->base + - JPEG_HW_VERSION); - JPEG_DBG_HIGH("%s:%d] jpeg HW version 0x%x", __func__, __LINE__, - pgmn_dev->hw_version); - pgmn_dev->state = MSM_JPEG_INIT; - - return 0; -err_reg_irq_fail: -err_fail_set_vbif: - msm_jpeg_detach_iommu(pgmn_dev); -err_fail_iommu: - msm_camera_clk_enable(&pdev->dev, pgmn_dev->jpeg_clk_info, - pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false); -err_clk_enable: - msm_camera_regulator_enable(pgmn_dev->jpeg_vdd, - pgmn_dev->num_reg, false); -err_reg_enable: - return rc; -} - -int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev) -{ - int rc = -1; - struct resource *jpeg_irq_res; - void *jpeg_base, *vbif_base; - struct platform_device *pdev = pgmn_dev->pdev; - - /* get the jpeg hardware device address */ - jpeg_base = msm_camera_get_reg_base(pdev, "jpeg_hw", true); - if (!jpeg_base) { - JPEG_PR_ERR("%s: jpeg no mem resource?\n", __func__); - rc = -ENXIO; - goto out; - } - - /* get the jpeg vbif device address */ - vbif_base = msm_camera_get_reg_base(pdev, "jpeg_vbif", false); - if (!vbif_base) { - JPEG_PR_ERR("%s: vbif no mem resource?\n", __func__); - rc = -ENXIO; - goto err_vbif_base; - } - - /* get the irq resource for the jpeg hardware */ - jpeg_irq_res = msm_camera_get_irq(pdev, "jpeg"); - if (!jpeg_irq_res) { - JPEG_PR_ERR("%s: no irq resource?\n", __func__); - rc = -ENXIO; - goto err_jpeg_irq_res; - } - - /* get all the clocks information */ - rc = msm_camera_get_clk_info(pdev, &pgmn_dev->jpeg_clk_info, - &pgmn_dev->jpeg_clk, &pgmn_dev->num_clk); - if (rc < 0) { - JPEG_PR_ERR("%s: failed to get the clocks\n", __func__); - rc = -ENXIO; - goto err_jpeg_clk; - } - - /* get all the regulators information */ - rc = msm_camera_get_regulator_info(pdev, &pgmn_dev->jpeg_vdd, - &pgmn_dev->num_reg); - if (rc < 0) { - JPEG_PR_ERR("%s: failed to get the regulators\n", __func__); - rc = -ENXIO; - goto err_jpeg_get_reg; - } - - /* map the dtsi cell id to bus client id */ - switch (pgmn_dev->pdev->id) { - case 0: - pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC0; - break; - case 1: - pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC1; - break; - case 2: - pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DEC; - break; - case 3: - pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DMA; - break; - default: - JPEG_PR_ERR("%s: invalid cell id :%d\n", - __func__, pgmn_dev->pdev->id); - goto err_jpeg_get_reg; - } - - /* register the bus client */ - rc = msm_camera_register_bus_client(pgmn_dev->pdev, - pgmn_dev->bus_client); - if (rc < 0) { - JPEG_PR_ERR("Fail to register bus client\n"); - rc = -EINVAL; - goto err_reg_bus; - } - - /* get the resource size of jpeg hardware */ - pgmn_dev->res_size = msm_camera_get_res_size(pdev, "jpeg_hw"); - if (!pgmn_dev->res_size) { - JPEG_PR_ERR("Fail to resource size\n"); - rc = -EINVAL; - goto err_res_size; - } - - pgmn_dev->base = jpeg_base; - pgmn_dev->vbif_base = vbif_base; - pgmn_dev->jpeg_irq_res = jpeg_irq_res; - - return 0; - -err_res_size: - msm_camera_unregister_bus_client(pgmn_dev->bus_client); -err_reg_bus: - msm_camera_put_regulators(pdev, &pgmn_dev->jpeg_vdd, - pgmn_dev->num_reg); -err_jpeg_get_reg: - msm_camera_put_clk_info(pdev, &pgmn_dev->jpeg_clk_info, - &pgmn_dev->jpeg_clk, pgmn_dev->num_clk); -err_jpeg_clk: -err_jpeg_irq_res: - msm_camera_put_reg_base(pdev, vbif_base, "jpeg_vbif", false); -err_vbif_base: - msm_camera_put_reg_base(pdev, jpeg_base, "jpeg_hw", true); -out: - return rc; -} - -void msm_jpeg_platform_cleanup(struct msm_jpeg_device *pgmn_dev) -{ - /* unregister the bus client */ - msm_camera_unregister_bus_client(pgmn_dev->bus_client); - /* release the regulators */ - msm_camera_put_regulators(pgmn_dev->pdev, &pgmn_dev->jpeg_vdd, - pgmn_dev->num_reg); - /* release all the clocks */ - msm_camera_put_clk_info(pgmn_dev->pdev, &pgmn_dev->jpeg_clk_info, - &pgmn_dev->jpeg_clk, pgmn_dev->num_clk); - /* release the jpeg device memory */ - msm_camera_put_reg_base(pgmn_dev->pdev, pgmn_dev->vbif_base, - "jpeg_vbif", false); - /* release the jpeg vbif device memory */ - msm_camera_put_reg_base(pgmn_dev->pdev, pgmn_dev->base, - "jpeg_hw", true); -} - -int msm_jpeg_platform_release(void *context) -{ - int result = 0; - - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *) context; - - /* release the irq */ - msm_camera_unregister_irq(pgmn_dev->pdev, - pgmn_dev->jpeg_irq_res, context); - - msm_jpeg_detach_iommu(pgmn_dev); - - if (pgmn_dev->bus_client) { - if (pgmn_dev->jpeg_bus_vote) { - /* update the bw with zeroth vector */ - msm_camera_update_bus_vector(pgmn_dev->bus_client, 0); - JPEG_BUS_UNVOTED(pgmn_dev); - JPEG_DBG("%s:%d] Bus unvoted\n", __func__, __LINE__); - } - } - - /* disable all the clocks */ - msm_camera_clk_enable(&pgmn_dev->pdev->dev, pgmn_dev->jpeg_clk_info, - pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false); - JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__); - - /* disable all the regulators */ - msm_camera_regulator_enable(pgmn_dev->jpeg_vdd, - pgmn_dev->num_reg, false); - JPEG_DBG("%s:%d] regulator disable done", __func__, __LINE__); - - pgmn_dev->state = MSM_JPEG_IDLE; - JPEG_DBG("%s:%d] success\n", __func__, __LINE__); - return result; -} - -/* - * msm_jpeg_platform_set_dt_config() - set jpeg device tree configuration. - * @pgmn_dev: Pointer to jpeg device. - * - * This function holds an array of device tree property names and calls - * msm_jpeg_set_init_dt_parms() for each property. - * - * Return: 0 on success and negative error on failure. - */ -int msm_jpeg_platform_set_dt_config(struct msm_jpeg_device *pgmn_dev) -{ - int rc = 0; - uint8_t dt_prop_cnt = JPEG_DT_PROP_CNT; - char *dt_prop_name[JPEG_DT_PROP_CNT] = {"qcom,qos-reg-settings", - "qcom,prefetch-reg-settings"}; - - while (dt_prop_cnt) { - dt_prop_cnt--; - rc = msm_jpeg_set_init_dt_parms(pgmn_dev, - dt_prop_name[dt_prop_cnt], - pgmn_dev->base); - if (rc == -ENOENT) { - JPEG_DBG("%s: No %s property\n", __func__, - dt_prop_name[dt_prop_cnt]); - } else if (rc < 0) { - JPEG_PR_ERR("%s: %s params set fail\n", __func__, - dt_prop_name[dt_prop_cnt]); - return rc; - } - } - return rc; -} - diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_platform.h deleted file mode 100644 index cbd9d3e22f09d1b2bc1058786282b0780e7148b0..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_platform.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_JPEG_PLATFORM_H -#define MSM_JPEG_PLATFORM_H - -#include -#include -#include -#include "msm_jpeg_sync.h" -#define JPEG_CLK_RATE 266670000 - -int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, - long clk_rate); -void msm_jpeg_platform_p2v(int iommu_hdl, int fd); -uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, - uint32_t len, int iommu_hdl); - -int msm_jpeg_platform_clk_enable(void); -int msm_jpeg_platform_clk_disable(void); - -int msm_jpeg_platform_init(irqreturn_t (*handler)(int, void *), - void *context); -int msm_jpeg_platform_release(void *context); -int msm_jpeg_platform_set_dt_config(struct msm_jpeg_device *pgmn_dev); -int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev); -void msm_jpeg_platform_cleanup(struct msm_jpeg_device *pgmn_dev); - -#endif /* MSM_JPEG_PLATFORM_H */ diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_sync.c deleted file mode 100644 index e085f0afaa7787602d0d6c6b2c8a4752339183e7..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_sync.c +++ /dev/null @@ -1,1584 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_jpeg_sync.h" -#include "msm_jpeg_core.h" -#include "msm_jpeg_platform.h" -#include "msm_jpeg_common.h" -#include "cam_hw_ops.h" - -#define JPEG_REG_SIZE 0x308 -#define JPEG_DEV_CNT 4 -#define JPEG_DEC_ID 2 -#define UINT32_MAX (0xFFFFFFFFU) - -#ifdef CONFIG_COMPAT - -#define MSM_JPEG_IOCTL_GET_HW_VERSION32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 1, struct msm_jpeg_hw_cmd32) - -#define MSM_JPEG_IOCTL_RESET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd32) - -#define MSM_JPEG_IOCTL_STOP32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 3, struct msm_jpeg_hw_cmds32) - -#define MSM_JPEG_IOCTL_START32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 4, struct msm_jpeg_hw_cmds32) - -#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_INPUT_GET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_OUTPUT_GET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_EVT_GET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd32) - -#define MSM_JPEG_IOCTL_HW_CMD32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 13, struct msm_jpeg_hw_cmd32) - -#define MSM_JPEG_IOCTL_HW_CMDS32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 14, struct msm_jpeg_hw_cmds32) - -#define MSM_JPEG_IOCTL_TEST_DUMP_REGION32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 15, compat_ulong_t) - -struct msm_jpeg_ctrl_cmd32 { - uint32_t type; - uint32_t len; - compat_uptr_t value; -}; -struct msm_jpeg_buf32 { - uint32_t type; - int fd; - - compat_uptr_t vaddr; - - uint32_t y_off; - uint32_t y_len; - uint32_t framedone_len; - - uint32_t cbcr_off; - uint32_t cbcr_len; - - uint32_t num_of_mcu_rows; - uint32_t offset; - uint32_t pln2_off; - uint32_t pln2_len; -}; - -struct msm_jpeg_hw_cmd32 { - - uint32_t type:4; - - /* n microseconds of timeout for WAIT */ - /* n microseconds of time for DELAY */ - /* repeat n times for READ/WRITE */ - /* max is 0xFFF, 4095 */ - uint32_t n:12; - uint32_t offset:16; - uint32_t mask; - union { - uint32_t data; /* for single READ/WRITE/WAIT, n = 1 */ - compat_uptr_t pdata; /* for multiple READ/WRITE/WAIT, n > 1 */ - }; -}; - -struct msm_jpeg_hw_cmds32 { - uint32_t m; /* number of elements in the hw_cmd array */ - struct msm_jpeg_hw_cmd32 hw_cmd[1]; -}; -#endif - - -inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p) -{ - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name); - q_p->name = name; - spin_lock_init(&q_p->lck); - INIT_LIST_HEAD(&q_p->q); - init_waitqueue_head(&q_p->wait); - q_p->unblck = 0; -} - -inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p) -{ - unsigned long flags; - struct msm_jpeg_q_entry *q_entry_p = NULL; - void *data = NULL; - - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - spin_lock_irqsave(&q_p->lck, flags); - if (!list_empty(&q_p->q)) { - q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry, - list); - list_del_init(&q_entry_p->list); - } - spin_unlock_irqrestore(&q_p->lck, flags); - - if (q_entry_p) { - data = q_entry_p->data; - kfree(q_entry_p); - } else { - JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__, - q_p->name); - } - - return data; -} - -inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data) -{ - unsigned long flags; - - struct msm_jpeg_q_entry *q_entry_p; - - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - - q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC); - if (!q_entry_p) { - JPEG_PR_ERR("%s: no mem\n", __func__); - return -EFAULT; - } - q_entry_p->data = data; - - spin_lock_irqsave(&q_p->lck, flags); - list_add_tail(&q_entry_p->list, &q_p->q); - spin_unlock_irqrestore(&q_p->lck, flags); - - return 0; -} - -inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p, - struct msm_jpeg_core_buf *buf) -{ - struct msm_jpeg_core_buf *buf_p; - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); - if (!buf_p) { - JPEG_PR_ERR("%s: no mem\n", __func__); - return -EFAULT; - } - - memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf)); - - msm_jpeg_q_in(q_p, buf_p); - return 0; -} - -inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p) -{ - long tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */ - int rc; - - JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name); - rc = wait_event_timeout(q_p->wait, - (!list_empty_careful(&q_p->q) || q_p->unblck), - msecs_to_jiffies(tm)); - JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name); - if (list_empty_careful(&q_p->q)) { - if (rc == 0) { - rc = -ETIMEDOUT; - JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__, - q_p->name); - } else if (q_p->unblck) { - JPEG_DBG("%s:%d] %s unblock is true\n", __func__, - __LINE__, q_p->name); - q_p->unblck = 0; - rc = -ECANCELED; - } - } - return rc; -} - -inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p) -{ - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - wake_up(&q_p->wait); - return 0; -} - -inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p) -{ - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - q_p->unblck = 1; - wake_up(&q_p->wait); - return 0; -} - -inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_q *q_p) -{ - struct msm_jpeg_core_buf *buf_p; - - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - do { - buf_p = msm_jpeg_q_out(q_p); - if (buf_p) { - msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, - buf_p->ion_fd); - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - kfree(buf_p); - } - } while (buf_p); - q_p->unblck = 0; -} - -inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p) -{ - void *data; - - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - do { - data = msm_jpeg_q_out(q_p); - if (data) { - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - kfree(data); - } - } while (data); - q_p->unblck = 0; -} - -/*************** event queue ****************/ - -int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf_in) -{ - int rc = 0; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - if (buf_in) { - buf_in->vbuf.framedone_len = buf_in->framedone_len; - buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE; - JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n", - __func__, __LINE__, - (int) buf_in->y_buffer_addr, buf_in->y_len, - buf_in->vbuf.framedone_len); - rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in); - } else { - JPEG_PR_ERR("%s:%d] no output return buffer\n", - __func__, __LINE__); - rc = -1; - } - - if (buf_in) - rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); - - return rc; -} - -int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev, - void __user *to) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_ctrl_cmd ctrl_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - msm_jpeg_q_wait(&pgmn_dev->evt_q); - buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q); - - if (!buf_p) { - JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__); - return -EAGAIN; - } - - memset(&ctrl_cmd, 0, sizeof(ctrl_cmd)); - ctrl_cmd.type = buf_p->vbuf.type; - kfree(buf_p); - - if (ctrl_cmd.type == MSM_JPEG_EVT_SESSION_DONE) { - /* update the bw with zeroth vector */ - msm_camera_update_bus_vector(pgmn_dev->bus_client, 0); - JPEG_BUS_UNVOTED(pgmn_dev); - JPEG_DBG("%s:%d] Bus unvoted\n", __func__, __LINE__); - } - - JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__, - (unsigned long) ctrl_cmd.value, ctrl_cmd.len); - - if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) { - JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_unblock(&pgmn_dev->evt_q); - return 0; -} - -void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d]\n", __func__, __LINE__); -} - -void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev, - int event) -{ - int rc = 0; - struct msm_jpeg_core_buf buf; - - JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event); - - buf.vbuf.type = MSM_JPEG_EVT_ERR; - rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf); - if (!rc) - rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); - - if (!rc) - JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__); -} - -/*************** output queue ****************/ - -int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf_in) -{ - int rc = 0; - struct msm_jpeg_core_buf *buf_out; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - if (buf_in) { - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_in->y_buffer_addr, buf_in->y_len); - rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in); - } else { - JPEG_DBG("%s:%d] no output return buffer\n", __func__, - __LINE__); - rc = -1; - return rc; - } - - buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q); - - if (buf_out) { - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_out->y_buffer_addr, buf_out->y_len); - rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out); - kfree(buf_out); - } else { - msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in); - JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__); - rc = -2; - } - - if (buf_in) - rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q); - - return rc; -} - -int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev, void __user *to) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_buf buf_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - msm_jpeg_q_wait(&pgmn_dev->output_rtn_q); - buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q); - - if (!buf_p) { - JPEG_DBG("%s:%d] no output buffer return\n", - __func__, __LINE__); - return -EAGAIN; - } - - buf_cmd = buf_p->vbuf; - msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, buf_p->ion_fd); - kfree(buf_p); - - JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__, - (unsigned long) buf_cmd.vaddr, buf_cmd.y_len); - - if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { - JPEG_PR_ERR("%s:%d]", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q); - return 0; -} - -static inline int msm_jpeg_add_u32_check(uint32_t *p, uint32_t n, uint32_t *res) -{ - *res = 0; - - while (n--) { - if ((*res + *p) < *res) - return -EFAULT; - *res += *p++; - } - return 0; -} - -int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev, - void __user *arg) -{ - struct msm_jpeg_buf buf_cmd; - struct msm_jpeg_core_buf *buf_p; - uint32_t buf_len_params[10]; - uint32_t total_len = 0; - int n = 0; - - memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - buf_len_params[n++] = buf_cmd.y_len; - buf_len_params[n++] = buf_cmd.cbcr_len; - buf_len_params[n++] = buf_cmd.pln2_len; - buf_len_params[n++] = buf_cmd.offset; - buf_len_params[n++] = buf_cmd.y_off; - if (msm_jpeg_add_u32_check(buf_len_params, n, &total_len) < 0) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); - if (!buf_p) { - JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); - return -EFAULT; - } - - - JPEG_DBG("%s:%d] vaddr = 0x%08lx y_len = %d\n, fd = %d", - __func__, __LINE__, (unsigned long) buf_cmd.vaddr, - buf_cmd.y_len, buf_cmd.fd); - - buf_p->ion_fd = buf_cmd.fd; - buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, - total_len, pgmn_dev->iommu_hdl); - - if (!buf_p->y_buffer_addr) { - JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); - kfree(buf_p); - return -EFAULT; - } - - buf_p->y_buffer_addr += buf_cmd.offset + buf_cmd.y_off; - - if (buf_cmd.cbcr_len) - buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + - buf_cmd.y_len; - else - buf_p->cbcr_buffer_addr = 0x0; - - if (buf_cmd.pln2_len) - buf_p->pln2_addr = buf_p->cbcr_buffer_addr + - buf_cmd.cbcr_len; - else - buf_p->pln2_addr = 0x0; - - JPEG_DBG("%s:%d]After v2p pln0_addr %x pln0_len %d", - __func__, __LINE__, buf_p->y_buffer_addr, - buf_cmd.y_len); - - JPEG_DBG("pl1_len %d, pln1_addr %x, pln2_adrr %x,pln2_len %d", - buf_cmd.cbcr_len, buf_p->cbcr_buffer_addr, - buf_p->pln2_addr, buf_cmd.pln2_len); - - buf_p->y_len = buf_cmd.y_len; - buf_p->cbcr_len = buf_cmd.cbcr_len; - buf_p->pln2_len = buf_cmd.pln2_len; - buf_p->vbuf = buf_cmd; - - msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p); - return 0; -} - -/*************** input queue ****************/ - -int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf_in) -{ - struct msm_jpeg_core_buf *buf_out; - int rc = 0; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - if (buf_in) { - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_in->y_buffer_addr, buf_in->y_len); - rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in); - } else { - JPEG_DBG("%s:%d] no input return buffer\n", __func__, - __LINE__); - rc = -EFAULT; - } - - buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); - - if (buf_out) { - rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); - kfree(buf_out); - msm_jpeg_core_fe_start(pgmn_dev); - } else { - JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__); - rc = -EFAULT; - } - - if (buf_in) - rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q); - - return rc; -} - -int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev, void __user *to) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_buf buf_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_wait(&pgmn_dev->input_rtn_q); - buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q); - - if (!buf_p) { - JPEG_DBG("%s:%d] no input buffer return\n", - __func__, __LINE__); - return -EAGAIN; - } - - buf_cmd = buf_p->vbuf; - - msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, buf_p->ion_fd); - kfree(buf_p); - - JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__, - (unsigned long) buf_cmd.vaddr, buf_cmd.y_len); - - if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { - JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q); - return 0; -} - -int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev, - void __user *arg) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_buf buf_cmd; - uint32_t buf_len_params[10]; - uint32_t total_len = 0; - int n = 0; - - memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); - - if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - buf_len_params[n++] = buf_cmd.y_len; - buf_len_params[n++] = buf_cmd.cbcr_len; - buf_len_params[n++] = buf_cmd.pln2_len; - buf_len_params[n++] = buf_cmd.offset; - buf_len_params[n++] = buf_cmd.y_off; - if (buf_cmd.cbcr_len) - buf_len_params[n++] = buf_cmd.cbcr_off; - if (buf_cmd.pln2_len) - buf_len_params[n++] = buf_cmd.pln2_off; - - if (msm_jpeg_add_u32_check(buf_len_params, n, &total_len) < 0) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); - if (!buf_p) { - JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); - return -EFAULT; - } - - JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__, - (unsigned long) buf_cmd.vaddr, buf_cmd.y_len); - - buf_p->ion_fd = buf_cmd.fd; - buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, - total_len, pgmn_dev->iommu_hdl); - - if (!buf_p->y_buffer_addr) { - JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); - kfree(buf_p); - return -EFAULT; - } - - buf_p->y_buffer_addr += buf_cmd.offset + buf_cmd.y_off; - - buf_p->y_len = buf_cmd.y_len; - buf_p->cbcr_len = buf_cmd.cbcr_len; - buf_p->pln2_len = buf_cmd.pln2_len; - buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows; - - if (buf_cmd.cbcr_len) - buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + - buf_cmd.y_len + buf_cmd.cbcr_off; - else - buf_p->cbcr_buffer_addr = 0x0; - - if (buf_cmd.pln2_len) - buf_p->pln2_addr = buf_p->cbcr_buffer_addr + - buf_cmd.cbcr_len + buf_cmd.pln2_off; - else - buf_p->pln2_addr = 0x0; - - JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%d", - __func__, buf_p->y_buffer_addr, buf_p->y_len, - buf_p->cbcr_buffer_addr, buf_p->cbcr_len); - JPEG_DBG("pln2_addr = %x, pln2_len = %d, fd =%d\n", - buf_p->pln2_addr, buf_p->pln2_len, buf_cmd.fd); - - buf_p->vbuf = buf_cmd; - - msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p); - - return 0; -} - -int msm_jpeg_irq(int event, void *context, void *data) -{ - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *) context; - - switch (event) { - case MSM_JPEG_EVT_SESSION_DONE: - msm_jpeg_framedone_irq(pgmn_dev, data); - msm_jpeg_we_pingpong_irq(pgmn_dev, data); - break; - - case MSM_JPEG_HW_MASK_COMP_FE: - msm_jpeg_fe_pingpong_irq(pgmn_dev, data); - break; - - case MSM_JPEG_HW_MASK_COMP_WE: - msm_jpeg_we_pingpong_irq(pgmn_dev, data); - break; - - case MSM_JPEG_HW_MASK_COMP_RESET_ACK: - msm_jpeg_reset_ack_irq(pgmn_dev); - break; - - case MSM_JPEG_HW_MASK_COMP_ERR: - default: - msm_jpeg_err_irq(pgmn_dev, event); - break; - } - - return 0; -} - -int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev) -{ - int rc; - irqreturn_t (*core_irq)(int, void *); - - mutex_lock(&pgmn_dev->lock); - if (pgmn_dev->open_count) { - /* only open once */ - JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__); - mutex_unlock(&pgmn_dev->lock); - return -EBUSY; - } - pgmn_dev->open_count++; - if (pgmn_dev->open_count == 1) - pgmn_dev->state = MSM_JPEG_INIT; - - mutex_unlock(&pgmn_dev->lock); - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - msm_jpeg_core_irq_install(msm_jpeg_irq); - if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) - core_irq = msm_jpeg_core_irq; - else - core_irq = msm_jpegdma_core_irq; - - /* initialize the platform resources */ - rc = msm_jpeg_platform_init(core_irq, pgmn_dev); - if (rc) { - JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__, - __LINE__, rc); - goto platform_init_fail; - } - JPEG_DBG("%s:%d] platform resources - base %pK, irq %d\n", - __func__, __LINE__, - pgmn_dev->base, (int)pgmn_dev->jpeg_irq_res->start); - msm_jpeg_q_cleanup(&pgmn_dev->evt_q); - msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); - msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q); - msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); - msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q); - msm_jpeg_core_init(pgmn_dev); - - JPEG_DBG("%s:%d] success\n", __func__, __LINE__); - return rc; - -platform_init_fail: - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - return rc; -} - -int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - mutex_lock(&pgmn_dev->lock); - if (!pgmn_dev->open_count) { - JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__); - mutex_unlock(&pgmn_dev->lock); - return -EINVAL; - } - pgmn_dev->open_count--; - mutex_unlock(&pgmn_dev->lock); - - msm_jpeg_core_release(pgmn_dev); - msm_jpeg_q_cleanup(&pgmn_dev->evt_q); - msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); - msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q); - msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); - msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - if (pgmn_dev->open_count) - JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__); - - /* release the platform resources */ - msm_jpeg_platform_release(pgmn_dev); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - - return 0; -} - -int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - struct msm_jpeg_hw_cmd hw_cmd; - int is_copy_to_user; - - if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_jpeg_hw_cmd))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1, - pgmn_dev->res_size, pgmn_dev->base); - JPEG_DBG( - "%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %lx\n", - __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset, - hw_cmd.mask, hw_cmd.data, (unsigned long) hw_cmd.pdata); - - if (is_copy_to_user >= 0) { - if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - } else { - return is_copy_to_user; - } - - return 0; -} - -int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - int is_copy_to_user; - uint32_t len; - uint32_t m; - struct msm_jpeg_hw_cmds *hw_cmds_p; - struct msm_jpeg_hw_cmd *hw_cmd_p; - - if (copy_from_user(&m, arg, sizeof(m))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) / - sizeof(struct msm_jpeg_hw_cmd)))) { - JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__); - return -EFAULT; - } - - len = sizeof(struct msm_jpeg_hw_cmds) + - sizeof(struct msm_jpeg_hw_cmd) * (m - 1); - hw_cmds_p = kmalloc(len, GFP_KERNEL); - if (!hw_cmds_p) { - JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len); - return -EFAULT; - } - - if (copy_from_user(hw_cmds_p, arg, len)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - kfree(hw_cmds_p); - return -EFAULT; - } - - hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd); - - is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m, - pgmn_dev->res_size, pgmn_dev->base); - - if (is_copy_to_user >= 0) { - if (copy_to_user(arg, hw_cmds_p, len)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - kfree(hw_cmds_p); - return -EFAULT; - } - } else { - kfree(hw_cmds_p); - return is_copy_to_user; - } - kfree(hw_cmds_p); - return 0; -} - -int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void * __user arg, - int (*hw_ioctl)(struct msm_jpeg_device *, void * __user)) -{ - struct msm_jpeg_core_buf *buf_out; - struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL}; - int i, rc; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - msm_jpeg_platform_set_dt_config(pgmn_dev); - - /* update the bw with vector index "1" */ - msm_camera_update_bus_vector(pgmn_dev->bus_client, 1); - JPEG_BUS_VOTED(pgmn_dev); - JPEG_DBG("%s:%d] Bus Voted\n", __func__, __LINE__); - - pgmn_dev->release_buf = 1; - for (i = 0; i < 2; i++) { - buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); - - if (buf_out) { - msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); - kfree(buf_out); - } else { - JPEG_DBG("%s:%d] no input buffer\n", __func__, - __LINE__); - break; - } - } - - for (i = 0; i < 2; i++) { - buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q); - - if (buf_out_free[i]) { - msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]); - pgmn_dev->release_buf = 0; - } else { - JPEG_DBG("%s:%d] no output buffer\n", - __func__, __LINE__); - break; - } - } - - for (i = 0; i < 2; i++) - kfree(buf_out_free[i]); - - JPEG_DBG_HIGH("%s:%d] START\n", __func__, __LINE__); - pgmn_dev->state = MSM_JPEG_EXECUTING; - /* ensure write is done */ - wmb(); - rc = hw_ioctl(pgmn_dev, arg); - /* ensure write is done */ - wmb(); - JPEG_DBG("%s:%d]", __func__, __LINE__); - return rc; -} - -int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev, void * __user arg) -{ - int rc; - struct msm_jpeg_ctrl_cmd ctrl_cmd, *p_ctrl_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - p_ctrl_cmd = &ctrl_cmd; - - if (pgmn_dev->state == MSM_JPEG_INIT) { - if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - pgmn_dev->op_mode = p_ctrl_cmd->type; - - rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode, - pgmn_dev->base, pgmn_dev->res_size); - } else { - JPEG_PR_ERR("%s:%d] JPEG not been initialized Wrong state\n", - __func__, __LINE__); - rc = -1; - } - return rc; -} - -int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev, - unsigned long arg) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE); - return 0; -} - -int msm_jpeg_ioctl_set_clk_rate(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - long clk_rate; - int rc; - - if ((pgmn_dev->state != MSM_JPEG_INIT) && - (pgmn_dev->state != MSM_JPEG_RESET)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - if (get_user(clk_rate, (unsigned int __user *)arg)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - JPEG_DBG("%s:%d] Requested clk rate %ld\n", __func__, __LINE__, - clk_rate); - if (clk_rate < 0) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - rc = msm_jpeg_platform_set_clk_rate(pgmn_dev, clk_rate); - if (rc < 0) { - JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); - return -EFAULT; - } - - return 0; -} -#ifdef CONFIG_COMPAT -int msm_jpeg_get_ctrl_cmd32(struct msm_jpeg_ctrl_cmd *ctrl_cmd, - void __user *arg) -{ - struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; - unsigned long temp; - - if (copy_from_user(&ctrl_cmd32, arg, - sizeof(struct msm_jpeg_ctrl_cmd32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - ctrl_cmd->type = ctrl_cmd32.type; - ctrl_cmd->len = ctrl_cmd32.len; - temp = (unsigned long) ctrl_cmd32.value; - ctrl_cmd->value = (void *) temp; - - return 0; -} -int msm_jpeg_put_ctrl_cmd32(struct msm_jpeg_ctrl_cmd *ctrl_cmd, - void __user *arg) -{ - struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; - unsigned long temp; - - ctrl_cmd32.type = ctrl_cmd->type; - ctrl_cmd32.len = ctrl_cmd->len; - temp = (unsigned long) ctrl_cmd->value; - ctrl_cmd32.value = (compat_uptr_t) temp; - - if (copy_to_user(arg, &ctrl_cmd32, - sizeof(struct msm_jpeg_ctrl_cmd32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_get_jpeg_buf32(struct msm_jpeg_buf *jpeg_buf, - void __user *arg) -{ - struct msm_jpeg_buf32 jpeg_buf32; - unsigned long temp; - - if (copy_from_user(&jpeg_buf32, arg, sizeof(struct msm_jpeg_buf32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - jpeg_buf->type = jpeg_buf32.type; - jpeg_buf->fd = jpeg_buf32.fd; - temp = (unsigned long) jpeg_buf32.vaddr; - jpeg_buf->vaddr = (void *) temp; - jpeg_buf->y_off = jpeg_buf32.y_off; - jpeg_buf->y_len = jpeg_buf32.y_len; - jpeg_buf->framedone_len = jpeg_buf32.framedone_len; - jpeg_buf->cbcr_off = jpeg_buf32.cbcr_off; - jpeg_buf->cbcr_len = jpeg_buf32.cbcr_len; - jpeg_buf->num_of_mcu_rows = jpeg_buf32.num_of_mcu_rows; - jpeg_buf->offset = jpeg_buf32.offset; - jpeg_buf->pln2_off = jpeg_buf32.pln2_off; - jpeg_buf->pln2_len = jpeg_buf32.pln2_len; - - return 0; -} -int msm_jpeg_put_jpeg_buf32(struct msm_jpeg_buf *jpeg_buf, - void __user *arg) -{ - struct msm_jpeg_buf32 jpeg_buf32; - unsigned long temp; - - jpeg_buf32.type = jpeg_buf->type; - jpeg_buf32.fd = jpeg_buf->fd; - temp = (unsigned long) jpeg_buf->vaddr; - jpeg_buf32.vaddr = (compat_uptr_t) temp; - jpeg_buf32.y_off = jpeg_buf->y_off; - jpeg_buf32.y_len = jpeg_buf->y_len; - jpeg_buf32.framedone_len = jpeg_buf->framedone_len; - jpeg_buf32.cbcr_off = jpeg_buf->cbcr_off; - jpeg_buf32.cbcr_len = jpeg_buf->cbcr_len; - jpeg_buf32.num_of_mcu_rows = jpeg_buf->num_of_mcu_rows; - jpeg_buf32.offset = jpeg_buf->offset; - jpeg_buf32.pln2_off = jpeg_buf->pln2_off; - jpeg_buf32.pln2_len = jpeg_buf->pln2_len; - - if (copy_to_user(arg, &jpeg_buf32, sizeof(struct msm_jpeg_buf32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - return 0; -} - -int msm_jpeg_put_hw_cmd32(void __user *arg, - struct msm_jpeg_hw_cmd *phw_cmd, int copy) -{ - struct msm_jpeg_hw_cmd32 hw_cmd32; - struct msm_jpeg_hw_cmd32 *phw_cmd32; - - phw_cmd32 = (struct msm_jpeg_hw_cmd32 *) arg; - if (copy) - phw_cmd32 = &hw_cmd32; - - - phw_cmd32->type = phw_cmd->type; - phw_cmd32->n = phw_cmd->n; - phw_cmd32->offset = phw_cmd->offset; - phw_cmd32->mask = phw_cmd->mask; - phw_cmd32->data = phw_cmd->data; - - if (copy && copy_to_user(arg, &hw_cmd32, sizeof(hw_cmd32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} -int msm_jpeg_get_hw_cmd32(struct msm_jpeg_hw_cmd *phw_cmd, - void __user *arg, int copy) -{ - struct msm_jpeg_hw_cmd32 hw_cmd32; - struct msm_jpeg_hw_cmd32 *phw_cmd32; - - if (copy) { - phw_cmd32 = &hw_cmd32; - if (copy_from_user(&hw_cmd32, arg, sizeof(hw_cmd32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - } else { - phw_cmd32 = (struct msm_jpeg_hw_cmd32 *) arg; - } - phw_cmd->type = phw_cmd32->type; - phw_cmd->n = phw_cmd32->n; - phw_cmd->offset = phw_cmd32->offset; - phw_cmd->mask = phw_cmd32->mask; - phw_cmd->data = phw_cmd32->data; - - return 0; -} -int msm_jpeg_ioctl_hw_cmds32(struct msm_jpeg_device *pgmn_dev, - void __user *arg) -{ - int is_copy_to_user; - uint32_t len, len32; - uint32_t m; - struct msm_jpeg_hw_cmds32 *phw_cmds32; - struct msm_jpeg_hw_cmds *phw_cmds; - - if (copy_from_user(&m, arg, sizeof(m))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds32)) / - sizeof(struct msm_jpeg_hw_cmd32)))) { - JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__); - return -EFAULT; - } - - len32 = sizeof(struct msm_jpeg_hw_cmds32) + - sizeof(struct msm_jpeg_hw_cmd32) * (m - 1); - phw_cmds32 = kmalloc(len32, GFP_KERNEL); - if (!phw_cmds32) { - JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len32); - return -EFAULT; - } - - if (copy_from_user(phw_cmds32, arg, len32)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - kfree(phw_cmds32); - return -EFAULT; - } - len = sizeof(struct msm_jpeg_hw_cmds) + - sizeof(struct msm_jpeg_hw_cmd) * (m - 1); - phw_cmds = kmalloc(len, GFP_KERNEL); - if (!phw_cmds) { - JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len); - kfree(phw_cmds32); - return -EFAULT; - } - (phw_cmds)->m = m; - while (m--) { - struct msm_jpeg_hw_cmd32 *src; - struct msm_jpeg_hw_cmd *dst; - - src = &phw_cmds32->hw_cmd[m]; - dst = &(phw_cmds)->hw_cmd[m]; - msm_jpeg_get_hw_cmd32(dst, src, 0); - } - - is_copy_to_user = msm_jpeg_hw_exec_cmds(phw_cmds->hw_cmd, phw_cmds->m, - pgmn_dev->res_size, pgmn_dev->base); - - if (is_copy_to_user >= 0) { - m = phw_cmds->m; - while (m--) { - struct msm_jpeg_hw_cmd *src; - struct msm_jpeg_hw_cmd32 *dst; - - dst = &phw_cmds32->hw_cmd[m]; - src = &phw_cmds->hw_cmd[m]; - - msm_jpeg_put_hw_cmd32(dst, src, 0); - } - if (copy_to_user(arg, phw_cmds32, len32)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - kfree(phw_cmds); - kfree(phw_cmds32); - return -EFAULT; - } - - } else { - kfree(phw_cmds); - kfree(phw_cmds32); - return is_copy_to_user; - } - kfree(phw_cmds); - kfree(phw_cmds32); - - return 0; -} -int msm_jpeg_ioctl_hw_cmd32(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - struct msm_jpeg_hw_cmd hw_cmd; - int is_copy_to_user; - - if (msm_jpeg_get_hw_cmd32(&hw_cmd, arg, 1)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1, - pgmn_dev->res_size, pgmn_dev->base); - JPEG_DBG("%s:%d] type %d, n %d, offst %d, mask %x, data %x pdata %lx\n", - __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset, - hw_cmd.mask, hw_cmd.data, (unsigned long) hw_cmd.pdata); - - if (is_copy_to_user >= 0) { - if (msm_jpeg_put_hw_cmd32(arg, &hw_cmd, 1)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - } else - return is_copy_to_user; - - - return 0; -} - -long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg) -{ - int rc = 0; - struct msm_jpeg_ctrl_cmd *pctrl_cmd = NULL, ctrl_cmd; - struct msm_jpeg_buf jpeg_buf; - mm_segment_t old_fs; - - old_fs = get_fs(); - - switch (cmd) { - case MSM_JPEG_IOCTL_GET_HW_VERSION: - JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - case MSM_JPEG_IOCTL_GET_HW_VERSION32: - JPEG_DBG("%s:%d] VERSION 1 32bit\n", __func__, __LINE__); - rc = msm_jpeg_ioctl_hw_cmd32(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_RESET: - rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_RESET32: - rc = msm_jpeg_get_ctrl_cmd32(&ctrl_cmd, - (void __user *) arg); - if (rc < 0) - break; - - set_fs(KERNEL_DS); - rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) &ctrl_cmd); - set_fs(old_fs); - kfree(pctrl_cmd); - break; - - case MSM_JPEG_IOCTL_STOP: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - pgmn_dev->state = MSM_JPEG_STOPPED; - break; - - case MSM_JPEG_IOCTL_STOP32: - rc = msm_jpeg_ioctl_hw_cmds32(pgmn_dev, (void __user *) arg); - pgmn_dev->state = MSM_JPEG_STOPPED; - break; - - case MSM_JPEG_IOCTL_START: - rc = msm_jpeg_start(pgmn_dev, (void __user *) arg, - msm_jpeg_ioctl_hw_cmds); - break; - - case MSM_JPEG_IOCTL_START32: - rc = msm_jpeg_start(pgmn_dev, (void __user *) arg, - msm_jpeg_ioctl_hw_cmds32); - break; - - case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: - rc = msm_jpeg_input_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32: - rc = msm_jpeg_get_jpeg_buf32(&jpeg_buf, (void __user *) arg); - if (rc < 0) - break; - set_fs(KERNEL_DS); - rc = msm_jpeg_input_buf_enqueue(pgmn_dev, - (void __user *) &jpeg_buf); - set_fs(old_fs); - break; - - case MSM_JPEG_IOCTL_INPUT_GET: - rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_GET32: - set_fs(KERNEL_DS); - rc = msm_jpeg_input_get(pgmn_dev, (void __user *) &jpeg_buf); - set_fs(old_fs); - if (rc < 0) - break; - rc = msm_jpeg_put_jpeg_buf32(&jpeg_buf, (void __user *) arg); - - break; - - case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: - rc = msm_jpeg_input_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: - rc = msm_jpeg_output_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32: - rc = msm_jpeg_get_jpeg_buf32(&jpeg_buf, (void __user *) arg); - if (rc < 0) - break; - set_fs(KERNEL_DS); - rc = msm_jpeg_output_buf_enqueue(pgmn_dev, - (void __user *) &jpeg_buf); - set_fs(old_fs); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET: - rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET32: - set_fs(KERNEL_DS); - rc = msm_jpeg_output_get(pgmn_dev, (void __user *) &jpeg_buf); - set_fs(old_fs); - if (rc < 0) - break; - rc = msm_jpeg_put_jpeg_buf32(&jpeg_buf, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: - rc = msm_jpeg_output_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_EVT_GET: - rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_EVT_GET32: - set_fs(KERNEL_DS); - rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) &ctrl_cmd); - set_fs(old_fs); - if (rc < 0) - break; - msm_jpeg_put_ctrl_cmd32(&ctrl_cmd, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: - rc = msm_jpeg_evt_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_HW_CMD32: - rc = msm_jpeg_ioctl_hw_cmd32(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_HW_CMD: - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_HW_CMDS32: - rc = msm_jpeg_ioctl_hw_cmds32(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_HW_CMDS: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_TEST_DUMP_REGION: - rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); - break; - - case MSM_JPEG_IOCTL_TEST_DUMP_REGION32: - rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); - break; - - case MSM_JPEG_IOCTL_SET_CLK_RATE: - rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, - (void __user *) arg); - break; - - default: - JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n", - __func__, __LINE__, _IOC_NR(cmd)); - rc = -EINVAL; - break; - } - return rc; -} -#else -long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg) -{ - return 0; -} -#endif - -long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg) -{ - int rc = 0; - - switch (cmd) { - case MSM_JPEG_IOCTL_GET_HW_VERSION: - JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_RESET: - rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_STOP: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - pgmn_dev->state = MSM_JPEG_STOPPED; - break; - - case MSM_JPEG_IOCTL_START: - rc = msm_jpeg_start(pgmn_dev, (void __user *) arg, - msm_jpeg_ioctl_hw_cmds); - break; - - case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: - rc = msm_jpeg_input_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_GET: - rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: - rc = msm_jpeg_input_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: - rc = msm_jpeg_output_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET: - rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: - rc = msm_jpeg_output_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_EVT_GET: - rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: - rc = msm_jpeg_evt_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_HW_CMD: - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_HW_CMDS: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_TEST_DUMP_REGION: - rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); - break; - - case MSM_JPEG_IOCTL_SET_CLK_RATE: - rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, (void __user *) arg); - break; - default: - pr_err_ratelimited("%s:%d] cmd = %d not supported\n", - __func__, __LINE__, _IOC_NR(cmd)); - rc = -EINVAL; - break; - } - return rc; -} - -int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev) -{ - int rc = 0; - int idx = 0; - - char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1", - "jpeg_dec", "jpeg_dma"}; - - - mutex_init(&pgmn_dev->lock); - - pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__, - pgmn_dev->pdev->id); - idx = pgmn_dev->pdev->id; - pgmn_dev->idx = idx; - pgmn_dev->decode_flag = (idx == JPEG_DEC_ID); - - msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q); - msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q); - msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q); - msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q); - msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q); - - /* get device context for IOMMU */ - rc = cam_smmu_get_handle(iommu_name[idx], &pgmn_dev->iommu_hdl); - JPEG_DBG("%s:%d] hdl %d", __func__, __LINE__, - pgmn_dev->iommu_hdl); - if (rc < 0) { - JPEG_PR_ERR("%s: No iommu fw context found\n", - __func__); - goto err_smmu; - } - - /* setup all the resources for the jpeg driver */ - rc = msm_jpeg_platform_setup(pgmn_dev); - if (rc < 0) { - JPEG_PR_ERR("%s: setup failed\n", - __func__); - goto err_setup; - } - - return rc; -err_setup: -err_smmu: - mutex_destroy(&pgmn_dev->lock); - return -EFAULT; -} - -int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev) -{ - msm_jpeg_platform_cleanup(pgmn_dev); - mutex_destroy(&pgmn_dev->lock); - kfree(pgmn_dev); - return 0; -} diff --git a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_sync.h deleted file mode 100644 index 1fe62a7b3555f11f53ad4f32873ee58ca750a5e4..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_10/msm_jpeg_sync.h +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_JPEG_SYNC_H -#define MSM_JPEG_SYNC_H - -#include -#include -#include -#include -#include -#include -#include "msm_camera_io_util.h" -#include "msm_jpeg_hw.h" -#include "cam_smmu_api.h" -#include "cam_soc_api.h" - -#define JPEG_8974_V1 0x10000000 -#define JPEG_8974_V2 0x10010000 -#define JPEG_8994 0x10020000 -#define JPEG_CLK_MAX 16 -#define JPEG_REGULATOR_MAX 3 - -enum msm_jpeg_state { - MSM_JPEG_INIT, - MSM_JPEG_RESET, - MSM_JPEG_EXECUTING, - MSM_JPEG_STOPPED, - MSM_JPEG_IDLE -}; - -enum msm_jpeg_core_type { - MSM_JPEG_CORE_CODEC, - MSM_JPEG_CORE_DMA -}; - -struct msm_jpeg_q { - char const *name; - struct list_head q; - spinlock_t lck; - wait_queue_head_t wait; - int unblck; -}; - -struct msm_jpeg_q_entry { - struct list_head list; - void *data; -}; - -struct msm_jpeg_device { - struct platform_device *pdev; - struct resource *jpeg_irq_res; - void *base; - void *vbif_base; - struct clk **jpeg_clk; - struct msm_cam_clk_info *jpeg_clk_info; - size_t num_clk; - int num_reg; - struct msm_cam_regulator *jpeg_vdd; - uint32_t hw_version; - - struct device *device; - struct cdev cdev; - struct mutex lock; - char open_count; - uint8_t op_mode; - - /* Flag to store the jpeg bus vote state - */ - int jpeg_bus_vote; - - /* event queue including frame done & err indications - */ - struct msm_jpeg_q evt_q; - - /* output return queue - */ - struct msm_jpeg_q output_rtn_q; - - /* output buf queue - */ - struct msm_jpeg_q output_buf_q; - - /* input return queue - */ - struct msm_jpeg_q input_rtn_q; - - /* input buf queue - */ - struct msm_jpeg_q input_buf_q; - - struct v4l2_subdev subdev; - - struct class *msm_jpeg_class; - - dev_t msm_jpeg_devno; - - /* iommu domain and context */ - int idx; - int iommu_hdl; - int decode_flag; - void *jpeg_vbif; - int release_buf; - struct msm_jpeg_hw_pingpong fe_pingpong_buf; - struct msm_jpeg_hw_pingpong we_pingpong_buf; - int we_pingpong_index; - int reset_done_ack; - spinlock_t reset_lock; - wait_queue_head_t reset_wait; - uint32_t res_size; - enum msm_jpeg_state state; - enum msm_jpeg_core_type core_type; - enum cam_bus_client bus_client; -}; - -int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev); -int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev); - -long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg); - -#ifdef CONFIG_COMPAT -long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg); -#endif - -int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev); -int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev); - -#endif /* MSM_JPEG_SYNC_H */ diff --git a/drivers/media/platform/msm/ais/jpeg_dma/Makefile b/drivers/media/platform/msm/ais/jpeg_dma/Makefile deleted file mode 100644 index a3311efa6ab1d9231d448b7f8779b38b68a9b3c7..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_dma/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) -ccflags-y += -Idrivers/media/video/msm -ccflags-y += -Idrivers/media/platform/msm/ais/common -obj-$(CONFIG_MSM_AIS_JPEGDMA) += msm_jpeg_dma_dev.o msm_jpeg_dma_hw.o diff --git a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_dev.h b/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_dev.h deleted file mode 100644 index ebdaf345121b5a810f62d028571fc3f292c373f0..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_dev.h +++ /dev/null @@ -1,374 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_JPEG_DMA_DEV_H__ -#define __MSM_JPEG_DMA_DEV_H__ - -#include -#include -#include -#include -#include "cam_soc_api.h" - -/* Max number of clocks defined in device tree */ -#define MSM_JPEGDMA_MAX_CLK 10 -/* Core clock index */ -#define MSM_JPEGDMA_CORE_CLK 0 -/* Max number of regulators defined in device tree */ -#define MSM_JPEGDMA_MAX_REGULATOR_NUM 3 -/* Max number of planes supported */ -#define MSM_JPEGDMA_MAX_PLANES 3 -/* Max number of hw pipes supported */ -#define MSM_JPEGDMA_MAX_PIPES 2 -/* Max number of hw configurations supported */ -#define MSM_JPEGDMA_MAX_CONFIGS 2 -/* Dma default fps */ -#define MSM_JPEGDMA_DEFAULT_FPS 30 - -/* Dma input output size limitations */ -#define MSM_JPEGDMA_MAX_WIDTH 65536 -#define MSM_JPEGDMA_MIN_WIDTH 32 -#define MSM_JPEGDMA_MAX_HEIGHT 65536 -#define MSM_JPEGDMA_MIN_HEIGHT 32 -#define MSM_JPEGDMA_STRIDE_ALIGN 8 - -/* - * enum msm_jpegdma_plane_type - Dma format. - * @JPEGDMA_PLANE_TYPE_Y: Y plane type. - * @JPEGDMA_PLANE_TYPE_CR: Chroma CB plane. - * @JPEGDMA_PLANE_TYPE_CB: Chroma CR plane. - * @JPEGDMA_PLANE_TYPE_CBCR: Interlevaed CbCr plane. - */ -enum msm_jpegdma_plane_type { - JPEGDMA_PLANE_TYPE_Y, - JPEGDMA_PLANE_TYPE_CR, - JPEGDMA_PLANE_TYPE_CB, - JPEGDMA_PLANE_TYPE_CBCR, -}; - -/* - * struct msm_jpegdma_format - Dma format. - * @name: Format name. - * @fourcc: v4l2 fourcc code. - * @depth: Number of bits per pixel. - * @num_planes: number of planes. - * @colplane_h: Color plane horizontal subsample. - * @colplane_v: Color plane vertical subsample. - * @h_align: Horizontal align. - * @v_align: Vertical align. - * @planes: Array with plane types. - */ -struct msm_jpegdma_format { - char *name; - u32 fourcc; - int depth; - int num_planes; - int colplane_h; - int colplane_v; - int h_align; - int v_align; - enum msm_jpegdma_plane_type planes[MSM_JPEGDMA_MAX_PLANES]; -}; - -/* - * struct msm_jpegdma_size - Dma size. - * @top: Top position. - * @left: Left position - * @width: Width - * @height: height. - * @scanline: Number of lines per plane. - * @stride: Stride bytes per line. - */ -struct msm_jpegdma_size { - unsigned int top; - unsigned int left; - unsigned int width; - unsigned int height; - unsigned int scanline; - unsigned int stride; -}; - -/* - * struct msm_jpegdma_size_config - Dma engine size configuration. - * @in_size: Input size. - * @out_size: Output size. - * @format: Format. - * @fps: Requested frames per second. - */ -struct msm_jpegdma_size_config { - struct msm_jpegdma_size in_size; - struct msm_jpegdma_size out_size; - struct msm_jpegdma_format format; - unsigned int fps; -}; - -/* - * struct msm_jpegdma_block - Dma hw block. - * @div: Block divider. - * @width: Block width. - * @reg_val: Block register value. - */ -struct msm_jpegdma_block { - unsigned int div; - unsigned int width; - unsigned int reg_val; -}; - -/* - * struct msm_jpegdma_block_config - Dma hw block configuration. - * @block: Block settings. - * @blocks_per_row: Blocks per row. - * @blocks_per_col: Blocks per column. - * @h_step: Horizontal step value - * @v_step: Vertical step value - * @h_step_last: Last horizontal step. - * @v_step_last: Last vertical step. - */ -struct msm_jpegdma_block_config { - struct msm_jpegdma_block block; - unsigned int blocks_per_row; - unsigned int blocks_per_col; - unsigned int h_step; - unsigned int v_step; - unsigned int h_step_last; - unsigned int v_step_last; -}; - -/* - * msm_jpegdma_scale - Dma hw scale configuration. - * @enable: Scale enable. - * @hor_scale: Horizontal scale factor in Q21 format. - * @ver_scale: Vertical scale factor in Q21 format. - */ -struct msm_jpegdma_scale { - int enable; - unsigned int hor_scale; - unsigned int ver_scale; -}; - -/* - * struct msm_jpegdma_config - Dma hw configuration. - * @size_cfg: Size configuration. - * @scale_cfg: Scale configuration - * @block_cfg: Block configuration. - * @phase: Starting phase. - * @in_offset: Input offset. - * @out_offset: Output offset. - */ -struct msm_jpegdma_config { - struct msm_jpegdma_size_config size_cfg; - struct msm_jpegdma_scale scale_cfg; - struct msm_jpegdma_block_config block_cfg; - unsigned int phase; - unsigned int in_offset; - unsigned int out_offset; -}; - -/* - * struct msm_jpegdma_plane_config - Contain input output address. - * @bus_ab: Bus average bandwidth. - * @bus_ib: Bus instantaneous bandwidth. - * @core_clock: Core clock freq. - */ -struct msm_jpegdma_speed { - u64 bus_ab; - u64 bus_ib; - u64 core_clock; -}; - -/* - * struct msm_jpegdma_plane_config - Contain input output address. - * @active_pipes: Number of active pipes. - * @config: Plane configurations. - * @type: Plane type. - */ -struct msm_jpegdma_plane { - unsigned int active_pipes; - struct msm_jpegdma_config config[MSM_JPEGDMA_MAX_PIPES]; - enum msm_jpegdma_plane_type type; -}; - -/* - * struct msm_jpegdma_plane_config - Contain input output address. - * @num_planes: Number of planes. - * @plane: Plane configuration. - * @speed: Processing speed. - */ -struct msm_jpegdma_plane_config { - unsigned int num_planes; - struct msm_jpegdma_plane plane[MSM_JPEGDMA_MAX_PLANES]; - struct msm_jpegdma_speed speed; -}; - -/* - * struct msm_jpegdma_addr - Contain input output address. - * @in_addr: Input dma address. - * @out_addr: Output dma address. - */ -struct msm_jpegdma_addr { - u32 in_addr; - u32 out_addr; -}; - -/* - * struct msm_jpegdma_buf_handle - Structure contain dma buffer information. - * @fd: ion dma from which this buffer is imported. - * @dma: Pointer to jpeg dma device. - * @size: Size of the buffer. - * @addr: Adders of dma mmu mapped buffer. This address should be set to dma hw. - */ -struct msm_jpegdma_buf_handle { - int fd; - struct msm_jpegdma_device *dma; - unsigned long size; - ion_phys_addr_t addr; -}; - -/* - * @jpegdma_ctx - Structure contains per open file handle context. - * @lock: Lock protecting dma ctx. - * @jdma_device: Pointer to dma device. - * @active: Set if context is active. - * @completion: Context processing completion. - * @fh: V4l2 file handle. - * @m2m_ctx: Memory to memory context. - * @format_cap: Current capture format. - * @format_out: Current output format. - * @crop: Current crop. - * @timeperframe: Time per frame in seconds. - * @config_idx: Plane configuration active index. - * @plane_config: Array of plane configurations. - * @pending_config: Flag set if there is pending plane configuration. - * @plane_idx: Processing plane index. - * @format_idx: Current format index. - */ -struct jpegdma_ctx { - struct mutex lock; - struct msm_jpegdma_device *jdma_device; - atomic_t active; - struct completion completion; - struct v4l2_fh fh; - struct v4l2_m2m_ctx *m2m_ctx; - struct v4l2_format format_cap; - struct v4l2_format format_out; - struct v4l2_rect crop; - struct v4l2_fract timeperframe; - - unsigned int config_idx; - struct msm_jpegdma_plane_config plane_config[MSM_JPEGDMA_MAX_CONFIGS]; - unsigned int pending_config; - - unsigned int plane_idx; - unsigned int format_idx; -}; - -/* - * struct jpegdma_reg_cfg - Registry values configuration - * @reg: Register offset. - * @val: Register value. - */ -struct jpegdma_reg_cfg { - unsigned int reg; - unsigned int val; -}; - -/* - * enum msm_jpegdma_mem_resources - jpegdma device iomem resources. - * @MSM_JPEGDMA_IOMEM_CORE: Index of jpegdma core registers. - * @MSM_JPEGDMA_IOMEM_VBIF: Index of jpegdma vbif registers. - * @MSM_JPEGDMA_IOMEM_LAST: Not valid. - */ -enum msm_jpegdma_mem_resources { - MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_IOMEM_VBIF, - MSM_JPEGDMA_IOMEM_LAST -}; - -/* - * struct msm_jpegdma_device - FD device structure. - * @lock: Lock protecting dma device. - * @ref_count: Device reference count. - * @irq_num: Face detection irq number. - * @res_mem: Array of memory resources used by Dma device. - * @iomem_base: Array of register mappings used by Dma device. - * @ioarea: Array of register ioarea used by Dma device. - * @vdd: Pointer to vdd regulator. - * @regulator_num: Number of regulators attached to the device. - * @clk_num: Number of clocks attached to the device. - * @clk: Array of clock resources used by dma device. - * @clk_rates: Array of clock rates. - * @vbif_regs_num: number of vbif regs. - * @vbif_regs: Array of vbif regs need to be set. - * @qos_regs_num: Number of qos regs . - * @qos_regs: Array of qos regs need to be set. - * @bus_client: Memory access bus client. - * @bus_vectors: Bus vector - * @bus_paths: Bus path. - * @bus_scale_data: Memory access bus scale data. - * @iommu_hndl: Dma device iommu handle. - * @iommu_attached_cnt: Iommu attached devices reference count. - * @iommu_dev: Pointer to Ion iommu device. - * @dev: Pointer to device struct. - * @v4l2_dev: V4l2 device. - * @video: Video device. - * @m2m_dev: Memory to memory device. - * @hw_num_pipes: Number of dma hw pipes. - * @active_clock_rate: Active clock rate index. - * @hw_reset_completion: Dma reset completion. - * @hw_halt_completion: Dma halt completion. - */ -struct msm_jpegdma_device { - struct mutex lock; - int ref_count; - - int irq_num; - void __iomem *iomem_base[MSM_JPEGDMA_IOMEM_LAST]; - - struct resource *irq; - struct msm_cam_regulator *dma_vdd; - int num_reg; - - struct clk **clk; - size_t num_clk; - struct msm_cam_clk_info *jpeg_clk_info; - - unsigned int vbif_regs_num; - struct jpegdma_reg_cfg *vbif_regs; - unsigned int qos_regs_num; - struct jpegdma_reg_cfg *qos_regs; - unsigned int prefetch_regs_num; - struct jpegdma_reg_cfg *prefetch_regs; - - enum cam_bus_client bus_client; - struct msm_bus_vectors bus_vectors; - struct msm_bus_paths bus_paths; - struct msm_bus_scale_pdata bus_scale_data; - - int iommu_hndl; - unsigned int iommu_attached_cnt; - - struct device *iommu_dev; - struct device *dev; - struct v4l2_device v4l2_dev; - struct video_device video; - struct v4l2_m2m_dev *m2m_dev; - - int hw_num_pipes; - struct completion hw_reset_completion; - struct completion hw_halt_completion; - u64 active_clock_rate; - struct platform_device *pdev; -}; - -void msm_jpegdma_isr_processing_done(struct msm_jpegdma_device *dma); - -#endif /* __MSM_JPEG_DMA_DEV_H__ */ diff --git a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_hw.c deleted file mode 100644 index 6ede5535e1ea1fe68d24cb905e325f8975da5ae3..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_hw.c +++ /dev/null @@ -1,1774 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_camera_io_util.h" -#include "cam_smmu_api.h" -#include "msm_jpeg_dma_dev.h" -#include "msm_jpeg_dma_hw.h" -#include "msm_jpeg_dma_regs.h" - -/* Jpeg dma scale unity */ -#define MSM_JPEGDMA_SCALE_UNI (1 << 21) -/* Jpeg dma bw numerator */ -#define MSM_JPEGDMA_BW_NUM 38 -/* Jpeg dma bw denominator */ -#define MSM_JPEGDMA_BW_DEN 10 -/* Jpeg bus client name */ -#define MSM_JPEGDMA_BUS_CLIENT_NAME "msm_jpeg_dma" -/* Jpeg dma engine timeout in ms */ -#define MSM_JPEGDMA_TIMEOUT_MS 500 -/* Jpeg dma smmu name */ -#define MSM_JPEGDMA_SMMU_NAME "jpeg_dma" - -static const struct msm_jpegdma_block msm_jpegdma_block_sel[] = { - { - .div = 0x3C0000, - .width = 256, - .reg_val = 4, - }, - { - .div = 0x7C0000, - .width = 128, - .reg_val = 3, - }, - { - .div = 0xFC0000, - .width = 64, - .reg_val = 2, - }, - { - .div = 0x1FC0000, - .width = 32, - .reg_val = 1, - }, - { - .div = 0x4000000, - .width = 16, - .reg_val = 0, - }, -}; - -/* - * msm_jpegdma_hw_read_reg - dma read from register. - * @dma: Pointer to dma device. - * @base_idx: dma memory resource index. - * @reg: Register addr need to be read from. - */ -static inline u32 msm_jpegdma_hw_read_reg(struct msm_jpegdma_device *dma, - enum msm_jpegdma_mem_resources base_idx, u32 reg) -{ - return msm_camera_io_r(dma->iomem_base[base_idx] + reg); -} - -/* - * msm_jpegdma_hw_write_reg - dma write to register. - * @dma: Pointer to dma device. - * @base_idx: dma memory resource index. - * @reg: Register addr need to be read from. - * @value: Value to be written. - */ -static inline void msm_jpegdma_hw_write_reg(struct msm_jpegdma_device *dma, - enum msm_jpegdma_mem_resources base_idx, u32 reg, u32 value) -{ - pr_debug("%s:%d]%pK %08x\n", __func__, __LINE__, - dma->iomem_base[base_idx] + reg, - value); - msm_camera_io_w(value, dma->iomem_base[base_idx] + reg); -} - -/* - * msm_jpegdma_hw_enable_irq - Enable dma interrupts. - * @dma: Pointer to dma device. - */ -static void msm_jpegdma_hw_enable_irq(struct msm_jpegdma_device *dma) -{ - u32 reg; - - reg = MSM_JPEGDMA_IRQ_MASK_SESSION_DONE | - MSM_JPEGDMA_IRQ_MASK_AXI_HALT | - MSM_JPEGDMA_IRQ_MASK_RST_DONE; - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_IRQ_MASK_ADDR, reg); -} - -/* - * msm_jpegdma_hw_disable_irq - Disable dma interrupts. - * @dma: Pointer to dma device. - */ -static void msm_jpegdma_hw_disable_irq(struct msm_jpegdma_device *dma) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_IRQ_MASK_ADDR, 0); -} - -/* - * msm_jpegdma_hw_clear_irq - Clear dma interrupts. - * @dma: Pointer to dma device. - * @status: Status to clear. - */ -static void msm_jpegdma_hw_clear_irq(struct msm_jpegdma_device *dma, - u32 status) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_IRQ_CLEAR_ADDR, status); -} - -/* - * msm_jpegdma_hw_get_irq_status - Get dma irq status - * @dma: Pointer to dma device. - */ -static u32 msm_jpegdma_hw_get_irq_status(struct msm_jpegdma_device *dma) -{ - return msm_jpegdma_hw_read_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_IRQ_STATUS); -} - -/* - * msm_jpegdma_hw_get_num_pipes - Get number of dma pipes - * @dma: Pointer to dma device. - */ -static int msm_jpegdma_hw_get_num_pipes(struct msm_jpegdma_device *dma) -{ - int num_pipes; - u32 reg; - - reg = msm_jpegdma_hw_read_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_HW_CAPABILITY); - - num_pipes = (reg & MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_BMSK) >> - MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_SHFT; - - return num_pipes; -} - -/* - * msm_jpegdma_hw_reset - Reset jpeg dma core. - * @dma: Pointer to dma device. - */ -static int msm_jpegdma_hw_reset(struct msm_jpegdma_device *dma) -{ - unsigned long time; - - init_completion(&dma->hw_reset_completion); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_HW_JPEGDMA_RESET, MSM_HW_JPEGDMA_RESET_DEFAULT); - - time = wait_for_completion_timeout(&dma->hw_reset_completion, - msecs_to_jiffies(MSM_JPEGDMA_TIMEOUT_MS)); - if (!time) { - dev_err(dma->dev, "Jpeg dma detection reset timeout\n"); - return -ETIME; - } - return 0; -} - -/* -* msm_jpegdma_hw_halt - Halt jpeg dma core. -* @dma: Pointer to dma device. -*/ -static int msm_jpegdma_hw_halt(struct msm_jpegdma_device *dma) -{ - unsigned long time; - - init_completion(&dma->hw_halt_completion); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_CMD_ADDR, 0x4); - - time = wait_for_completion_timeout(&dma->hw_halt_completion, - msecs_to_jiffies(MSM_JPEGDMA_TIMEOUT_MS)); - if (!time) { - dev_err(dma->dev, "Jpeg dma detection halt timeout\n"); - return -ETIME; - } - return 0; -} - -/* -* msm_jpegdma_hw_run - Enable dma processing. -* @dma: Pointer to dma device. -*/ -static int msm_jpegdma_hw_run(struct msm_jpegdma_device *dma) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_CMD_ADDR, 0x1); - - return 0; -} - -/* - * msm_jpegdma_hw_core_config - Set jpeg dma core configuration. - * @dma: Pointer to dma device. - * @num_pipes: Number of pipes. - * @scale_0: Scaler 0 enable. - * @scale_1: Scaler 1 enable. - */ -static int msm_jpegdma_hw_core_config(struct msm_jpegdma_device *dma, - int num_pipes, int scale_0, int scale_1) -{ - u32 reg; - - reg = (scale_0 << MSM_JPEGDMA_CORE_CFG_SCALE_0_ENABLE_SHFT) | - (0x1 << MSM_JPEGDMA_CORE_CFG_TEST_BUS_ENABLE_SHFT) | - (0x1 << MSM_JPEGDMA_CORE_CFG_BRIDGE_ENABLE_SHFT) | - (0x1 << MSM_JPEGDMA_CORE_CFG_WE_0_ENABLE_SHFT) | - (0x1 << MSM_JPEGDMA_CORE_CFG_FE_0_ENABLE_SHFT); - - /* Enable read write ports for second pipe */ - if (num_pipes > 1) { - reg |= (scale_1 << MSM_JPEGDMA_CORE_CFG_SCALE_1_ENABLE_SHFT) | - (0x1 << MSM_JPEGDMA_CORE_CFG_WE_1_ENABLE_SHFT) | - (0x1 << MSM_JPEGDMA_CORE_CFG_FE_1_ENABLE_SHFT); - } - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_CORE_CFG_ADDR, reg); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_0_block - Fetch engine 0 block configuration. - * @dma: Pointer to dma device. - * @block_config: Pointer to block configuration. - * @plane_type: Plane type. - */ -static int msm_jpegdma_hw_fe_0_block(struct msm_jpegdma_device *dma, - struct msm_jpegdma_block_config *block_config, - enum msm_jpegdma_plane_type plane_type) -{ - u32 reg; - - switch (plane_type) { - case JPEGDMA_PLANE_TYPE_Y: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_Y << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - case JPEGDMA_PLANE_TYPE_CB: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CB << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - case JPEGDMA_PLANE_TYPE_CR: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CR << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - case JPEGDMA_PLANE_TYPE_CBCR: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CBCR << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - default: - dev_err(dma->dev, "Unsupported plane type %d\n", plane_type); - return -EINVAL; - } - - reg |= (block_config->block.reg_val << - MSM_JPEGDMA_FE_CFG_BLOCK_WIDTH_SHFT) | - (0x1 << MSM_JPEGDMA_FE_CFG_MAL_BOUNDARY_SHFT) | - (0x1 << MSM_JPEGDMA_FE_CFG_MAL_EN_SHFT) | - (0xF << MSM_JPEGDMA_FE_CFG_BURST_LENGTH_MAX_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_0_CFG_ADDR, reg); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_1_block - Fetch engine 1 block configuration. - * @dma: Pointer to dma device. - * @block_config: Pointer to block configuration. - * @plane_type: Plane type. - */ -static int msm_jpegdma_hw_fe_1_block(struct msm_jpegdma_device *dma, - struct msm_jpegdma_block_config *block_config, - enum msm_jpegdma_plane_type plane_type) -{ - u32 reg; - - switch (plane_type) { - case JPEGDMA_PLANE_TYPE_Y: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_Y << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - case JPEGDMA_PLANE_TYPE_CB: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CB << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - case JPEGDMA_PLANE_TYPE_CR: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CR << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - case JPEGDMA_PLANE_TYPE_CBCR: - reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CBCR << - MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT; - break; - default: - dev_err(dma->dev, "Unsupported plane type %d\n", plane_type); - return -EINVAL; - } - - reg |= (block_config->block.reg_val << - MSM_JPEGDMA_FE_CFG_BLOCK_WIDTH_SHFT) | - (0xF << MSM_JPEGDMA_FE_CFG_BURST_LENGTH_MAX_SHFT) | - (0x1 << MSM_JPEGDMA_FE_CFG_MAL_EN_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_1_CFG_ADDR, reg); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_0_phase - Fetch engine 0 phase configuration. - * @dma: Pointer to dma device. - * @phase: Fetch engine 0 phase. - */ -static int msm_jpegdma_hw_fe_0_phase(struct msm_jpegdma_device *dma, int phase) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_HINIT_ADDR, 0x00); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR, 0x00); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR, 0x00); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR, phase); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_1_phase - Fetch engine 1 phase configuration. - * @dma: Pointer to dma device. - * @phase: Fetch engine 1 phase. - */ -static int msm_jpegdma_hw_fe_1_phase(struct msm_jpegdma_device *dma, int phase) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_HINIT_ADDR, 0x00); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR, 0x00); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR, 0x00); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR, phase); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_0_size - Fetch engine 0 size configuration. - * @dma: Pointer to dma device. - * @size: Pointer to size configuration. - * @plane_type: Plane type. - */ -static int msm_jpegdma_hw_fe_0_size(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size *size, enum msm_jpegdma_plane_type plane_type) -{ - u32 reg; - - reg = (size->width + size->left - 1) | - ((size->height + size->top - 1) << - MSM_JPEGDMA_FE_RD_BUFFER_SIZE_HEIGHT_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_BUFFER_SIZE_0_ADDR, reg); - - if (size->left && plane_type == JPEGDMA_PLANE_TYPE_CBCR) - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR, size->left / 2); - else - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR, size->left); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR, size->top); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_STRIDE_ADDR, size->stride); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_1_size - Fetch engine 1 size configuration. - * @dma: Pointer to dma device. - * @size: Pointer to size configuration. - * @plane_type: Plane type. - */ -static int msm_jpegdma_hw_fe_1_size(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size *size, enum msm_jpegdma_plane_type plane_type) -{ - u32 reg; - - reg = (size->width + size->left - 1) | - ((size->height + size->top - 1) << - MSM_JPEGDMA_FE_RD_BUFFER_SIZE_HEIGHT_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_BUFFER_SIZE_1_ADDR, reg); - - if (size->left && plane_type == JPEGDMA_PLANE_TYPE_CBCR) - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR, size->left / 2); - else - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR, size->left); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR, size->top); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_STRIDE_ADDR, size->stride); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_0_addr - Set fetch engine 0 address. - * @dma: Pointer to dma device. - * @addr: Fetch engine address. - */ -static int msm_jpegdma_hw_fe_0_addr(struct msm_jpegdma_device *dma, u32 addr) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_CMD_ADDR, MSM_JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_0_PNTR_ADDR, addr); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_1_addr - Set fetch engine 1 address. - * @dma: Pointer to dma device. - * @addr: Fetch engine address. - */ -static int msm_jpegdma_hw_fe_1_addr(struct msm_jpegdma_device *dma, u32 addr) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_FE_RD_1_PNTR_ADDR, addr); - - return 0; -} - -/* - * msm_jpegdma_hw_fe_0_block - Write engine 0 block configuration. - * @dma: Pointer to dma device. - * @block_config: Pointer to block configuration. - * @plane_type: Plane type. - */ -static int msm_jpegdma_hw_we_0_block(struct msm_jpegdma_device *dma, - struct msm_jpegdma_block_config *block, - enum msm_jpegdma_plane_type plane_type) -{ - u32 reg; - - reg = (0xF << MSM_JPEGDMA_WE_CFG_BURST_LENGTH_MAX_SHFT) | - (0x1 << MSM_JPEGDMA_WE_CFG_MAL_BOUNDARY_SHFT) | - (0x1 << MSM_JPEGDMA_WE_CFG_MAL_EN_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_CFG_ADDR, reg); - - reg = ((block->blocks_per_row - 1) << - MSM_JPEGDMA_WE_PLN_WR_CFG_0_BLOCKS_PER_ROW_SHFT) | - (block->blocks_per_col - 1); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_0_WR_CFG_0_ADDR, reg); - - reg = ((block->h_step_last - 1) << - MSM_JPEGDMA_WE_PLN_WR_CFG_1_LAST_H_STEP_SHFT) | - (block->h_step - 1); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_0_WR_CFG_1_ADDR, reg); - - reg = ((block->v_step_last - 1) << - MSM_JPEGDMA_WE_PLN_WR_CFG_2_LAST_V_STEP_SHFT) | - (block->v_step - 1); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_0_WR_CFG_2_ADDR, reg); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_0_WR_CFG_3_ADDR, 0x0); - - return 0; -} - -/* - * msm_jpegdma_hw_we_1_block - Write engine 1 block configuration. - * @dma: Pointer to dma device. - * @block_config: Pointer to block configuration. - * @plane_type: Plane type. - */ -static int msm_jpegdma_hw_we_1_block(struct msm_jpegdma_device *dma, - struct msm_jpegdma_block_config *block, - enum msm_jpegdma_plane_type plane_type) -{ - u32 reg; - - reg = ((block->blocks_per_row - 1) << - MSM_JPEGDMA_WE_PLN_WR_CFG_0_BLOCKS_PER_ROW_SHFT) | - (block->blocks_per_col - 1); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_1_WR_CFG_0_ADDR, reg); - - reg = ((block->h_step_last - 1) << - MSM_JPEGDMA_WE_PLN_WR_CFG_1_LAST_H_STEP_SHFT) | - (block->h_step - 1); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_1_WR_CFG_1_ADDR, reg); - - reg = ((block->v_step_last - 1) << - MSM_JPEGDMA_WE_PLN_WR_CFG_2_LAST_V_STEP_SHFT) | - (block->v_step - 1); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_1_WR_CFG_2_ADDR, reg); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_1_WR_CFG_3_ADDR, 0x0); - - return 0; -} - -/* - * msm_jpegdma_hw_we_0_size - Write engine 0 size configuration. - * @dma: Pointer to dma device. - * @size: Pointer to size configuration. - */ -static int msm_jpegdma_hw_we_0_size(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size *size) -{ - u32 reg; - - reg = (size->width) | ((size->height) << - MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_HEIGHT_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_0_ADDR, reg); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_0_WR_STRIDE_ADDR, size->stride); - - return 0; -} - -/* - * msm_jpegdma_hw_we_1_size - Write engine 1 size configuration. - * @dma: Pointer to dma device. - * @size: Pointer to size configuration. - */ -static int msm_jpegdma_hw_we_1_size(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size *size) -{ - u32 reg; - - reg = (size->width) | ((size->height) << - MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_HEIGHT_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_1_ADDR, reg); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_1_WR_STRIDE_ADDR, size->stride); - - return 0; -} - -/* - * msm_jpegdma_hw_we_0_addr - Set write engine 0 address. - * @dma: Pointer to dma device. - * @addr: Fetch engine address. - */ -static int msm_jpegdma_hw_we_0_addr(struct msm_jpegdma_device *dma, u32 addr) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_CMD_ADDR, MSM_JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_0_WR_PNTR_ADDR, addr); - - return 0; -} - -/* - * msm_jpegdma_hw_we_1_addr - Set write engine 1 address. - * @dma: Pointer to dma device. - * @addr: Fetch engine address. - */ -static int msm_jpegdma_hw_we_1_addr(struct msm_jpegdma_device *dma, u32 addr) -{ - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_WE_PLN_1_WR_PNTR_ADDR, addr); - - return 0; -} - -/* - * msm_jpegdma_hw_scale_0_config - Scale configuration for 0 pipeline. - * @dma: Pointer to dma device. - * @scale: Scale configuration. - */ -static int msm_jpegdma_hw_scale_0_config(struct msm_jpegdma_device *dma, - struct msm_jpegdma_scale *scale) -{ - u32 reg; - u32 h_down_en; - u32 v_down_en; - - h_down_en = (scale->hor_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1; - v_down_en = (scale->ver_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1; - - reg = (h_down_en << MSM_JPEGDMA_PP_SCALE_CFG_HSCALE_ENABLE_SHFT) | - (v_down_en << MSM_JPEGDMA_PP_SCALE_CFG_VSCALE_ENABLE_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_PP_0_SCALE_CFG_ADDR, reg); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_PP_0_SCALE_PHASEH_STEP_ADDR, scale->hor_scale); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_PP_0_SCALE_PHASEV_STEP_ADDR, scale->ver_scale); - - return 0; -} - -/* - * msm_jpegdma_hw_scale_1_config - Scale configuration for 1 pipeline. - * @dma: Pointer to dma device. - * @scale: Scale configuration. - */ -static int msm_jpegdma_hw_scale_1_config(struct msm_jpegdma_device *dma, - struct msm_jpegdma_scale *scale) -{ - u32 reg; - u32 h_down_en; - u32 v_down_en; - - h_down_en = (scale->hor_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1; - v_down_en = (scale->ver_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1; - - reg = (h_down_en << MSM_JPEGDMA_PP_SCALE_CFG_HSCALE_ENABLE_SHFT) | - (v_down_en << MSM_JPEGDMA_PP_SCALE_CFG_VSCALE_ENABLE_SHFT); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_PP_1_SCALE_CFG_ADDR, reg); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_PP_1_SCALE_PHASEH_STEP_ADDR, scale->hor_scale); - - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_PP_1_SCALE_PHASEV_STEP_ADDR, scale->ver_scale); - - return 0; -} - -/* - * msm_jpegdma_hw_config_qos - Configure qos registers. - * @dma: Pointer to dma device. - */ -static void msm_jpegdma_hw_config_qos(struct msm_jpegdma_device *dma) -{ - int i; - - if (!dma->qos_regs_num) - return; - - for (i = 0; i < dma->qos_regs_num; i++) - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - dma->qos_regs[i].reg, dma->qos_regs[i].val); -} - -/* - * msm_jpegdma_hw_config_vbif - Configure and vbif interface. - * @dma: Pointer to dma device. - */ -static void msm_jpegdma_hw_config_vbif(struct msm_jpegdma_device *dma) -{ - int i; - - if (!dma->vbif_regs_num) - return; - - for (i = 0; i < dma->vbif_regs_num; i++) - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_VBIF, - dma->vbif_regs[i].reg, dma->vbif_regs[i].val); -} - -/* - * msm_jpegdma_hw_config_mmu_prefetch - Configure mmu prefetch registers. - * @dma: Pointer to dma device. - * @min_addr: Pointer to jpeg dma addr, containing min addrs of the plane. - * @max_addr: Pointer to jpeg dma addr, containing max addrs of the plane. - */ -static void msm_jpegdma_hw_config_mmu_prefetch(struct msm_jpegdma_device *dma, - struct msm_jpegdma_addr *min_addr, - struct msm_jpegdma_addr *max_addr) -{ - int i; - - if (!dma->prefetch_regs_num) - return; - - for (i = 0; i < dma->prefetch_regs_num; i++) - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_VBIF, - dma->prefetch_regs[i].reg, dma->prefetch_regs[i].val); - - if (min_addr != NULL && max_addr != NULL) { - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN, min_addr->in_addr); - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX, max_addr->in_addr); - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN, min_addr->out_addr); - msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE, - MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX, max_addr->out_addr); - } -} - -/* -* msm_jpegdma_hw_calc_speed - Calculate speed based on framerate and size. -* @dma: Pointer to dma device. -* @size: Dma user size configuration. -* @speed: Calculated speed. -*/ -static int msm_jpegdma_hw_calc_speed(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size_config *size, - struct msm_jpegdma_speed *speed) -{ - u64 width; - u64 height; - u64 real_clock; - u64 calc_rate; - - width = size->in_size.width + size->in_size.left; - height = size->in_size.height + size->in_size.top; - - calc_rate = (width * height * size->format.depth * size->fps) / 16; - real_clock = clk_round_rate(dma->clk[MSM_JPEGDMA_CORE_CLK], calc_rate); - if (real_clock < 0) { - dev_err(dma->dev, "Can not round core clock\n"); - return -EINVAL; - } - - speed->bus_ab = calc_rate * 2; - speed->bus_ib = (real_clock * - (MSM_JPEGDMA_BW_NUM + MSM_JPEGDMA_BW_DEN - 1)) / - MSM_JPEGDMA_BW_DEN; - speed->core_clock = real_clock; - dev_dbg(dma->dev, "Speed core clk %llu ab %llu ib %llu fps %d\n", - speed->core_clock, speed->bus_ab, speed->bus_ib, size->fps); - - return 0; -} - -/* -* msm_jpegdma_hw_set_speed - Configure clock and bus bandwidth based on -* requested speed and dma clients. -* @size: Jpeg dma size configuration. -* @speed: Requested dma speed. -*/ -static int msm_jpegdma_hw_set_speed(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size_config *size, - struct msm_jpegdma_speed *speed) -{ - struct msm_jpegdma_speed new_sp; - struct msm_jpegdma_size_config new_size; - int ret; - - if (dma->active_clock_rate >= speed->core_clock) - return 0; - - new_sp = *speed; - if (dma->ref_count > 2) { - new_size = *size; - new_size.fps = size->fps * ((dma->ref_count + 1) / 2); - ret = msm_jpegdma_hw_calc_speed(dma, &new_size, &new_sp); - if (ret < 0) - return -EINVAL; - } - - ret = clk_set_rate(dma->clk[MSM_JPEGDMA_CORE_CLK], new_sp.core_clock); - if (ret < 0) { - dev_err(dma->dev, "Fail Core clock rate %d\n", ret); - return -EINVAL; - } - dma->active_clock_rate = speed->core_clock; - - dma->bus_vectors.ab = new_sp.bus_ab; - dma->bus_vectors.ib = new_sp.bus_ib; - - ret = msm_bus_scale_client_update_request(dma->bus_client, 0); - if (ret < 0) { - dev_err(dma->dev, "Fail bus scale update %d\n", ret); - return -EINVAL; - } - - return 0; -} - -/* -* msm_jpegdma_hw_add_plane_offset - Add plane offset to all pipelines. -* @plane: Jpeg dma plane configuration. -* @in_offset: Input plane offset. -* @out_offset: Output plane offset. -*/ -static int msm_jpegdma_hw_add_plane_offset(struct msm_jpegdma_plane *plane, - unsigned int in_offset, unsigned int out_offset) -{ - int i; - - for (i = 0; i < plane->active_pipes; i++) { - plane->config[i].in_offset += in_offset; - plane->config[i].out_offset += out_offset; - } - - return 0; -} - -/* -* msm_jpegdma_hw_calc_config - Calculate plane configuration. -* @size_cfg: Size configuration. -* @plane: Plane configuration need to be calculated. -*/ -static int msm_jpegdma_hw_calc_config(struct msm_jpegdma_size_config *size_cfg, - struct msm_jpegdma_plane *plane) -{ - u64 scale_hor, scale_ver, phase; - u64 in_width, in_height; - u64 out_width, out_height; - struct msm_jpegdma_config *config; - int i; - - if (!size_cfg->out_size.width || !size_cfg->out_size.height) - return -EINVAL; - - config = &plane->config[0]; - config->scale_cfg.enable = 0; - - in_width = size_cfg->in_size.width; - out_width = size_cfg->out_size.width; - scale_hor = (in_width * MSM_JPEGDMA_SCALE_UNI) / out_width; - if (scale_hor != MSM_JPEGDMA_SCALE_UNI) - config->scale_cfg.enable = 1; - - in_height = size_cfg->in_size.height; - out_height = size_cfg->out_size.height; - scale_ver = (in_height * MSM_JPEGDMA_SCALE_UNI) / out_height; - if (scale_ver != MSM_JPEGDMA_SCALE_UNI) - config->scale_cfg.enable = 1; - - config->scale_cfg.ver_scale = scale_ver; - config->scale_cfg.hor_scale = scale_hor; - - for (i = 0; ARRAY_SIZE(msm_jpegdma_block_sel); i++) - if (scale_hor <= msm_jpegdma_block_sel[i].div) - break; - - if (i == ARRAY_SIZE(msm_jpegdma_block_sel)) - return -EINVAL; - - config->block_cfg.block = msm_jpegdma_block_sel[i]; - - if (plane->active_pipes > 1) { - phase = (out_height * scale_ver + (plane->active_pipes - 1)) / - plane->active_pipes; - phase &= (MSM_JPEGDMA_SCALE_UNI - 1); - out_height = (out_height + (plane->active_pipes - 1)) / - plane->active_pipes; - in_height = (out_height * scale_ver) / MSM_JPEGDMA_SCALE_UNI; - } - - config->block_cfg.blocks_per_row = out_width / - config->block_cfg.block.width; - - config->block_cfg.blocks_per_col = out_height; - - config->block_cfg.h_step = config->block_cfg.block.width; - - config->block_cfg.h_step_last = out_width % - config->block_cfg.block.width; - if (!config->block_cfg.h_step_last) - config->block_cfg.h_step_last = config->block_cfg.h_step; - else - config->block_cfg.blocks_per_row++; - - config->block_cfg.v_step = 1; - config->block_cfg.v_step_last = 1; - - config->size_cfg = *size_cfg; - config->size_cfg.in_size.width = in_width; - config->size_cfg.in_size.height = in_height; - config->size_cfg.out_size.width = out_width; - config->size_cfg.out_size.height = out_height; - config->in_offset = 0; - config->out_offset = 0; - - if (plane->active_pipes > 1) { - plane->config[1] = *config; - /* Recalculate offset for second pipe */ - plane->config[1].in_offset = - config->size_cfg.in_size.scanline * - config->size_cfg.in_size.stride; - - plane->config[1].out_offset = - config->size_cfg.out_size.scanline * - config->size_cfg.out_size.stride; - - plane->config[1].phase = phase; - } - - return 0; -} - -/* -* msm_jpegdma_hw_check_config - Check configuration based on size is possible. - *@dma: Pointer to dma device. -* @size_cfg: Size configuration. -*/ -int msm_jpegdma_hw_check_config(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size_config *size_cfg) -{ - u64 in_width, in_height; - u64 out_width, out_height; - u64 scale; - - if (!size_cfg->out_size.width || !size_cfg->out_size.height) - return -EINVAL; - - in_width = size_cfg->in_size.width; - out_width = size_cfg->out_size.width; - scale = ((in_width * MSM_JPEGDMA_SCALE_UNI)) / out_width; - if (scale < MSM_JPEGDMA_SCALE_UNI) - return -EINVAL; - - - in_height = size_cfg->in_size.height; - out_height = size_cfg->out_size.height; - scale = (in_height * MSM_JPEGDMA_SCALE_UNI) / out_height; - if (scale < MSM_JPEGDMA_SCALE_UNI) - return -EINVAL; - - return 0; -} - -/* -* msm_jpegdma_hw_set_config - Set dma configuration based on size. - *@dma: Pointer to dma device. -* @size_cfg: Size configuration. -* @plane_cfg: Calculated plane configuration. -*/ -int msm_jpegdma_hw_set_config(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size_config *size_cfg, - struct msm_jpegdma_plane_config *plane_cfg) -{ - unsigned int in_offset; - unsigned int out_offset; - struct msm_jpegdma_size_config plane_size; - int ret; - int i; - - if (!size_cfg->format.colplane_h || !size_cfg->format.colplane_v) - return -EINVAL; - - ret = msm_jpegdma_hw_calc_speed(dma, size_cfg, &plane_cfg->speed); - if (ret < 0) - return -EINVAL; - - dma->active_clock_rate = 0; - - plane_cfg->plane[0].active_pipes = dma->hw_num_pipes; - plane_cfg->plane[0].type = size_cfg->format.planes[0]; - msm_jpegdma_hw_calc_config(size_cfg, &plane_cfg->plane[0]); - if (size_cfg->format.num_planes == 1) - return 0; - - in_offset = size_cfg->in_size.scanline * - size_cfg->in_size.stride; - out_offset = size_cfg->out_size.scanline * - size_cfg->out_size.stride; - - memset(&plane_size, 0x00, sizeof(plane_size)); - for (i = 1; i < size_cfg->format.num_planes; i++) { - plane_cfg->plane[i].active_pipes = dma->hw_num_pipes; - plane_cfg->plane[i].type = size_cfg->format.planes[i]; - - if (size_cfg->in_size.top) - plane_size.in_size.top = size_cfg->in_size.top / - size_cfg->format.colplane_v; - - if (size_cfg->in_size.left) - plane_size.in_size.left = size_cfg->in_size.left / - size_cfg->format.colplane_h; - - plane_size.in_size.width = size_cfg->in_size.width / - size_cfg->format.colplane_h; - plane_size.in_size.height = size_cfg->in_size.height / - size_cfg->format.colplane_v; - plane_size.in_size.scanline = size_cfg->in_size.scanline / - size_cfg->format.colplane_v; - - plane_size.in_size.stride = size_cfg->in_size.stride; - - plane_size.out_size.width = size_cfg->out_size.width / - size_cfg->format.colplane_h; - plane_size.out_size.height = size_cfg->out_size.height / - size_cfg->format.colplane_v; - plane_size.out_size.scanline = size_cfg->out_size.scanline / - size_cfg->format.colplane_v; - - plane_size.out_size.stride = size_cfg->out_size.stride; - - plane_size.format = size_cfg->format; - plane_size.fps = size_cfg->fps; - - msm_jpegdma_hw_calc_config(&plane_size, - &plane_cfg->plane[i]); - - msm_jpegdma_hw_add_plane_offset(&plane_cfg->plane[i], - in_offset, out_offset); - - in_offset += (plane_size.in_size.scanline * - plane_size.in_size.stride); - out_offset += (plane_size.out_size.scanline * - plane_size.out_size.stride); - } - return 0; -} - -/* -* msm_jpegdma_hw_start - Start dma processing. - *@dma: Pointer to dma device. -* @addr: Input address. -* @plane: Plane configuration. -* @speed: Clock and bus bandwidth configuration. -*/ -int msm_jpegdma_hw_start(struct msm_jpegdma_device *dma, - struct msm_jpegdma_addr *addr, - struct msm_jpegdma_plane *plane, - struct msm_jpegdma_speed *speed) -{ - struct msm_jpegdma_config *cfg; - struct msm_jpegdma_addr prefetch_max_addr; - unsigned int prefetch_in_size; - unsigned int prefetch_out_size; - - int ret; - - if (!plane->active_pipes) - return -EINVAL; - - if (plane->active_pipes > MSM_JPEGDMA_MAX_PIPES) - return -EINVAL; - ret = msm_jpegdma_hw_set_speed(dma, &plane->config[0].size_cfg, speed); - if (ret < 0) - return -EINVAL; - - msm_jpegdma_hw_core_config(dma, plane->active_pipes, - plane->config[0].scale_cfg.enable, - plane->config[1].scale_cfg.enable); - - cfg = &plane->config[0]; - msm_jpegdma_hw_scale_0_config(dma, &cfg->scale_cfg); - - msm_jpegdma_hw_fe_0_block(dma, &cfg->block_cfg, plane->type); - msm_jpegdma_hw_fe_0_phase(dma, cfg->phase); - msm_jpegdma_hw_fe_0_size(dma, &cfg->size_cfg.in_size, plane->type); - msm_jpegdma_hw_fe_0_addr(dma, addr->in_addr + cfg->in_offset); - prefetch_in_size = cfg->size_cfg.in_size.stride * - cfg->size_cfg.in_size.scanline; - - msm_jpegdma_hw_we_0_block(dma, &cfg->block_cfg, plane->type); - msm_jpegdma_hw_we_0_size(dma, &cfg->size_cfg.out_size); - msm_jpegdma_hw_we_0_addr(dma, addr->out_addr + cfg->out_offset); - prefetch_out_size = cfg->size_cfg.out_size.stride * - cfg->size_cfg.out_size.scanline; - - if (plane->active_pipes > 1) { - cfg = &plane->config[1]; - msm_jpegdma_hw_scale_1_config(dma, &cfg->scale_cfg); - - msm_jpegdma_hw_fe_1_block(dma, &cfg->block_cfg, plane->type); - msm_jpegdma_hw_fe_1_phase(dma, cfg->phase); - msm_jpegdma_hw_fe_1_size(dma, &cfg->size_cfg.in_size, - plane->type); - msm_jpegdma_hw_fe_1_addr(dma, addr->in_addr + cfg->in_offset); - prefetch_in_size += (cfg->size_cfg.in_size.stride * - cfg->size_cfg.in_size.scanline); - - msm_jpegdma_hw_we_1_block(dma, &cfg->block_cfg, plane->type); - msm_jpegdma_hw_we_1_size(dma, &cfg->size_cfg.out_size); - msm_jpegdma_hw_we_1_addr(dma, addr->out_addr + cfg->out_offset); - prefetch_out_size += (cfg->size_cfg.out_size.stride * - cfg->size_cfg.out_size.scanline); - } - - if (prefetch_in_size > 0 && prefetch_out_size > 0) { - prefetch_max_addr.in_addr = addr->in_addr + - (prefetch_in_size - 1); - prefetch_max_addr.out_addr = addr->out_addr + - (prefetch_out_size - 1); - msm_jpegdma_hw_config_mmu_prefetch(dma, addr, - &prefetch_max_addr); - } - - msm_jpegdma_hw_run(dma); - - return 1; -} - -/* -* msm_jpegdma_hw_abort - abort dma processing. - *@dma: Pointer to dma device. -*/ -int msm_jpegdma_hw_abort(struct msm_jpegdma_device *dma) -{ - int ret; - - ret = msm_jpegdma_hw_halt(dma); - if (ret < 0) { - dev_err(dma->dev, "Fail to halt hw\n"); - return ret; - } - - ret = msm_jpegdma_hw_reset(dma); - if (ret < 0) { - dev_err(dma->dev, "Fail to reset hw\n"); - return ret; - } - return 0; -} - -/* - * msm_jpegdma_hw_irq - Dma irq handler. - * @irq: Irq number. - * @dev_id: Pointer to dma device. - */ -static irqreturn_t msm_jpegdma_hw_irq(int irq, void *dev_id) -{ - struct msm_jpegdma_device *dma = dev_id; - - u32 irq_status; - - irq_status = msm_jpegdma_hw_get_irq_status(dma); - msm_jpegdma_hw_clear_irq(dma, irq_status); - - if (irq_status & MSM_JPEGDMA_IRQ_STATUS_RST_DONE) { - dev_dbg(dma->dev, "Jpeg v4l2 dma IRQ reset done\n"); - complete_all(&dma->hw_reset_completion); - } - - if (irq_status & MSM_JPEGDMA_IRQ_STATUS_AXI_HALT) { - dev_dbg(dma->dev, "Jpeg v4l2 dma IRQ AXI halt\n"); - complete_all(&dma->hw_halt_completion); - } - - if (irq_status & MSM_JPEGDMA_IRQ_STATUS_SESSION_DONE) { - dev_dbg(dma->dev, "Jpeg v4l2 dma IRQ session done\n"); - msm_jpegdma_isr_processing_done(dma); - } - - return IRQ_HANDLED; -} - -/* - * msm_jpegdma_hw_request_irq - Request dma irq. - * @pdev: Pointer to platform device. - * @dma: Pointer to dma device. - */ -int msm_jpegdma_hw_request_irq(struct platform_device *pdev, - struct msm_jpegdma_device *dma) -{ - int ret; - - dma->irq_num = platform_get_irq(pdev, 0); - if (dma->irq_num < 0) { - dev_err(dma->dev, "Can not get dma core irq resource\n"); - ret = -ENODEV; - goto error_irq; - } - - ret = request_threaded_irq(dma->irq_num, NULL, - msm_jpegdma_hw_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, - dev_name(&pdev->dev), dma); - if (ret) { - dev_err(dma->dev, "Can not claim wrapper IRQ %d\n", - dma->irq_num); - goto error_irq; - } - - return 0; - -error_irq: - return ret; -} - -/* - * msm_jpegdma_hw_release_mem_resources - Releases memory resources. - * @dma: Pointer to dma device. - */ -void msm_jpegdma_hw_release_mem_resources(struct msm_jpegdma_device *dma) -{ - int i, reserve_mem_flag; - char *dev_name; - - /* Prepare memory resources */ - for (i = 0; i < MSM_JPEGDMA_IOMEM_LAST; i++) { - - switch (i) { - case MSM_JPEGDMA_IOMEM_CORE: - dev_name = "jpeg_hw"; - reserve_mem_flag = true; - break; - case MSM_JPEGDMA_IOMEM_VBIF: - dev_name = "jpeg_vbif"; - reserve_mem_flag = false; - break; - default: - pr_err("%s: Invalid device : %d\n", __func__, i); - return; - } - /* release the device address */ - msm_camera_put_reg_base(dma->pdev, dma->iomem_base[i], dev_name, - reserve_mem_flag); - } -} - -/* - * msm_jpegdma_hw_get_mem_resources - Get memory resources. - * @pdev: Pointer to dma platform device. - * @dma: Pointer to dma device. - * - * Get and ioremap platform memory resources. - */ -int msm_jpegdma_hw_get_mem_resources(struct platform_device *pdev, - struct msm_jpegdma_device *dma) -{ - int i; - int ret = 0; - char *dev_name; - int reserve_mem_flag; - - /* Prepare memory resources */ - for (i = 0; i < MSM_JPEGDMA_IOMEM_LAST; i++) { - - switch (i) { - case MSM_JPEGDMA_IOMEM_CORE: - dev_name = "jpeg_hw"; - reserve_mem_flag = true; - break; - case MSM_JPEGDMA_IOMEM_VBIF: - dev_name = "jpeg_vbif"; - reserve_mem_flag = false; - break; - default: - pr_err("%s: Invalid device : %d\n", __func__, i); - return -EINVAL; - } - /* get the device address base */ - dma->iomem_base[i] = - msm_camera_get_reg_base(pdev, dev_name, - reserve_mem_flag); - if (!dma->iomem_base[i]) { - dev_err(dma->dev, "%s can not remap region\n", - dev_name); - ret = -ENODEV; - break; - } - } - - if (ret < 0) - msm_jpegdma_hw_release_mem_resources(dma); - - return ret; -} - -/* - * msm_jpegdma_hw_get_qos - Get dma qos settings from device-tree. - * @dma: Pointer to dma device. - */ -int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma) -{ - int i; - int ret; - unsigned int cnt; - const void *property; - - property = of_get_property(dma->dev->of_node, "qcom,qos-regs", &cnt); - if (!property || !cnt) { - dev_dbg(dma->dev, "Missing qos settings\n"); - return 0; - } - cnt /= 4; - - dma->qos_regs = kzalloc((sizeof(*dma->qos_regs) * cnt), GFP_KERNEL); - if (!dma->qos_regs) - return -ENOMEM; - - for (i = 0; i < cnt; i++) { - ret = of_property_read_u32_index(dma->dev->of_node, - "qcom,qos-regs", i, - &dma->qos_regs[i].reg); - if (ret < 0) { - dev_err(dma->dev, "can not read qos reg %d\n", i); - goto error; - } - - ret = of_property_read_u32_index(dma->dev->of_node, - "qcom,qos-settings", i, - &dma->qos_regs[i].val); - if (ret < 0) { - dev_err(dma->dev, "can not read qos setting %d\n", i); - goto error; - } - dev_dbg(dma->dev, "Qos idx %d, reg %x val %x\n", i, - dma->qos_regs[i].reg, dma->qos_regs[i].val); - } - dma->qos_regs_num = cnt; - - return 0; -error: - kfree(dma->qos_regs); - dma->qos_regs = NULL; - - return ret; -} - -/* - * msm_jpegdma_hw_put_qos - Free dma qos settings. - * @dma: Pointer to dma device. - */ -void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma) -{ - kfree(dma->qos_regs); - dma->qos_regs = NULL; -} - -/* - * msm_jpegdma_hw_get_vbif - Get dma vbif settings from device-tree. - * @dma: Pointer to dma device. - */ -int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma) -{ - int i; - int ret; - unsigned int cnt; - const void *property; - - property = of_get_property(dma->dev->of_node, "qcom,vbif-regs", &cnt); - if (!property || !cnt) { - dev_dbg(dma->dev, "Missing vbif settings\n"); - return 0; - } - cnt /= 4; - - dma->vbif_regs = kzalloc((sizeof(*dma->vbif_regs) * cnt), GFP_KERNEL); - if (!dma->vbif_regs) - return -ENOMEM; - - for (i = 0; i < cnt; i++) { - ret = of_property_read_u32_index(dma->dev->of_node, - "qcom,vbif-regs", i, - &dma->vbif_regs[i].reg); - if (ret < 0) { - dev_err(dma->dev, "can not read vbif reg %d\n", i); - goto error; - } - - ret = of_property_read_u32_index(dma->dev->of_node, - "qcom,vbif-settings", i, - &dma->vbif_regs[i].val); - if (ret < 0) { - dev_err(dma->dev, "can not read vbif setting %d\n", i); - goto error; - } - - dev_dbg(dma->dev, "Vbif idx %d, reg %x val %x\n", i, - dma->vbif_regs[i].reg, dma->vbif_regs[i].val); - } - dma->vbif_regs_num = cnt; - - return 0; -error: - kfree(dma->vbif_regs); - dma->vbif_regs = NULL; - - return ret; -} - -/* - * msm_jpegdma_hw_put_vbif - Put dma clocks. - * @dma: Pointer to dma device. - */ -void msm_jpegdma_hw_put_vbif(struct msm_jpegdma_device *dma) -{ - kfree(dma->vbif_regs); - dma->vbif_regs = NULL; -} - -/* - * msm_jpegdma_hw_get_prefetch - Get dma prefetch settings from device-tree. - * @dma: Pointer to dma device. - */ -int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma) -{ - int i; - int ret; - unsigned int cnt; - const void *property; - - property = of_get_property(dma->dev->of_node, "qcom,prefetch-regs", - &cnt); - if (!property || !cnt) { - dev_dbg(dma->dev, "Missing prefetch settings\n"); - return 0; - } - cnt /= 4; - - dma->prefetch_regs = kcalloc(cnt, sizeof(*dma->prefetch_regs), - GFP_KERNEL); - if (!dma->prefetch_regs) - return -ENOMEM; - - for (i = 0; i < cnt; i++) { - ret = of_property_read_u32_index(dma->dev->of_node, - "qcom,prefetch-regs", i, - &dma->prefetch_regs[i].reg); - if (ret < 0) { - dev_err(dma->dev, "can not read prefetch reg %d\n", i); - goto error; - } - - ret = of_property_read_u32_index(dma->dev->of_node, - "qcom,prefetch-settings", i, - &dma->prefetch_regs[i].val); - if (ret < 0) { - dev_err(dma->dev, "can not read prefetch setting %d\n", - i); - goto error; - } - - dev_dbg(dma->dev, "Prefetch idx %d, reg %x val %x\n", i, - dma->prefetch_regs[i].reg, dma->prefetch_regs[i].val); - } - dma->prefetch_regs_num = cnt; - - return 0; -error: - kfree(dma->prefetch_regs); - dma->prefetch_regs = NULL; - - return ret; -} - -/* - * msm_jpegdma_hw_put_prefetch - free prefetch settings. - * @dma: Pointer to dma device. - */ -void msm_jpegdma_hw_put_prefetch(struct msm_jpegdma_device *dma) -{ - kfree(dma->prefetch_regs); - dma->prefetch_regs = NULL; -} - -/* - * msm_jpegdma_hw_get_capabilities - Get dma hw for performing any hw operation. - * @dma: Pointer to dma device. - */ -int msm_jpegdma_hw_get_capabilities(struct msm_jpegdma_device *dma) -{ - int ret = 0; - - mutex_lock(&dma->lock); - - /* enable all the regulators */ - ret = msm_camera_regulator_enable(dma->dma_vdd, - dma->num_reg, true); - if (ret < 0) { - dev_err(dma->dev, "Fail to enable regulators\n"); - goto error_regulators_get; - } - - /* enable all the clocks */ - ret = msm_camera_clk_enable(&dma->pdev->dev, - dma->jpeg_clk_info, dma->clk, - dma->num_clk, true); - if (ret < 0) { - dev_err(dma->dev, "Fail to enable clocks\n"); - goto error_clocks; - } - - dma->hw_num_pipes = msm_jpegdma_hw_get_num_pipes(dma); - - /* disable all the clocks */ - msm_camera_clk_enable(&dma->pdev->dev, - dma->jpeg_clk_info, dma->clk, - dma->num_clk, false); - /* disable all the regulators */ - msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); - - mutex_unlock(&dma->lock); - - return 0; - -error_clocks: - msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); -error_regulators_get: - mutex_unlock(&dma->lock); - return ret; -} - -/* - * msm_jpegdma_hw_get - Get dma hw for performing any hw operation. - * @dma: Pointer to dma device. - * @clock_rate_idx: Clock rate index. - * - * Prepare dma hw for operation. Have reference count protected by - * dma device mutex. - */ -int msm_jpegdma_hw_get(struct msm_jpegdma_device *dma) -{ - int ret; - - mutex_lock(&dma->lock); - if (dma->ref_count == 0) { - - dev_dbg(dma->dev, "msm_jpegdma_hw_get E\n"); - /* enable all the regulators */ - ret = msm_camera_regulator_enable(dma->dma_vdd, - dma->num_reg, true); - if (ret < 0) { - dev_err(dma->dev, "Fail to enable regulators\n"); - goto error_regulators_get; - } - - /* enable all the clocks */ - ret = msm_camera_clk_enable(&dma->pdev->dev, - dma->jpeg_clk_info, dma->clk, - dma->num_clk, true); - if (ret < 0) { - dev_err(dma->dev, "Fail to enable clocks\n"); - goto error_clocks; - } - - /* update the bus vector with valid bw */ - msm_camera_update_bus_vector(dma->bus_client, 1); - msm_jpegdma_hw_config_qos(dma); - msm_jpegdma_hw_config_vbif(dma); - - msm_jpegdma_hw_enable_irq(dma); - - ret = msm_jpegdma_hw_reset(dma); - if (ret < 0) { - dev_err(dma->dev, "Fail to reset hw\n"); - goto error_hw_reset; - } - msm_jpegdma_hw_config_qos(dma); - msm_jpegdma_hw_config_mmu_prefetch(dma, NULL, NULL); - msm_jpegdma_hw_enable_irq(dma); - } - dma->ref_count++; - dev_dbg(dma->dev, "msm_jpegdma_hw_get X\n"); - mutex_unlock(&dma->lock); - - return 0; - -error_hw_reset: - msm_jpegdma_hw_disable_irq(dma); - msm_camera_clk_enable(&dma->pdev->dev, dma->jpeg_clk_info, - dma->clk, dma->num_clk, false); -error_clocks: - msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); -error_regulators_get: - mutex_unlock(&dma->lock); - return ret; -} - -/* - * msm_jpegdma_hw_put - Put dma hw. - * @dma: Pointer to dma device. - * - * Release dma hw. Have reference count protected by - * dma device mutex. - */ -void msm_jpegdma_hw_put(struct msm_jpegdma_device *dma) -{ - mutex_lock(&dma->lock); - BUG_ON(dma->ref_count == 0); - - if (--dma->ref_count == 0) { - msm_jpegdma_hw_halt(dma); - msm_jpegdma_hw_disable_irq(dma); - /* release the irq */ - msm_camera_unregister_irq(dma->pdev, - dma->irq, dma); - /* update the bus vector with zeroth vector */ - msm_camera_update_bus_vector(dma->bus_client, 0); - /* disable all the clocks */ - msm_camera_clk_enable(&dma->pdev->dev, dma->jpeg_clk_info, - dma->clk, dma->num_clk, false); - /* disable all the regulators */ - msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false); - } - /* Reset clock rate, need to be updated on next processing */ - dma->active_clock_rate = -1; - mutex_unlock(&dma->lock); -} - -/* - * msm_jpegdma_hw_attach_iommu - Attach iommu to jpeg dma engine. - * @dma: Pointer to dma device. - * - * Iommu attach have reference count protected by - * dma device mutex. - */ -static int msm_jpegdma_hw_attach_iommu(struct msm_jpegdma_device *dma) -{ - int ret; - - mutex_lock(&dma->lock); - - if (dma->iommu_attached_cnt == UINT_MAX) { - dev_err(dma->dev, "Max count reached! can not attach iommu\n"); - goto error; - } - - if (dma->iommu_attached_cnt == 0) { - ret = cam_smmu_get_handle(MSM_JPEGDMA_SMMU_NAME, - &dma->iommu_hndl); - if (ret < 0) { - dev_err(dma->dev, "Smmu get handle failed\n"); - ret = -ENOMEM; - goto error; - } - ret = cam_smmu_ops(dma->iommu_hndl, CAM_SMMU_ATTACH); - if (ret < 0) { - dev_err(dma->dev, "Can not attach smmu.\n"); - goto error_attach; - } - } - dma->iommu_attached_cnt++; - mutex_unlock(&dma->lock); - - return 0; -error_attach: - cam_smmu_destroy_handle(dma->iommu_hndl); -error: - mutex_unlock(&dma->lock); - return ret; -} - -/* - * msm_jpegdma_hw_detach_iommu - Detach iommu from jpeg dma engine. - * @dma: Pointer to dma device. - * - * Iommu detach have reference count protected by - * dma device mutex. - */ -static void msm_jpegdma_hw_detach_iommu(struct msm_jpegdma_device *dma) -{ - mutex_lock(&dma->lock); - if (dma->iommu_attached_cnt == 0) { - dev_err(dma->dev, "There is no attached device\n"); - mutex_unlock(&dma->lock); - return; - } - - if (--dma->iommu_attached_cnt == 0) { - cam_smmu_ops(dma->iommu_hndl, CAM_SMMU_DETACH); - cam_smmu_destroy_handle(dma->iommu_hndl); - } - mutex_unlock(&dma->lock); -} - -/* - * msm_jpegdma_hw_map_buffer - Map buffer to dma hw mmu. - * @dma: Pointer to dma device. - * @fd: Ion fd. - * @buf: dma buffer handle, for storing mapped buffer information. - * - * It will map ion fd to dma hw smmu. - */ -int msm_jpegdma_hw_map_buffer(struct msm_jpegdma_device *dma, int fd, - struct msm_jpegdma_buf_handle *buf) -{ - int ret; - - if (!dma || fd < 0) - return -EINVAL; - - ret = msm_jpegdma_hw_attach_iommu(dma); - if (ret < 0) - goto error; - - buf->dma = dma; - buf->fd = fd; - - ret = cam_smmu_get_phy_addr(dma->iommu_hndl, buf->fd, - CAM_SMMU_MAP_RW, &buf->addr, &buf->size); - if (ret < 0) { - dev_err(dma->dev, "Can not get physical address\n"); - goto error_get_phy; - } - - return buf->size; - -error_get_phy: - msm_jpegdma_hw_detach_iommu(dma); -error: - return -ENOMEM; -} - -/* - * msm_jpegdma_hw_unmap_buffer - Unmap buffer from dma hw mmu. - * @buf: dma buffer handle, for storing mapped buffer information. - */ -void msm_jpegdma_hw_unmap_buffer(struct msm_jpegdma_buf_handle *buf) -{ - if (buf->size && buf->dma) { - cam_smmu_put_phy_addr(buf->dma->iommu_hndl, - buf->fd); - msm_jpegdma_hw_detach_iommu(buf->dma); - buf->size = 0; - } - buf->fd = -1; - buf->dma = NULL; -} diff --git a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_hw.h b/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_hw.h deleted file mode 100644 index 60c2577034644dc434afa6d0d1379b3b161b5afc..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_hw.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_JPEG_DMA_HW_H__ -#define __MSM_JPEG_DMA_HW_H__ - -#include "msm_jpeg_dma_dev.h" - -int msm_jpegdma_hw_check_config(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size_config *size_cfg); - -int msm_jpegdma_hw_set_config(struct msm_jpegdma_device *dma, - struct msm_jpegdma_size_config *size_cfg, - struct msm_jpegdma_plane_config *plane_cfg); - -int msm_jpegdma_hw_start(struct msm_jpegdma_device *dma, - struct msm_jpegdma_addr *addr, - struct msm_jpegdma_plane *plane, - struct msm_jpegdma_speed *speed); - -int msm_jpegdma_hw_abort(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_update_bus_data(struct msm_jpegdma_device *dma, - u64 ab, u64 ib); - -int msm_jpegdma_hw_handle_irq(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_request_irq(struct platform_device *pdev, - struct msm_jpegdma_device *dma); - -void msm_jpegdma_hw_release_irq(struct msm_jpegdma_device *dma); - -void msm_jpegdma_hw_release_mem_resources(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get_mem_resources(struct platform_device *pdev, - struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get_regulators(struct msm_jpegdma_device *dma); - -void msm_jpegdma_hw_put_regulators(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get_clocks(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_put_clocks(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma); - -void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma); - -void msm_jpegdma_hw_put_vbif(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma); - -void msm_jpegdma_hw_put_prefetch(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get_capabilities(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_get(struct msm_jpegdma_device *dma); - -void msm_jpegdma_hw_put(struct msm_jpegdma_device *dma); - -int msm_jpegdma_hw_map_buffer(struct msm_jpegdma_device *dma, int fd, - struct msm_jpegdma_buf_handle *buf); - -void msm_jpegdma_hw_unmap_buffer(struct msm_jpegdma_buf_handle *buf); - -#endif /* __MSM_JPEG_DMA_HW_H__ */ diff --git a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_regs.h b/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_regs.h deleted file mode 100644 index 83a79717754f8e89ba9cb8e0febbeb85fa95a93b..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/jpeg_dma/msm_jpeg_dma_regs.h +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_JPEGDMA_REGS_H__ -#define __MSM_JPEGDMA_REGS_H__ - -#define MSM_JPEGDMA_HW_REVISION 0x00 -#define MSM_JPEGDMA_HW_CAPABILITY 0x04 -#define MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_BMSK 0x06 -#define MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_SHFT 0x01 - -#define MSM_JPEGDMA_IRQ_MASK_ADDR 0x0C -#define MSM_JPEGDMA_IRQ_MASK_SESSION_DONE (1 << 0) -#define MSM_JPEGDMA_IRQ_MASK_RD_BUF_DONE (1 << 1) -#define MSM_JPEGDMA_IRQ_MASK_WR_BUF_DONE (1 << 5) -#define MSM_JPEGDMA_IRQ_MASK_AXI_HALT (1 << 9) -#define MSM_JPEGDMA_IRQ_MASK_RST_DONE (1 << 10) - -#define MSM_JPEGDMA_IRQ_STATUS 0x10 -#define MSM_JPEGDMA_IRQ_STATUS_SESSION_DONE (1 << 0) -#define MSM_JPEGDMA_IRQ_STATUS_RD_BUF_DONE (1 << 1) -#define MSM_JPEGDMA_IRQ_STATUS_WR_BUF_DONE (1 << 5) -#define MSM_JPEGDMA_IRQ_STATUS_AXI_HALT (1 << 9) -#define MSM_JPEGDMA_IRQ_STATUS_RST_DONE (1 << 10) - -#define MSM_JPEGDMA_IRQ_CLEAR_ADDR 0x14 -#define MSM_JPEGDMA_IRQ_CLEAR_BMSK 0xFFFFFFFF - -#define MSM_JPEGDMA_CORE_CFG_ADDR 0x18 -#define MSM_JPEGDMA_CMD_ADDR 0x1C - -#define MSM_JPEGDMA_CORE_CFG_TEST_BUS_ENABLE_SHFT 19 -#define MSM_JPEGDMA_CORE_CFG_BRIDGE_ENABLE_SHFT 6 -#define MSM_JPEGDMA_CORE_CFG_SCALE_1_ENABLE_SHFT 5 -#define MSM_JPEGDMA_CORE_CFG_SCALE_0_ENABLE_SHFT 4 - -#define MSM_JPEGDMA_CORE_CFG_WE_1_ENABLE_SHFT 0x03 -#define MSM_JPEGDMA_CORE_CFG_WE_0_ENABLE_SHFT 0x02 -#define MSM_JPEGDMA_CORE_CFG_FE_1_ENABLE_SHFT 0x01 -#define MSM_JPEGDMA_CORE_CFG_FE_0_ENABLE_SHFT 0x00 - -#define MSM_JPEGDMA_FE_0_CFG_ADDR 0x2C -#define MSM_JPEGDMA_FE_1_CFG_ADDR 0x70 -#define MSM_JPEGDMA_FE_CFG_MAL_BOUNDARY_SHFT 25 -#define MSM_JPEGDMA_FE_CFG_MAL_EN_SHFT 21 -#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CBCR 0x03 -#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CR 0x02 -#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CB 0x01 -#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_Y 0x00 -#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT 19 -#define MSM_JPEGDMA_FE_CFG_BLOCK_WIDTH_SHFT 0x04 -#define MSM_JPEGDMA_FE_CFG_BURST_LENGTH_MAX_SHFT 0x00 - -#define MSM_JPEGDMA_FE_RD_0_PNTR_ADDR 0x34 -#define MSM_JPEGDMA_FE_RD_1_PNTR_ADDR 0x78 -#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_0_ADDR 0x44 -#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_1_ADDR 0x88 -#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_HEIGHT_SHFT 16 -#define MSM_JPEGDMA_FE_RD_0_STRIDE_ADDR 0x48 -#define MSM_JPEGDMA_FE_RD_1_STRIDE_ADDR 0x8C -#define MSM_JPEGDMA_FE_RD_0_HINIT_ADDR 0x4C -#define MSM_JPEGDMA_FE_RD_1_HINIT_ADDR 0x90 -#define MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR 0x50 -#define MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR 0x94 -#define MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR 0x58 -#define MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR 0x9C - -#define MSM_JPEGDMA_WE_CFG_ADDR 0xB8 -#define MSM_JPEGDMA_WE_CFG_MAL_BOUNDARY_SHFT 0x08 -#define MSM_JPEGDMA_WE_CFG_MAL_EN_SHFT 0x07 -#define MSM_JPEGDMA_WE_CFG_BURST_LENGTH_MAX_SHFT 0x00 -#define MSM_JPEGDMA_WE_PLN_0_WR_PNTR_ADDR 0xBC -#define MSM_JPEGDMA_WE_PLN_1_WR_PNTR_ADDR 0xEC -#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_0_ADDR 0xC4 -#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_1_ADDR 0xF4 -#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_HEIGHT_SHFT 16 -#define MSM_JPEGDMA_WE_PLN_0_WR_STRIDE_ADDR 0xC8 -#define MSM_JPEGDMA_WE_PLN_1_WR_STRIDE_ADDR 0xF8 -#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_0_ADDR 0xCC -#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_0_ADDR 0xFC -#define MSM_JPEGDMA_WE_PLN_WR_CFG_0_BLOCKS_PER_ROW_SHFT 16 -#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_1_ADDR 0xD0 -#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_1_ADDR 0x100 -#define MSM_JPEGDMA_WE_PLN_WR_CFG_1_LAST_H_STEP_SHFT 16 -#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_2_ADDR 0xD4 -#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_2_ADDR 0x104 -#define MSM_JPEGDMA_WE_PLN_WR_CFG_2_LAST_V_STEP_SHFT 16 -#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_3_ADDR 0xD8 -#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_3_ADDR 0x108 - -#define MSM_JPEGDMA_PP_0_SCALE_PHASEV_STEP_ADDR 0x19C -#define MSM_JPEGDMA_PP_1_SCALE_PHASEV_STEP_ADDR 0x1BC -#define MSM_JPEGDMA_PP_0_SCALE_PHASEH_STEP_ADDR 0x194 -#define MSM_JPEGDMA_PP_1_SCALE_PHASEH_STEP_ADDR 0x1B4 -#define MSM_JPEGDMA_PP_0_SCALE_CFG_ADDR 0x188 -#define MSM_JPEGDMA_PP_1_SCALE_CFG_ADDR 0x1A8 -#define MSM_JPEGDMA_PP_SCALE_CFG_VSCALE_ENABLE_SHFT 0x05 -#define MSM_JPEGDMA_PP_SCALE_CFG_HSCALE_ENABLE_SHFT 0x04 - -#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN 0x190 -#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX 0x198 -#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN 0x1A4 -#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX 0x1AC - -#define MSM_JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES 0x030 -#define MSM_JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES 0x300 - -#define MSM_HW_JPEGDMA_RESET 0x08 -#define MSM_HW_JPEGDMA_RESET_DEFAULT 0x32083 - -#define MSM_JPEGDMA_RESET_CMD_BMSK 0xFFFFFFFF - -#endif /* __MSM_JPEG_DMA_REGS_H__ */ diff --git a/drivers/media/platform/msm/ais/msm_buf_mgr/Makefile b/drivers/media/platform/msm/ais/msm_buf_mgr/Makefile deleted file mode 100644 index ec75622d193adc1179dbf92b8a8c617a4a634c35..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/msm_buf_mgr/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -obj-$(CONFIG_MSM_AIS) += msm_generic_buf_mgr.o diff --git a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c deleted file mode 100644 index 53904e3cd9626589c3463a2f9414fa39a66a9a34..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c +++ /dev/null @@ -1,892 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "CAM-BUFMGR %s:%d " fmt, __func__, __LINE__ - -#include "msm_generic_buf_mgr.h" - -static struct msm_buf_mngr_device *msm_buf_mngr_dev; - -struct v4l2_subdev *msm_buf_mngr_get_subdev(void) -{ - return &msm_buf_mngr_dev->subdev.sd; -} - -static int32_t msm_buf_mngr_hdl_cont_get_buf(struct msm_buf_mngr_device *dev, - struct msm_buf_mngr_info *buf_info) -{ - unsigned int i; - struct msm_buf_mngr_user_buf_cont_info *cbuf, *cont_save; - - list_for_each_entry_safe(cbuf, cont_save, &dev->cont_qhead, entry) { - if ((cbuf->sessid == buf_info->session_id) && - (cbuf->index == buf_info->index) && - (cbuf->strid == buf_info->stream_id)) { - buf_info->user_buf.buf_cnt = cbuf->paddr->buf_cnt; - if (buf_info->user_buf.buf_cnt > - MSM_CAMERA_MAX_USER_BUFF_CNT) { - pr_err("Invalid cnt%d,%d,%d\n", - cbuf->paddr->buf_cnt, - buf_info->session_id, - buf_info->stream_id); - return -EINVAL; - } - for (i = 0 ; i < buf_info->user_buf.buf_cnt; i++) { - buf_info->user_buf.buf_idx[i] = - cbuf->paddr->buf_idx[i]; - } - break; - } - } - return 0; -} - -static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev, - void __user *argp) -{ - unsigned long flags; - int32_t rc = 0; - struct msm_buf_mngr_info *buf_info = - (struct msm_buf_mngr_info *)argp; - struct msm_get_bufs *new_entry = - kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL); - - if (!new_entry) { - pr_err("%s:No mem\n", __func__); - return -ENOMEM; - } - INIT_LIST_HEAD(&new_entry->entry); - new_entry->vb2_buf = dev->vb2_ops.get_buf(buf_info->session_id, - buf_info->stream_id); - if (!new_entry->vb2_buf) { - pr_debug("%s:Get buf is null\n", __func__); - kfree(new_entry); - return -EINVAL; - } - new_entry->session_id = buf_info->session_id; - new_entry->stream_id = buf_info->stream_id; - new_entry->index = new_entry->vb2_buf->v4l2_buf.index; - spin_lock_irqsave(&dev->buf_q_spinlock, flags); - list_add_tail(&new_entry->entry, &dev->buf_qhead); - spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); - buf_info->index = new_entry->vb2_buf->v4l2_buf.index; - if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { - mutex_lock(&dev->cont_mutex); - if (!list_empty(&dev->cont_qhead)) { - rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info); - } else { - pr_err("Nothing mapped in user buf for %d,%d\n", - buf_info->session_id, buf_info->stream_id); - rc = -EINVAL; - } - mutex_unlock(&dev->cont_mutex); - } - return rc; -} - -static int32_t msm_buf_mngr_get_buf_by_idx(struct msm_buf_mngr_device *dev, - void *argp) -{ - unsigned long flags; - int32_t rc = 0; - struct msm_buf_mngr_info *buf_info = - (struct msm_buf_mngr_info *)argp; - struct msm_get_bufs *new_entry = - kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL); - - if (!new_entry) { - pr_err("%s:No mem\n", __func__); - return -ENOMEM; - } - if (!buf_info) { - kfree(new_entry); - return -EIO; - } - - INIT_LIST_HEAD(&new_entry->entry); - new_entry->vb2_buf = dev->vb2_ops.get_buf_by_idx(buf_info->session_id, - buf_info->stream_id, buf_info->index); - if (!new_entry->vb2_buf) { - pr_debug("%s:Get buf is null\n", __func__); - kfree(new_entry); - return -EINVAL; - } - new_entry->session_id = buf_info->session_id; - new_entry->stream_id = buf_info->stream_id; - new_entry->index = new_entry->vb2_buf->v4l2_buf.index; - spin_lock_irqsave(&dev->buf_q_spinlock, flags); - list_add_tail(&new_entry->entry, &dev->buf_qhead); - spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); - if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { - mutex_lock(&dev->cont_mutex); - if (!list_empty(&dev->cont_qhead)) { - rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info); - } else { - pr_err("Nothing mapped in user buf for %d,%d\n", - buf_info->session_id, buf_info->stream_id); - rc = -EINVAL; - } - mutex_unlock(&dev->cont_mutex); - } - return rc; -} - -static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev, - struct msm_buf_mngr_info *buf_info) -{ - unsigned long flags; - struct msm_get_bufs *bufs, *save; - int32_t ret = -EINVAL; - - spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); - list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { - if ((bufs->session_id == buf_info->session_id) && - (bufs->stream_id == buf_info->stream_id) && - (bufs->index == buf_info->index)) { - ret = buf_mngr_dev->vb2_ops.buf_done - (bufs->vb2_buf, - buf_info->session_id, - buf_info->stream_id, - buf_info->frame_id, - &buf_info->timestamp, - buf_info->reserved); - list_del_init(&bufs->entry); - kfree(bufs); - break; - } - } - spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); - return ret; -} - - -static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev, - struct msm_buf_mngr_info *buf_info) -{ - unsigned long flags; - struct msm_get_bufs *bufs, *save; - int32_t ret = -EINVAL; - - spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); - list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { - if ((bufs->session_id == buf_info->session_id) && - (bufs->stream_id == buf_info->stream_id) && - (bufs->index == buf_info->index)) { - ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf, - buf_info->session_id, buf_info->stream_id); - list_del_init(&bufs->entry); - kfree(bufs); - break; - } - } - spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); - return ret; -} - -static int32_t msm_generic_buf_mngr_flush( - struct msm_buf_mngr_device *buf_mngr_dev, - struct msm_buf_mngr_info *buf_info) -{ - unsigned long flags; - struct msm_get_bufs *bufs, *save; - int32_t ret = -EINVAL; - struct timeval ts; - - spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); - /* - * Sanity check on client buf list, remove buf mgr - * queue entries in case any - */ - list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { - if ((bufs->session_id == buf_info->session_id) && - (bufs->stream_id == buf_info->stream_id)) { - ret = buf_mngr_dev->vb2_ops.buf_done(bufs->vb2_buf, - buf_info->session_id, - buf_info->stream_id, 0, &ts, 0); - pr_err("Bufs not flushed: str_id = %d buf_index = %d ret = %d\n", - buf_info->stream_id, bufs->vb2_buf->v4l2_buf.index, - ret); - list_del_init(&bufs->entry); - kfree(bufs); - } - } - spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); - /* Flush the remaining vb2 buffers in stream list */ - ret = buf_mngr_dev->vb2_ops.flush_buf(buf_info->session_id, - buf_info->stream_id); - return ret; -} - -static int32_t msm_buf_mngr_find_cont_stream(struct msm_buf_mngr_device *dev, - uint32_t *cnt, uint32_t *tstream, - struct msm_sd_close_ioctl *session) -{ - struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save; - int32_t ret = -1; - - list_for_each_entry_safe(cont_bufs, - cont_save, &dev->cont_qhead, entry) { - if (cont_bufs->sessid == session->session) { - *cnt = cont_bufs->cnt; - *tstream = cont_bufs->strid; - return 0; - } - } - return ret; -} - -static void msm_buf_mngr_contq_listdel(struct msm_buf_mngr_device *dev, - uint32_t session, int32_t stream, - bool unmap, uint32_t cnt) -{ - struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save; - - list_for_each_entry_safe(cont_bufs, - cont_save, &dev->cont_qhead, entry) { - if ((cont_bufs->sessid == session) && - (cont_bufs->strid == stream)) { - if ((cnt == 1) && (unmap == 1)) { - ion_unmap_kernel(dev->ion_client, - cont_bufs->ion_handle); - ion_free(dev->ion_client, - cont_bufs->ion_handle); - } - list_del_init(&cont_bufs->entry); - kfree(cont_bufs); - cnt--; - } - } - if (cnt != 0) - pr_err("Buffers pending cnt = %d\n", cnt); -} - -static void msm_buf_mngr_contq_cleanup(struct msm_buf_mngr_device *dev, - struct msm_sd_close_ioctl *session) -{ - int32_t stream = -1, found = -1; - uint32_t cnt = 0; - - do { - found = msm_buf_mngr_find_cont_stream(dev, &cnt, - &stream, session); - if (found == -1) - break; - msm_buf_mngr_contq_listdel(dev, session->session, - stream, 1, cnt); - } while (found == 0); -} - -static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *dev, - struct msm_sd_close_ioctl *session) -{ - unsigned long flags; - struct msm_get_bufs *bufs, *save; - - if (WARN_ON(!dev) || WARN_ON(!session)) - return; - - spin_lock_irqsave(&dev->buf_q_spinlock, flags); - if (!list_empty(&dev->buf_qhead)) { - list_for_each_entry_safe(bufs, - save, &dev->buf_qhead, entry) { - pr_info("%s: Delete invalid bufs =%pK, session_id=%u, bufs->ses_id=%d, str_id=%d, idx=%d\n", - __func__, (void *)bufs, session->session, - bufs->session_id, bufs->stream_id, - bufs->index); - if (session->session == bufs->session_id) { - list_del_init(&bufs->entry); - kfree(bufs); - } - } - } - spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); - mutex_lock(&dev->cont_mutex); - if (!list_empty(&dev->cont_qhead)) - msm_buf_mngr_contq_cleanup(dev, session); - mutex_unlock(&dev->cont_mutex); -} - -static int msm_buf_mngr_handle_cont_cmd(struct msm_buf_mngr_device *dev, - struct msm_buf_mngr_main_cont_info - *cont_cmd) -{ - int rc = 0, i = 0; - struct ion_handle *ion_handle = NULL; - struct msm_camera_user_buf_cont_t *iaddr, *temp_addr; - struct msm_buf_mngr_user_buf_cont_info *new_entry, *bufs, *save; - size_t size; - - if ((cont_cmd->cmd >= MSM_CAMERA_BUF_MNGR_CONT_MAX) || - (cont_cmd->cmd < 0) || - (cont_cmd->cnt > VB2_MAX_FRAME) || - (cont_cmd->cont_fd < 0)) { - pr_debug("Invalid arg passed Cmd:%d, cnt:%d, fd:%d\n", - cont_cmd->cmd, cont_cmd->cnt, - cont_cmd->cont_fd); - return -EINVAL; - } - - mutex_lock(&dev->cont_mutex); - - if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_MAP) { - if (!list_empty(&dev->cont_qhead)) { - list_for_each_entry_safe(bufs, - save, &dev->cont_qhead, entry) { - if ((bufs->sessid == cont_cmd->session_id) && - (bufs->strid == cont_cmd->stream_id)) { - pr_err("Map exist %d,%d unmap first\n", - cont_cmd->session_id, - cont_cmd->stream_id); - rc = -EINVAL; - goto end; - } - } - } - ion_handle = ion_import_dma_buf(dev->ion_client, - cont_cmd->cont_fd); - if (IS_ERR_OR_NULL(ion_handle)) { - pr_err("Failed to create ion handle for fd %d\n", - cont_cmd->cont_fd); - rc = -EINVAL; - goto end; - } - if (ion_handle_get_size(dev->ion_client, - ion_handle, &size) < 0) { - pr_err("Get ion size failed\n"); - rc = -EINVAL; - goto free_ion_handle; - } - if ((size == 0) || (size < - (sizeof(struct msm_camera_user_buf_cont_t) * - cont_cmd->cnt))) { - pr_err("Invalid or zero size ION buffer %zu\n", size); - rc = -EINVAL; - goto free_ion_handle; - } - iaddr = ion_map_kernel(dev->ion_client, ion_handle); - if (IS_ERR_OR_NULL(iaddr)) { - pr_err("Mapping cont buff failed\n"); - rc = -EINVAL; - goto free_ion_handle; - } - for (i = 0; i < cont_cmd->cnt; i++) { - temp_addr = iaddr + i; - if (temp_addr->buf_cnt > - MSM_CAMERA_MAX_USER_BUFF_CNT) { - pr_err("%s:Invalid buf_cnt:%d for cont:%d\n", - __func__, temp_addr->buf_cnt, i); - rc = -EINVAL; - goto free_list; - } - new_entry = kzalloc(sizeof( - struct msm_buf_mngr_user_buf_cont_info), - GFP_KERNEL); - if (!new_entry) { - pr_err("%s:No mem\n", __func__); - rc = -ENOMEM; - goto free_list; - } - INIT_LIST_HEAD(&new_entry->entry); - new_entry->sessid = cont_cmd->session_id; - new_entry->strid = cont_cmd->stream_id; - new_entry->index = i; - new_entry->main_fd = cont_cmd->cont_fd; - new_entry->ion_handle = ion_handle; - new_entry->cnt = cont_cmd->cnt; - new_entry->paddr = temp_addr; - list_add_tail(&new_entry->entry, &dev->cont_qhead); - } - goto end; - } else if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_UNMAP) { - if (!list_empty(&dev->cont_qhead)) { - msm_buf_mngr_contq_listdel(dev, cont_cmd->session_id, - cont_cmd->stream_id, 1, cont_cmd->cnt); - } else { - pr_err("Nothing mapped for %d,%d\n", - cont_cmd->session_id, cont_cmd->stream_id); - rc = -EINVAL; - } - goto end; - } - -free_list: - if (i != 0) { - if (!list_empty(&dev->cont_qhead)) { - msm_buf_mngr_contq_listdel(dev, cont_cmd->session_id, - cont_cmd->stream_id, 0, i); - } - } - ion_unmap_kernel(dev->ion_client, ion_handle); -free_ion_handle: - ion_free(dev->ion_client, ion_handle); -end: - mutex_unlock(&dev->cont_mutex); - return rc; -} - -static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - int rc = 0; - struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); - - if (!buf_mngr_dev) { - pr_err("%s buf manager device NULL\n", __func__); - rc = -ENODEV; - return rc; - } - return rc; -} - -static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - int rc = 0; - struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); - - if (!buf_mngr_dev) { - pr_err("%s buf manager device NULL\n", __func__); - rc = -ENODEV; - return rc; - } - return rc; -} - -int msm_cam_buf_mgr_ops(unsigned int cmd, void *argp) -{ - int rc = 0; - - if (!msm_buf_mngr_dev) - return -ENODEV; - if (!argp) - return -EINVAL; - - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_GET_BUF: - rc = msm_buf_mngr_get_buf(msm_buf_mngr_dev, argp); - break; - case VIDIOC_MSM_BUF_MNGR_BUF_DONE: - rc = msm_buf_mngr_buf_done(msm_buf_mngr_dev, argp); - break; - case VIDIOC_MSM_BUF_MNGR_PUT_BUF: - rc = msm_buf_mngr_put_buf(msm_buf_mngr_dev, argp); - break; - case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: { - struct msm_camera_private_ioctl_arg *k_ioctl = argp; - - switch (k_ioctl->id) { - case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { - struct msm_buf_mngr_info *tmp = NULL; - - if (!k_ioctl->ioctl_ptr) - return -EINVAL; - if (k_ioctl->size != sizeof(struct msm_buf_mngr_info)) - return -EINVAL; - - MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr, - sizeof(tmp)); - rc = msm_buf_mngr_get_buf_by_idx(msm_buf_mngr_dev, - tmp); - } - break; - default: - pr_debug("unimplemented id %d", k_ioctl->id); - return -EINVAL; - } - break; - } - default: - return -ENOIOCTLCMD; - } - - return rc; -} - -int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct) -{ - if (!msm_buf_mngr_dev) - return -ENODEV; - if (!cb_struct) - return -EINVAL; - - cb_struct->msm_cam_buf_mgr_ops = msm_cam_buf_mgr_ops; - return 0; -} - -static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int32_t rc = 0; - struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); - void __user *argp = (void __user *)arg; - - if (!buf_mngr_dev) { - pr_err("%s buf manager device NULL\n", __func__); - rc = -ENOMEM; - return rc; - } - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: { - struct msm_camera_private_ioctl_arg k_ioctl, *ptr; - - if (!arg) - return -EINVAL; - ptr = arg; - k_ioctl = *ptr; - switch (k_ioctl.id) { - case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { - struct msm_buf_mngr_info buf_info, *tmp = NULL; - - if (k_ioctl.size != sizeof(struct msm_buf_mngr_info)) - return -EINVAL; - if (!k_ioctl.ioctl_ptr) - return -EINVAL; - - MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr, - sizeof(tmp)); - if (copy_from_user(&buf_info, tmp, - sizeof(struct msm_buf_mngr_info))) { - return -EFAULT; - } - k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; - - argp = &k_ioctl; - rc = msm_cam_buf_mgr_ops(cmd, argp); - } - break; - default: - pr_debug("unimplemented id %d", k_ioctl.id); - return -EINVAL; - } - } - break; - case VIDIOC_MSM_BUF_MNGR_GET_BUF: - case VIDIOC_MSM_BUF_MNGR_BUF_DONE: - case VIDIOC_MSM_BUF_MNGR_PUT_BUF: - rc = msm_cam_buf_mgr_ops(cmd, argp); - break; - case VIDIOC_MSM_BUF_MNGR_INIT: - rc = msm_generic_buf_mngr_open(sd, NULL); - break; - case VIDIOC_MSM_BUF_MNGR_DEINIT: - rc = msm_generic_buf_mngr_close(sd, NULL); - break; - case MSM_SD_NOTIFY_FREEZE: - break; - case VIDIOC_MSM_BUF_MNGR_FLUSH: - rc = msm_generic_buf_mngr_flush(buf_mngr_dev, argp); - break; - case MSM_SD_UNNOTIFY_FREEZE: - break; - case MSM_SD_SHUTDOWN: - msm_buf_mngr_sd_shutdown(buf_mngr_dev, argp); - break; - case VIDIOC_MSM_BUF_MNGR_CONT_CMD: - rc = msm_buf_mngr_handle_cont_cmd(buf_mngr_dev, argp); - break; - default: - return -ENOIOCTLCMD; - } - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_camera_buf_mgr_fetch_buf_info( - struct msm_buf_mngr_info32_t *buf_info32, - struct msm_buf_mngr_info *buf_info, unsigned long arg) -{ - if (!arg || !buf_info32 || !buf_info) - return -EINVAL; - - if (copy_from_user(buf_info32, (void __user *)arg, - sizeof(struct msm_buf_mngr_info32_t))) - return -EFAULT; - - buf_info->session_id = buf_info32->session_id; - buf_info->stream_id = buf_info32->stream_id; - buf_info->frame_id = buf_info32->frame_id; - buf_info->index = buf_info32->index; - buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec; - buf_info->timestamp.tv_usec = (long) buf_info32-> - timestamp.tv_usec; - buf_info->reserved = buf_info32->reserved; - buf_info->type = buf_info32->type; - return 0; -} - -static long msm_camera_buf_mgr_update_buf_info( - struct msm_buf_mngr_info32_t *buf_info32, - struct msm_buf_mngr_info *buf_info, unsigned long arg) -{ - if (!arg || !buf_info32 || !buf_info) - return -EINVAL; - - buf_info32->session_id = buf_info->session_id; - buf_info32->stream_id = buf_info->stream_id; - buf_info32->index = buf_info->index; - buf_info32->timestamp.tv_sec = (int32_t) buf_info-> - timestamp.tv_sec; - buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp. - tv_usec; - buf_info32->reserved = buf_info->reserved; - buf_info32->type = buf_info->type; - buf_info32->user_buf.buf_cnt = buf_info->user_buf.buf_cnt; - memcpy(&buf_info32->user_buf.buf_idx, - &buf_info->user_buf.buf_idx, - sizeof(buf_info->user_buf.buf_idx)); - if (copy_to_user((void __user *)arg, buf_info32, - sizeof(struct msm_buf_mngr_info32_t))) - return -EFAULT; - return 0; -} -static long msm_camera_buf_mgr_internal_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - long rc = 0; - struct msm_camera_private_ioctl_arg k_ioctl; - void __user *tmp_compat_ioctl_ptr = NULL; - - rc = msm_copy_camera_private_ioctl_args(arg, - &k_ioctl, &tmp_compat_ioctl_ptr); - if (rc < 0) { - pr_err("Subdev cmd %d failed\n", cmd); - return rc; - } - - switch (k_ioctl.id) { - case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { - struct msm_buf_mngr_info32_t buf_info32; - struct msm_buf_mngr_info buf_info; - - if (k_ioctl.size != sizeof(struct msm_buf_mngr_info32_t)) { - pr_err("Invalid size for id %d with size %d", - k_ioctl.id, k_ioctl.size); - return -EINVAL; - } - if (!tmp_compat_ioctl_ptr) { - pr_err("Invalid ptr for id %d", k_ioctl.id); - return -EINVAL; - } - k_ioctl.ioctl_ptr = (__u64)&buf_info; - rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info, - (unsigned long)tmp_compat_ioctl_ptr); - if (rc < 0) { - pr_err("Fetch buf info failed for cmd=%d", cmd); - return rc; - } - rc = v4l2_subdev_call(sd, core, ioctl, cmd, &k_ioctl); - if (rc < 0) { - pr_err("Subdev cmd %d failed for id %d", cmd, - k_ioctl.id); - return rc; - } - } - break; - default: - pr_debug("unimplemented id %d", k_ioctl.id); - return -EINVAL; - } - - return 0; -} - -static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - int32_t rc = 0; - - /* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's - * except VIDIOC_MSM_CPP_CFG32, which needs special - * processing - */ - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_GET_BUF32: - cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF; - break; - case VIDIOC_MSM_BUF_MNGR_BUF_DONE32: - cmd = VIDIOC_MSM_BUF_MNGR_BUF_DONE; - break; - case VIDIOC_MSM_BUF_MNGR_PUT_BUF32: - cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF; - break; - case VIDIOC_MSM_BUF_MNGR_CONT_CMD: - break; - case VIDIOC_MSM_BUF_MNGR_FLUSH32: - cmd = VIDIOC_MSM_BUF_MNGR_FLUSH; - break; - case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: - break; - default: - pr_debug("unsupported compat type\n"); - return -ENOIOCTLCMD; - } - - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_GET_BUF: - case VIDIOC_MSM_BUF_MNGR_BUF_DONE: - case VIDIOC_MSM_BUF_MNGR_FLUSH: - case VIDIOC_MSM_BUF_MNGR_PUT_BUF: { - struct msm_buf_mngr_info32_t buf_info32; - struct msm_buf_mngr_info buf_info; - - rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info, - arg); - if (rc < 0) { - pr_err("Fetch buf info failed for cmd=%d\n", cmd); - return rc; - } - rc = v4l2_subdev_call(sd, core, ioctl, cmd, &buf_info); - if (rc < 0) { - pr_debug("Subdev cmd %d fail\n", cmd); - return rc; - } - rc = msm_camera_buf_mgr_update_buf_info(&buf_info32, &buf_info, - arg); - if (rc < 0) { - pr_err("Update buf info failed for cmd=%d\n", cmd); - return rc; - } - } - break; - case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: { - rc = msm_camera_buf_mgr_internal_compat_ioctl(file, cmd, arg); - if (rc < 0) { - pr_debug("Subdev cmd %d fail\n", cmd); - return rc; - } - } - break; - case VIDIOC_MSM_BUF_MNGR_CONT_CMD: { - struct msm_buf_mngr_main_cont_info cont_cmd; - - if (copy_from_user(&cont_cmd, (void __user *)arg, - sizeof(struct msm_buf_mngr_main_cont_info))) - return -EFAULT; - rc = v4l2_subdev_call(sd, core, ioctl, cmd, &cont_cmd); - if (rc < 0) { - pr_debug("Subdev cmd %d fail\n", cmd); - return rc; - } - } - break; - default: - pr_debug("unsupported compat type\n"); - return -ENOIOCTLCMD; - } - return 0; -} -#endif - -static struct v4l2_subdev_core_ops msm_buf_mngr_subdev_core_ops = { - .ioctl = msm_buf_mngr_subdev_ioctl, -}; - -static const struct v4l2_subdev_internal_ops - msm_generic_buf_mngr_subdev_internal_ops = { - .open = msm_generic_buf_mngr_open, - .close = msm_generic_buf_mngr_close, -}; - -static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = { - .core = &msm_buf_mngr_subdev_core_ops, -}; - -static struct v4l2_file_operations msm_buf_v4l2_subdev_fops; - -static long msm_bmgr_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); -} - - -static long msm_buf_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_bmgr_subdev_do_ioctl); -} - -static int32_t __init msm_buf_mngr_init(void) -{ - int32_t rc = 0; - - msm_buf_mngr_dev = kzalloc(sizeof(*msm_buf_mngr_dev), - GFP_KERNEL); - if (!msm_buf_mngr_dev) - return -ENOMEM; - - /* Sub-dev */ - v4l2_subdev_init(&msm_buf_mngr_dev->subdev.sd, - &msm_buf_mngr_subdev_ops); - msm_cam_copy_v4l2_subdev_fops(&msm_buf_v4l2_subdev_fops); - msm_buf_v4l2_subdev_fops.unlocked_ioctl = msm_buf_subdev_fops_ioctl; -#ifdef CONFIG_COMPAT - msm_buf_v4l2_subdev_fops.compat_ioctl32 = - msm_bmgr_subdev_fops_compat_ioctl; -#endif - snprintf(msm_buf_mngr_dev->subdev.sd.name, - ARRAY_SIZE(msm_buf_mngr_dev->subdev.sd.name), "msm_buf_mngr"); - msm_buf_mngr_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - v4l2_set_subdevdata(&msm_buf_mngr_dev->subdev.sd, msm_buf_mngr_dev); - - media_entity_init(&msm_buf_mngr_dev->subdev.sd.entity, 0, NULL, 0); - msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - msm_buf_mngr_dev->subdev.sd.entity.group_id = - MSM_CAMERA_SUBDEV_BUF_MNGR; - msm_buf_mngr_dev->subdev.sd.internal_ops = - &msm_generic_buf_mngr_subdev_internal_ops; - msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY; - rc = msm_sd_register(&msm_buf_mngr_dev->subdev); - if (rc != 0) { - pr_err("%s: msm_sd_register error = %d\n", __func__, rc); - goto end; - } - - msm_buf_mngr_dev->subdev.sd.devnode->fops = &msm_buf_v4l2_subdev_fops; - - v4l2_subdev_notify(&msm_buf_mngr_dev->subdev.sd, MSM_SD_NOTIFY_REQ_CB, - &msm_buf_mngr_dev->vb2_ops); - - INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead); - spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock); - - mutex_init(&msm_buf_mngr_dev->cont_mutex); - INIT_LIST_HEAD(&msm_buf_mngr_dev->cont_qhead); - msm_buf_mngr_dev->ion_client = - msm_ion_client_create("msm_cam_generic_buf_mgr"); - if (!msm_buf_mngr_dev->ion_client) { - pr_err("%s: Failed to create ion client\n", __func__); - rc = -EBADFD; - } - -end: - return rc; -} - -static void __exit msm_buf_mngr_exit(void) -{ - msm_sd_unregister(&msm_buf_mngr_dev->subdev); - mutex_destroy(&msm_buf_mngr_dev->cont_mutex); - kfree(msm_buf_mngr_dev); -} - -module_init(msm_buf_mngr_init); -module_exit(msm_buf_mngr_exit); -MODULE_DESCRIPTION("MSM Buffer Manager"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.h deleted file mode 100644 index 9bc2f666065f866bce882402d6263b207fa0981b..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_BUF_GENERIC_MNGR_H__ -#define __MSM_BUF_GENERIC_MNGR_H__ - -#include -#include -#include -#include -#include -#include -#include - -#include "msm.h" -#include "msm_sd.h" - -struct msm_get_bufs { - struct list_head entry; - struct vb2_buffer *vb2_buf; - uint32_t session_id; - uint32_t stream_id; - uint32_t index; -}; - -struct msm_buf_mngr_device { - struct list_head buf_qhead; - spinlock_t buf_q_spinlock; - struct ion_client *ion_client; - struct msm_sd_subdev subdev; - struct msm_sd_req_vb2_q vb2_ops; - struct list_head cont_qhead; - struct mutex cont_mutex; -}; - -struct msm_buf_mngr_user_buf_cont_info { - struct list_head entry; - uint32_t sessid; - uint32_t strid; - uint32_t index; - int32_t main_fd; - struct msm_camera_user_buf_cont_t *paddr; - uint32_t cnt; - struct ion_handle *ion_handle; -}; - -/* kernel space functions*/ -struct msm_cam_buf_mgr_req_ops { - int (*msm_cam_buf_mgr_ops)(unsigned int cmd, void *argp); -}; - -/* API to register callback from client. This assumes cb_struct is allocated by - * client. - */ -int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct); -#endif diff --git a/drivers/media/platform/msm/ais/msm_sd.h b/drivers/media/platform/msm/ais/msm_sd.h deleted file mode 100644 index 9ba3d09b06c926ba9ef8e175de48d5e04481f164..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/msm_sd.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef _MSM_SD_H -#define _MSM_SD_H - -#include -#include - -/* NOTE: this header file should ONLY be included by subdev drivers */ - -struct msm_sd_close_ioctl { - unsigned int session; - unsigned int stream; -}; - -#define MSM_SD_CLOSE_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 26, struct msm_sd_close_ioctl) - -#define MSM_SD_CLOSE_SESSION \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 27, struct msm_sd_close_ioctl) - -#define MSM_SD_CLOSE_SESSION_AND_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 28, struct msm_sd_close_ioctl) - -#define MSM_SD_SHUTDOWN \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 29, struct msm_sd_close_ioctl) - -#define MSM_SD_NOTIFY_FREEZE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 30, struct msm_sd_close_ioctl) - -#define MSM_SD_UNNOTIFY_FREEZE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 31, struct msm_sd_close_ioctl) -/* - * This is used to install Sequence in msm_sd_register. - * During msm_close, proper close sequence will be triggered. - * For example: - * - * close_sequence = 0x00100001 (ISP) - * close_sequence = 0x00100002 (ISP) - * close_sequence = 0x00100003 (ISP) - * close_sequence = 0x00200001 (sensor) - * close_sequence = 0x00200002 (sensor) - * close_sequence = 0x00200003 (sensor) - */ -#define MSM_SD_CLOSE_1ST_CATEGORY 0x00010000 -#define MSM_SD_CLOSE_2ND_CATEGORY 0x00020000 -#define MSM_SD_CLOSE_3RD_CATEGORY 0x00030000 -#define MSM_SD_CLOSE_4TH_CATEGORY 0x00040000 - -struct msm_sd_subdev { - struct v4l2_subdev sd; - int close_seq; - struct list_head list; -}; - -struct msm_sd_req_sd { - char *name; - struct v4l2_subdev *subdev; -}; - -struct msm_sd_req_vb2_q { - struct vb2_buffer * (*get_buf)(int session_id, unsigned int stream_id); - struct vb2_queue * (*get_vb2_queue)(int session_id, - unsigned int stream_id); - struct vb2_buffer * (*get_buf_by_idx)(int session_id, - unsigned int stream_id, uint32_t index); - int (*put_buf)(struct vb2_buffer *vb2_buf, int session_id, - unsigned int stream_id); - int (*buf_done)(struct vb2_buffer *vb2_buf, int session_id, - unsigned int stream_id, uint32_t sequence, struct timeval *ts, - uint32_t reserved); - int (*flush_buf)(int session_id, unsigned int stream_id); -}; - -#define MSM_SD_NOTIFY_GET_SD 0x00000001 -#define MSM_SD_NOTIFY_PUT_SD 0x00000002 -#define MSM_SD_NOTIFY_REQ_CB 0x00000003 - -#define MSM_CAM_GET_IOCTL_ARG_PTR(ptr, \ - ioctl_ptr, len) memcpy(ptr, ioctl_ptr, len) - -int msm_sd_register(struct msm_sd_subdev *msm_subdev); -int msm_sd_unregister(struct msm_sd_subdev *sd); -struct v4l2_subdev *msm_sd_get_subdev(struct v4l2_subdev *sd, - const char *get_name); -void msm_sd_put_subdev(struct v4l2_subdev *sd, struct v4l2_subdev *put); -void msm_cam_copy_v4l2_subdev_fops(struct v4l2_file_operations *d1); - -#endif /*_MSM_SD_H */ diff --git a/drivers/media/platform/msm/ais/msm_vb2/Makefile b/drivers/media/platform/msm/ais/msm_vb2/Makefile deleted file mode 100644 index 96b5b4e5b0e30b760a2fdf8a1b24ae721fc2e66a..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/msm_vb2/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2 -obj-$(CONFIG_MSM_AIS) += msm_vb2.o diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h deleted file mode 100644 index 6d93454c6409f885e0144aff57ffa1fe6a592e5a..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef _MSM_VB_H -#define _MSM_VB_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm.h" -#include "msm_sd.h" - -struct msm_vb2_buffer { - /* - * vb2 buffer has to be first in the structure - * because both v4l2 frameworks and driver directly - * cast msm_vb2_buffer to a vb2_buf. - */ - struct vb2_buffer vb2_buf; - struct list_head list; - int in_freeq; -}; - -struct msm_vb2_private_data { - void *vaddr; - unsigned long size; - /* Offset of the plane inside the buffer */ - void *alloc_ctx; -}; - -struct msm_stream { - struct list_head list; - - /* stream index per session, same - * as stream_id but set through s_parm */ - unsigned int stream_id; - /* vb2 buffer handling */ - struct vb2_queue *vb2_q; - spinlock_t stream_lock; - struct list_head queued_list; -}; - -struct vb2_ops *msm_vb2_get_q_ops(void); -struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void); -int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd); -long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, - uint32_t index); -int msm_vb2_get_stream_state(struct msm_stream *stream); - -#endif /*_MSM_VB_H */ diff --git a/drivers/media/platform/msm/ais/pproc/Makefile b/drivers/media/platform/msm/ais/pproc/Makefile deleted file mode 100644 index bc6b5fff9ead8533b790b7e4c40b1849cafd4502..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/pproc/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_MSM_AIS_CPP) += cpp/ diff --git a/drivers/media/platform/msm/ais/pproc/cpp/Makefile b/drivers/media/platform/msm/ais/pproc/cpp/Makefile deleted file mode 100644 index 5edd3b5b5e7895897fcd79061a8e2519f49671de..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/pproc/cpp/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/isp/ -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/msm_buf_mgr/ -obj-$(CONFIG_MSM_AIS_CPP) += msm_cpp_soc.o msm_cpp.o diff --git a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.h deleted file mode 100644 index f6a1f1f20bf48703fc6b2e5e0b9ccaa11a220567..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.h +++ /dev/null @@ -1,294 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_CPP_H__ -#define __MSM_CPP_H__ - -#include -#include -#include -#include -#include -#include -#include "msm_generic_buf_mgr.h" -#include "msm_sd.h" -#include "cam_soc_api.h" -#include "cam_hw_ops.h" -#include - -/* hw version info: - 31:28 Major version - 27:16 Minor version - 15:0 Revision bits -**/ -#define CPP_HW_VERSION_1_1_0 0x10010000 -#define CPP_HW_VERSION_1_1_1 0x10010001 -#define CPP_HW_VERSION_2_0_0 0x20000000 -#define CPP_HW_VERSION_4_0_0 0x40000000 -#define CPP_HW_VERSION_4_1_0 0x40010000 -#define CPP_HW_VERSION_5_0_0 0x50000000 -#define CPP_HW_VERSION_5_1_0 0x50010000 - -#define VBIF_VERSION_2_3_0 0x20030000 - -#define MAX_ACTIVE_CPP_INSTANCE 8 -#define MAX_CPP_PROCESSING_FRAME 2 -#define MAX_CPP_V4l2_EVENTS 30 - -#define MSM_CPP_MICRO_BASE 0x4000 -#define MSM_CPP_MICRO_HW_VERSION 0x0000 -#define MSM_CPP_MICRO_IRQGEN_STAT 0x0004 -#define MSM_CPP_MICRO_IRQGEN_CLR 0x0008 -#define MSM_CPP_MICRO_IRQGEN_MASK 0x000C -#define MSM_CPP_MICRO_FIFO_TX_DATA 0x0010 -#define MSM_CPP_MICRO_FIFO_TX_STAT 0x0014 -#define MSM_CPP_MICRO_FIFO_RX_DATA 0x0018 -#define MSM_CPP_MICRO_FIFO_RX_STAT 0x001C -#define MSM_CPP_MICRO_BOOT_START 0x0020 -#define MSM_CPP_MICRO_BOOT_LDORG 0x0024 -#define MSM_CPP_MICRO_CLKEN_CTL 0x0030 - -#define MSM_CPP_CMD_GET_BOOTLOADER_VER 0x1 -#define MSM_CPP_CMD_FW_LOAD 0x2 -#define MSM_CPP_CMD_EXEC_JUMP 0x3 -#define MSM_CPP_CMD_RESET_HW 0x5 -#define MSM_CPP_CMD_PROCESS_FRAME 0x6 -#define MSM_CPP_CMD_FLUSH_STREAM 0x7 -#define MSM_CPP_CMD_CFG_MEM_PARAM 0x8 -#define MSM_CPP_CMD_ERROR_REQUEST 0x9 -#define MSM_CPP_CMD_GET_STATUS 0xA -#define MSM_CPP_CMD_GET_FW_VER 0xB -#define MSM_CPP_CMD_GROUP_BUFFER_DUP 0x12 -#define MSM_CPP_CMD_GROUP_BUFFER 0xF - -#define MSM_CPP_MSG_ID_CMD 0x3E646D63 -#define MSM_CPP_MSG_ID_OK 0x0A0A4B4F -#define MSM_CPP_MSG_ID_TRAILER 0xABCDEFAA - -#define MSM_CPP_MSG_ID_JUMP_ACK 0x00000001 -#define MSM_CPP_MSG_ID_FRAME_ACK 0x00000002 -#define MSM_CPP_MSG_ID_FRAME_NACK 0x00000003 -#define MSM_CPP_MSG_ID_FLUSH_ACK 0x00000004 -#define MSM_CPP_MSG_ID_FLUSH_NACK 0x00000005 -#define MSM_CPP_MSG_ID_CFG_MEM_ACK 0x00000006 -#define MSM_CPP_MSG_ID_CFG_MEM_INV 0x00000007 -#define MSM_CPP_MSG_ID_ERROR_STATUS 0x00000008 -#define MSM_CPP_MSG_ID_INVALID_CMD 0x00000009 -#define MSM_CPP_MSG_ID_GEN_STATUS 0x0000000A -#define MSM_CPP_MSG_ID_FLUSHED 0x0000000B -#define MSM_CPP_MSG_ID_FW_VER 0x0000000C - -#define MSM_CPP_JUMP_ADDRESS 0x20 -#define MSM_CPP_START_ADDRESS 0x0 -#define MSM_CPP_END_ADDRESS 0x3F00 - -#define MSM_CPP_POLL_RETRIES 200 -#define MSM_CPP_TASKLETQ_SIZE 16 -#define MSM_CPP_TX_FIFO_LEVEL 16 -#define MSM_CPP_RX_FIFO_LEVEL 512 - -enum cpp_vbif_error { - CPP_VBIF_ERROR_HANG, - CPP_VBIF_ERROR_MAX, -}; - -enum cpp_vbif_client { - VBIF_CLIENT_CPP, - VBIF_CLIENT_FD, - VBIF_CLIENT_MAX, -}; - -struct msm_cpp_vbif_data { - int (*err_handler[VBIF_CLIENT_MAX])(void *, uint32_t); - void *dev[VBIF_CLIENT_MAX]; -}; - -struct cpp_subscribe_info { - struct v4l2_fh *vfh; - uint32_t active; -}; - -enum cpp_state { - CPP_STATE_BOOT, - CPP_STATE_IDLE, - CPP_STATE_ACTIVE, - CPP_STATE_OFF, -}; - -enum cpp_iommu_state { - CPP_IOMMU_STATE_DETACHED, - CPP_IOMMU_STATE_ATTACHED, -}; - -enum msm_queue { - MSM_CAM_Q_CTRL, /* control command or control command status */ - MSM_CAM_Q_VFE_EVT, /* adsp event */ - MSM_CAM_Q_VFE_MSG, /* adsp message */ - MSM_CAM_Q_V4L2_REQ, /* v4l2 request */ - MSM_CAM_Q_VPE_MSG, /* vpe message */ - MSM_CAM_Q_PP_MSG, /* pp message */ -}; - -struct msm_queue_cmd { - struct list_head list_config; - struct list_head list_control; - struct list_head list_frame; - struct list_head list_pict; - struct list_head list_vpe_frame; - struct list_head list_eventdata; - enum msm_queue type; - void *command; - atomic_t on_heap; - struct timespec ts; - uint32_t error_code; - uint32_t trans_code; -}; - -struct msm_device_queue { - struct list_head list; - spinlock_t lock; - wait_queue_head_t wait; - int max; - int len; - const char *name; -}; - -struct msm_cpp_tasklet_queue_cmd { - struct list_head list; - uint32_t irq_status; - uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; - uint32_t tx_level; - uint8_t cmd_used; -}; - -struct msm_cpp_buffer_map_info_t { - unsigned long len; - dma_addr_t phy_addr; - int buf_fd; - struct msm_cpp_buffer_info_t buff_info; -}; - -struct msm_cpp_buffer_map_list_t { - struct msm_cpp_buffer_map_info_t map_info; - struct list_head entry; -}; - -struct msm_cpp_buff_queue_info_t { - uint32_t used; - uint16_t session_id; - uint16_t stream_id; - struct list_head vb2_buff_head; - struct list_head native_buff_head; -}; - -struct msm_cpp_work_t { - struct work_struct my_work; - struct cpp_device *cpp_dev; -}; - -struct msm_cpp_payload_params { - uint32_t stripe_base; - uint32_t stripe_size; - uint32_t plane_base; - uint32_t plane_size; - - /* offsets for stripe/plane pointers in payload */ - uint32_t rd_pntr_off; - uint32_t wr_0_pntr_off; - uint32_t rd_ref_pntr_off; - uint32_t wr_ref_pntr_off; - uint32_t wr_0_meta_data_wr_pntr_off; - uint32_t fe_mmu_pf_ptr_off; - uint32_t ref_fe_mmu_pf_ptr_off; - uint32_t we_mmu_pf_ptr_off; - uint32_t dup_we_mmu_pf_ptr_off; - uint32_t ref_we_mmu_pf_ptr_off; - uint32_t set_group_buffer_len; - uint32_t dup_frame_indicator_off; -}; - -struct cpp_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *irq; - void __iomem *vbif_base; - void __iomem *base; - void __iomem *cpp_hw_base; - void __iomem *camss_cpp_base; - struct clk **cpp_clk; - struct msm_cam_clk_info *clk_info; - size_t num_clks; - struct msm_cam_regulator *cpp_vdd; - int num_reg; - struct mutex mutex; - enum cpp_state state; - enum cpp_iommu_state iommu_state; - uint8_t is_firmware_loaded; - char *fw_name_bin; - const struct firmware *fw; - struct workqueue_struct *timer_wq; - struct msm_cpp_work_t *work; - uint32_t fw_version; - uint8_t stream_cnt; - uint8_t timeout_trial_cnt; - uint8_t max_timeout_trial_cnt; - - int domain_num; - struct iommu_domain *domain; - struct device *iommu_ctx; - uint32_t num_clk; - uint32_t min_clk_rate; - - int iommu_hdl; - /* Reusing proven tasklet from msm isp */ - atomic_t irq_cnt; - uint8_t taskletq_idx; - spinlock_t tasklet_lock; - struct list_head tasklet_q; - struct tasklet_struct cpp_tasklet; - struct msm_cpp_tasklet_queue_cmd - tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE]; - - struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE]; - uint32_t cpp_open_cnt; - struct cpp_hw_info hw_info; - - struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ - - /* Processing Queue - * store frame info for frames sent to microcontroller - */ - struct msm_device_queue processing_q; - - struct msm_cpp_buff_queue_info_t *buff_queue; - uint32_t num_buffq; - struct msm_cam_buf_mgr_req_ops buf_mgr_ops; - - uint32_t bus_client; - uint32_t bus_idx; - uint32_t bus_master_flag; - struct msm_cpp_payload_params payload_params; - struct msm_cpp_vbif_data *vbif_data; -}; - -int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev); -int msm_update_freq_tbl(struct cpp_device *cpp_dev); -int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name); -long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx); -void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev); -int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev); -void msm_cpp_vbif_register_error_handler(void *dev, - enum cpp_vbif_client client, - int (*client_vbif_error_handler)(void *, uint32_t)); - -#endif /* __MSM_CPP_H__ */ diff --git a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp_soc.c b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp_soc.c deleted file mode 100644 index ac85340bcdcfcc12a6f30547ded548b828b12d6b..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp_soc.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "MSM-CPP-SOC %s:%d " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include "msm_cpp.h" - - -#define CPP_DT_READ_U32_ERR(_dev, _key, _str, _ret, _out) { \ - _key = _str; \ - _ret = of_property_read_u32(_dev, _key, &_out); \ - if (_ret) \ - break; \ - } - -#define CPP_DT_READ_U32(_dev, _str, _out) { \ - of_property_read_u32(_dev, _str, &_out); \ - } - -void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev) -{ - int rc = 0; - struct device_node *of_node = cpp_dev->pdev->dev.of_node; - - if (!of_node) { - pr_err("%s: invalid params\n", __func__); - return; - } - - of_property_read_u32(of_node, "cell-index", &cpp_dev->pdev->id); - - rc = of_property_read_u32(of_node, "qcom,min-clock-rate", - &cpp_dev->min_clk_rate); - if (rc < 0) { - pr_debug("min-clk-rate not defined, setting it to 0\n"); - cpp_dev->min_clk_rate = 0; - } - - rc = of_property_read_u32(of_node, "qcom,bus-master", - &cpp_dev->bus_master_flag); - if (rc) - cpp_dev->bus_master_flag = 0; -} - -int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name) -{ - uint32_t i = 0; - - for (i = 0; i < cpp_dev->num_clks; i++) { - if (!strcmp(clk_name, cpp_dev->clk_info[i].clk_name)) - return i; - } - return -EINVAL; -} - -static int cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info, - uint32_t min_clk_rate) -{ - uint32_t i; - uint32_t idx = 0; - signed long freq_tbl_entry = 0; - - if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) || - (clk->ops->list_rate == NULL)) { - pr_err("Bad parameter\n"); - return -EINVAL; - } - - for (i = 0; i < MAX_FREQ_TBL; i++) { - freq_tbl_entry = clk->ops->list_rate(clk, i); - pr_debug("entry=%ld\n", freq_tbl_entry); - if (freq_tbl_entry >= 0) { - if (freq_tbl_entry >= min_clk_rate) { - hw_info->freq_tbl[idx++] = freq_tbl_entry; - pr_debug("tbl[%d]=%ld\n", idx-1, - freq_tbl_entry); - } - } else { - pr_debug("freq table returned invalid entry/end %ld\n", - freq_tbl_entry); - break; - } - } - - pr_debug("%s: idx %d", __func__, idx); - hw_info->freq_tbl_count = idx; - - return 0; -} - -int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev) -{ -#ifdef ENABLE_CPP_MICRO - uint32_t msm_micro_iface_idx; - int rc; - - msm_micro_iface_idx = msm_cpp_get_clock_index(cpp_dev, - "micro_iface_clk"); - if (msm_micro_iface_idx < 0) { - pr_err("Fail to get clock index\n"); - return -EINVAL; - } - - - rc = msm_clk_reset(cpp_dev->cpp_clk[msm_micro_iface_idx], - CLK_RESET_ASSERT); - if (rc) { - pr_err("%s:micro_iface_clk assert failed\n", - __func__); - return -EINVAL; - } - - /* - * Below usleep values are chosen based on experiments - * and this was the smallest number which works. This - * sleep is needed to leave enough time for Microcontroller - * to resets all its registers. - */ - usleep_range(1000, 1200); - - rc = msm_clk_reset(cpp_dev->cpp_clk[msm_micro_iface_idx], - CLK_RESET_DEASSERT); - if (rc) { - pr_err("%s:micro_iface_clk de-assert failed\n", __func__); - return -EINVAL; - } - /* - * Below usleep values are chosen based on experiments - * and this was the smallest number which works. This - * sleep is needed to leave enough time for Microcontroller - * to resets all its registers. - */ - usleep_range(1000, 1200); -#endif - return 0; -} - -int msm_update_freq_tbl(struct cpp_device *cpp_dev) -{ - uint32_t msm_cpp_core_clk_idx; - int rc = 0; - - msm_cpp_core_clk_idx = msm_cpp_get_clock_index(cpp_dev, "cpp_core_clk"); - if (msm_cpp_core_clk_idx < 0) { - pr_err("%s: fail to get clock index\n", __func__); - rc = msm_cpp_core_clk_idx; - return rc; - } - rc = cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[msm_cpp_core_clk_idx], - &cpp_dev->hw_info, cpp_dev->min_clk_rate); - if (rc < 0) { - pr_err("%s: fail to get frequency table\n", __func__); - return rc; - } - - return rc; -} - -long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx) -{ - long rc = 0; - - rc = msm_camera_clk_set_rate(&cpp_dev->pdev->dev, - cpp_dev->cpp_clk[idx], rate); - if (rc < 0) { - pr_err("%s: fail to get frequency table\n", __func__); - return rc; - } - - return rc; -} - -int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev) -{ - struct platform_device *pdev = cpp_dev->pdev; - struct device_node *fw_info_node = NULL, *dev_node = NULL; - char *key = "qcom,cpp-fw-payload-info"; - struct msm_cpp_payload_params *payload_params; - int ret = 0; - - if (!pdev || !pdev->dev.of_node) { - pr_err("%s: Invalid platform device/node\n", __func__); - ret = -ENODEV; - goto no_cpp_node; - } - - dev_node = pdev->dev.of_node; - fw_info_node = of_find_node_by_name(dev_node, key); - if (!fw_info_node) { - ret = -ENODEV; - goto no_binding; - } - payload_params = &cpp_dev->payload_params; - memset(payload_params, 0x0, sizeof(struct msm_cpp_payload_params)); - - do { - CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-base", ret, - payload_params->stripe_base); - CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-base", ret, - payload_params->plane_base); - CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-size", ret, - payload_params->stripe_size); - CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-size", ret, - payload_params->plane_size); - CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,fe-ptr-off", ret, - payload_params->rd_pntr_off); - CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,we-ptr-off", ret, - payload_params->wr_0_pntr_off); - - CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-ptr-off", - payload_params->rd_ref_pntr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-ptr-off", - payload_params->wr_ref_pntr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,we-meta-ptr-off", - payload_params->wr_0_meta_data_wr_pntr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,fe-mmu-pf-ptr-off", - payload_params->fe_mmu_pf_ptr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-mmu-pf-ptr-off", - payload_params->ref_fe_mmu_pf_ptr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,we-mmu-pf-ptr-off", - payload_params->we_mmu_pf_ptr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,dup-we-mmu-pf-ptr-off", - payload_params->dup_we_mmu_pf_ptr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-mmu-pf-ptr-off", - payload_params->ref_we_mmu_pf_ptr_off); - CPP_DT_READ_U32(fw_info_node, "qcom,set-group-buffer-len", - payload_params->set_group_buffer_len); - CPP_DT_READ_U32(fw_info_node, "qcom,dup-frame-indicator-off", - payload_params->dup_frame_indicator_off); - } while (0); - -no_binding: - if (ret) - pr_err("%s: Error reading binding %s, ret %d\n", - __func__, key, ret); -no_cpp_node: - return ret; -} diff --git a/drivers/media/platform/msm/ais/pproc/vpe/Makefile b/drivers/media/platform/msm/ais/pproc/vpe/Makefile deleted file mode 100644 index 9bdaa78998129b0c59a622807fcd029e0a793604..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/pproc/vpe/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_vpe.o diff --git a/drivers/media/platform/msm/ais/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/ais/pproc/vpe/msm_vpe.c deleted file mode 100644 index abb3eb3d68f93e8500b67d8c39a498e00a1f2e73..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/pproc/vpe/msm_vpe.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "MSM-VPE %s:%d " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_vpe.h" -#include "msm_camera_io_util.h" - -#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF) -#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF) - -#define MSM_VPE_DRV_NAME "msm_vpe" - -#define MSM_VPE_MAX_BUFF_QUEUE 16 - -#define CONFIG_MSM_VPE_DBG 0 - -#if CONFIG_MSM_VPE_DBG -#define VPE_DBG(fmt, args...) pr_err(fmt, ##args) -#else -#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -static void vpe_mem_dump(const char * const name, const void * const addr, - int size) -{ - char line_str[128], *p_str; - int i; - u32 *p = (u32 *) addr; - u32 data; - - VPE_DBG("%s: (%s) %pK %d\n", __func__, name, addr, size); - line_str[0] = '\0'; - p_str = line_str; - for (i = 0; i < size/4; i++) { - if (i % 4 == 0) { - snprintf(p_str, 12, "%pK: ", p); - p_str += 10; - } - data = *p++; - snprintf(p_str, 12, "%08x ", data); - p_str += 9; - if ((i + 1) % 4 == 0) { - VPE_DBG("%s\n", line_str); - line_str[0] = '\0'; - p_str = line_str; - } - } - if (line_str[0] != '\0') - VPE_DBG("%s\n", line_str); -} - -static inline long long vpe_do_div(long long num, long long den) -{ - do_div(num, den); - return num; -} - -#define msm_dequeue(queue, member) ({ \ - unsigned long flags; \ - struct msm_device_queue *__q = (queue); \ - struct msm_queue_cmd *qcmd = 0; \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - __q->len--; \ - qcmd = list_first_entry(&__q->list, \ - struct msm_queue_cmd, \ - member); \ - list_del_init(&qcmd->member); \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ - qcmd; \ - }) - -static void msm_queue_init(struct msm_device_queue *queue, const char *name) -{ - spin_lock_init(&queue->lock); - queue->len = 0; - queue->max = 0; - queue->name = name; - INIT_LIST_HEAD(&queue->list); - init_waitqueue_head(&queue->wait); -} - -static struct msm_cam_clk_info vpe_clk_info[] = { - {"vpe_clk", 160000000}, - {"vpe_pclk", -1}, -}; - -static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev); - -static void msm_enqueue(struct msm_device_queue *queue, - struct list_head *entry) -{ - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - queue->len++; - if (queue->len > queue->max) { - queue->max = queue->len; - pr_debug("queue %s new max is %d\n", queue->name, queue->max); - } - list_add_tail(entry, &queue->list); - wake_up(&queue->wait); - VPE_DBG("woke up %s\n", queue->name); - spin_unlock_irqrestore(&queue->lock, flags); -} - -static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry( - struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id) -{ - uint32_t i = 0; - struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL; - - for (i = 0; i < vpe_dev->num_buffq; i++) { - if ((vpe_dev->buff_queue[i].used == 1) && - (vpe_dev->buff_queue[i].session_id == session_id) && - (vpe_dev->buff_queue[i].stream_id == stream_id)) { - buff_queue_info = &vpe_dev->buff_queue[i]; - break; - } - } - - if (buff_queue_info == NULL) { - pr_err("error buffer queue entry for sess:%d strm:%d not found\n", - session_id, stream_id); - } - return buff_queue_info; -} - -static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev, - struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index, - uint8_t native_buff) -{ - unsigned long phy_add = 0; - struct list_head *buff_head; - struct msm_vpe_buffer_map_list_t *buff, *save; - - if (native_buff) - buff_head = &buff_queue_info->native_buff_head; - else - buff_head = &buff_queue_info->vb2_buff_head; - - list_for_each_entry_safe(buff, save, buff_head, entry) { - if (buff->map_info.buff_info.index == buff_index) { - phy_add = buff->map_info.phy_addr; - break; - } - } - - return phy_add; -} - -static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev, - struct msm_vpe_buff_queue_info_t *buff_queue, - struct msm_vpe_buffer_info_t *buffer_info) -{ - struct list_head *buff_head; - struct msm_vpe_buffer_map_list_t *buff, *save; - int rc = 0; - - if (buffer_info->native_buff) - buff_head = &buff_queue->native_buff_head; - else - buff_head = &buff_queue->vb2_buff_head; - - list_for_each_entry_safe(buff, save, buff_head, entry) { - if (buff->map_info.buff_info.index == buffer_info->index) { - pr_err("error buffer index already queued\n"); - return -EINVAL; - } - } - - buff = kzalloc( - sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL); - if (!buff) - return -EINVAL; - - buff->map_info.buff_info = *buffer_info; - buff->map_info.dbuf = dma_buf_get(buffer_info->fd); - if (IS_ERR_OR_NULL(buff->map_info.dbuf)) { - pr_err("Ion dma get buf failed\n"); - rc = PTR_ERR(buff->map_info.dbuf); - goto err_get; - } - - buff->map_info.attachment = dma_buf_attach(buff->map_info.dbuf, - &vpe_dev->pdev->dev); - if (IS_ERR_OR_NULL(buff->map_info.attachment)) { - pr_err("Ion dma buf attach failed\n"); - rc = PTR_ERR(buff->map_info.attachment); - goto err_put; - } - - buff->map_info.table = - dma_buf_map_attachment(buff->map_info.attachment, - DMA_BIDIRECTIONAL); - if (IS_ERR_OR_NULL(buff->map_info.table)) { - pr_err("DMA buf map attachment failed\n"); - rc = PTR_ERR(buff->map_info.table); - goto err_detach; - } - if (msm_map_dma_buf(buff->map_info.dbuf, buff->map_info.table, - vpe_dev->domain_num, 0, SZ_4K, 0, - &buff->map_info.phy_addr, - &buff->map_info.len, 0, 0)) { - pr_err("%s: cannot map address", __func__); - goto err_detachment; - } - - INIT_LIST_HEAD(&buff->entry); - list_add_tail(&buff->entry, buff_head); - - return buff->map_info.phy_addr; - -err_detachment: - dma_buf_unmap_attachment(buff->map_info.attachment, - buff->map_info.table, DMA_BIDIRECTIONAL); -err_detach: - dma_buf_detach(buff->map_info.dbuf, buff->map_info.attachment); -err_put: - dma_buf_put(buff->map_info.dbuf); -err_get: - kzfree(buff); - return 0; -} - -static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev, - struct msm_vpe_buffer_map_list_t *buff) -{ - msm_unmap_dma_buf(buff->map_info.table, vpe_dev->domain_num, 0); - dma_buf_unmap_attachment(buff->map_info.attachment, - buff->map_info.table, DMA_BIDIRECTIONAL); - dma_buf_detach(buff->map_info.dbuf, buff->map_info.attachment); - dma_buf_put(buff->map_info.dbuf); - list_del_init(&buff->entry); - kzfree(buff); -} - -static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev, - struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id, - uint32_t stream_id) -{ - unsigned long phy_addr = 0; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - uint8_t native_buff = buffer_info->native_buff; - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, - stream_id); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - session_id, stream_id); - return phy_addr; - } - - phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info, - buffer_info->index, native_buff); - if ((phy_addr == 0) && (native_buff)) { - phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, - buffer_info); - } - return phy_addr; -} - -static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev, - struct msm_vpe_stream_buff_info_t *stream_buff_info) -{ - uint32_t j; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, - (stream_buff_info->identity >> 16) & 0xFFFF, - stream_buff_info->identity & 0xFFFF); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - (stream_buff_info->identity >> 16) & 0xFFFF, - stream_buff_info->identity & 0xFFFF); - return -EINVAL; - } - - for (j = 0; j < stream_buff_info->num_buffs; j++) { - msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, - &stream_buff_info->buffer_info[j]); - } - return 0; -} - -static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev, - struct msm_vpe_buff_queue_info_t *buff_queue_info) -{ - struct msm_vpe_buffer_map_list_t *buff, *save; - struct list_head *buff_head; - - buff_head = &buff_queue_info->native_buff_head; - list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_vpe_dequeue_buffer_info(vpe_dev, buff); - } - - buff_head = &buff_queue_info->vb2_buff_head; - list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_vpe_dequeue_buffer_info(vpe_dev, buff); - } - - return 0; -} - -static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev, - uint16_t session_id, uint16_t stream_id) -{ - uint32_t i; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - for (i = 0; i < vpe_dev->num_buffq; i++) { - if (vpe_dev->buff_queue[i].used == 0) { - buff_queue_info = &vpe_dev->buff_queue[i]; - buff_queue_info->used = 1; - buff_queue_info->session_id = session_id; - buff_queue_info->stream_id = stream_id; - INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); - INIT_LIST_HEAD(&buff_queue_info->native_buff_head); - return 0; - } - } - pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", - session_id, stream_id); - return -EINVAL; -} - -static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev, - uint32_t session_id, uint32_t stream_id) -{ - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, - stream_id); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - session_id, stream_id); - return -EINVAL; - } - - buff_queue_info->used = 0; - buff_queue_info->session_id = 0; - buff_queue_info->stream_id = 0; - INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); - INIT_LIST_HEAD(&buff_queue_info->native_buff_head); - return 0; -} - -static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev, - uint32_t num_buffq) -{ - struct msm_vpe_buff_queue_info_t *buff_queue; - - buff_queue = kzalloc( - sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq, - GFP_KERNEL); - if (!buff_queue) { - pr_err("Buff queue allocation failure\n"); - return -ENOMEM; - } - - if (vpe_dev->buff_queue) { - pr_err("Buff queue not empty\n"); - kzfree(buff_queue); - return -EINVAL; - } - vpe_dev->buff_queue = buff_queue; - vpe_dev->num_buffq = num_buffq; - return 0; -} - -static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev) -{ - uint32_t i; - - for (i = 0; i < vpe_dev->num_buffq; i++) { - if (vpe_dev->buff_queue[i].used == 1) { - pr_err("Queue not free sessionid: %d, streamid: %d\n", - vpe_dev->buff_queue[i].session_id, - vpe_dev->buff_queue[i].stream_id); - msm_vpe_free_buff_queue_entry(vpe_dev, - vpe_dev->buff_queue[i].session_id, - vpe_dev->buff_queue[i].stream_id); - } - } - kzfree(vpe_dev->buff_queue); - vpe_dev->buff_queue = NULL; - vpe_dev->num_buffq = 0; -} - -void vpe_release_ion_client(struct kref *ref) -{ - struct vpe_device *vpe_dev = container_of(ref, - struct vpe_device, refcount); - ion_client_destroy(vpe_dev->client); -} - -static int vpe_init_mem(struct vpe_device *vpe_dev) -{ - kref_init(&vpe_dev->refcount); - kref_get(&vpe_dev->refcount); - vpe_dev->client = msm_ion_client_create("vpe"); - - if (!vpe_dev->client) { - pr_err("couldn't create ion client\n"); - return -ENODEV; - } - - return 0; -} - -static void vpe_deinit_mem(struct vpe_device *vpe_dev) -{ - kref_put(&vpe_dev->refcount, vpe_release_ion_client); -} - -static irqreturn_t msm_vpe_irq(int irq_num, void *data) -{ - unsigned long flags; - uint32_t irq_status; - struct msm_vpe_tasklet_queue_cmd *queue_cmd; - struct vpe_device *vpe_dev = (struct vpe_device *) data; - - irq_status = msm_camera_io_r_mb(vpe_dev->base + - VPE_INTR_STATUS_OFFSET); - - spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); - queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx]; - if (queue_cmd->cmd_used) { - VPE_DBG("%s: vpe tasklet queue overflow\n", __func__); - list_del(&queue_cmd->list); - } else { - atomic_add(1, &vpe_dev->irq_cnt); - } - queue_cmd->irq_status = irq_status; - - queue_cmd->cmd_used = 1; - vpe_dev->taskletq_idx = - (vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE; - list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q); - spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); - - tasklet_schedule(&vpe_dev->vpe_tasklet); - - msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); - msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); - VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status); - - return IRQ_HANDLED; -} - -static void msm_vpe_do_tasklet(unsigned long data) -{ - unsigned long flags; - struct vpe_device *vpe_dev = (struct vpe_device *)data; - struct msm_vpe_tasklet_queue_cmd *queue_cmd; - - while (atomic_read(&vpe_dev->irq_cnt)) { - spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); - queue_cmd = list_first_entry(&vpe_dev->tasklet_q, - struct msm_vpe_tasklet_queue_cmd, list); - if (!queue_cmd) { - atomic_set(&vpe_dev->irq_cnt, 0); - spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); - return; - } - atomic_sub(1, &vpe_dev->irq_cnt); - list_del(&queue_cmd->list); - queue_cmd->cmd_used = 0; - - spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); - - VPE_DBG("Frame done!!\n"); - msm_vpe_notify_frame_done(vpe_dev); - } -} - -static int vpe_init_hardware(struct vpe_device *vpe_dev) -{ - int rc = 0; - - if (vpe_dev->fs_vpe == NULL) { - vpe_dev->fs_vpe = - regulator_get(&vpe_dev->pdev->dev, "vdd"); - if (IS_ERR(vpe_dev->fs_vpe)) { - pr_err("Regulator vpe vdd get failed %ld\n", - PTR_ERR(vpe_dev->fs_vpe)); - vpe_dev->fs_vpe = NULL; - rc = -ENODEV; - goto fail; - } else if (regulator_enable(vpe_dev->fs_vpe)) { - pr_err("Regulator vpe vdd enable failed\n"); - regulator_put(vpe_dev->fs_vpe); - vpe_dev->fs_vpe = NULL; - rc = -ENODEV; - goto fail; - } - } - - rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, - vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1); - if (rc < 0) { - pr_err("clk enable failed\n"); - goto disable_and_put_regulator; - } - - vpe_dev->base = ioremap(vpe_dev->mem->start, - resource_size(vpe_dev->mem)); - if (!vpe_dev->base) { - rc = -ENOMEM; - pr_err("ioremap failed\n"); - goto disable_and_put_regulator; - } - - if (vpe_dev->state != VPE_STATE_BOOT) { - rc = request_irq(vpe_dev->irq->start, msm_vpe_irq, - IRQF_TRIGGER_RISING, - "vpe", vpe_dev); - if (rc < 0) { - pr_err("irq request fail! start=%u\n", - (uint32_t) vpe_dev->irq->start); - rc = -EBUSY; - goto unmap_base; - } else { - VPE_DBG("Got irq! %d\n", (int)vpe_dev->irq->start); - } - } else { - VPE_DBG("Skip requesting the irq since device is booting\n"); - } - vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); - - msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE); - return rc; - -unmap_base: - iounmap(vpe_dev->base); -disable_and_put_regulator: - regulator_disable(vpe_dev->fs_vpe); - regulator_put(vpe_dev->fs_vpe); -fail: - return rc; -} - -static int vpe_release_hardware(struct vpe_device *vpe_dev) -{ - if (vpe_dev->state != VPE_STATE_BOOT) { - free_irq(vpe_dev->irq->start, vpe_dev); - tasklet_kill(&vpe_dev->vpe_tasklet); - atomic_set(&vpe_dev->irq_cnt, 0); - } - - msm_vpe_delete_buff_queue(vpe_dev); - iounmap(vpe_dev->base); - msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, - vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0); - return 0; -} - -static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - int rc = 0; - uint32_t i; - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - - mutex_lock(&vpe_dev->mutex); - if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) { - pr_err("No free VPE instance\n"); - rc = -ENODEV; - goto err_mutex_unlock; - } - - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].active == 0) { - vpe_dev->vpe_subscribe_list[i].active = 1; - vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh; - break; - } - } - if (i == MAX_ACTIVE_VPE_INSTANCE) { - pr_err("No free instance\n"); - rc = -ENODEV; - goto err_mutex_unlock; - } - - VPE_DBG("open %d %pK\n", i, &fh->vfh); - vpe_dev->vpe_open_cnt++; - if (vpe_dev->vpe_open_cnt == 1) { - rc = vpe_init_hardware(vpe_dev); - if (rc < 0) { - pr_err("%s: Couldn't init vpe hardware\n", __func__); - vpe_dev->vpe_open_cnt--; - goto err_fixup_sub_list; - } - rc = vpe_init_mem(vpe_dev); - if (rc < 0) { - pr_err("%s: Couldn't init mem\n", __func__); - vpe_dev->vpe_open_cnt--; - rc = -ENODEV; - goto err_release_hardware; - } - vpe_dev->state = VPE_STATE_IDLE; - } - mutex_unlock(&vpe_dev->mutex); - - return rc; - -err_release_hardware: - vpe_release_hardware(vpe_dev); -err_fixup_sub_list: - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { - vpe_dev->vpe_subscribe_list[i].active = 0; - vpe_dev->vpe_subscribe_list[i].vfh = NULL; - break; - } - } -err_mutex_unlock: - mutex_unlock(&vpe_dev->mutex); - return rc; -} - -static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - uint32_t i; - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - - mutex_lock(&vpe_dev->mutex); - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { - vpe_dev->vpe_subscribe_list[i].active = 0; - vpe_dev->vpe_subscribe_list[i].vfh = NULL; - break; - } - } - if (i == MAX_ACTIVE_VPE_INSTANCE) { - pr_err("Invalid close\n"); - mutex_unlock(&vpe_dev->mutex); - return -ENODEV; - } - - VPE_DBG("close %d %pK\n", i, &fh->vfh); - vpe_dev->vpe_open_cnt--; - if (vpe_dev->vpe_open_cnt == 0) { - vpe_deinit_mem(vpe_dev); - vpe_release_hardware(vpe_dev); - vpe_dev->state = VPE_STATE_OFF; - } - mutex_unlock(&vpe_dev->mutex); - return 0; -} - -static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = { - .open = vpe_open_node, - .close = vpe_close_node, -}; - -static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev, - uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) -{ - int rc = -EINVAL; - - rc = v4l2_subdev_call(vpe_dev->buf_mgr_subdev, core, ioctl, - buff_mgr_ops, buff_mgr_info); - if (rc < 0) - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; -} - -static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev) -{ - struct v4l2_event v4l2_evt; - struct msm_queue_cmd *frame_qcmd; - struct msm_queue_cmd *event_qcmd; - struct msm_vpe_frame_info_t *processed_frame; - struct msm_device_queue *queue = &vpe_dev->processing_q; - struct msm_buf_mngr_info buff_mgr_info; - int rc = 0; - - if (queue->len > 0) { - frame_qcmd = msm_dequeue(queue, list_frame); - if (!frame_qcmd) { - pr_err("%s: %d frame_qcmd is NULL\n", - __func__ , __LINE__); - return -EINVAL; - } - processed_frame = frame_qcmd->command; - do_gettimeofday(&(processed_frame->out_time)); - kfree(frame_qcmd); - event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); - if (!event_qcmd) { - pr_err("%s: Insufficient memory\n", __func__); - return -ENOMEM; - } - atomic_set(&event_qcmd->on_heap, 1); - event_qcmd->command = processed_frame; - VPE_DBG("fid %d\n", processed_frame->frame_id); - msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata); - - if (!processed_frame->output_buffer_info.processed_divert) { - memset(&buff_mgr_info, 0 , - sizeof(buff_mgr_info)); - buff_mgr_info.session_id = - ((processed_frame->identity >> 16) & 0xFFFF); - buff_mgr_info.stream_id = - (processed_frame->identity & 0xFFFF); - buff_mgr_info.frame_id = processed_frame->frame_id; - buff_mgr_info.timestamp = processed_frame->timestamp; - buff_mgr_info.index = - processed_frame->output_buffer_info.index; - rc = msm_vpe_buffer_ops(vpe_dev, - VIDIOC_MSM_BUF_MNGR_BUF_DONE, - &buff_mgr_info); - if (rc < 0) { - pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n", - __func__); - rc = -EINVAL; - } - } - - v4l2_evt.id = processed_frame->inst_id; - v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE; - v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt); - } - return rc; -} - -static void vpe_update_scaler_params(struct vpe_device *vpe_dev, - struct msm_vpe_frame_strip_info strip_info) -{ - uint32_t out_ROI_width, out_ROI_height; - uint32_t src_ROI_width, src_ROI_height; - - /* - * phase_step_x, phase_step_y, phase_init_x and phase_init_y - * are represented in fixed-point, unsigned 3.29 format - */ - uint32_t phase_step_x = 0; - uint32_t phase_step_y = 0; - uint32_t phase_init_x = 0; - uint32_t phase_init_y = 0; - - uint32_t src_roi, src_x, src_y, src_xy, temp; - uint32_t yscale_filter_sel, xscale_filter_sel; - uint32_t scale_unit_sel_x, scale_unit_sel_y; - uint64_t numerator, denominator; - - /* - * assumption is both direction need zoom. this can be - * improved. - */ - temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3; - msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET); - - src_ROI_width = strip_info.src_w; - src_ROI_height = strip_info.src_h; - out_ROI_width = strip_info.dst_w; - out_ROI_height = strip_info.dst_h; - - VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n", - src_ROI_width, src_ROI_height, out_ROI_width, - out_ROI_height); - src_roi = (src_ROI_height << 16) + src_ROI_width; - - msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET); - - src_x = strip_info.src_x; - src_y = strip_info.src_y; - - VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y); - - src_xy = src_y*(1<<16) + src_x; - msm_camera_io_w(src_xy, vpe_dev->base + - VPE_SRC_XY_OFFSET); - VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi); - - /* decide whether to use FIR or M/N for scaling */ - if ((out_ROI_width == 1 && src_ROI_width < 4) || - (src_ROI_width < 4 * out_ROI_width - 3)) - scale_unit_sel_x = 0;/* use FIR scalar */ - else - scale_unit_sel_x = 1;/* use M/N scalar */ - - if ((out_ROI_height == 1 && src_ROI_height < 4) || - (src_ROI_height < 4 * out_ROI_height - 3)) - scale_unit_sel_y = 0;/* use FIR scalar */ - else - scale_unit_sel_y = 1;/* use M/N scalar */ - - /* calculate phase step for the x direction */ - - /* - * if destination is only 1 pixel wide, the value of - * phase_step_x is unimportant. Assigning phase_step_x to src - * ROI width as an arbitrary value. - */ - if (out_ROI_width == 1) - phase_step_x = (uint32_t) ((src_ROI_width) << - SCALER_PHASE_BITS); - - /* if using FIR scalar */ - else if (scale_unit_sel_x == 0) { - - /* - * Calculate the quotient ( src_ROI_width - 1 ) ( - * out_ROI_width - 1) with u3.29 precision. Quotient - * is rounded up to the larger 29th decimal point - */ - numerator = (uint64_t)(src_ROI_width - 1) << - SCALER_PHASE_BITS; - /* - * never equals to 0 because of the "(out_ROI_width == - * 1 )" - */ - denominator = (uint64_t)(out_ROI_width - 1); - /* - * divide and round up to the larger 29th decimal - * point. - */ - phase_step_x = (uint32_t) vpe_do_div((numerator + - denominator - 1), denominator); - } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ - /* - * Calculate the quotient ( src_ROI_width ) / ( - * out_ROI_width) with u3.29 precision. Quotient is - * rounded down to the smaller 29th decimal point. - */ - numerator = (uint64_t)(src_ROI_width) << - SCALER_PHASE_BITS; - denominator = (uint64_t)(out_ROI_width); - phase_step_x = - (uint32_t) vpe_do_div(numerator, denominator); - } - /* calculate phase step for the y direction */ - - /* - * if destination is only 1 pixel wide, the value of - * phase_step_x is unimportant. Assigning phase_step_x to src - * ROI width as an arbitrary value. - */ - if (out_ROI_height == 1) - phase_step_y = - (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); - - /* if FIR scalar */ - else if (scale_unit_sel_y == 0) { - /* - * Calculate the quotient ( src_ROI_height - 1 ) / ( - * out_ROI_height - 1) with u3.29 precision. Quotient - * is rounded up to the larger 29th decimal point. - */ - numerator = (uint64_t)(src_ROI_height - 1) << - SCALER_PHASE_BITS; - /* - * never equals to 0 because of the " ( out_ROI_height - * == 1 )" case - */ - denominator = (uint64_t)(out_ROI_height - 1); - /* - * Quotient is rounded up to the larger 29th decimal - * point. - */ - phase_step_y = - (uint32_t) vpe_do_div( - (numerator + denominator - 1), denominator); - } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ - /* - * Calculate the quotient ( src_ROI_height ) ( - * out_ROI_height) with u3.29 precision. Quotient is - * rounded down to the smaller 29th decimal point. - */ - numerator = (uint64_t)(src_ROI_height) << - SCALER_PHASE_BITS; - denominator = (uint64_t)(out_ROI_height); - phase_step_y = (uint32_t) vpe_do_div( - numerator, denominator); - } - - /* decide which set of FIR coefficients to use */ - if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) - xscale_filter_sel = 0; - else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) - xscale_filter_sel = 1; - else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) - xscale_filter_sel = 2; - else - xscale_filter_sel = 3; - - if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) - yscale_filter_sel = 0; - else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) - yscale_filter_sel = 1; - else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) - yscale_filter_sel = 2; - else - yscale_filter_sel = 3; - - /* calculate phase init for the x direction */ - - /* if using FIR scalar */ - if (scale_unit_sel_x == 0) { - if (out_ROI_width == 1) - phase_init_x = - (uint32_t) ((src_ROI_width - 1) << - SCALER_PHASE_BITS); - else - phase_init_x = 0; - } else if (scale_unit_sel_x == 1) /* M over N scalar */ - phase_init_x = 0; - - /* - * calculate phase init for the y direction if using FIR - * scalar - */ - if (scale_unit_sel_y == 0) { - if (out_ROI_height == 1) - phase_init_y = - (uint32_t) ((src_ROI_height - - 1) << SCALER_PHASE_BITS); - else - phase_init_y = 0; - } else if (scale_unit_sel_y == 1) /* M over N scalar */ - phase_init_y = 0; - - strip_info.phase_step_x = phase_step_x; - strip_info.phase_step_y = phase_step_y; - strip_info.phase_init_x = phase_init_x; - strip_info.phase_init_y = phase_init_y; - VPE_DBG("phase step x = %d, step y = %d.\n", - strip_info.phase_step_x, strip_info.phase_step_y); - VPE_DBG("phase init x = %d, init y = %d.\n", - strip_info.phase_init_x, strip_info.phase_init_y); - - msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base + - VPE_SCALE_PHASEX_STEP_OFFSET); - msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base + - VPE_SCALE_PHASEY_STEP_OFFSET); - - msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base + - VPE_SCALE_PHASEX_INIT_OFFSET); - msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base + - VPE_SCALE_PHASEY_INIT_OFFSET); -} - -static void vpe_program_buffer_addresses( - struct vpe_device *vpe_dev, - unsigned long srcP0, - unsigned long srcP1, - unsigned long outP0, - unsigned long outP1) -{ - VPE_DBG("%s VPE Configured with:\n" - "Src %x, %x Dest %x, %x", - __func__, (uint32_t)srcP0, (uint32_t)srcP1, - (uint32_t)outP0, (uint32_t)outP1); - - msm_camera_io_w(srcP0, vpe_dev->base + VPE_SRCP0_ADDR_OFFSET); - msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET); - msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET); - msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET); -} - -static int vpe_start(struct vpe_device *vpe_dev) -{ - /* enable the frame irq, bit 0 = Display list 0 ROI done */ - msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); - msm_camera_io_dump(vpe_dev->base, 0x120, CONFIG_MSM_VPE_DBG); - msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18, CONFIG_MSM_VPE_DBG); - msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250, CONFIG_MSM_VPE_DBG); - msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20, CONFIG_MSM_VPE_DBG); - msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30, CONFIG_MSM_VPE_DBG); - msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10, CONFIG_MSM_VPE_DBG); - - /* - * This triggers the operation. When the VPE is done, - * msm_vpe_irq will fire. - */ - msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET); - return 0; -} - -static void vpe_config_axi_default(struct vpe_device *vpe_dev) -{ - msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET); -} - -static int vpe_reset(struct vpe_device *vpe_dev) -{ - uint32_t vpe_version; - uint32_t rc = 0; - - vpe_version = msm_camera_io_r( - vpe_dev->base + VPE_HW_VERSION_OFFSET); - VPE_DBG("vpe_version = 0x%x\n", vpe_version); - /* disable all interrupts.*/ - msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); - /* clear all pending interrupts*/ - msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); - /* write sw_reset to reset the core. */ - msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET); - /* then poll the reset bit, it should be self-cleared. */ - while (1) { - rc = msm_camera_io_r( - vpe_dev->base + VPE_SW_RESET_OFFSET) & 0x10; - if (rc == 0) - break; - cpu_relax(); - } - /* - * at this point, hardware is reset. Then pogram to default - * values. - */ - msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE, - vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET); - - msm_camera_io_w(VPE_CGC_ENABLE_VALUE, - vpe_dev->base + VPE_CGC_EN_OFFSET); - msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET); - msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE, - vpe_dev->base + VPE_OP_MODE_OFFSET); - msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG, - vpe_dev->base + VPE_SCALE_CONFIG_OFFSET); - vpe_config_axi_default(vpe_dev); - return rc; -} - -static int vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p) -{ - uint32_t i, offset; - - offset = *p; - - if (offset > VPE_SCALE_COEFF_MAX_N-VPE_SCALE_COEFF_NUM) { - pr_err("%s: invalid offset %d passed in", __func__, offset); - return -EINVAL; - } - - for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) { - VPE_DBG("Setting scale table %d\n", i); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_SCALE_COEFF_LSBn(i)); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_SCALE_COEFF_MSBn(i)); - } - - return 0; -} - -static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p) -{ - msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET); -} - -static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p) -{ - msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET); -} - -static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p) -{ - msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET); -} - -/** - * msm_vpe_transaction_setup() - send setup for one frame to VPE - * @vpe_dev: vpe device - * @data: packed setup commands - * - * See msm_vpe.h for the expected format of `data' - */ -static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data) -{ - int i, rc = 0; - void *iter = data; - - vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN); - - for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) { - rc = vpe_update_scale_coef(vpe_dev, (uint32_t *)iter); - if (rc != 0) - return; - - iter += VPE_SCALER_CONFIG_LEN; - } - vpe_input_plane_config(vpe_dev, (uint32_t *)iter); - iter += VPE_INPUT_PLANE_CFG_LEN; - vpe_output_plane_config(vpe_dev, (uint32_t *)iter); - iter += VPE_OUTPUT_PLANE_CFG_LEN; - vpe_operation_config(vpe_dev, (uint32_t *)iter); -} - -static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev, - struct msm_queue_cmd *frame_qcmd) -{ - struct msm_vpe_frame_info_t *process_frame; - - if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) { - process_frame = frame_qcmd->command; - msm_enqueue(&vpe_dev->processing_q, - &frame_qcmd->list_frame); - - vpe_update_scaler_params(vpe_dev, process_frame->strip_info); - vpe_program_buffer_addresses( - vpe_dev, - process_frame->src_phyaddr, - process_frame->src_phyaddr - + process_frame->src_chroma_plane_offset, - process_frame->dest_phyaddr, - process_frame->dest_phyaddr - + process_frame->dest_chroma_plane_offset); - vpe_start(vpe_dev); - do_gettimeofday(&(process_frame->in_time)); - } - return 0; -} - -static int msm_vpe_cfg(struct vpe_device *vpe_dev, - struct msm_camera_v4l2_ioctl_t *ioctl_ptr) -{ - int rc = 0; - struct msm_queue_cmd *frame_qcmd = NULL; - struct msm_vpe_frame_info_t *new_frame = - kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL); - unsigned long in_phyaddr, out_phyaddr; - struct msm_buf_mngr_info buff_mgr_info; - - if (!new_frame) { - pr_err("Insufficient memory. return\n"); - return -ENOMEM; - } - - rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr, - sizeof(struct msm_vpe_frame_info_t)); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - rc = -EINVAL; - goto err_free_new_frame; - } - - in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, - &new_frame->input_buffer_info, - ((new_frame->identity >> 16) & 0xFFFF), - (new_frame->identity & 0xFFFF)); - if (!in_phyaddr) { - pr_err("error gettting input physical address\n"); - rc = -EINVAL; - goto err_free_new_frame; - } - - memset(&new_frame->output_buffer_info, 0, - sizeof(struct msm_vpe_buffer_info_t)); - memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); - buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF); - buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); - buff_mgr_info.type = MSM_CAMERA_BUF_MNGR_BUF_PLANAR; - rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, - &buff_mgr_info); - if (rc < 0) { - pr_err("error getting buffer\n"); - rc = -EINVAL; - goto err_free_new_frame; - } - - new_frame->output_buffer_info.index = buff_mgr_info.index; - out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, - &new_frame->output_buffer_info, - ((new_frame->identity >> 16) & 0xFFFF), - (new_frame->identity & 0xFFFF)); - if (!out_phyaddr) { - pr_err("error gettting output physical address\n"); - rc = -EINVAL; - goto err_put_buf; - } - - new_frame->src_phyaddr = in_phyaddr; - new_frame->dest_phyaddr = out_phyaddr; - - frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); - if (!frame_qcmd) { - rc = -ENOMEM; - goto err_put_buf; - } - - atomic_set(&frame_qcmd->on_heap, 1); - frame_qcmd->command = new_frame; - rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd); - if (rc < 0) { - pr_err("error cannot send frame to hardware\n"); - rc = -EINVAL; - goto err_free_frame_qcmd; - } - - return rc; - -err_free_frame_qcmd: - kfree(frame_qcmd); -err_put_buf: - msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, - &buff_mgr_info); -err_free_new_frame: - kfree(new_frame); - return rc; -} - -static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; - int rc = 0; - - mutex_lock(&vpe_dev->mutex); - switch (cmd) { - case VIDIOC_MSM_VPE_TRANSACTION_SETUP: { - struct msm_vpe_transaction_setup_cfg *cfg; - - VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n"); - if (sizeof(*cfg) != ioctl_ptr->len) { - pr_err("%s: size mismatch cmd=%d, len=%zu, expected=%zu", - __func__, cmd, ioctl_ptr->len, - sizeof(*cfg)); - rc = -EINVAL; - break; - } - - cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL); - if (!cfg) { - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - kfree(cfg); - break; - } - - msm_vpe_transaction_setup(vpe_dev, (void *)cfg); - kfree(cfg); - break; - } - case VIDIOC_MSM_VPE_CFG: { - VPE_DBG("VIDIOC_MSM_VPE_CFG\n"); - rc = msm_vpe_cfg(vpe_dev, ioctl_ptr); - break; - } - case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: { - struct msm_vpe_stream_buff_info_t *u_stream_buff_info; - struct msm_vpe_stream_buff_info_t k_stream_buff_info; - - VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n"); - - if (sizeof(struct msm_vpe_stream_buff_info_t) != - ioctl_ptr->len) { - pr_err("%s:%d: invalid length\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); - if (!u_stream_buff_info) { - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(u_stream_buff_info, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - if ((u_stream_buff_info->num_buffs == 0) || - (u_stream_buff_info->num_buffs > - MSM_CAMERA_MAX_STREAM_BUF)) { - pr_err("%s:%d: Invalid number of buffers\n", __func__, - __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; - k_stream_buff_info.identity = u_stream_buff_info->identity; - k_stream_buff_info.buffer_info = - kzalloc(k_stream_buff_info.num_buffs * - sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL); - if (!k_stream_buff_info.buffer_info) { - pr_err("%s:%d: malloc error\n", __func__, __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(k_stream_buff_info.buffer_info, - (void __user *)u_stream_buff_info->buffer_info, - k_stream_buff_info.num_buffs * - sizeof(struct msm_vpe_buffer_info_t)) ? - -EFAULT : 0); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - kfree(k_stream_buff_info.buffer_info); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = msm_vpe_add_buff_queue_entry(vpe_dev, - ((k_stream_buff_info.identity >> 16) & 0xFFFF), - (k_stream_buff_info.identity & 0xFFFF)); - if (!rc) - rc = msm_vpe_enqueue_buff_info_list(vpe_dev, - &k_stream_buff_info); - - kfree(k_stream_buff_info.buffer_info); - kfree(u_stream_buff_info); - break; - } - case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: { - uint32_t identity; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n"); - if (ioctl_ptr->len != sizeof(uint32_t)) { - pr_err("%s:%d Invalid len\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(&identity, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, - ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for identity:%d\n", - identity); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info); - rc = msm_vpe_free_buff_queue_entry(vpe_dev, - buff_queue_info->session_id, - buff_queue_info->stream_id); - break; - } - case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: { - struct msm_device_queue *queue = &vpe_dev->eventData_q; - struct msm_queue_cmd *event_qcmd; - struct msm_vpe_frame_info_t *process_frame; - - VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n"); - event_qcmd = msm_dequeue(queue, list_eventdata); - if (!event_qcmd) { - pr_err("%s: %d event_qcmd is NULL\n", - __func__ , __LINE__); - return -EINVAL; - } - process_frame = event_qcmd->command; - VPE_DBG("fid %d\n", process_frame->frame_id); - if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, - process_frame, - sizeof(struct msm_vpe_frame_info_t))) { - mutex_unlock(&vpe_dev->mutex); - kfree(process_frame); - kfree(event_qcmd); - return -EINVAL; - } - - kfree(process_frame); - kfree(event_qcmd); - break; - } - } - mutex_unlock(&vpe_dev->mutex); - return rc; -} - -static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS, NULL); -} - -static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_unsubscribe(fh, sub); -} - -static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = { - .ioctl = msm_vpe_subdev_ioctl, - .subscribe_event = msm_vpe_subscribe_event, - .unsubscribe_event = msm_vpe_unsubscribe_event, -}; - -static const struct v4l2_subdev_ops msm_vpe_subdev_ops = { - .core = &msm_vpe_subdev_core_ops, -}; - -static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops; - -static long msm_vpe_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; - - switch (cmd) { - case VIDIOC_DQEVENT: - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return -ENOIOCTLCMD; - - return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); - - case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); - case VIDIOC_MSM_VPE_GET_INST_INFO: { - uint32_t i; - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; - struct msm_vpe_frame_info_t inst_info; - - memset(&inst_info, 0, sizeof(struct msm_vpe_frame_info_t)); - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) { - inst_info.inst_id = i; - break; - } - } - if (copy_to_user( - (void __user *)ioctl_ptr->ioctl_ptr, &inst_info, - sizeof(struct msm_vpe_frame_info_t))) { - return -EINVAL; - } - } - default: - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); - } - - return 0; -} - -static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl); -} - -static int vpe_register_domain(void) -{ - struct msm_iova_partition vpe_iommu_partition = { - /* TODO: verify that these are correct? */ - .start = SZ_128K, - .size = SZ_2G - SZ_128K, - }; - struct msm_iova_layout vpe_iommu_layout = { - .partitions = &vpe_iommu_partition, - .npartitions = 1, - .client_name = "camera_vpe", - .domain_flags = 0, - }; - - return msm_register_domain(&vpe_iommu_layout); -} - -static int vpe_probe(struct platform_device *pdev) -{ - struct vpe_device *vpe_dev; - int rc = 0; - - vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL); - if (!vpe_dev) - return -ENOMEM; - - vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) * - ARRAY_SIZE(vpe_clk_info), GFP_KERNEL); - if (!vpe_dev->vpe_clk) { - rc = -ENOMEM; - goto err_free_vpe_dev; - } - - v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops); - vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops; - snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name), - "vpe"); - vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; - v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev); - platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd); - mutex_init(&vpe_dev->mutex); - spin_lock_init(&vpe_dev->tasklet_lock); - - vpe_dev->pdev = pdev; - - vpe_dev->mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "vpe"); - if (!vpe_dev->mem) { - pr_err("no mem resource?\n"); - rc = -ENODEV; - goto err_free_vpe_clk; - } - - vpe_dev->irq = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "vpe"); - if (!vpe_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - vpe_dev->domain_num = vpe_register_domain(); - if (vpe_dev->domain_num < 0) { - pr_err("%s: could not register domain\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - vpe_dev->domain = - msm_get_iommu_domain(vpe_dev->domain_num); - if (!vpe_dev->domain) { - pr_err("%s: cannot find domain\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src"); - vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst"); - if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) { - pr_err("%s: cannot get iommu_ctx\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0); - vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE; - vpe_dev->msm_sd.sd.entity.name = pdev->name; - msm_sd_register(&vpe_dev->msm_sd); - msm_cam_copy_v4l2_subdev_fops(&msm_vpe_v4l2_subdev_fops); - vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops; - vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num; - vpe_dev->state = VPE_STATE_BOOT; - rc = vpe_init_hardware(vpe_dev); - if (rc < 0) { - pr_err("%s: Couldn't init vpe hardware\n", __func__); - goto err_unregister_sd; - } - vpe_reset(vpe_dev); - vpe_release_hardware(vpe_dev); - vpe_dev->state = VPE_STATE_OFF; - - rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); - if (rc < 0) { - pr_err("Couldn't attach to vpe_src context bank\n"); - rc = -ENODEV; - goto err_unregister_sd; - } - rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); - if (rc < 0) { - pr_err("Couldn't attach to vpe_dst context bank\n"); - rc = -ENODEV; - goto err_detach_src; - } - - vpe_dev->state = VPE_STATE_OFF; - - msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata"); - msm_queue_init(&vpe_dev->processing_q, "vpe-frame"); - INIT_LIST_HEAD(&vpe_dev->tasklet_q); - tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet, - (unsigned long)vpe_dev); - vpe_dev->vpe_open_cnt = 0; - - return rc; - -err_detach_src: - iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); -err_unregister_sd: - msm_sd_unregister(&vpe_dev->msm_sd); -err_release_mem: - release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); -err_free_vpe_clk: - kfree(vpe_dev->vpe_clk); -err_free_vpe_dev: - kfree(vpe_dev); - return rc; -} - -static int vpe_device_remove(struct platform_device *dev) -{ - struct v4l2_subdev *sd = platform_get_drvdata(dev); - struct vpe_device *vpe_dev; - - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd); - if (!vpe_dev) { - pr_err("%s: vpe device is NULL\n", __func__); - return 0; - } - - iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); - iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); - msm_sd_unregister(&vpe_dev->msm_sd); - release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); - mutex_destroy(&vpe_dev->mutex); - kfree(vpe_dev); - return 0; -} - -static struct platform_driver vpe_driver = { - .probe = vpe_probe, - .remove = vpe_device_remove, - .driver = { - .name = MSM_VPE_DRV_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init msm_vpe_init_module(void) -{ - return platform_driver_register(&vpe_driver); -} - -static void __exit msm_vpe_exit_module(void) -{ - platform_driver_unregister(&vpe_driver); -} - -module_init(msm_vpe_init_module); -module_exit(msm_vpe_exit_module); -MODULE_DESCRIPTION("MSM VPE driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/ais/pproc/vpe/msm_vpe.h deleted file mode 100644 index 7ae9bc1be69642b07eafef98a1581422760af52b..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/pproc/vpe/msm_vpe.h +++ /dev/null @@ -1,258 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_VPE_H__ -#define __MSM_VPE_H__ - -#include -#include -#include -#include -#include -#include "msm_sd.h" - -/*********** start of register offset *********************/ -#define VPE_INTR_ENABLE_OFFSET 0x0020 -#define VPE_INTR_STATUS_OFFSET 0x0024 -#define VPE_INTR_CLEAR_OFFSET 0x0028 -#define VPE_DL0_START_OFFSET 0x0030 -#define VPE_HW_VERSION_OFFSET 0x0070 -#define VPE_SW_RESET_OFFSET 0x0074 -#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078 -#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C -#define VPE_CGC_EN_OFFSET 0x0100 -#define VPE_CMD_STATUS_OFFSET 0x10008 -#define VPE_PROFILE_EN_OFFSET 0x10010 -#define VPE_PROFILE_COUNT_OFFSET 0x10014 -#define VPE_CMD_MODE_OFFSET 0x10060 -#define VPE_SRC_SIZE_OFFSET 0x10108 -#define VPE_SRCP0_ADDR_OFFSET 0x1010C -#define VPE_SRCP1_ADDR_OFFSET 0x10110 -#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C -#define VPE_SRC_FORMAT_OFFSET 0x10124 -#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128 -#define VPE_OP_MODE_OFFSET 0x10138 -#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C -#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140 -#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144 -#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148 -#define VPE_OUT_FORMAT_OFFSET 0x10150 -#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154 -#define VPE_OUT_SIZE_OFFSET 0x10164 -#define VPE_OUTP0_ADDR_OFFSET 0x10168 -#define VPE_OUTP1_ADDR_OFFSET 0x1016C -#define VPE_OUT_YSTRIDE1_OFFSET 0x10178 -#define VPE_OUT_XY_OFFSET 0x1019C -#define VPE_SRC_XY_OFFSET 0x10200 -#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208 -#define VPE_SCALE_CONFIG_OFFSET 0x10230 -#define VPE_DEINT_STATUS_OFFSET 0x30000 -#define VPE_DEINT_DECISION_OFFSET 0x30004 -#define VPE_DEINT_COEFF0_OFFSET 0x30010 -#define VPE_SCALE_STATUS_OFFSET 0x50000 -#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010 -#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020 -#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400 -#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404 - -#define VPE_AXI_ARB_1_OFFSET 0x00408 -#define VPE_AXI_ARB_2_OFFSET 0x0040C - -#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n)) -#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n)) -#define VPE_SCALE_COEFF_NUM 32 -#define VPE_SCALE_COEFF_MAX_N 127 - -/*********** end of register offset ********************/ - - -#define VPE_HARDWARE_VERSION 0x00080308 -#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/ -#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924 -#define VPE_CMD_MODE_VALUE 0x1 -#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004 -#define VPE_CGC_ENABLE_VALUE 0xffff -#define VPE_DEFAULT_SCALE_CONFIG 0x3c - -#define VPE_NORMAL_MODE_CLOCK_RATE 150000000 -#define VPE_TURBO_MODE_CLOCK_RATE 200000000 -#define VPE_SUBDEV_MAX_EVENTS 30 - -/**************************************************/ -/*********** End of command id ********************/ -/**************************************************/ - -#define SCALER_PHASE_BITS 29 -#define HAL_MDP_PHASE_STEP_2P50 0x50000000 -#define HAL_MDP_PHASE_STEP_1P66 0x35555555 -#define HAL_MDP_PHASE_STEP_1P25 0x28000000 - - -#define MAX_ACTIVE_VPE_INSTANCE 8 -#define MAX_VPE_PROCESSING_FRAME 2 -#define MAX_VPE_V4l2_EVENTS 30 - -#define MSM_VPE_TASKLETQ_SIZE 16 - -/** - * The format of the msm_vpe_transaction_setup_cfg is as follows: - * - * - vpe_update_scale_coef (65*4 uint32_t's) - * - Each table is 65 uint32_t's long - * - 1st uint32_t in each table indicates offset - * - Following 64 uint32_t's are the data - * - * - vpe_input_plane_config (6 uint32_t's) - * - VPE_SRC_FORMAT_OFFSET - * - VPE_SRC_UNPACK_PATTERN1_OFFSET - * - VPE_SRC_IMAGE_SIZE_OFFSET - * - VPE_SRC_YSTRIDE1_OFFSET - * - VPE_SRC_SIZE_OFFSET - * - VPE_SRC_XY_OFFSET - * - * - vpe_output_plane_config (5 uint32_t's) - * - VPE_OUT_FORMAT_OFFSET - * - VPE_OUT_PACK_PATTERN1_OFFSET - * - VPE_OUT_YSTRIDE1_OFFSET - * - VPE_OUT_SIZE_OFFSET - * - VPE_OUT_XY_OFFSET - * - * - vpe_operation_config (1 uint32_t) - * - VPE_OP_MODE_OFFSET - * - */ - -#define VPE_SCALER_CONFIG_LEN 260 -#define VPE_INPUT_PLANE_CFG_LEN 24 -#define VPE_OUTPUT_PLANE_CFG_LEN 20 -#define VPE_OPERATION_MODE_CFG_LEN 4 -#define VPE_NUM_SCALER_TABLES 4 - -#define VPE_TRANSACTION_SETUP_CONFIG_LEN ( \ - (VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES) \ - + VPE_INPUT_PLANE_CFG_LEN \ - + VPE_OUTPUT_PLANE_CFG_LEN \ - + VPE_OPERATION_MODE_CFG_LEN) -/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */ - -struct msm_vpe_transaction_setup_cfg { - uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN]; -}; - -struct vpe_subscribe_info { - struct v4l2_fh *vfh; - uint32_t active; -}; - -enum vpe_state { - VPE_STATE_BOOT, - VPE_STATE_IDLE, - VPE_STATE_ACTIVE, - VPE_STATE_OFF, -}; - -struct msm_queue_cmd { - struct list_head list_config; - struct list_head list_control; - struct list_head list_frame; - struct list_head list_pict; - struct list_head list_vpe_frame; - struct list_head list_eventdata; - void *command; - atomic_t on_heap; - struct timespec ts; - uint32_t error_code; - uint32_t trans_code; -}; - -struct msm_device_queue { - struct list_head list; - spinlock_t lock; - wait_queue_head_t wait; - int max; - int len; - const char *name; -}; - -struct msm_vpe_tasklet_queue_cmd { - struct list_head list; - uint32_t irq_status; - uint8_t cmd_used; -}; - -struct msm_vpe_buffer_map_info_t { - unsigned long len; - dma_addr_t phy_addr; - struct dma_buf *dbuf; - struct dma_buf_attachment *attachment; - struct sg_table *table; - struct msm_vpe_buffer_info_t buff_info; -}; - -struct msm_vpe_buffer_map_list_t { - struct msm_vpe_buffer_map_info_t map_info; - struct list_head entry; -}; - -struct msm_vpe_buff_queue_info_t { - uint32_t used; - uint16_t session_id; - uint16_t stream_id; - struct list_head vb2_buff_head; - struct list_head native_buff_head; -}; - -struct vpe_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *mem; - struct resource *irq; - void __iomem *base; - struct clk **vpe_clk; - struct regulator *fs_vpe; - struct mutex mutex; - enum vpe_state state; - - int domain_num; - struct iommu_domain *domain; - struct device *iommu_ctx_src; - struct device *iommu_ctx_dst; - struct ion_client *client; - struct kref refcount; - - /* Reusing proven tasklet from msm isp */ - atomic_t irq_cnt; - uint8_t taskletq_idx; - spinlock_t tasklet_lock; - struct list_head tasklet_q; - struct tasklet_struct vpe_tasklet; - struct msm_vpe_tasklet_queue_cmd - tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE]; - - struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE]; - uint32_t vpe_open_cnt; - - struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ - - /* - * Processing Queue: store frame info for frames sent to - * microcontroller - */ - struct msm_device_queue processing_q; - - struct msm_vpe_buff_queue_info_t *buff_queue; - uint32_t num_buffq; - struct v4l2_subdev *buf_mgr_subdev; -}; - -#endif /* __MSM_VPE_H__ */ diff --git a/drivers/media/platform/msm/ais/sensor/Makefile b/drivers/media/platform/msm/ais/sensor/Makefile deleted file mode 100644 index 6541a0816f8e7077a2ff26bfb20b014a608dffdb..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2 -ccflags-y += -Idrivers/media/platform/msm/ais/camera -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci -obj-$(CONFIG_MSM_AIS) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/ ir_cut/ -obj-$(CONFIG_MSM_AIS_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o diff --git a/drivers/media/platform/msm/ais/sensor/actuator/Makefile b/drivers/media/platform/msm/ais/sensor/actuator/Makefile deleted file mode 100644 index bc2d5ccf0920b0a2ec0765b353c79261a11c85f1..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/actuator/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci -obj-$(CONFIG_MSM_AIS) += msm_actuator.o diff --git a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.h deleted file mode 100644 index 78fddb2b056321e56647f1258127d2418183739d..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_ACTUATOR_H -#define MSM_ACTUATOR_H - -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_camera_dt_util.h" -#include "msm_camera_io_util.h" - - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -#define MSM_ACTUATOR_MAX_VREGS (10) -#define ACTUATOR_MAX_POLL_COUNT 10 - -struct msm_actuator_ctrl_t; - -enum msm_actuator_state_t { - ACT_ENABLE_STATE, - ACT_OPS_ACTIVE, - ACT_OPS_INACTIVE, - ACT_DISABLE_STATE, -}; - -struct msm_actuator_func_tbl { - int32_t (*actuator_i2c_write_b_af)(struct msm_actuator_ctrl_t *, - uint8_t, - uint8_t); - int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *, - struct msm_actuator_set_info_t *); - int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *, - uint16_t, struct reg_settings_t *); - int32_t (*actuator_set_default_focus)(struct msm_actuator_ctrl_t *, - struct msm_actuator_move_params_t *); - int32_t (*actuator_move_focus)(struct msm_actuator_ctrl_t *, - struct msm_actuator_move_params_t *); - void (*actuator_parse_i2c_params)(struct msm_actuator_ctrl_t *, - int16_t, uint32_t, uint16_t); - void (*actuator_write_focus)(struct msm_actuator_ctrl_t *, - uint16_t, - struct damping_params_t *, - int8_t, - int16_t); - int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *, - struct msm_actuator_set_position_t *); - int32_t (*actuator_park_lens)(struct msm_actuator_ctrl_t *); -}; - -struct msm_actuator { - enum actuator_type act_type; - struct msm_actuator_func_tbl func_tbl; -}; - -struct msm_actuator_vreg { - struct camera_vreg_t *cam_vreg; - void *data[MSM_ACTUATOR_MAX_VREGS]; - int num_vreg; -}; - -struct msm_actuator_ctrl_t { - struct i2c_driver *i2c_driver; - struct platform_driver *pdriver; - struct platform_device *pdev; - struct msm_camera_i2c_client i2c_client; - enum msm_camera_device_type_t act_device_type; - struct msm_sd_subdev msm_sd; - enum af_camera_name cam_name; - struct mutex *actuator_mutex; - struct msm_actuator_func_tbl *func_tbl; - enum msm_camera_i2c_data_type i2c_data_type; - struct v4l2_subdev sdev; - struct v4l2_subdev_ops *act_v4l2_subdev_ops; - - int16_t curr_step_pos; - uint16_t curr_region_index; - uint16_t *step_position_table; - struct region_params_t region_params[MAX_ACTUATOR_REGION]; - uint16_t reg_tbl_size; - struct msm_actuator_reg_params_t reg_tbl[MAX_ACTUATOR_REG_TBL_SIZE]; - uint16_t region_size; - void *user_data; - uint32_t total_steps; - uint16_t pwd_step; - uint16_t initial_code; - struct msm_camera_i2c_reg_array *i2c_reg_tbl; - uint16_t i2c_tbl_index; - enum cci_i2c_master_t cci_master; - uint32_t subdev_id; - enum msm_actuator_state_t actuator_state; - struct msm_actuator_vreg vreg_cfg; - struct park_lens_data_t park_lens; - uint32_t max_code_size; - struct msm_camera_gpio_conf *gconf; - struct msm_pinctrl_info pinctrl_info; - uint8_t cam_pinctrl_status; -}; - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/cci/Makefile b/drivers/media/platform/msm/ais/sensor/cci/Makefile deleted file mode 100644 index b8b8c83bc6de8ec05dfe661d72c7d0c869431e2e..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/cci/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_cci.o -obj-$(CONFIG_MSM_AIS) += msm_early_cam.o diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/ais/sensor/cci/msm_cam_cci_hwreg.h deleted file mode 100644 index d131ec583bf2a7b4b1af14e19e98c8811713f7ad..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_cam_cci_hwreg.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_CAM_CCI_HWREG__ -#define __MSM_CAM_CCI_HWREG__ - -#define CCI_HW_VERSION_ADDR 0x00000000 -#define CCI_RESET_CMD_ADDR 0x00000004 -#define CCI_RESET_CMD_RMSK 0x0f73f3f7 -#define CCI_M0_RESET_RMSK 0x3F1 -#define CCI_M1_RESET_RMSK 0x3F001 -#define CCI_QUEUE_START_ADDR 0x00000008 -#define CCI_SET_CID_SYNC_TIMER_ADDR 0x00000010 -#define CCI_SET_CID_SYNC_TIMER_OFFSET 0x00000004 -#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100 -#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104 -#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108 -#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c -#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118 -#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110 -#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C -#define CCI_HALT_REQ_ADDR 0x00000034 -#define CCI_M0_HALT_REQ_RMSK 0x1 -#define CCI_M1_HALT_REQ_RMSK 0x2 -#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200 -#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204 -#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208 -#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c -#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210 -#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304 -#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308 -#define CCI_I2C_M0_Q0_REPORT_STATUS_ADDR 0x0000030c -#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300 -#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310 -#define CCI_IRQ_MASK_0_ADDR 0x00000c04 -#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7 -#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08 -#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c -#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000 -#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000 -#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000 -#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000 -#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000 -#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000 -#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100 -#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 -#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 -#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 -#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 -#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00 - -#define DEBUG_TOP_REG_START 0x0 -#define DEBUG_TOP_REG_COUNT 14 -#define DEBUG_MASTER_REG_START 0x100 -#define DEBUG_MASTER_REG_COUNT 8 -#define DEBUG_MASTER_QUEUE_REG_START 0x300 -#define DEBUG_MASTER_QUEUE_REG_COUNT 6 -#define DEBUG_INTR_REG_START 0xC00 -#define DEBUG_INTR_REG_COUNT 7 -#endif /* __MSM_CAM_CCI_HWREG__ */ diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_cci.c b/drivers/media/platform/msm/ais/sensor/cci/msm_cci.c deleted file mode 100644 index bad43f4c4a80294ed1e9bf087f2642eebf15a46c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_cci.c +++ /dev/null @@ -1,2166 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include "msm_sd.h" -#include "msm_cci.h" -#include "msm_cam_cci_hwreg.h" -#include "msm_camera_io_util.h" -#include "msm_camera_dt_util.h" -#include "cam_hw_ops.h" - -#define V4L2_IDENT_CCI 50005 -#define CCI_I2C_QUEUE_0_SIZE 64 -#define CCI_I2C_Q0_SIZE_128W 128 -#define CCI_I2C_QUEUE_1_SIZE 16 -#define CCI_I2C_Q1_SIZE_32W 32 -#define CYCLES_PER_MICRO_SEC_DEFAULT 4915 -#define CCI_MAX_DELAY 1000000 - -#define CCI_TIMEOUT msecs_to_jiffies(500) - -/* TODO move this somewhere else */ -#define MSM_CCI_DRV_NAME "msm_cci" - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -#undef CCI_DBG -#ifdef MSM_CCI_DEBUG -#define CCI_DBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CCI_DBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -/* Max bytes that can be read per CCI read transaction */ -#define CCI_READ_MAX 12 -#define CCI_I2C_READ_MAX_RETRIES 3 -#define CCI_I2C_MAX_READ 8192 -#define CCI_I2C_MAX_WRITE 8192 - -#define PRIORITY_QUEUE (QUEUE_0) -#define SYNC_QUEUE (QUEUE_1) - -static struct v4l2_subdev *g_cci_subdev; - -static void msm_cci_dump_registers(struct cci_device *cci_dev, - enum cci_i2c_master_t master, enum cci_i2c_queue_t queue) -{ - uint32_t read_val = 0; - uint32_t i = 0; - uint32_t reg_offset = 0; - - /* CCI Top Registers */ - CCI_DBG(" **** %s : %d CCI TOP Registers ****\n", __func__, __LINE__); - for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) { - reg_offset = DEBUG_TOP_REG_START + i * 4; - read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset); - CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n", - __func__, __LINE__, reg_offset, read_val); - } - - /* CCI Master registers */ - CCI_DBG(" **** %s : %d CCI MASTER%d Registers ****\n", - __func__, __LINE__, master); - for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) { - if (i == 6) - continue; - reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4; - read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset); - CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n", - __func__, __LINE__, reg_offset, read_val); - } - - /* CCI Master Queue registers */ - CCI_DBG(" **** %s : %d CCI MASTER%d QUEUE%d Registers ****\n", - __func__, __LINE__, master, queue); - for (i = 0; i < DEBUG_MASTER_QUEUE_REG_COUNT; i++) { - reg_offset = DEBUG_MASTER_QUEUE_REG_START + master*0x200 + - queue*0x100 + i * 4; - read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset); - CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n", - __func__, __LINE__, reg_offset, read_val); - } - - /* CCI Interrupt registers */ - CCI_DBG(" **** %s : %d CCI Interrupt Registers ****\n", - __func__, __LINE__); - for (i = 0; i < DEBUG_INTR_REG_COUNT; i++) { - reg_offset = DEBUG_INTR_REG_START + i * 4; - read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset); - CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n", - __func__, __LINE__, reg_offset, read_val); - } -} - -static int32_t msm_cci_set_clk_param(struct cci_device *cci_dev, - struct msm_camera_cci_ctrl *c_ctrl) -{ - struct msm_cci_clk_params_t *clk_params = NULL; - enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; - enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; - - if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { - pr_err("%s:%d invalid i2c_freq_mode = %d", - __func__, __LINE__, i2c_freq_mode); - return -EINVAL; - } - - if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode) - return 0; - - clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; - if (MASTER_0 == master) { - msm_camera_io_w_mb(clk_params->hw_thigh << 16 | - clk_params->hw_tlow, - cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR); - msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | - clk_params->hw_tsu_sta, - cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR); - msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | - clk_params->hw_thd_sta, - cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR); - msm_camera_io_w_mb(clk_params->hw_tbuf, - cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR); - msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | - clk_params->hw_trdhld << 4 | clk_params->hw_tsp, - cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR); - } else if (MASTER_1 == master) { - msm_camera_io_w_mb(clk_params->hw_thigh << 16 | - clk_params->hw_tlow, - cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR); - msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | - clk_params->hw_tsu_sta, - cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR); - msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | - clk_params->hw_thd_sta, - cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR); - msm_camera_io_w_mb(clk_params->hw_tbuf, - cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR); - msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | - clk_params->hw_trdhld << 4 | clk_params->hw_tsp, - cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR); - } - cci_dev->i2c_freq_mode[master] = i2c_freq_mode; - return 0; -} - -static void msm_cci_flush_queue(struct cci_device *cci_dev, - enum cci_i2c_master_t master) -{ - int32_t rc = 0; - - msm_camera_io_w_mb(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR); - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); - if (rc < 0) { - pr_err("%s:%d wait failed\n", __func__, __LINE__); - } else if (rc == 0) { - pr_err("%s:%d wait timeout\n", __func__, __LINE__); - - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; - - /* Set proper mask to RESET CMD address based on MASTER */ - if (master == MASTER_0) - msm_camera_io_w_mb(CCI_M0_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - else - msm_camera_io_w_mb(CCI_M1_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - - /* wait for reset done irq */ - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, - CCI_TIMEOUT); - if (rc <= 0) - pr_err("%s:%d wait failed %d\n", __func__, __LINE__, - rc); - } -} - -static int32_t msm_cci_validate_queue(struct cci_device *cci_dev, - uint32_t len, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - int32_t rc = 0; - uint32_t read_val = 0; - uint32_t reg_offset = master * 0x200 + queue * 0x100; - - read_val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); - CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d\n", - __func__, __LINE__, read_val, len, - cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); - if ((read_val + len + 1) > cci_dev-> - cci_i2c_queue_info[master][queue].max_queue_size) { - uint32_t reg_val = 0; - uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); - - CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__); - msm_camera_io_w_mb(report_val, - cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset); - read_val++; - CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d, queue: %d\n", - __func__, __LINE__, read_val, queue); - msm_camera_io_w_mb(read_val, cci_dev->base + - CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); - reg_val = 1 << ((master * 2) + queue); - CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__); - atomic_set(&cci_dev->cci_master_info[master]. - done_pending[queue], 1); - msm_camera_io_w_mb(reg_val, cci_dev->base + - CCI_QUEUE_START_ADDR); - CDBG("%s line %d wait_for_completion_timeout\n", - __func__, __LINE__); - atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); - rc = wait_for_completion_timeout(&cci_dev-> - cci_master_info[master].report_q[queue], CCI_TIMEOUT); - if (rc <= 0) { - pr_err("%s: wait_for_completion_timeout %d\n", - __func__, __LINE__); - if (rc == 0) - rc = -ETIMEDOUT; - msm_cci_flush_queue(cci_dev, master); - return rc; - } - rc = cci_dev->cci_master_info[master].status; - if (rc < 0) - pr_err("%s failed rc %d\n", __func__, rc); - } - return rc; -} - -static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev, - uint32_t val, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - int32_t rc = 0; - uint32_t reg_offset = master * 0x200 + queue * 0x100; - - if (!cci_dev) { - pr_err("%s: failed %d", __func__, __LINE__); - return -EINVAL; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - rc = msm_cci_validate_queue(cci_dev, 1, master, queue); - if (rc < 0) { - pr_err("%s: failed %d", __func__, __LINE__); - return rc; - } - CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n", - __func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset, val); - msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset); - return rc; -} - -static uint32_t msm_cci_wait(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - int32_t rc = 0; - - if (!cci_dev) { - pr_err("%s: failed %d", __func__, __LINE__); - return -EINVAL; - } - - rc = wait_for_completion_timeout(&cci_dev-> - cci_master_info[master].report_q[queue], CCI_TIMEOUT); - CDBG("%s line %d wait DONE_for_completion_timeout\n", - __func__, __LINE__); - - if (rc <= 0) { - msm_cci_dump_registers(cci_dev, master, queue); - pr_err("%s: %d wait for queue: %d\n", - __func__, __LINE__, queue); - if (rc == 0) - rc = -ETIMEDOUT; - msm_cci_flush_queue(cci_dev, master); - return rc; - } - rc = cci_dev->cci_master_info[master].status; - if (rc < 0) { - pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc); - return rc; - } - return 0; -} - -static int32_t msm_cci_addr_to_num_bytes( - enum msm_camera_i2c_reg_addr_type addr_type) -{ - int32_t retVal; - - switch (addr_type) { - case MSM_CAMERA_I2C_BYTE_ADDR: - retVal = 1; - break; - case MSM_CAMERA_I2C_WORD_ADDR: - retVal = 2; - break; - case MSM_CAMERA_I2C_3B_ADDR: - retVal = 3; - break; - default: - pr_err("%s: %d failed: %d\n", __func__, __LINE__, addr_type); - retVal = 1; - break; - } - return retVal; -} - -static int32_t msm_cci_data_to_num_bytes( - enum msm_camera_i2c_data_type data_type) -{ - int32_t retVal; - - switch (data_type) { - case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - case MSM_CAMERA_I2C_BYTE_DATA: - retVal = 1; - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - case MSM_CAMERA_I2C_WORD_DATA: - retVal = 2; - break; - case MSM_CAMERA_I2C_DWORD_DATA: - retVal = 4; - break; - default: - pr_err("%s: %d failed: %d\n", __func__, __LINE__, data_type); - retVal = 1; - break; - } - return retVal; -} - -static int32_t msm_cci_calc_cmd_len(struct cci_device *cci_dev, - struct msm_camera_cci_ctrl *c_ctrl, uint32_t cmd_size, - struct msm_camera_i2c_reg_array *i2c_cmd, uint32_t *pack) -{ - uint8_t i; - uint32_t len = 0; - uint8_t data_len = 0, addr_len = 0; - uint8_t pack_max_len; - struct msm_camera_i2c_reg_setting *msg; - struct msm_camera_i2c_reg_array *cmd = i2c_cmd; - uint32_t size = cmd_size; - - if (!cci_dev || !c_ctrl) { - pr_err("%s: failed %d", __func__, __LINE__); - return -EINVAL; - } - - msg = &c_ctrl->cfg.cci_i2c_write_cfg; - *pack = 0; - - if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) { - addr_len = msm_cci_addr_to_num_bytes(msg->addr_type); - len = (size + addr_len) <= (cci_dev->payload_size) ? - (size + addr_len):cci_dev->payload_size; - } else { - addr_len = msm_cci_addr_to_num_bytes(msg->addr_type); - data_len = msm_cci_data_to_num_bytes(msg->data_type); - len = data_len + addr_len; - pack_max_len = size < (cci_dev->payload_size-len) ? - size : (cci_dev->payload_size-len); - for (i = 0; i < pack_max_len;) { - if (cmd->delay || ((cmd - i2c_cmd) >= (cmd_size - 1))) - break; - if (cmd->reg_addr + 1 == - (cmd+1)->reg_addr) { - len += data_len; - *pack += data_len; - } else - break; - i += data_len; - cmd++; - } - } - - if (len > cci_dev->payload_size) { - pr_err("Len error: %d", len); - return -EINVAL; - } - - len += 1; /*add i2c WR command*/ - len = len/4 + 1; - - return len; -} - -static void msm_cci_load_report_cmd(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - uint32_t reg_offset = master * 0x200 + queue * 0x100; - uint32_t read_val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); - uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); - - CDBG("%s:%d CCI_I2C_REPORT_CMD curr_w_cnt: %d\n", - __func__, __LINE__, read_val); - msm_camera_io_w_mb(report_val, - cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset); - read_val++; - - CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d\n", - __func__, __LINE__, read_val); - msm_camera_io_w_mb(read_val, cci_dev->base + - CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); -} - -static int32_t msm_cci_wait_report_cmd(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - uint32_t reg_val = 1 << ((master * 2) + queue); - - msm_cci_load_report_cmd(cci_dev, master, queue); - atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); - atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1); - msm_camera_io_w_mb(reg_val, cci_dev->base + - CCI_QUEUE_START_ADDR); - return msm_cci_wait(cci_dev, master, queue); -} - -static void msm_cci_process_half_q(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - uint32_t reg_val = 1 << ((master * 2) + queue); - - if (0 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) { - msm_cci_load_report_cmd(cci_dev, master, queue); - atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); - msm_camera_io_w_mb(reg_val, cci_dev->base + - CCI_QUEUE_START_ADDR); - } -} - -static int32_t msm_cci_process_full_q(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - int32_t rc = 0; - - if (1 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) { - atomic_set(&cci_dev->cci_master_info[master]. - done_pending[queue], 1); - rc = msm_cci_wait(cci_dev, master, queue); - if (rc < 0) { - pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc); - return rc; - } - } else { - rc = msm_cci_wait_report_cmd(cci_dev, master, queue); - if (rc < 0) { - pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc); - return rc; - } - } - return rc; -} - -static int32_t msm_cci_lock_queue(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue, uint32_t en) -{ - uint32_t val; - - if (queue != PRIORITY_QUEUE) - return 0; - - val = en ? CCI_I2C_LOCK_CMD : CCI_I2C_UNLOCK_CMD; - return msm_cci_write_i2c_queue(cci_dev, val, master, queue); -} - -static int32_t msm_cci_transfer_end(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - int32_t rc = 0; - - if (0 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) { - rc = msm_cci_lock_queue(cci_dev, master, queue, 0); - if (rc < 0) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - rc = msm_cci_wait_report_cmd(cci_dev, master, queue); - if (rc < 0) { - pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc); - return rc; - } - } else { - atomic_set(&cci_dev->cci_master_info[master]. - done_pending[queue], 1); - rc = msm_cci_wait(cci_dev, master, queue); - if (rc < 0) { - pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc); - return rc; - } - rc = msm_cci_lock_queue(cci_dev, master, queue, 0); - if (rc < 0) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - rc = msm_cci_wait_report_cmd(cci_dev, master, queue); - if (rc < 0) { - pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc); - return rc; - } - } - return rc; -} - -static int32_t msm_cci_get_queue_free_size(struct cci_device *cci_dev, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - uint32_t read_val = 0; - uint32_t reg_offset = master * 0x200 + queue * 0x100; - - read_val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); - CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d max %d\n", - __func__, __LINE__, read_val, - cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); - return (cci_dev-> - cci_i2c_queue_info[master][queue].max_queue_size) - - read_val; -} - -static int32_t msm_cci_data_queue(struct cci_device *cci_dev, - struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, - enum cci_i2c_sync sync_en) -{ - uint16_t i = 0, j = 0, k = 0, h = 0, len = 0; - int32_t rc = 0, free_size = 0, en_seq_write = 0; - uint32_t cmd = 0, delay = 0; - uint8_t data[12]; - uint16_t reg_addr = 0; - struct msm_camera_i2c_reg_setting *i2c_msg = - &c_ctrl->cfg.cci_i2c_write_cfg; - uint16_t cmd_size = i2c_msg->size; - struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting; - enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; - - uint32_t read_val = 0; - uint32_t reg_offset; - uint32_t val = 0; - uint32_t max_queue_size, queue_size = 0; - - if (i2c_cmd == NULL) { - pr_err("%s:%d Failed line\n", __func__, - __LINE__); - return -EINVAL; - } - - if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) { - pr_err("%s:%d failed: invalid cmd_size %d\n", - __func__, __LINE__, cmd_size); - return -EINVAL; - } - - CDBG("%s addr type %d data type %d cmd_size %d\n", __func__, - i2c_msg->addr_type, i2c_msg->data_type, cmd_size); - - if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { - pr_err("%s:%d failed: invalid addr_type 0x%X\n", - __func__, __LINE__, i2c_msg->addr_type); - return -EINVAL; - } - if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) { - pr_err("%s:%d failed: invalid data_type 0x%X\n", - __func__, __LINE__, i2c_msg->data_type); - return -EINVAL; - } - reg_offset = master * 0x200 + queue * 0x100; - - msm_camera_io_w_mb(cci_dev->cci_wait_sync_cfg.cid, - cci_dev->base + CCI_SET_CID_SYNC_TIMER_ADDR + - cci_dev->cci_wait_sync_cfg.csid * - CCI_SET_CID_SYNC_TIMER_OFFSET); - - val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | - c_ctrl->cci_info->retries << 16 | - c_ctrl->cci_info->id_map << 18; - - CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n", - __func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset, val); - msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset); - - atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0); - - max_queue_size = cci_dev->cci_i2c_queue_info[master][queue]. - max_queue_size; - - if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) - queue_size = max_queue_size; - else - queue_size = max_queue_size/2; - reg_addr = i2c_cmd->reg_addr; - - if (sync_en == MSM_SYNC_ENABLE && cci_dev->valid_sync && - cmd_size < max_queue_size) { - val = CCI_I2C_WAIT_SYNC_CMD | - ((cci_dev->cci_wait_sync_cfg.line) << 4); - msm_camera_io_w_mb(val, - cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset); - } - - rc = msm_cci_lock_queue(cci_dev, master, queue, 1); - if (rc < 0) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - - while (cmd_size) { - uint32_t pack = 0; - - len = msm_cci_calc_cmd_len(cci_dev, c_ctrl, cmd_size, - i2c_cmd, &pack); - if (len <= 0) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return -EINVAL; - } - - read_val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); - CDBG("%s line %d CUR_WORD_CNT_ADDR %d len %d max %d\n", - __func__, __LINE__, read_val, len, max_queue_size); - /* + 1 - space alocation for Report CMD */ - if ((read_val + len + 1) > queue_size) { - if ((read_val + len + 1) > max_queue_size) { - rc = msm_cci_process_full_q(cci_dev, - master, queue); - if (rc < 0) { - pr_err("%s failed line %d\n", - __func__, __LINE__); - return rc; - } - continue; - } - msm_cci_process_half_q(cci_dev, master, queue); - } - - CDBG("%s cmd_size %d addr 0x%x data 0x%x\n", __func__, - cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data); - delay = i2c_cmd->delay; - i = 0; - data[i++] = CCI_I2C_WRITE_CMD; - - /* in case of multiple command - * MSM_CCI_I2C_WRITE : address is not continuous, so update - * address for a new packet. - * MSM_CCI_I2C_WRITE_SEQ : address is continuous, need to keep - * the incremented address for a - * new packet */ - if (c_ctrl->cmd == MSM_CCI_I2C_WRITE || - c_ctrl->cmd == MSM_CCI_I2C_WRITE_ASYNC || - c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC || - c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC_BLOCK) - reg_addr = i2c_cmd->reg_addr; - - if (en_seq_write == 0) { - /* either byte or word addr */ - if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) - data[i++] = reg_addr; - else { - data[i++] = (reg_addr & 0xFF00) >> 8; - data[i++] = reg_addr & 0x00FF; - } - } - /* max of 10 data bytes */ - do { - if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) { - data[i++] = i2c_cmd->reg_data; - reg_addr++; - } else { - if ((i + 1) <= cci_dev->payload_size) { - data[i++] = (i2c_cmd->reg_data & - 0xFF00) >> 8; /* MSB */ - data[i++] = i2c_cmd->reg_data & - 0x00FF; /* LSB */ - reg_addr++; - } else - break; - } - i2c_cmd++; - --cmd_size; - } while (((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) || pack--) && - (cmd_size > 0) && (i <= cci_dev->payload_size)); - free_size = msm_cci_get_queue_free_size(cci_dev, master, - queue); - if ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) && - ((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) && - cci_dev->support_seq_write && cmd_size > 0 && - free_size > BURST_MIN_FREE_SIZE) { - data[0] |= 0xF0; - en_seq_write = 1; - } else { - data[0] |= ((i-1) << 4); - en_seq_write = 0; - } - len = ((i-1)/4) + 1; - - read_val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); - for (h = 0, k = 0; h < len; h++) { - cmd = 0; - for (j = 0; (j < 4 && k < i); j++) - cmd |= (data[k++] << (j * 8)); - CDBG("%s LOAD_DATA_ADDR 0x%x, q: %d, len:%d, cnt: %d\n", - __func__, cmd, queue, len, read_val); - msm_camera_io_w_mb(cmd, cci_dev->base + - CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - master * 0x200 + queue * 0x100); - - read_val += 1; - msm_camera_io_w_mb(read_val, cci_dev->base + - CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); - } - - if ((delay > 0) && (delay < CCI_MAX_DELAY) && - en_seq_write == 0) { - cmd = (uint32_t)((delay * cci_dev->cycles_per_us) / - 0x100); - cmd <<= 4; - cmd |= CCI_I2C_WAIT_CMD; - CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n", - __func__, cmd); - msm_camera_io_w_mb(cmd, cci_dev->base + - CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - master * 0x200 + queue * 0x100); - read_val += 1; - msm_camera_io_w_mb(read_val, cci_dev->base + - CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); - } - } - - rc = msm_cci_transfer_end(cci_dev, master, queue); - if (rc < 0) { - pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc); - return rc; - } - return rc; -} - -static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - int32_t rc = 0; - uint32_t val = 0; - int32_t read_words = 0, exp_words = 0; - int32_t index = 0, first_byte = 0; - uint32_t i = 0; - enum cci_i2c_master_t master; - enum cci_i2c_queue_t queue = QUEUE_1; - struct cci_device *cci_dev = NULL; - struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; - - CDBG("%s line %d\n", __func__, __LINE__); - cci_dev = v4l2_get_subdevdata(sd); - master = c_ctrl->cci_info->cci_i2c_master; - read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; - - if (master >= MASTER_MAX || master < 0) { - pr_err("%s:%d Invalid I2C master %d\n", - __func__, __LINE__, master); - return -EINVAL; - } - - mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); - - /* Set the I2C Frequency */ - rc = msm_cci_set_clk_param(cci_dev, c_ctrl); - if (rc < 0) { - pr_err("%s:%d msm_cci_set_clk_param failed rc = %d\n", - __func__, __LINE__, rc); - return rc; - } - - /* - * Call validate queue to make sure queue is empty before starting. - * If this call fails, don't proceed with i2c_read call. This is to - * avoid overflow / underflow of queue - */ - rc = msm_cci_validate_queue(cci_dev, - cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, - master, queue); - if (rc < 0) { - pr_err("%s:%d Initial validataion failed rc %d\n", __func__, - __LINE__, rc); - goto ERROR; - } - - if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { - pr_err("%s:%d More than max retries\n", __func__, - __LINE__); - goto ERROR; - } - - if (read_cfg->data == NULL) { - pr_err("%s:%d Data ptr is NULL\n", __func__, - __LINE__); - goto ERROR; - } - - CDBG("%s master %d, queue %d\n", __func__, master, queue); - CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, - c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, - c_ctrl->cci_info->id_map); - val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | - c_ctrl->cci_info->retries << 16 | - c_ctrl->cci_info->id_map << 18; - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_LOCK_CMD; - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); - for (i = 0; i < read_cfg->addr_type; i++) { - val |= ((read_cfg->addr >> (i << 3)) & 0xFF) << - ((read_cfg->addr_type - i) << 3); - } - - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_UNLOCK_CMD; - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR - + master * 0x200 + queue * 0x100); - CDBG("%s cur word cnt 0x%x\n", __func__, val); - msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR - + master * 0x200 + queue * 0x100); - - val = 1 << ((master * 2) + queue); - msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR); - CDBG("%s:%d E wait_for_completion_timeout\n", __func__, - __LINE__); - - rc = wait_for_completion_timeout(&cci_dev-> - cci_master_info[master].reset_complete, CCI_TIMEOUT); - if (rc <= 0) { - msm_cci_dump_registers(cci_dev, master, queue); - if (rc == 0) - rc = -ETIMEDOUT; - pr_err("%s: %d wait_for_completion_timeout rc = %d\n", - __func__, __LINE__, rc); - msm_cci_flush_queue(cci_dev, master); - goto ERROR; - } else { - rc = 0; - } - - read_words = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); - exp_words = ((read_cfg->num_byte / 4) + 1); - if (read_words != exp_words) { - pr_err("%s:%d read_words = %d, exp words = %d\n", __func__, - __LINE__, read_words, exp_words); - memset(read_cfg->data, 0, read_cfg->num_byte); - rc = -EINVAL; - goto ERROR; - } - index = 0; - CDBG("%s index %d num_type %d\n", __func__, index, - read_cfg->num_byte); - first_byte = 0; - do { - val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); - CDBG("%s read val 0x%x\n", __func__, val); - for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) { - CDBG("%s i %d index %d\n", __func__, i, index); - if (!first_byte) { - CDBG("%s sid 0x%x\n", __func__, val & 0xFF); - first_byte++; - } else { - read_cfg->data[index] = - (val >> (i * 8)) & 0xFF; - CDBG("%s data[%d] 0x%x\n", __func__, index, - read_cfg->data[index]); - index++; - } - } - } while (--read_words > 0); -ERROR: - mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); - return rc; -} - -static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - int32_t rc = 0; - struct cci_device *cci_dev = NULL; - enum cci_i2c_master_t master; - struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; - uint16_t read_bytes = 0; - - if (!sd || !c_ctrl) { - pr_err("%s:%d sd %pK c_ctrl %pK\n", __func__, - __LINE__, sd, c_ctrl); - return -EINVAL; - } - if (!c_ctrl->cci_info) { - pr_err("%s:%d cci_info NULL\n", __func__, __LINE__); - return -EINVAL; - } - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev) { - pr_err("%s:%d cci_dev NULL\n", __func__, __LINE__); - return -EINVAL; - } - if (cci_dev->cci_state != CCI_STATE_ENABLED) { - pr_err("%s invalid cci state %d\n", - __func__, cci_dev->cci_state); - return -EINVAL; - } - - if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX - || c_ctrl->cci_info->cci_i2c_master < 0) { - pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); - return -EINVAL; - } - - master = c_ctrl->cci_info->cci_i2c_master; - read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; - if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) { - pr_err("%s:%d read num bytes 0\n", __func__, __LINE__); - rc = -EINVAL; - goto ERROR; - } - - read_bytes = read_cfg->num_byte; - do { - if (read_bytes > CCI_READ_MAX) - read_cfg->num_byte = CCI_READ_MAX; - else - read_cfg->num_byte = read_bytes; - rc = msm_cci_i2c_read(sd, c_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); - goto ERROR; - } - if (read_bytes > CCI_READ_MAX) { - read_cfg->addr += CCI_READ_MAX; - read_cfg->data += CCI_READ_MAX; - read_bytes -= CCI_READ_MAX; - } else { - read_bytes = 0; - } - } while (read_bytes); -ERROR: - return rc; -} - -static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, - enum cci_i2c_sync sync_en) -{ - int32_t rc = 0; - struct cci_device *cci_dev; - enum cci_i2c_master_t master; - - cci_dev = v4l2_get_subdevdata(sd); - if (cci_dev->cci_state != CCI_STATE_ENABLED) { - pr_err("%s invalid cci state %d\n", - __func__, cci_dev->cci_state); - return -EINVAL; - } - master = c_ctrl->cci_info->cci_i2c_master; - CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, - c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, - c_ctrl->cci_info->id_map); - - /* Set the I2C Frequency */ - rc = msm_cci_set_clk_param(cci_dev, c_ctrl); - if (rc < 0) { - pr_err("%s:%d msm_cci_set_clk_param failed rc = %d\n", - __func__, __LINE__, rc); - return rc; - } - /* - * Call validate queue to make sure queue is empty before starting. - * If this call fails, don't proceed with i2c_write call. This is to - * avoid overflow / underflow of queue - */ - rc = msm_cci_validate_queue(cci_dev, - cci_dev->cci_i2c_queue_info[master][queue].max_queue_size-1, - master, queue); - if (rc < 0) { - pr_err("%s:%d Initial validataion failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } - if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { - pr_err("%s:%d More than max retries\n", __func__, - __LINE__); - goto ERROR; - } - rc = msm_cci_data_queue(cci_dev, c_ctrl, queue, sync_en); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - -ERROR: - return rc; -} - -static void msm_cci_write_async_helper(struct work_struct *work) -{ - int rc; - struct cci_device *cci_dev; - struct cci_write_async *write_async = - container_of(work, struct cci_write_async, work); - struct msm_camera_i2c_reg_setting *i2c_msg; - enum cci_i2c_master_t master; - struct msm_camera_cci_master_info *cci_master_info; - - cci_dev = write_async->cci_dev; - i2c_msg = &write_async->c_ctrl.cfg.cci_i2c_write_cfg; - master = write_async->c_ctrl.cci_info->cci_i2c_master; - cci_master_info = &cci_dev->cci_master_info[master]; - - mutex_lock(&cci_master_info->mutex_q[write_async->queue]); - rc = msm_cci_i2c_write(&cci_dev->msm_sd.sd, - &write_async->c_ctrl, write_async->queue, write_async->sync_en); - mutex_unlock(&cci_master_info->mutex_q[write_async->queue]); - if (rc < 0) - pr_err("%s: %d failed\n", __func__, __LINE__); - - kfree(write_async->c_ctrl.cfg.cci_i2c_write_cfg.reg_setting); - kfree(write_async); - - CDBG("%s: %d Exit\n", __func__, __LINE__); -} - -static int32_t msm_cci_i2c_write_async(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, - enum cci_i2c_sync sync_en) -{ - struct cci_write_async *write_async; - struct cci_device *cci_dev; - struct msm_camera_i2c_reg_setting *cci_i2c_write_cfg; - struct msm_camera_i2c_reg_setting *cci_i2c_write_cfg_w; - - cci_dev = v4l2_get_subdevdata(sd); - - CDBG("%s: %d Enter\n", __func__, __LINE__); - - write_async = kzalloc(sizeof(*write_async), GFP_KERNEL); - if (!write_async) - return -ENOMEM; - - INIT_WORK(&write_async->work, msm_cci_write_async_helper); - write_async->cci_dev = cci_dev; - write_async->c_ctrl = *c_ctrl; - write_async->queue = queue; - write_async->sync_en = sync_en; - - cci_i2c_write_cfg = &c_ctrl->cfg.cci_i2c_write_cfg; - cci_i2c_write_cfg_w = &write_async->c_ctrl.cfg.cci_i2c_write_cfg; - - if (cci_i2c_write_cfg->size == 0) { - pr_err("%s: %d Size = 0\n", __func__, __LINE__); - kfree(write_async); - return -EINVAL; - } - - cci_i2c_write_cfg_w->reg_setting = - kzalloc(sizeof(struct msm_camera_i2c_reg_array)* - cci_i2c_write_cfg->size, GFP_KERNEL); - if (!cci_i2c_write_cfg_w->reg_setting) { - pr_err("%s: %d Couldn't allocate memory\n", __func__, __LINE__); - kfree(write_async); - return -ENOMEM; - } - memcpy(cci_i2c_write_cfg_w->reg_setting, - cci_i2c_write_cfg->reg_setting, - (sizeof(struct msm_camera_i2c_reg_array)* - cci_i2c_write_cfg->size)); - - cci_i2c_write_cfg_w->addr_type = cci_i2c_write_cfg->addr_type; - cci_i2c_write_cfg_w->data_type = cci_i2c_write_cfg->data_type; - cci_i2c_write_cfg_w->size = cci_i2c_write_cfg->size; - cci_i2c_write_cfg_w->delay = cci_i2c_write_cfg->delay; - - queue_work(cci_dev->write_wq[write_async->queue], &write_async->work); - - CDBG("%s: %d Exit\n", __func__, __LINE__); - - return 0; -} - -static int32_t msm_cci_pinctrl_init(struct cci_device *cci_dev) -{ - struct msm_pinctrl_info *cci_pctrl = NULL; - - cci_pctrl = &cci_dev->cci_pinctrl; - cci_pctrl->pinctrl = devm_pinctrl_get(&cci_dev->pdev->dev); - if (IS_ERR_OR_NULL(cci_pctrl->pinctrl)) { - pr_err("%s:%d devm_pinctrl_get cci_pinctrl failed\n", - __func__, __LINE__); - return -EINVAL; - } - cci_pctrl->gpio_state_active = pinctrl_lookup_state( - cci_pctrl->pinctrl, - CCI_PINCTRL_STATE_DEFAULT); - if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_active)) { - pr_err("%s:%d look up state for active state failed\n", - __func__, __LINE__); - return -EINVAL; - } - cci_pctrl->gpio_state_suspend = pinctrl_lookup_state( - cci_pctrl->pinctrl, - CCI_PINCTRL_STATE_SLEEP); - if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_suspend)) { - pr_err("%s:%d look up state for suspend state failed\n", - __func__, __LINE__); - return -EINVAL; - } - return 0; -} - -static uint32_t msm_cci_cycles_per_ms(unsigned long clk) -{ - uint32_t cycles_per_us; - - if (clk) - cycles_per_us = ((clk/1000)*256)/1000; - else { - pr_err("%s:%d, failed: Can use default: %d", - __func__, __LINE__, CYCLES_PER_MICRO_SEC_DEFAULT); - cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT; - } - return cycles_per_us; -} - -static uint32_t *msm_cci_get_clk_rates(struct cci_device *cci_dev, - struct msm_camera_cci_ctrl *c_ctrl) -{ - uint32_t j; - int32_t idx; - uint32_t cci_clk_src; - unsigned long clk; - - struct msm_cci_clk_params_t *clk_params = NULL; - enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; - struct device_node *of_node = cci_dev->pdev->dev.of_node; - - if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { - pr_err("%s:%d invalid i2c_freq_mode %d\n", - __func__, __LINE__, i2c_freq_mode); - return NULL; - } - - clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; - cci_clk_src = clk_params->cci_clk_src; - - idx = of_property_match_string(of_node, - "clock-names", CCI_CLK_SRC_NAME); - if (idx < 0) { - cci_dev->cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT; - return cci_dev->cci_clk_rates[0]; - } - - if (cci_clk_src == 0) { - clk = cci_dev->cci_clk_rates[0][idx]; - cci_dev->cycles_per_us = msm_cci_cycles_per_ms(clk); - return cci_dev->cci_clk_rates[0]; - } - - for (j = 0; j < cci_dev->num_clk_cases; j++) { - clk = cci_dev->cci_clk_rates[j][idx]; - if (clk == cci_clk_src) { - cci_dev->cycles_per_us = msm_cci_cycles_per_ms(clk); - cci_dev->cci_clk_src = cci_clk_src; - return cci_dev->cci_clk_rates[j]; - } - } - - return NULL; -} - -static int32_t msm_cci_i2c_set_sync_prms(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - int32_t rc = 0; - struct cci_device *cci_dev; - - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev || !c_ctrl) { - pr_err("%s:%d failed: invalid params %pK %pK\n", __func__, - __LINE__, cci_dev, c_ctrl); - rc = -EINVAL; - return rc; - } - cci_dev->cci_wait_sync_cfg = c_ctrl->cfg.cci_wait_sync_cfg; - cci_dev->valid_sync = cci_dev->cci_wait_sync_cfg.csid < 0 ? 0 : 1; - - return rc; -} - -static int32_t msm_cci_init(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - uint8_t i = 0, j = 0; - int32_t rc = 0, ret = 0; - struct cci_device *cci_dev; - enum cci_i2c_master_t master = MASTER_0; - uint32_t *clk_rates = NULL; - - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev || !c_ctrl) { - pr_err("%s:%d failed: invalid params %pK %pK\n", __func__, - __LINE__, cci_dev, c_ctrl); - rc = -EINVAL; - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - if (cci_dev->ref_count++) { - CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count); - master = c_ctrl->cci_info->cci_i2c_master; - CDBG("%s:%d master %d\n", __func__, __LINE__, master); - if (master < MASTER_MAX && master >= 0) { - mutex_lock(&cci_dev->cci_master_info[master].mutex); - mutex_lock(&cci_dev->cci_master_info[master]. - mutex_q[PRIORITY_QUEUE]); - mutex_lock(&cci_dev->cci_master_info[master]. - mutex_q[SYNC_QUEUE]); - flush_workqueue(cci_dev->write_wq[master]); - /* Re-initialize the completion */ - reinit_completion(&cci_dev-> - cci_master_info[master].reset_complete); - for (i = 0; i < NUM_QUEUES; i++) - reinit_completion(&cci_dev-> - cci_master_info[master].report_q[i]); - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; - /* Set proper mask to RESET CMD address */ - if (master == MASTER_0) - msm_camera_io_w_mb(CCI_M0_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - else - msm_camera_io_w_mb(CCI_M1_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - /* wait for reset done irq */ - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master]. - reset_complete, - CCI_TIMEOUT); - if (rc <= 0) - pr_err("%s:%d wait failed %d\n", __func__, - __LINE__, rc); - mutex_unlock(&cci_dev->cci_master_info[master]. - mutex_q[SYNC_QUEUE]); - mutex_unlock(&cci_dev->cci_master_info[master]. - mutex_q[PRIORITY_QUEUE]); - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - } - return 0; - } - ret = msm_cci_pinctrl_init(cci_dev); - if (ret < 0) { - pr_err("%s:%d Initialization of pinctrl failed\n", - __func__, __LINE__); - cci_dev->cci_pinctrl_status = 0; - } else { - cci_dev->cci_pinctrl_status = 1; - } - rc = msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, - cci_dev->cci_gpio_tbl_size, 1); - if (cci_dev->cci_pinctrl_status) { - ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, - cci_dev->cci_pinctrl.gpio_state_active); - if (ret) - pr_err("%s:%d cannot set pin to active state\n", - __func__, __LINE__); - } - if (rc < 0) { - CDBG("%s: request gpio failed\n", __func__); - goto request_gpio_failed; - } - - rc = msm_camera_config_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg, - cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d cci config_vreg failed\n", __func__, __LINE__); - goto clk_enable_failed; - } - - rc = msm_camera_enable_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg, - cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d cci enable_vreg failed\n", __func__, __LINE__); - goto reg_enable_failed; - } - - clk_rates = msm_cci_get_clk_rates(cci_dev, c_ctrl); - if (!clk_rates) { - pr_err("%s: clk enable failed\n", __func__); - goto reg_enable_failed; - } - - for (i = 0; i < cci_dev->num_clk; i++) { - cci_dev->cci_clk_info[i].clk_rate = - clk_rates[i]; - } - rc = msm_camera_clk_enable(&cci_dev->pdev->dev, - cci_dev->cci_clk_info, cci_dev->cci_clk, - cci_dev->num_clk, true); - if (rc < 0) { - pr_err("%s: clk enable failed\n", __func__); - goto reg_enable_failed; - } - - /* Re-initialize the completion */ - reinit_completion(&cci_dev->cci_master_info[master].reset_complete); - for (i = 0; i < NUM_QUEUES; i++) - reinit_completion(&cci_dev->cci_master_info[master]. - report_q[i]); - rc = msm_camera_enable_irq(cci_dev->irq, true); - if (rc < 0) - pr_err("%s: irq enable failed\n", __func__); - cci_dev->hw_version = msm_camera_io_r_mb(cci_dev->base + - CCI_HW_VERSION_ADDR); - pr_info("%s:%d: hw_version = 0x%x\n", __func__, __LINE__, - cci_dev->hw_version); - cci_dev->payload_size = - MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_10; - cci_dev->support_seq_write = 0; - if (cci_dev->hw_version >= 0x10020000) { - cci_dev->payload_size = - MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; - cci_dev->support_seq_write = 1; - } - for (i = 0; i < NUM_MASTERS; i++) { - for (j = 0; j < NUM_QUEUES; j++) { - if (j == QUEUE_0) { - if (cci_dev->hw_version >= 0x10060000) - cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size = - CCI_I2C_Q0_SIZE_128W; - else - cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size = - CCI_I2C_QUEUE_0_SIZE; - } else { - if (cci_dev->hw_version >= 0x10060000) - cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size = - CCI_I2C_Q1_SIZE_32W; - else - cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size = - CCI_I2C_QUEUE_1_SIZE; - } - CDBG("CCI Master[%d] :: Q0 size: %d Q1 size: %d\n", i, - cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size, - cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size); - } - } - - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; - msm_camera_io_w_mb(CCI_RESET_CMD_RMSK, cci_dev->base + - CCI_RESET_CMD_ADDR); - msm_camera_io_w_mb(0x1, cci_dev->base + CCI_RESET_CMD_ADDR); - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[MASTER_0].reset_complete, - CCI_TIMEOUT); - if (rc <= 0) { - pr_err("%s: wait_for_completion_timeout %d\n", - __func__, __LINE__); - if (rc == 0) - rc = -ETIMEDOUT; - goto reset_complete_failed; - } - for (i = 0; i < MASTER_MAX; i++) - cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; - msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, - cci_dev->base + CCI_IRQ_MASK_0_ADDR); - msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, - cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); - msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); - - for (i = 0; i < MASTER_MAX; i++) { - if (!cci_dev->write_wq[i]) { - pr_err("Failed to flush write wq\n"); - rc = -ENOMEM; - goto reset_complete_failed; - } else { - flush_workqueue(cci_dev->write_wq[i]); - } - } - cci_dev->cci_state = CCI_STATE_ENABLED; - - return 0; - -reset_complete_failed: - msm_camera_enable_irq(cci_dev->irq, false); - msm_camera_clk_enable(&cci_dev->pdev->dev, cci_dev->cci_clk_info, - cci_dev->cci_clk, cci_dev->num_clk, false); -reg_enable_failed: - msm_camera_config_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg, - cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 0); -clk_enable_failed: - if (cci_dev->cci_pinctrl_status) { - ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, - cci_dev->cci_pinctrl.gpio_state_suspend); - if (ret) - pr_err("%s:%d cannot set pin to suspend state\n", - __func__, __LINE__); - } - msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, - cci_dev->cci_gpio_tbl_size, 0); -request_gpio_failed: - cci_dev->ref_count--; - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - return rc; -} - -static int32_t msm_cci_release(struct v4l2_subdev *sd) -{ - uint8_t i = 0, rc = 0; - struct cci_device *cci_dev; - - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { - pr_err("%s invalid ref count %d / cci state %d\n", - __func__, cci_dev->ref_count, cci_dev->cci_state); - rc = -EINVAL; - goto ahb_vote_suspend; - } - if (--cci_dev->ref_count) { - CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count); - rc = 0; - goto ahb_vote_suspend; - } - for (i = 0; i < MASTER_MAX; i++) - if (cci_dev->write_wq[i]) - flush_workqueue(cci_dev->write_wq[i]); - - msm_camera_enable_irq(cci_dev->irq, false); - msm_camera_clk_enable(&cci_dev->pdev->dev, cci_dev->cci_clk_info, - cci_dev->cci_clk, cci_dev->num_clk, false); - - rc = msm_camera_enable_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg, - cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 0); - if (rc < 0) - pr_err("%s:%d cci disable_vreg failed\n", __func__, __LINE__); - - rc = msm_camera_config_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg, - cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 0); - if (rc < 0) - pr_err("%s:%d cci unconfig_vreg failed\n", __func__, __LINE__); - - if (cci_dev->cci_pinctrl_status) { - rc = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, - cci_dev->cci_pinctrl.gpio_state_suspend); - if (rc) - pr_err("%s:%d cannot set pin to active state\n", - __func__, __LINE__); - } - cci_dev->cci_pinctrl_status = 0; - msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, - cci_dev->cci_gpio_tbl_size, 0); - for (i = 0; i < MASTER_MAX; i++) - cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; - cci_dev->cci_state = CCI_STATE_DISABLED; - cci_dev->cycles_per_us = 0; - cci_dev->cci_clk_src = 0; - -ahb_vote_suspend: - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - return rc; -} - -static int32_t msm_cci_write(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - int32_t rc = 0; - struct cci_device *cci_dev; - enum cci_i2c_master_t master; - struct msm_camera_cci_master_info *cci_master_info; - uint32_t i; - - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev || !c_ctrl) { - pr_err("%s:%d failed: invalid params %pK %pK\n", __func__, - __LINE__, cci_dev, c_ctrl); - rc = -EINVAL; - return rc; - } - - if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX - || c_ctrl->cci_info->cci_i2c_master < 0) { - pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); - return -EINVAL; - } - master = c_ctrl->cci_info->cci_i2c_master; - cci_master_info = &cci_dev->cci_master_info[master]; - - switch (c_ctrl->cmd) { - case MSM_CCI_I2C_WRITE_SYNC_BLOCK: - mutex_lock(&cci_master_info->mutex_q[SYNC_QUEUE]); - rc = msm_cci_i2c_write(sd, c_ctrl, - SYNC_QUEUE, MSM_SYNC_ENABLE); - mutex_unlock(&cci_master_info->mutex_q[SYNC_QUEUE]); - break; - case MSM_CCI_I2C_WRITE_SYNC: - rc = msm_cci_i2c_write_async(sd, c_ctrl, - SYNC_QUEUE, MSM_SYNC_ENABLE); - break; - case MSM_CCI_I2C_WRITE: - case MSM_CCI_I2C_WRITE_SEQ: - for (i = 0; i < NUM_QUEUES; i++) { - if (mutex_trylock(&cci_master_info->mutex_q[i])) { - rc = msm_cci_i2c_write(sd, c_ctrl, i, - MSM_SYNC_DISABLE); - mutex_unlock(&cci_master_info->mutex_q[i]); - return rc; - } - } - mutex_lock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); - rc = msm_cci_i2c_write(sd, c_ctrl, - PRIORITY_QUEUE, MSM_SYNC_DISABLE); - mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); - break; - case MSM_CCI_I2C_WRITE_ASYNC: - rc = msm_cci_i2c_write_async(sd, c_ctrl, - PRIORITY_QUEUE, MSM_SYNC_DISABLE); - break; - default: - rc = -ENOIOCTLCMD; - } - return rc; -} - -static int32_t msm_cci_config(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *cci_ctrl) -{ - int32_t rc = 0; - - CDBG("%s line %d cmd %d\n", __func__, __LINE__, - cci_ctrl->cmd); - switch (cci_ctrl->cmd) { - case MSM_CCI_INIT: - rc = msm_cci_init(sd, cci_ctrl); - break; - case MSM_CCI_RELEASE: - rc = msm_cci_release(sd); - break; - case MSM_CCI_I2C_READ: - rc = msm_cci_i2c_read_bytes(sd, cci_ctrl); - break; - case MSM_CCI_I2C_WRITE: - case MSM_CCI_I2C_WRITE_SEQ: - case MSM_CCI_I2C_WRITE_SYNC: - case MSM_CCI_I2C_WRITE_ASYNC: - case MSM_CCI_I2C_WRITE_SYNC_BLOCK: - rc = msm_cci_write(sd, cci_ctrl); - break; - case MSM_CCI_GPIO_WRITE: - break; - case MSM_CCI_SET_SYNC_CID: - rc = msm_cci_i2c_set_sync_prms(sd, cci_ctrl); - break; - - default: - rc = -ENOIOCTLCMD; - } - CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); - cci_ctrl->status = rc; - return rc; -} - -static irqreturn_t msm_cci_irq(int irq_num, void *data) -{ - uint32_t irq; - struct cci_device *cci_dev = data; - - irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR); - msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); - msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); - CDBG("%s CCI_I2C_M0_STATUS_ADDR = 0x%x\n", __func__, irq); - if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { - if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { - cci_dev->cci_master_info[MASTER_0].reset_pending = - FALSE; - complete(&cci_dev->cci_master_info[MASTER_0]. - reset_complete); - } - if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { - cci_dev->cci_master_info[MASTER_1].reset_pending = - FALSE; - complete(&cci_dev->cci_master_info[MASTER_1]. - reset_complete); - } - } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) { - cci_dev->cci_master_info[MASTER_0].status = 0; - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) { - struct msm_camera_cci_master_info *cci_master_info; - - cci_master_info = &cci_dev->cci_master_info[MASTER_0]; - atomic_set(&cci_master_info->q_free[QUEUE_0], 0); - cci_master_info->status = 0; - if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) { - complete(&cci_master_info->report_q[QUEUE_0]); - atomic_set(&cci_master_info->done_pending[QUEUE_0], 0); - } - } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) { - struct msm_camera_cci_master_info *cci_master_info; - - cci_master_info = &cci_dev->cci_master_info[MASTER_0]; - atomic_set(&cci_master_info->q_free[QUEUE_1], 0); - cci_master_info->status = 0; - if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) { - complete(&cci_master_info->report_q[QUEUE_1]); - atomic_set(&cci_master_info->done_pending[QUEUE_1], 0); - } - } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) { - cci_dev->cci_master_info[MASTER_1].status = 0; - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) { - struct msm_camera_cci_master_info *cci_master_info; - - cci_master_info = &cci_dev->cci_master_info[MASTER_1]; - atomic_set(&cci_master_info->q_free[QUEUE_0], 0); - cci_master_info->status = 0; - if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) { - complete(&cci_master_info->report_q[QUEUE_0]); - atomic_set(&cci_master_info->done_pending[QUEUE_0], 0); - } - } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) { - struct msm_camera_cci_master_info *cci_master_info; - - cci_master_info = &cci_dev->cci_master_info[MASTER_1]; - atomic_set(&cci_master_info->q_free[QUEUE_1], 0); - cci_master_info->status = 0; - if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) { - complete(&cci_master_info->report_q[QUEUE_1]); - atomic_set(&cci_master_info->done_pending[QUEUE_1], 0); - } - } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; - msm_camera_io_w_mb(CCI_M0_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; - msm_camera_io_w_mb(CCI_M1_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { - pr_err("%s:%d MASTER_0 error 0x%x\n", __func__, __LINE__, irq); - cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - msm_camera_io_w_mb(CCI_M0_HALT_REQ_RMSK, - cci_dev->base + CCI_HALT_REQ_ADDR); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { - pr_err("%s:%d MASTER_1 error 0x%x\n", __func__, __LINE__, irq); - cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - msm_camera_io_w_mb(CCI_M1_HALT_REQ_RMSK, - cci_dev->base + CCI_HALT_REQ_ADDR); - } - return IRQ_HANDLED; -} - -static int msm_cci_irq_routine(struct v4l2_subdev *sd, u32 status, - bool *handled) -{ - struct cci_device *cci_dev = v4l2_get_subdevdata(sd); - irqreturn_t ret; - - CDBG("%s line %d\n", __func__, __LINE__); - ret = msm_cci_irq(cci_dev->irq->start, cci_dev); - CDBG("%s: msm_cci_irq return %d\n", __func__, ret); - *handled = TRUE; - return 0; -} - -static long msm_cci_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int32_t rc = 0; - - CDBG("%s line %d\n", __func__, __LINE__); - switch (cmd) { - case VIDIOC_MSM_CCI_CFG: - rc = msm_cci_config(sd, arg); - break; - case MSM_SD_NOTIFY_FREEZE: - break; - case MSM_SD_UNNOTIFY_FREEZE: - break; - case MSM_SD_SHUTDOWN: { - struct msm_camera_cci_ctrl ctrl_cmd; - - ctrl_cmd.cmd = MSM_CCI_RELEASE; - rc = msm_cci_config(sd, &ctrl_cmd); - break; - } - default: - rc = -ENOIOCTLCMD; - } - CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); - return rc; -} - -static struct v4l2_subdev_core_ops msm_cci_subdev_core_ops = { - .ioctl = &msm_cci_subdev_ioctl, - .interrupt_service_routine = msm_cci_irq_routine, -}; - -static const struct v4l2_subdev_ops msm_cci_subdev_ops = { - .core = &msm_cci_subdev_core_ops, -}; - -static const struct v4l2_subdev_internal_ops msm_cci_internal_ops; - -static void msm_cci_init_cci_params(struct cci_device *new_cci_dev) -{ - uint8_t i = 0, j = 0; - - for (i = 0; i < NUM_MASTERS; i++) { - new_cci_dev->cci_master_info[i].status = 0; - mutex_init(&new_cci_dev->cci_master_info[i].mutex); - init_completion(&new_cci_dev-> - cci_master_info[i].reset_complete); - - for (j = 0; j < NUM_QUEUES; j++) { - mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]); - init_completion(&new_cci_dev-> - cci_master_info[i].report_q[j]); - } - } -} - -static int32_t msm_cci_init_gpio_params(struct cci_device *cci_dev) -{ - int32_t rc = 0, i = 0; - uint32_t *val_array = NULL; - uint8_t tbl_size = 0; - struct device_node *of_node = cci_dev->pdev->dev.of_node; - struct gpio *gpio_tbl = NULL; - - cci_dev->cci_gpio_tbl_size = tbl_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, tbl_size); - if (!tbl_size) { - pr_err("%s:%d gpio count 0\n", __func__, __LINE__); - return 0; - } - - gpio_tbl = cci_dev->cci_gpio_tbl = - kzalloc(sizeof(struct gpio) * tbl_size, GFP_KERNEL); - if (!gpio_tbl) { - pr_err("%s failed %d\n", __func__, __LINE__); - return 0; - } - - for (i = 0; i < tbl_size; i++) { - gpio_tbl[i].gpio = of_get_gpio(of_node, i); - CDBG("%s gpio_tbl[%d].gpio = %d\n", __func__, i, - gpio_tbl[i].gpio); - } - - val_array = kcalloc(tbl_size, sizeof(uint32_t), GFP_KERNEL); - if (!val_array) { - rc = -ENOMEM; - goto ERROR1; - } - - rc = of_property_read_u32_array(of_node, "qcom,gpio-tbl-flags", - val_array, tbl_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < tbl_size; i++) { - gpio_tbl[i].flags = val_array[i]; - CDBG("%s gpio_tbl[%d].flags = %ld\n", __func__, i, - gpio_tbl[i].flags); - } - - for (i = 0; i < tbl_size; i++) { - rc = of_property_read_string_index(of_node, - "qcom,gpio-tbl-label", i, &gpio_tbl[i].label); - CDBG("%s gpio_tbl[%d].label = %s\n", __func__, i, - gpio_tbl[i].label); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - } - - kfree(val_array); - return rc; - -ERROR2: - kfree(val_array); -ERROR1: - kfree(cci_dev->cci_gpio_tbl); - cci_dev->cci_gpio_tbl = NULL; - cci_dev->cci_gpio_tbl_size = 0; - return rc; -} - -static void msm_cci_init_default_clk_params(struct cci_device *cci_dev, - uint8_t index) -{ - /* default clock params are for 100Khz */ - cci_dev->cci_clk_params[index].hw_thigh = 201; - cci_dev->cci_clk_params[index].hw_tlow = 174; - cci_dev->cci_clk_params[index].hw_tsu_sto = 204; - cci_dev->cci_clk_params[index].hw_tsu_sta = 231; - cci_dev->cci_clk_params[index].hw_thd_dat = 22; - cci_dev->cci_clk_params[index].hw_thd_sta = 162; - cci_dev->cci_clk_params[index].hw_tbuf = 227; - cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0; - cci_dev->cci_clk_params[index].hw_trdhld = 6; - cci_dev->cci_clk_params[index].hw_tsp = 3; - cci_dev->cci_clk_params[index].cci_clk_src = 37500000; -} - -static void msm_cci_init_clk_params(struct cci_device *cci_dev) -{ - int32_t rc = 0; - uint32_t val = 0; - uint8_t count = 0; - struct device_node *of_node = cci_dev->pdev->dev.of_node; - struct device_node *src_node = NULL; - - for (count = 0; count < I2C_MAX_MODES; count++) { - - if (I2C_STANDARD_MODE == count) - src_node = of_find_node_by_name(of_node, - "qcom,i2c_standard_mode"); - else if (I2C_FAST_MODE == count) - src_node = of_find_node_by_name(of_node, - "qcom,i2c_fast_mode"); - else if (I2C_FAST_PLUS_MODE == count) - src_node = of_find_node_by_name(of_node, - "qcom,i2c_fast_plus_mode"); - else - src_node = of_find_node_by_name(of_node, - "qcom,i2c_custom_mode"); - - rc = of_property_read_u32(src_node, "qcom,hw-thigh", &val); - CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc); - if (!rc) { - cci_dev->cci_clk_params[count].hw_thigh = val; - rc = of_property_read_u32(src_node, "qcom,hw-tlow", - &val); - CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tlow = val; - rc = of_property_read_u32(src_node, "qcom,hw-tsu-sto", - &val); - CDBG("%s qcom,hw-tsu-sto %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tsu_sto = val; - rc = of_property_read_u32(src_node, "qcom,hw-tsu-sta", - &val); - CDBG("%s qcom,hw-tsu-sta %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tsu_sta = val; - rc = of_property_read_u32(src_node, "qcom,hw-thd-dat", - &val); - CDBG("%s qcom,hw-thd-dat %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_thd_dat = val; - rc = of_property_read_u32(src_node, "qcom,hw-thd-sta", - &val); - CDBG("%s qcom,hw-thd-sta %d, rc %d\n", __func__, - val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_thd_sta = val; - rc = of_property_read_u32(src_node, "qcom,hw-tbuf", - &val); - CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tbuf = val; - rc = of_property_read_u32(src_node, - "qcom,hw-scl-stretch-en", &val); - CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_scl_stretch_en = val; - rc = of_property_read_u32(src_node, "qcom,hw-trdhld", - &val); - CDBG("%s qcom,hw-trdhld %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_trdhld = val; - rc = of_property_read_u32(src_node, "qcom,hw-tsp", - &val); - CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tsp = val; - val = 0; - rc = of_property_read_u32(src_node, "qcom,cci-clk-src", - &val); - CDBG("%s qcom,cci-clk-src %d, rc %d\n", - __func__, val, rc); - cci_dev->cci_clk_params[count].cci_clk_src = val; - } else - msm_cci_init_default_clk_params(cci_dev, count); - - of_node_put(src_node); - src_node = NULL; - } -} - -struct v4l2_subdev *msm_cci_get_subdev(void) -{ - return g_cci_subdev; -} - -static int msm_cci_probe(struct platform_device *pdev) -{ - struct cci_device *new_cci_dev; - int rc = 0, i = 0; - - CDBG("%s: pdev %pK device id = %d\n", __func__, pdev, pdev->id); - new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL); - if (!new_cci_dev) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops); - new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops; - snprintf(new_cci_dev->msm_sd.sd.name, - ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci"); - new_cci_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CCI; - v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev); - platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd); - CDBG("%s sd %pK\n", __func__, &new_cci_dev->msm_sd.sd); - if (pdev->dev.of_node) - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - - rc = msm_camera_get_clk_info_and_rates(pdev, - &new_cci_dev->cci_clk_info, &new_cci_dev->cci_clk, - &new_cci_dev->cci_clk_rates, &new_cci_dev->num_clk_cases, - &new_cci_dev->num_clk); - if (rc < 0) { - pr_err("%s: msm_cci_get_clk_info() failed", __func__); - kfree(new_cci_dev); - return -EFAULT; - } - - new_cci_dev->ref_count = 0; - new_cci_dev->base = msm_camera_get_reg_base(pdev, "cci", true); - if (!new_cci_dev->base) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto cci_no_resource; - } - new_cci_dev->irq = msm_camera_get_irq(pdev, "cci"); - if (!new_cci_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto cci_no_resource; - } - CDBG("%s line %d cci irq start %d end %d\n", __func__, - __LINE__, - (int) new_cci_dev->irq->start, - (int) new_cci_dev->irq->end); - rc = msm_camera_register_irq(pdev, new_cci_dev->irq, - msm_cci_irq, IRQF_TRIGGER_RISING, "cci", new_cci_dev); - if (rc < 0) { - pr_err("%s: irq request fail\n", __func__); - rc = -EBUSY; - goto cci_release_mem; - } - - msm_camera_enable_irq(new_cci_dev->irq, false); - new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6; - msm_sd_register(&new_cci_dev->msm_sd); - new_cci_dev->pdev = pdev; - msm_cci_init_cci_params(new_cci_dev); - msm_cci_init_clk_params(new_cci_dev); - msm_cci_init_gpio_params(new_cci_dev); - - rc = msm_camera_get_dt_vreg_data(new_cci_dev->pdev->dev.of_node, - &(new_cci_dev->cci_vreg), &(new_cci_dev->regulator_count)); - if (rc < 0) { - pr_err("%s: msm_camera_get_dt_vreg_data fail\n", __func__); - rc = -EFAULT; - goto cci_release_mem; - } - - if ((new_cci_dev->regulator_count < 0) || - (new_cci_dev->regulator_count > MAX_REGULATOR)) { - pr_err("%s: invalid reg count = %d, max is %d\n", __func__, - new_cci_dev->regulator_count, MAX_REGULATOR); - rc = -EFAULT; - goto cci_invalid_vreg_data; - } - - rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); - if (rc) - pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc); - new_cci_dev->cci_state = CCI_STATE_DISABLED; - g_cci_subdev = &new_cci_dev->msm_sd.sd; - for (i = 0; i < MASTER_MAX; i++) { - new_cci_dev->write_wq[i] = create_singlethread_workqueue( - "msm_cci_wq"); - if (!new_cci_dev->write_wq[i]) - pr_err("Failed to create write wq\n"); - } - CDBG("%s cci subdev %pK\n", __func__, &new_cci_dev->msm_sd.sd); - CDBG("%s line %d\n", __func__, __LINE__); - return 0; - -cci_invalid_vreg_data: - kfree(new_cci_dev->cci_vreg); -cci_release_mem: - msm_camera_put_reg_base(pdev, new_cci_dev->base, "cci", true); -cci_no_resource: - kfree(new_cci_dev); - return rc; -} - -static int msm_cci_exit(struct platform_device *pdev) -{ - struct v4l2_subdev *subdev = platform_get_drvdata(pdev); - struct cci_device *cci_dev = - v4l2_get_subdevdata(subdev); - - msm_camera_put_clk_info_and_rates(pdev, - &cci_dev->cci_clk_info, &cci_dev->cci_clk, - &cci_dev->cci_clk_rates, cci_dev->num_clk_cases, - cci_dev->num_clk); - - msm_camera_put_reg_base(pdev, cci_dev->base, "cci", true); - kfree(cci_dev); - return 0; -} - -static const struct of_device_id msm_cci_dt_match[] = { - {.compatible = "qcom,cci"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_cci_dt_match); - -static struct platform_driver cci_driver = { - .probe = msm_cci_probe, - .remove = msm_cci_exit, - .driver = { - .name = MSM_CCI_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_cci_dt_match, - }, -}; - -static int __init msm_cci_init_module(void) -{ - return platform_driver_register(&cci_driver); -} - -static void __exit msm_cci_exit_module(void) -{ - platform_driver_unregister(&cci_driver); -} - -module_init(msm_cci_init_module); -module_exit(msm_cci_exit_module); -MODULE_DESCRIPTION("MSM CCI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_cci.h b/drivers/media/platform/msm/ais/sensor/cci/msm_cci.h deleted file mode 100644 index 9a2bb6ff6b6925ec92b1b5db11c16960e389ec30..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_cci.h +++ /dev/null @@ -1,231 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CCI_H -#define MSM_CCI_H - -#include -#include -#include -#include -#include -#include -#include -#include "msm_sd.h" -#include "cam_soc_api.h" - -#define NUM_MASTERS 2 -#define NUM_QUEUES 2 - -#define TRUE 1 -#define FALSE 0 - -#define CCI_PINCTRL_STATE_DEFAULT "cci_default" -#define CCI_PINCTRL_STATE_SLEEP "cci_suspend" - -#define CCI_NUM_CLK_MAX 16 -#define CCI_NUM_CLK_CASES 5 -#define CCI_CLK_SRC_NAME "cci_src_clk" -#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_10 10 -#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 11 -#define BURST_MIN_FREE_SIZE 8 - -enum cci_i2c_sync { - MSM_SYNC_DISABLE, - MSM_SYNC_ENABLE, -}; - -enum cci_i2c_queue_t { - QUEUE_0, - QUEUE_1, - QUEUE_INVALID, -}; - -struct msm_camera_cci_client { - struct v4l2_subdev *cci_subdev; - uint32_t freq; - enum i2c_freq_mode_t i2c_freq_mode; - enum cci_i2c_master_t cci_i2c_master; - uint16_t sid; - uint16_t cid; - uint32_t timeout; - uint16_t retries; - uint16_t id_map; -}; - -enum msm_cci_cmd_type { - MSM_CCI_INIT, - MSM_CCI_RELEASE, - MSM_CCI_SET_SID, - MSM_CCI_SET_FREQ, - MSM_CCI_SET_SYNC_CID, - MSM_CCI_I2C_READ, - MSM_CCI_I2C_WRITE, - MSM_CCI_I2C_WRITE_SEQ, - MSM_CCI_I2C_WRITE_ASYNC, - MSM_CCI_GPIO_WRITE, - MSM_CCI_I2C_WRITE_SYNC, - MSM_CCI_I2C_WRITE_SYNC_BLOCK, -}; - -struct msm_camera_cci_wait_sync_cfg { - uint16_t cid; - int16_t csid; - uint16_t line; - uint16_t delay; -}; - -struct msm_camera_cci_gpio_cfg { - uint16_t gpio_queue; - uint16_t i2c_queue; -}; - -struct msm_camera_cci_i2c_read_cfg { - uint32_t addr; - enum msm_camera_i2c_reg_addr_type addr_type; - uint8_t *data; - uint16_t num_byte; -}; - -struct msm_camera_cci_i2c_queue_info { - uint32_t max_queue_size; - uint32_t report_id; - uint32_t irq_en; - uint32_t capture_rep_data; -}; - -struct msm_camera_cci_ctrl { - int32_t status; - struct msm_camera_cci_client *cci_info; - enum msm_cci_cmd_type cmd; - union { - struct msm_camera_i2c_reg_setting cci_i2c_write_cfg; - struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg; - struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg; - struct msm_camera_cci_gpio_cfg gpio_cfg; - } cfg; -}; - -struct msm_camera_cci_master_info { - uint32_t status; - atomic_t q_free[NUM_QUEUES]; - uint8_t q_lock[NUM_QUEUES]; - uint8_t reset_pending; - struct mutex mutex; - struct completion reset_complete; - struct mutex mutex_q[NUM_QUEUES]; - struct completion report_q[NUM_QUEUES]; - atomic_t done_pending[NUM_QUEUES]; -}; - -struct msm_cci_clk_params_t { - uint16_t hw_thigh; - uint16_t hw_tlow; - uint16_t hw_tsu_sto; - uint16_t hw_tsu_sta; - uint16_t hw_thd_dat; - uint16_t hw_thd_sta; - uint16_t hw_tbuf; - uint8_t hw_scl_stretch_en; - uint8_t hw_trdhld; - uint8_t hw_tsp; - uint32_t cci_clk_src; -}; - -enum msm_cci_state_t { - CCI_STATE_ENABLED, - CCI_STATE_DISABLED, -}; - -struct cci_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *irq; - void __iomem *base; - - uint32_t hw_version; - uint8_t ref_count; - enum msm_cci_state_t cci_state; - size_t num_clk; - size_t num_clk_cases; - struct clk **cci_clk; - uint32_t **cci_clk_rates; - struct msm_cam_clk_info *cci_clk_info; - struct msm_camera_cci_i2c_queue_info - cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; - struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS]; - enum i2c_freq_mode_t i2c_freq_mode[NUM_MASTERS]; - struct msm_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; - struct gpio *cci_gpio_tbl; - uint8_t cci_gpio_tbl_size; - struct msm_pinctrl_info cci_pinctrl; - uint8_t cci_pinctrl_status; - uint32_t cycles_per_us; - uint32_t cci_clk_src; - struct camera_vreg_t *cci_vreg; - struct regulator *cci_reg_ptr[MAX_REGULATOR]; - int32_t regulator_count; - uint8_t payload_size; - uint8_t support_seq_write; - struct workqueue_struct *write_wq[MASTER_MAX]; - struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg; - uint8_t valid_sync; -}; - -enum msm_cci_i2c_cmd_type { - CCI_I2C_SET_PARAM_CMD = 1, - CCI_I2C_WAIT_CMD, - CCI_I2C_WAIT_SYNC_CMD, - CCI_I2C_WAIT_GPIO_EVENT_CMD, - CCI_I2C_TRIG_I2C_EVENT_CMD, - CCI_I2C_LOCK_CMD, - CCI_I2C_UNLOCK_CMD, - CCI_I2C_REPORT_CMD, - CCI_I2C_WRITE_CMD, - CCI_I2C_READ_CMD, - CCI_I2C_WRITE_DISABLE_P_CMD, - CCI_I2C_READ_DISABLE_P_CMD, - CCI_I2C_WRITE_CMD2, - CCI_I2C_WRITE_CMD3, - CCI_I2C_REPEAT_CMD, - CCI_I2C_INVALID_CMD, -}; - -enum msm_cci_gpio_cmd_type { - CCI_GPIO_SET_PARAM_CMD = 1, - CCI_GPIO_WAIT_CMD, - CCI_GPIO_WAIT_SYNC_CMD, - CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD, - CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD, - CCI_GPIO_OUT_CMD, - CCI_GPIO_TRIG_EVENT_CMD, - CCI_GPIO_REPORT_CMD, - CCI_GPIO_REPEAT_CMD, - CCI_GPIO_CONTINUE_CMD, - CCI_GPIO_INVALID_CMD, -}; - -struct cci_write_async { - struct cci_device *cci_dev; - struct msm_camera_cci_ctrl c_ctrl; - enum cci_i2c_queue_t queue; - struct work_struct work; - enum cci_i2c_sync sync_en; -}; - -struct v4l2_subdev *msm_cci_get_subdev(void); - -#define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *) - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c b/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c deleted file mode 100644 index c8953954b14465d4fb3a3c5b4e67fe38f5f63e62..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c +++ /dev/null @@ -1,277 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include "msm_sd.h" -#include "msm_early_cam.h" -#include "msm_cam_cci_hwreg.h" -#include "msm_camera_io_util.h" -#include "msm_camera_dt_util.h" -#include "cam_hw_ops.h" - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -#undef EARLY_CAM_DBG -#ifdef MSM_EARLY_CAM_DEBUG -#define EARLY_CAM_DBG(fmt, args...) pr_err(fmt, ##args) -#else -#define EARLY_CAM_DBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -#define MSM_EARLY_CAM_DRV_NAME "msm_early_cam" -static struct platform_driver msm_early_camera_driver; -static struct early_cam_device *new_early_cam_dev; - -int msm_early_cam_disable_clocks(void) -{ - int rc = 0; - - CDBG("%s:\n", __func__); - /* Vote OFF for clocks */ - if (new_early_cam_dev == NULL) { - rc = -EINVAL; - pr_err("%s: clock structure uninitialised %d\n", __func__, - rc); - return rc; - } - - if ((new_early_cam_dev->pdev == NULL) || - (new_early_cam_dev->early_cam_clk_info == NULL) || - (new_early_cam_dev->early_cam_clk == NULL) || - (new_early_cam_dev->num_clk == 0)) { - rc = -EINVAL; - pr_err("%s: Clock details uninitialised %d\n", __func__, - rc); - return rc; - } - - rc = msm_camera_clk_enable(&new_early_cam_dev->pdev->dev, - new_early_cam_dev->early_cam_clk_info, - new_early_cam_dev->early_cam_clk, - new_early_cam_dev->num_clk, false); - if (rc < 0) { - pr_err("%s: clk disable failed %d\n", __func__, rc); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SUSPEND_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote OFF AHB_CLIENT_CSIPHY %d\n", - __func__, rc); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID, - CAM_AHB_SUSPEND_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote OFF AHB_CLIENT_CSID %d\n", - __func__, rc); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI, - CAM_AHB_SUSPEND_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote OFF AHB_CLIENT_CCI %d\n", - __func__, rc); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF, - CAM_AHB_SUSPEND_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote OFF AHB_CLIENT_ISPIF %d\n", - __func__, rc); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_VFE0, - CAM_AHB_SUSPEND_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote OFF AHB_CLIENT_VFE0 %d\n", - __func__, rc); - return rc; - } - pr_debug("Turned OFF camera clocks\n"); - return 0; - -} -static int msm_early_cam_probe(struct platform_device *pdev) -{ - int rc = 0; - - CDBG("%s: pdev %pK device id = %d\n", __func__, pdev, pdev->id); - - /* Vote for Early camera if enabled */ - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_VFE0, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - new_early_cam_dev = kzalloc(sizeof(struct early_cam_device), - GFP_KERNEL); - - if (pdev->dev.of_node) - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - - rc = msm_camera_get_clk_info_and_rates(pdev, - &new_early_cam_dev->early_cam_clk_info, - &new_early_cam_dev->early_cam_clk, - &new_early_cam_dev->early_cam_clk_rates, - &new_early_cam_dev->num_clk_cases, - &new_early_cam_dev->num_clk); - if (rc < 0) { - pr_err("%s: msm_early_cam_get_clk_info() failed", __func__); - kfree(new_early_cam_dev); - return -EFAULT; - } - - new_early_cam_dev->ref_count = 0; - new_early_cam_dev->pdev = pdev; - - rc = msm_camera_get_dt_vreg_data( - new_early_cam_dev->pdev->dev.of_node, - &(new_early_cam_dev->early_cam_vreg), - &(new_early_cam_dev->regulator_count)); - if (rc < 0) { - pr_err("%s: msm_camera_get_dt_vreg_data fail\n", __func__); - rc = -EFAULT; - goto early_cam_release_mem; - } - - if ((new_early_cam_dev->regulator_count < 0) || - (new_early_cam_dev->regulator_count > MAX_REGULATOR)) { - pr_err("%s: invalid reg count = %d, max is %d\n", __func__, - new_early_cam_dev->regulator_count, MAX_REGULATOR); - rc = -EFAULT; - goto early_cam_invalid_vreg_data; - } - - rc = msm_camera_config_vreg(&new_early_cam_dev->pdev->dev, - new_early_cam_dev->early_cam_vreg, - new_early_cam_dev->regulator_count, - NULL, - 0, - &new_early_cam_dev->early_cam_reg_ptr[0], 1); - if (rc < 0) - pr_err("%s:%d early_cam config_vreg failed\n", __func__, - __LINE__); - - rc = msm_camera_enable_vreg(&new_early_cam_dev->pdev->dev, - new_early_cam_dev->early_cam_vreg, - new_early_cam_dev->regulator_count, - NULL, - 0, - &new_early_cam_dev->early_cam_reg_ptr[0], 1); - if (rc < 0) - pr_err("%s:%d early_cam enable_vreg failed\n", __func__, - __LINE__); - - rc = msm_camera_clk_enable(&new_early_cam_dev->pdev->dev, - new_early_cam_dev->early_cam_clk_info, - new_early_cam_dev->early_cam_clk, - new_early_cam_dev->num_clk, true); - - if (rc < 0) { - pr_err("%s: clk enable failed %d\n", __func__, rc); - rc = 0; - goto early_cam_release_mem; - } - - platform_set_drvdata(pdev, new_early_cam_dev); - - return 0; - -early_cam_invalid_vreg_data: - kfree(new_early_cam_dev->early_cam_vreg); -early_cam_release_mem: - kfree(new_early_cam_dev); - new_early_cam_dev = NULL; - return rc; -} - -static int msm_early_cam_exit(struct platform_device *pdev) -{ - return 0; -} - -static int __init msm_early_cam_init_module(void) -{ - return platform_driver_register(&msm_early_camera_driver); -} - -static void __exit msm_early_cam_exit_module(void) -{ - kfree(new_early_cam_dev); - platform_driver_unregister(&msm_early_camera_driver); -} - -static const struct of_device_id msm_early_camera_match_table[] = { - { .compatible = "qcom,early-cam" }, - {}, -}; - -static struct platform_driver msm_early_camera_driver = { - .probe = msm_early_cam_probe, - .remove = msm_early_cam_exit, - .driver = { - .name = MSM_EARLY_CAM_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_early_camera_match_table, - }, -}; - -MODULE_DEVICE_TABLE(of, msm_early_camera_match_table); - -module_init(msm_early_cam_init_module); -module_exit(msm_early_cam_exit_module); -MODULE_DESCRIPTION("MSM early camera driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.h b/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.h deleted file mode 100644 index a40ab2d1ebc358046620261edfc76224f521e31d..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_EARLY_CAM_H -#define MSM_EARLY_CAM_H - -#include -#include -#include -#include -#include -#include -#include -#include "msm_sd.h" -#include "cam_soc_api.h" - -#define NUM_MASTERS 2 -#define NUM_QUEUES 2 - -#define TRUE 1 -#define FALSE 0 - - -enum msm_early_cam_state_t { - STATE_DISABLED, - STATE_ENABLED, -}; - -struct early_cam_device { - struct platform_device *pdev; - uint8_t ref_count; - enum msm_early_cam_state_t early_cam_state; - size_t num_clk; - size_t num_clk_cases; - struct clk **early_cam_clk; - uint32_t **early_cam_clk_rates; - struct msm_cam_clk_info *early_cam_clk_info; - struct camera_vreg_t *early_cam_vreg; - struct regulator *early_cam_reg_ptr[MAX_REGULATOR]; - int32_t regulator_count; -}; - -int msm_early_cam_disable_clocks(void); -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/Makefile b/drivers/media/platform/msm/ais/sensor/csid/Makefile deleted file mode 100644 index 5a21052f73478f8baf8514183e6a78545fc5229e..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_csid.o diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_2_0_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_2_0_hwreg.h deleted file mode 100644 index f88c0ef82499d19588d891e9327fe22e4277e956..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_2_0_hwreg.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_2_0_HWREG_H -#define MSM_CSID_2_0_HWREG_H - -#include - -uint8_t csid_lane_assign_v2_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4}; - -struct csid_reg_parms_t csid_v2_0 = { - - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x4, - 0x8, - 0xc, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x5c, - 0x60, - 0x64, - 0x68, - 0x6c, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x9C, - 0xA0, - 0xA8, - 0xAC, - 0xB0, - 11, - 0x7FFF, - 0x2, - 17, - 0x02000011, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_2_2_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_2_2_hwreg.h deleted file mode 100644 index e2bb6cd499ff0621916400633fe943f59d0070d6..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_2_2_hwreg.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_2_2_HWREG_H -#define MSM_CSID_2_2_HWREG_H - -#include - -uint8_t csid_lane_assign_v2_2[PHY_LANE_MAX] = {0, 1, 2, 3, 4}; - -struct csid_reg_parms_t csid_v2_2 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x4, - 0x8, - 0xc, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x5c, - 0x60, - 0x64, - 0x68, - 0x6c, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x9C, - 0xA0, - 0xA8, - 0xAC, - 0xB0, - 11, - 0x7FFF, - 0x2, - 17, - 0x02001000, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_0_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_0_hwreg.h deleted file mode 100644 index 440f869692f758a00d56f76d06d7657039e9d967..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_0_hwreg.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_0_HWREG_H -#define MSM_CSID_3_0_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4}; - -struct csid_reg_parms_t csid_v3_0 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30000000, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_1_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_1_hwreg.h deleted file mode 100644 index dde47046b6794fd03873bb25d2218a463073dadd..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_1_hwreg.h +++ /dev/null @@ -1,64 +0,0 @@ - /* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_1_HWREG_H -#define MSM_CSID_3_1_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_1[PHY_LANE_MAX] = {0, 1, 2, 3, 4}; - -struct csid_reg_parms_t csid_v3_1 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30010000, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_2_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_2_hwreg.h deleted file mode 100644 index 5241a90fbc86d6c8dca2110b31fd2c65acd24b3f..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_2_hwreg.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_2_HWREG_H -#define MSM_CSID_3_2_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_2[PHY_LANE_MAX] = {0, 1, 2, 3, 4}; - -struct csid_reg_parms_t csid_v3_2 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30020000, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_1_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_1_hwreg.h deleted file mode 100644 index 0e8ff6c0986d25a148e5f6898a83e8aaecd78db8..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_1_hwreg.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_4_1_HWREG_H -#define MSM_CSID_3_4_1_HWREG_H - -#include -uint8_t csid_lane_assign_v3_4_1[PHY_LANE_MAX] = {0, 1, 2, 3, 4}; - -struct csid_reg_parms_t csid_v3_4_1 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30040001, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_2_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_2_hwreg.h deleted file mode 100644 index 651526cb3db843e5fe49ccd5a3e26bf29138c244..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_2_hwreg.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_4_2_HWREG_H -#define MSM_CSID_3_4_2_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_4_2[PHY_LANE_MAX] = {0, 4, 1, 2, 3}; -struct csid_reg_parms_t csid_v3_4_2 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30040002, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_3_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_3_hwreg.h deleted file mode 100644 index fff29fc9d4c49418f53985eb90608c8b77b84e63..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_4_3_hwreg.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_4_3_HWREG_H -#define MSM_CSID_3_4_3_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_4_3[PHY_LANE_MAX] = {0, 4, 1, 2, 3}; -struct csid_reg_parms_t csid_v3_4_3 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30040003, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_1_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_1_hwreg.h deleted file mode 100644 index f7d7d3548c4b81718044334456a3240fa9be4b94..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_1_hwreg.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_5_1_HWREG_H -#define MSM_CSID_3_5_1_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_5_1[PHY_LANE_MAX] = {0, 4, 1, 2, 3}; - -struct csid_reg_parms_t csid_v3_5_1 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x24, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0x9C, - 0xA0, - 0xA8, - 0xAC, - 0xB4, - 0xB8, - 0xBC, - 11, - 0x7FFF, - 0x4, - 17, - 0x30050001, - 0xC, - 0x84, - 0xA4, - 0x7f010800, - 20, - 17, - 16, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h deleted file mode 100644 index b423b6e510a01e872bd6f14252442583d5b08fe6..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_5_HWREG_H -#define MSM_CSID_3_5_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_5[PHY_LANE_MAX] = {0, 4, 1, 2, 3}; - -struct csid_reg_parms_t csid_v3_5 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x24, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0x9C, - 0xA0, - 0xA8, - 0xAC, - 0xB4, - 0xB8, - 0xBC, - 11, - 0x7FFF, - 0x4, - 17, - 0x30050000, - 0xC, - 0x84, - 0xA4, - 0x7f010800, - 20, - 17, - 16, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_6_0_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_6_0_hwreg.h deleted file mode 100644 index b95a774ca7376060a382d3cdb78b765de3f6cdeb..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_6_0_hwreg.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_3_6_0_HWREG_H -#define MSM_CSID_3_6_0_HWREG_H - -#include - -uint8_t csid_lane_assign_v3_6_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4}; -struct csid_reg_parms_t csid_v3_6_0 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30060000, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0x7f010800, - 20, - 0xFFFFFFFF, - 0xFFFFFFFF, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c b/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c deleted file mode 100644 index aba9e4296e8355f70fd19eca3788d51e1be7b5e0..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include "msm_csid.h" -#include "msm_sd.h" -#include "msm_camera_io_util.h" -#include "msm_camera_dt_util.h" -#include "include/msm_csid_2_0_hwreg.h" -#include "include/msm_csid_2_2_hwreg.h" -#include "include/msm_csid_3_0_hwreg.h" -#include "include/msm_csid_3_1_hwreg.h" -#include "include/msm_csid_3_2_hwreg.h" -#include "include/msm_csid_3_5_hwreg.h" -#include "include/msm_csid_3_4_1_hwreg.h" -#include "include/msm_csid_3_4_2_hwreg.h" -#include "include/msm_csid_3_4_3_hwreg.h" -#include "include/msm_csid_3_6_0_hwreg.h" -#include "include/msm_csid_3_5_1_hwreg.h" -#include "cam_hw_ops.h" - -#define V4L2_IDENT_CSID 50002 -#define CSID_VERSION_V20 0x02000011 -#define CSID_VERSION_V22 0x02001000 -#define CSID_VERSION_V30 0x30000000 -#define CSID_VERSION_V31 0x30010000 -#define CSID_VERSION_V31_1 0x30010001 -#define CSID_VERSION_V31_3 0x30010003 -#define CSID_VERSION_V32 0x30020000 -#define CSID_VERSION_V33 0x30030000 -#define CSID_VERSION_V34 0x30040000 -#define CSID_VERSION_V34_1 0x30040001 -#define CSID_VERSION_V34_2 0x30040002 -#define CSID_VERSION_V34_3 0x30040003 -#define CSID_VERSION_V36 0x30060000 -#define CSID_VERSION_V37 0x30070000 -#define CSID_VERSION_V35 0x30050000 -#define CSID_VERSION_V35_1 0x30050001 -#define CSID_VERSION_V40 0x40000000 -#define MSM_CSID_DRV_NAME "msm_csid" - -#define DBG_CSID 0 -#define SHORT_PKT_CAPTURE 0 -#define SHORT_PKT_OFFSET 0x200 -#define ENABLE_3P_BIT 1 -#define SOF_DEBUG_ENABLE 1 -#define SOF_DEBUG_DISABLE 0 - -#define TRUE 1 -#define FALSE 0 - -#define MAX_LANE_COUNT 4 -#define CSID_TIMEOUT msecs_to_jiffies(100) - -#undef CDBG -#ifdef CONFIG_MSM_AIS_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) -#endif - -static struct camera_vreg_t csid_vreg_info[] = { - {"qcom,mipi-csi-vdd", 0, 0, 12000}, -}; - -#ifdef CONFIG_COMPAT -static struct v4l2_file_operations msm_csid_v4l2_subdev_fops; -#endif - -static int msm_csid_cid_lut(struct csid_device *csid_dev) -{ - int rc = 0, i = 0; - uint32_t val = 0; - - struct msm_camera_csid_lut_params *csid_lut_params = - &csid_dev->current_csid_params.lut_params; - - for (i = 0; i < MAX_CID; i++) { - if (i != csid_lut_params->vc_cfg_a[i].cid) - continue; - - CDBG("%s lut params num_cid = %d, cid = %d\n", - __func__, - csid_lut_params->num_cid, - csid_lut_params->vc_cfg_a[i].cid); - CDBG("%s lut params dt = 0x%x, df = %d\n", __func__, - csid_lut_params->vc_cfg_a[i].dt, - csid_lut_params->vc_cfg_a[i].decode_format); - if (csid_lut_params->vc_cfg_a[i].dt < 0x12 || - csid_lut_params->vc_cfg_a[i].dt > 0x37) { - CDBG("%s: unsupported data type 0x%x\n", - __func__, csid_lut_params->vc_cfg_a[i].dt); - continue; - } - val = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + - (csid_lut_params->vc_cfg_a[i].cid >> 2) * 4) - & ~(0xFF << ((csid_lut_params->vc_cfg_a[i].cid % 4) * - 8)); - val |= (csid_lut_params->vc_cfg_a[i].dt << - ((csid_lut_params->vc_cfg_a[i].cid % 4) * 8)); - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + - (csid_lut_params->vc_cfg_a[i].cid >> 2) * 4); - } - return rc; -} - -static int msm_csid_start(struct csid_device *csid_dev, uint32_t cid_mask) -{ - uint32_t val = 0, i = 0; - struct msm_camera_csid_lut_params *csid_lut_params = - &csid_dev->current_csid_params.lut_params; - - for (i = 0; i < MAX_CID; i++) { - if (!(cid_mask & (1 << i))) - continue; - - val = (csid_lut_params->vc_cfg_a[i].decode_format << 4) | 0x3; - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_cid_n_cfg_addr + - (i * 4)); - } - - return 0; -} - -static int msm_csid_stop(struct csid_device *csid_dev, uint32_t cid_mask) -{ - uint32_t val = 0, i = 0; - struct msm_camera_csid_lut_params *csid_lut_params; - - csid_lut_params = &csid_dev->current_csid_params.lut_params; - for (i = 0; i < MAX_CID; i++) { - if (!(cid_mask & (1 << i))) - continue; - - val = 0; - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_cid_n_cfg_addr + - (i * 4)); - } - - return 0; -} - -#if (DBG_CSID) -static void msm_csid_set_debug_reg(struct csid_device *csid_dev, - struct msm_camera_csid_params *csid_params) -{ - uint32_t val = 0; - - if ((csid_dev->hw_dts_version == CSID_VERSION_V34_1) || - (csid_dev->hw_dts_version == CSID_VERSION_V36)) { - val = ((1 << csid_params->lane_cnt) - 1) << 20; - msm_camera_io_w(0x7f010800 | val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - msm_camera_io_w(0x7f010800 | val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - } else { - if (csid_dev->csid_3p_enabled == 1) { - val = ((1 << csid_params->lane_cnt) - 1) << - csid_dev->ctrl_reg-> - csid_reg.csid_err_lane_overflow_offset_3p; - } else { - val = ((1 << csid_params->lane_cnt) - 1) << - csid_dev->ctrl_reg-> - csid_reg.csid_err_lane_overflow_offset_2p; - } - val |= csid_dev->ctrl_reg->csid_reg.csid_irq_mask_val; - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - } -} -#elif(SHORT_PKT_CAPTURE) -static void msm_csid_set_debug_reg(struct csid_device *csid_dev, - struct msm_camera_csid_params *csid_params) -{ - uint32_t val = 0; - - if ((csid_dev->hw_dts_version == CSID_VERSION_V34_1) || - (csid_dev->hw_dts_version == CSID_VERSION_V36)) { - val = ((1 << csid_params->lane_cnt) - 1) << 20; - msm_camera_io_w(0x7f010a00 | val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - msm_camera_io_w(0x7f010a00 | val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - } else { - if (csid_dev->csid_3p_enabled == 1) { - val = ((1 << csid_params->lane_cnt) - 1) << - csid_dev->ctrl_reg-> - csid_reg.csid_err_lane_overflow_offset_3p; - } else { - val = ((1 << csid_params->lane_cnt) - 1) << - csid_dev->ctrl_reg-> - csid_reg.csid_err_lane_overflow_offset_2p; - } - val |= csid_dev->ctrl_reg->csid_reg.csid_irq_mask_val; - val |= SHORT_PKT_OFFSET; - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - } -} -#else -static void msm_csid_set_debug_reg(struct csid_device *csid_dev, - struct msm_camera_csid_params *csid_params) {} -#endif - -static void msm_csid_set_sof_freeze_debug_reg( - struct csid_device *csid_dev, uint8_t irq_enable) -{ - uint32_t val = 0; - - if (!irq_enable) { - val = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - msm_camera_io_w(0, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - return; - } - - if (csid_dev->csid_3p_enabled == 1) { - val = ((1 << csid_dev->current_csid_params.lane_cnt) - 1) << - csid_dev->ctrl_reg-> - csid_reg.csid_err_lane_overflow_offset_3p; - } else { - val = ((1 << csid_dev->current_csid_params.lane_cnt) - 1) << - csid_dev->ctrl_reg-> - csid_reg.csid_err_lane_overflow_offset_2p; - } - val |= csid_dev->ctrl_reg->csid_reg.csid_irq_mask_val; - val |= SHORT_PKT_OFFSET; - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); -} - -static int msm_csid_reset(struct csid_device *csid_dev) -{ - int32_t rc = 0; - - msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all, - csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr); - rc = wait_for_completion_timeout(&csid_dev->reset_complete, - CSID_TIMEOUT); - if (rc <= 0) { - pr_err("wait_for_completion in msm_csid_reset fail rc = %d\n", - rc); - if (rc == 0) - rc = -ETIMEDOUT; - } - return rc; -} - -static bool msm_csid_find_max_clk_rate(struct csid_device *csid_dev) -{ - int i; - bool ret = FALSE; - - for (i = 0; i < csid_dev->num_clk; i++) { - if (!strcmp(csid_dev->csid_clk_info[i].clk_name, - "csi_src_clk")) { - CDBG("%s:%d, copy csi_src_clk, clk_rate[%d] = %ld", - __func__, __LINE__, i, - csid_dev->csid_clk_info[i].clk_rate); - csid_dev->csid_max_clk = - csid_dev->csid_clk_info[i].clk_rate; - csid_dev->csid_clk_index = i; - ret = TRUE; - break; - } - } - return ret; -} - -static int msm_csid_config(struct csid_device *csid_dev) -{ - int rc = 0; - uint32_t val = 0; - long clk_rate = 0; - uint32_t input_sel; - uint32_t lane_assign = 0; - uint8_t lane_num = 0; - uint8_t i, j; - void __iomem *csidbase; - struct msm_camera_csid_params *csid_params = &csid_dev-> - current_csid_params; - - csidbase = csid_dev->base; - if (!csidbase) { - pr_err("%s:%d csidbase %pK\n", __func__, - __LINE__, csidbase); - return -EINVAL; - } - - CDBG("%s csid_params, lane_cnt = %d, lane_assign = 0x%x\n", - __func__, - csid_params->lane_cnt, - csid_params->lane_assign); - CDBG("%s csid_params phy_sel = %d\n", __func__, - csid_params->phy_sel); - if ((csid_params->lane_cnt == 0) || - (csid_params->lane_cnt > MAX_LANE_COUNT)) { - pr_err("%s:%d invalid lane count = %d\n", - __func__, __LINE__, csid_params->lane_cnt); - return -EINVAL; - } - -#ifdef RESET_CSID_CFG - rc = msm_csid_reset(csid_dev); - if (rc < 0) { - pr_err("%s:%d msm_csid_reset failed\n", __func__, __LINE__); - return rc; - } -#endif - - if (!msm_csid_find_max_clk_rate(csid_dev)) - pr_err("msm_csid_find_max_clk_rate failed\n"); - - clk_rate = (csid_params->csi_clk > 0) ? - (csid_params->csi_clk) : csid_dev->csid_max_clk; - - clk_rate = msm_camera_clk_set_rate(&csid_dev->pdev->dev, - csid_dev->csid_clk[csid_dev->csid_clk_index], clk_rate); - if (clk_rate < 0) { - pr_err("csi_src_clk set failed\n"); - return -EINVAL; - } - - if (csid_dev->is_testmode == 1) { - struct msm_camera_csid_testmode_parms *tm; - - tm = &csid_dev->testmode_params; - - /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT, 1:0 VC */ - val = ((tm->v_blanking_count & 0xFF) << 24) | - ((tm->h_blanking_count & 0x7FF) << 13); - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_tg_vc_cfg_addr); - CDBG("[TG] CSID_TG_VC_CFG_ADDR 0x%08x\n", val); - - /* 28:16 bytes per lines, 12:0 num of lines */ - val = ((tm->num_bytes_per_line & 0x1FFF) << 16) | - (tm->num_lines & 0x1FFF); - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_tg_dt_n_cfg_0_addr); - CDBG("[TG] CSID_TG_DT_n_CFG_0_ADDR 0x%08x\n", val); - - /* 5:0 data type */ - val = csid_params->lut_params.vc_cfg_a[0].dt; - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_tg_dt_n_cfg_1_addr); - CDBG("[TG] CSID_TG_DT_n_CFG_1_ADDR 0x%08x\n", val); - - /* 2:0 output random */ - msm_camera_io_w(csid_dev->testmode_params.payload_mode, - csidbase + - csid_dev->ctrl_reg->csid_reg.csid_tg_dt_n_cfg_2_addr); - } else { - val = csid_params->lane_cnt - 1; - - for (i = 0, j = 0; i < PHY_LANE_MAX; i++) { - if (i == PHY_LANE_CLK) - continue; - lane_num = (csid_params->lane_assign >> j) & 0xF; - if (lane_num >= PHY_LANE_MAX) { - pr_err("%s:%d invalid lane number %d\n", - __func__, __LINE__, lane_num); - return -EINVAL; - } - if (csid_dev->ctrl_reg->csid_lane_assign[lane_num] >= - PHY_LANE_MAX){ - pr_err("%s:%d invalid lane map %d\n", - __func__, __LINE__, - csid_dev->ctrl_reg-> - csid_lane_assign[lane_num]); - return -EINVAL; - } - lane_assign |= - csid_dev->ctrl_reg->csid_lane_assign[lane_num] - << j; - j += 4; - } - - CDBG("%s csid_params calculated lane_assign = 0x%X\n", - __func__, lane_assign); - - val |= lane_assign << - csid_dev->ctrl_reg->csid_reg.csid_dl_input_sel_shift; - if (csid_dev->hw_version < CSID_VERSION_V30) { - val |= (0xF << 10); - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); - } else { - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); - val = csid_params->phy_sel << - csid_dev->ctrl_reg->csid_reg.csid_phy_sel_shift; - val |= 0xF; - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_1_addr); - } - if ((csid_dev->hw_version == CSID_VERSION_V35) && - (csid_params->csi_3p_sel == 1)) { - csid_dev->csid_3p_enabled = 1; - val = (csid_params->lane_cnt - 1) << ENABLE_3P_BIT; - - for (i = 0; i < csid_params->lane_cnt; i++) { - input_sel = - (csid_params->lane_assign >> (4*i)) - & 0xF; - val |= input_sel << (4*(i+1)); - } - val |= csid_params->phy_sel << - csid_dev->ctrl_reg->csid_reg.csid_phy_sel_shift_3p; - val |= ENABLE_3P_BIT; - msm_camera_io_w(val, csidbase + csid_dev->ctrl_reg - ->csid_reg.csid_3p_ctrl_0_addr); - } - } - - rc = msm_csid_cid_lut(csid_dev); - if (rc < 0) { - pr_err("%s:%d config cid lut failed\n", __func__, __LINE__); - return rc; - } - msm_csid_set_debug_reg(csid_dev, csid_params); - - if (csid_dev->is_testmode == 1) - msm_camera_io_w(0x00A06437, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_tg_ctrl_addr); - - return rc; -} - -#if SHORT_PKT_CAPTURE -static irqreturn_t msm_csid_irq(int irq_num, void *data) -{ - uint32_t irq; - uint32_t short_dt = 0; - uint32_t count = 0, dt = 0; - struct csid_device *csid_dev = data; - - if (!csid_dev) { - pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__); - return IRQ_HANDLED; - } - irq = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); - CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n", - __func__, csid_dev->pdev->id, irq); - if (irq & (0x1 << - csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift)) - complete(&csid_dev->reset_complete); - if (irq & SHORT_PKT_OFFSET) { - short_dt = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg-> - csid_reg.csid_captured_short_pkt_addr); - count = (short_dt >> 8) & 0xffff; - dt = short_dt >> 24; - CDBG("CSID:: %s:%d core %d dt: 0x%x, count: %d\n", - __func__, __LINE__, csid_dev->pdev->id, dt, count); - msm_camera_io_w(0x101, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr); - } - msm_camera_io_w(irq, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - return IRQ_HANDLED; -} -#else -static irqreturn_t msm_csid_irq(int irq_num, void *data) -{ - uint32_t irq; - struct csid_device *csid_dev = data; - - if (!csid_dev) { - pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__); - return IRQ_HANDLED; - } - - if (csid_dev->csid_sof_debug == SOF_DEBUG_ENABLE) { - if (csid_dev->csid_sof_debug_count < CSID_SOF_DEBUG_COUNT) - csid_dev->csid_sof_debug_count++; - else { - msm_csid_set_sof_freeze_debug_reg(csid_dev, false); - return IRQ_HANDLED; - } - } - - irq = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); - pr_err_ratelimited("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n", - __func__, csid_dev->pdev->id, irq); - if (irq & (0x1 << - csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift)) - complete(&csid_dev->reset_complete); - msm_camera_io_w(irq, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - return IRQ_HANDLED; -} -#endif - -static int msm_csid_irq_routine(struct v4l2_subdev *sd, u32 status, - bool *handled) -{ - struct csid_device *csid_dev = v4l2_get_subdevdata(sd); - irqreturn_t ret; - - CDBG("%s E\n", __func__); - ret = msm_csid_irq(csid_dev->irq->start, csid_dev); - *handled = TRUE; - return 0; -} - -static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version) -{ - int rc = 0; - - if (!csid_version) { - pr_err("%s:%d csid_version NULL\n", __func__, __LINE__); - rc = -EINVAL; - return rc; - } - - csid_dev->csid_sof_debug_count = 0; - csid_dev->reg_ptr = NULL; - - if (csid_dev->csid_state == CSID_POWER_UP) { - pr_err("%s: csid invalid state %d\n", __func__, - csid_dev->csid_state); - return -EINVAL; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - pr_info("%s: CSID_VERSION = 0x%x\n", __func__, - csid_dev->ctrl_reg->csid_reg.csid_version); - /* power up */ - rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg, - csid_dev->regulator_count, NULL, 0, - &csid_dev->csid_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d csid config_vreg failed\n", __func__, __LINE__); - goto top_vreg_config_failed; - } - - rc = msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 1); - if (rc < 0) { - pr_err("%s: regulator on failed\n", __func__); - goto csid_vreg_config_failed; - } - - rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg, - csid_dev->regulator_count, NULL, 0, - &csid_dev->csid_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d csid enable_vreg failed\n", __func__, __LINE__); - goto top_vreg_enable_failed; - } - - rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 1); - if (rc < 0) { - pr_err("%s: regulator enable failed\n", __func__); - goto csid_vreg_enable_failed; - } - rc = msm_camera_clk_enable(&csid_dev->pdev->dev, - csid_dev->csid_clk_info, csid_dev->csid_clk, - csid_dev->num_clk, true); - if (rc < 0) { - pr_err("%s:%d clock enable failed\n", - __func__, __LINE__); - goto clk_enable_failed; - } - CDBG("%s:%d called\n", __func__, __LINE__); - csid_dev->hw_version = - msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_hw_version_addr); - CDBG("%s:%d called csid_dev->hw_version %x\n", __func__, __LINE__, - csid_dev->hw_version); - *csid_version = csid_dev->hw_version; - csid_dev->csid_sof_debug = SOF_DEBUG_DISABLE; - - csid_dev->is_testmode = 0; - - init_completion(&csid_dev->reset_complete); - - rc = msm_camera_enable_irq(csid_dev->irq, true); - if (rc < 0) - pr_err("%s: irq enable failed\n", __func__); - rc = msm_csid_reset(csid_dev); - if (rc < 0) { - pr_err("%s:%d msm_csid_reset failed\n", __func__, __LINE__); - goto msm_csid_reset_fail; - } - - csid_dev->csid_state = CSID_POWER_UP; - return rc; - -msm_csid_reset_fail: - msm_camera_enable_irq(csid_dev->irq, false); - msm_camera_clk_enable(&csid_dev->pdev->dev, csid_dev->csid_clk_info, - csid_dev->csid_clk, csid_dev->num_clk, false); -clk_enable_failed: - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); -csid_vreg_enable_failed: - msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg, - csid_dev->regulator_count, NULL, 0, - &csid_dev->csid_reg_ptr[0], 0); -top_vreg_enable_failed: - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); -csid_vreg_config_failed: - msm_camera_config_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg, - csid_dev->regulator_count, NULL, 0, - &csid_dev->csid_reg_ptr[0], 0); -top_vreg_config_failed: - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote from AHB\n", __func__); - return rc; -} - -static int msm_csid_release(struct csid_device *csid_dev) -{ - uint32_t irq; - - if (csid_dev->csid_state != CSID_POWER_UP) { - pr_err("%s: csid invalid state %d\n", __func__, - csid_dev->csid_state); - return -EINVAL; - } - - CDBG("%s:%d, hw_version = 0x%x\n", __func__, __LINE__, - csid_dev->hw_version); - - irq = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); - msm_camera_io_w(irq, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - msm_camera_io_w(0, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - - msm_camera_enable_irq(csid_dev->irq, false); - - msm_camera_clk_enable(&csid_dev->pdev->dev, - csid_dev->csid_clk_info, - csid_dev->csid_clk, - csid_dev->num_clk, false); - - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_dev->csid_vreg, csid_dev->regulator_count, NULL, - 0, &csid_dev->csid_reg_ptr[0], 0); - - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_dev->csid_vreg, csid_dev->regulator_count, NULL, - 0, &csid_dev->csid_reg_ptr[0], 0); - - if (!IS_ERR_OR_NULL(csid_dev->reg_ptr)) { - regulator_disable(csid_dev->reg_ptr); - regulator_put(csid_dev->reg_ptr); - } - - csid_dev->csid_state = CSID_POWER_DOWN; - - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote from AHB\n", __func__); - return 0; -} - -static int32_t msm_csid_cmd(struct csid_device *csid_dev, void __user *arg) -{ - int rc = 0; - struct csid_cfg_data *cdata = (struct csid_cfg_data *)arg; - - if (!csid_dev || !cdata) { - pr_err("%s:%d csid_dev %pK, cdata %pK\n", __func__, __LINE__, - csid_dev, cdata); - return -EINVAL; - } - CDBG("%s cfgtype = %d\n", __func__, cdata->cfgtype); - switch (cdata->cfgtype) { - case CSID_INIT: - rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version); - CDBG("%s csid version 0x%x\n", __func__, - cdata->cfg.csid_version); - break; - case CSID_TESTMODE_CFG: { - csid_dev->is_testmode = 1; - if (copy_from_user(&csid_dev->testmode_params, - (void *)cdata->cfg.csid_testmode_params, - sizeof(struct msm_camera_csid_testmode_parms))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - break; - } - case CSID_CFG: { - struct msm_camera_csid_params csid_params; - int i = 0; - - if (copy_from_user(&csid_params, - (void *)cdata->cfg.csid_params, - sizeof(struct msm_camera_csid_params))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - if (csid_params.lut_params.num_cid < 1 || - csid_params.lut_params.num_cid > MAX_CID) { - pr_err("%s: %d num_cid outside range\n", - __func__, __LINE__); - rc = -EINVAL; - break; - } - - memset(&csid_dev->current_csid_params, 0x0, - sizeof(csid_dev->current_csid_params)); - csid_dev->current_csid_params.lane_cnt = csid_params.lane_cnt; - csid_dev->current_csid_params.lane_assign = csid_params. - lane_assign; - csid_dev->current_csid_params.phy_sel = csid_params.phy_sel; - csid_dev->current_csid_params.csi_clk = csid_params.csi_clk; - csid_dev->current_csid_params.csi_3p_sel = csid_params. - csi_3p_sel; - - for (i = 0; i < csid_params.lut_params.num_cid; i++) { - unsigned char cid = csid_params.lut_params.vc_cfg_a[i]. - cid; - - csid_dev->current_csid_params.lut_params.vc_cfg_a[cid] = - csid_params.lut_params.vc_cfg_a[i]; - - CDBG("vc_cfg_a[%d] : dt=%d, decode_fmt=%d", - csid_params.lut_params.vc_cfg_a[i].cid, - csid_params.lut_params.vc_cfg_a[i].dt, - csid_params.lut_params.vc_cfg_a[i]. - decode_format); - } - - rc = msm_csid_config(csid_dev); - break; - } - case CSID_RELEASE: - rc = msm_csid_release(csid_dev); - break; - case CSID_UPDATE_CFG: { - struct msm_camera_csid_params csid_params; - int i = 0; - - if (copy_from_user(&csid_params, - (void *)cdata->cfg.csid_params, - sizeof(struct msm_camera_csid_params))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - if (csid_params.lut_params.num_cid < 1 || - csid_params.lut_params.num_cid > MAX_CID) { - pr_err("%s: %d num_cid outside range\n", - __func__, __LINE__); - rc = -EINVAL; - break; - } - - for (i = 0; i < csid_params.lut_params.num_cid; i++) { - unsigned char cid = csid_params.lut_params.vc_cfg_a[i]. - cid; - - csid_dev->current_csid_params.lut_params.vc_cfg_a[cid] = - csid_params.lut_params.vc_cfg_a[i]; - - CDBG("vc_cfg_a[%d] : dt=%d, decode_fmt=%d", - csid_params.lut_params.vc_cfg_a[i].cid, - csid_params.lut_params.vc_cfg_a[i].dt, - csid_params.lut_params.vc_cfg_a[i]. - decode_format); - } - - rc = msm_csid_cid_lut(csid_dev); - - break; - } - case CSID_START: - rc = msm_csid_start(csid_dev, cdata->cfg.csid_cidmask); - break; - case CSID_STOP: - rc = msm_csid_stop(csid_dev, cdata->cfg.csid_cidmask); - break; - default: - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -ENOIOCTLCMD; - break; - } - return rc; -} - -static int32_t msm_csid_get_subdev_id(struct csid_device *csid_dev, void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - - if (!subdev_id) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -EINVAL; - } - *subdev_id = csid_dev->pdev->id; - CDBG("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); - return 0; -} - -static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = -ENOIOCTLCMD; - struct csid_device *csid_dev = v4l2_get_subdevdata(sd); - - mutex_lock(&csid_dev->mutex); - CDBG("%s:%d id %d\n", __func__, __LINE__, csid_dev->pdev->id); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - rc = msm_csid_get_subdev_id(csid_dev, arg); - break; - case VIDIOC_MSM_CSID_IO_CFG: - rc = msm_csid_cmd(csid_dev, arg); - break; - case MSM_SD_NOTIFY_FREEZE: - if (csid_dev->csid_state != CSID_POWER_UP) - break; - if (csid_dev->csid_sof_debug == SOF_DEBUG_DISABLE) { - csid_dev->csid_sof_debug = SOF_DEBUG_ENABLE; - msm_csid_set_sof_freeze_debug_reg(csid_dev, true); - } - break; - case MSM_SD_UNNOTIFY_FREEZE: - if (csid_dev->csid_state != CSID_POWER_UP) - break; - csid_dev->csid_sof_debug = SOF_DEBUG_DISABLE; - msm_csid_set_sof_freeze_debug_reg(csid_dev, false); - break; - case VIDIOC_MSM_CSID_RELEASE: - case MSM_SD_SHUTDOWN: - rc = msm_csid_release(csid_dev); - break; - default: - pr_err_ratelimited("%s: command not found\n", __func__); - } - CDBG("%s:%d\n", __func__, __LINE__); - mutex_unlock(&csid_dev->mutex); - return rc; -} - - -#ifdef CONFIG_COMPAT -static int32_t msm_csid_cmd32(struct csid_device *csid_dev, void __user *arg) -{ - int rc = 0; - struct csid_cfg_data32 *arg32 = (struct csid_cfg_data32 *) (arg); - - if (!csid_dev || !arg32) { - pr_err("%s:%d csid_dev %pK, arg32 %pK\n", __func__, __LINE__, - csid_dev, arg32); - return -EINVAL; - } - - CDBG("%s cfgtype = %d\n", __func__, arg32->cfgtype); - switch (arg32->cfgtype) { - case CSID_INIT: - rc = msm_csid_init(csid_dev, &arg32->cfg.csid_version); - CDBG("%s csid version 0x%x\n", __func__, - arg32->cfg.csid_version); - break; - case CSID_TESTMODE_CFG: { - csid_dev->is_testmode = 1; - if (copy_from_user(&csid_dev->testmode_params, - (void *)compat_ptr(arg32->cfg.csid_testmode_params), - sizeof(struct msm_camera_csid_testmode_parms))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - break; - } - case CSID_CFG: { - int i = 0; - struct msm_camera_csid_params32 csid_params32; - - if (copy_from_user(&csid_params32, - (void *)compat_ptr(arg32->cfg.csid_params), - sizeof(struct msm_camera_csid_params32))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (csid_params32.lut_params.num_cid < 1 || - csid_params32.lut_params.num_cid > MAX_CID) { - pr_err("%s: %d num_cid outside range\n", __func__, - __LINE__); - rc = -EINVAL; - break; - } - - memset(&csid_dev->current_csid_params, 0x0, - sizeof(csid_dev->current_csid_params)); - csid_dev->current_csid_params.lane_cnt = csid_params32.lane_cnt; - csid_dev->current_csid_params.lane_assign = csid_params32. - lane_assign; - csid_dev->current_csid_params.phy_sel = csid_params32.phy_sel; - csid_dev->current_csid_params.csi_clk = csid_params32.csi_clk; - csid_dev->current_csid_params.csi_3p_sel = csid_params32. - csi_3p_sel; - - for (i = 0; i < csid_params32.lut_params.num_cid; i++) { - unsigned char cid = - csid_params32.lut_params.vc_cfg_a[i].cid; - csid_dev->current_csid_params.lut_params.vc_cfg_a[cid] = - csid_params32.lut_params.vc_cfg_a[i]; - - CDBG("vc_cfg_a[%d] : dt=%d, decode_fmt=%d", - csid_params32.lut_params.vc_cfg_a[i].cid, - csid_params32.lut_params.vc_cfg_a[i].dt, - csid_params32.lut_params.vc_cfg_a[i]. - decode_format); - } - - rc = msm_csid_config(csid_dev); - break; - } - case CSID_RELEASE: - rc = msm_csid_release(csid_dev); - break; - case CSID_UPDATE_CFG: { - int i = 0; - struct msm_camera_csid_params32 csid_params32; - - if (copy_from_user(&csid_params32, - (void *)compat_ptr(arg32->cfg.csid_params), - sizeof(struct msm_camera_csid_params32))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (csid_params32.lut_params.num_cid < 1 || - csid_params32.lut_params.num_cid > MAX_CID) { - pr_err("%s: %d num_cid outside range\n", __func__, - __LINE__); - rc = -EINVAL; - break; - } - - for (i = 0; i < csid_params32.lut_params.num_cid; i++) { - unsigned char cid = - csid_params32.lut_params.vc_cfg_a[i].cid; - csid_dev->current_csid_params.lut_params.vc_cfg_a[cid] = - csid_params32.lut_params.vc_cfg_a[i]; - - CDBG("vc_cfg_a[%d] : dt=%d, decode_fmt=%d", - csid_params32.lut_params.vc_cfg_a[i].cid, - csid_params32.lut_params.vc_cfg_a[i].dt, - csid_params32.lut_params.vc_cfg_a[i]. - decode_format); - } - - rc = msm_csid_cid_lut(csid_dev); - break; - } - case CSID_START: - rc = msm_csid_start(csid_dev, arg32->cfg.csid_cidmask); - break; - case CSID_STOP: - rc = msm_csid_stop(csid_dev, arg32->cfg.csid_cidmask); - break; - default: - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -ENOIOCTLCMD; - break; - } - return rc; -} - -static long msm_csid_subdev_ioctl32(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = -ENOIOCTLCMD; - struct csid_device *csid_dev = v4l2_get_subdevdata(sd); - - mutex_lock(&csid_dev->mutex); - CDBG("%s:%d id %d\n", __func__, __LINE__, csid_dev->pdev->id); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - rc = msm_csid_get_subdev_id(csid_dev, arg); - break; - case VIDIOC_MSM_CSID_IO_CFG32: - rc = msm_csid_cmd32(csid_dev, arg); - break; - case MSM_SD_NOTIFY_FREEZE: - if (csid_dev->csid_state != CSID_POWER_UP) - break; - if (csid_dev->csid_sof_debug == SOF_DEBUG_DISABLE) { - csid_dev->csid_sof_debug = SOF_DEBUG_ENABLE; - msm_csid_set_sof_freeze_debug_reg(csid_dev, true); - } - break; - case MSM_SD_UNNOTIFY_FREEZE: - if (csid_dev->csid_state != CSID_POWER_UP) - break; - csid_dev->csid_sof_debug = SOF_DEBUG_DISABLE; - msm_csid_set_sof_freeze_debug_reg(csid_dev, false); - break; - case VIDIOC_MSM_CSID_RELEASE: - case MSM_SD_SHUTDOWN: - rc = msm_csid_release(csid_dev); - break; - default: - pr_err_ratelimited("%s: command not found\n", __func__); - } - CDBG("%s:%d\n", __func__, __LINE__); - mutex_unlock(&csid_dev->mutex); - return rc; -} - -static long msm_csid_subdev_do_ioctl32( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - - return msm_csid_subdev_ioctl32(sd, cmd, arg); -} - -static long msm_csid_subdev_fops_ioctl32(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_csid_subdev_do_ioctl32); -} -#endif -static const struct v4l2_subdev_internal_ops msm_csid_internal_ops; - -static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = { - .ioctl = &msm_csid_subdev_ioctl, - .interrupt_service_routine = msm_csid_irq_routine, -}; - -static const struct v4l2_subdev_ops msm_csid_subdev_ops = { - .core = &msm_csid_subdev_core_ops, -}; - -static int csid_probe(struct platform_device *pdev) -{ - struct csid_device *new_csid_dev; - uint32_t csi_vdd_voltage = 0; - int rc = 0; - - new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL); - if (!new_csid_dev) - return -ENOMEM; - - new_csid_dev->csid_3p_enabled = 0; - new_csid_dev->ctrl_reg = NULL; - new_csid_dev->ctrl_reg = kzalloc(sizeof(struct csid_ctrl_t), - GFP_KERNEL); - if (!new_csid_dev->ctrl_reg) { - kfree(new_csid_dev); - return -ENOMEM; - } - - v4l2_subdev_init(&new_csid_dev->msm_sd.sd, &msm_csid_subdev_ops); - v4l2_set_subdevdata(&new_csid_dev->msm_sd.sd, new_csid_dev); - platform_set_drvdata(pdev, &new_csid_dev->msm_sd.sd); - mutex_init(&new_csid_dev->mutex); - - if (pdev->dev.of_node) { - rc = of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - if (rc < 0) { - pr_err("%s:%d failed to read cell-index\n", __func__, - __LINE__); - goto csid_no_resource; - } - CDBG("%s device id %d\n", __func__, pdev->id); - - rc = of_property_read_u32((&pdev->dev)->of_node, - "qcom,csi-vdd-voltage", &csi_vdd_voltage); - if (rc < 0) { - pr_err("%s:%d failed to read qcom,csi-vdd-voltage\n", - __func__, __LINE__); - goto csid_no_resource; - } - CDBG("%s:%d reading mipi_csi_vdd is %d\n", __func__, __LINE__, - csi_vdd_voltage); - - csid_vreg_info[0].min_voltage = csi_vdd_voltage; - csid_vreg_info[0].max_voltage = csi_vdd_voltage; - } - - rc = msm_camera_get_clk_info(pdev, &new_csid_dev->csid_clk_info, - &new_csid_dev->csid_clk, &new_csid_dev->num_clk); - if (rc < 0) { - pr_err("%s: msm_camera_get_clk_info failed", __func__); - rc = -EFAULT; - goto csid_no_resource; - } - - rc = msm_camera_get_dt_vreg_data(pdev->dev.of_node, - &(new_csid_dev->csid_vreg), &(new_csid_dev->regulator_count)); - if (rc < 0) { - pr_err("%s: get vreg data from dtsi fail\n", __func__); - rc = -EFAULT; - goto csid_no_resource; - } - - if ((new_csid_dev->regulator_count < 0) || - (new_csid_dev->regulator_count > MAX_REGULATOR)) { - pr_err("%s: invalid reg count = %d, max is %d\n", __func__, - new_csid_dev->regulator_count, MAX_REGULATOR); - rc = -EFAULT; - goto csid_no_resource; - } - - new_csid_dev->base = msm_camera_get_reg_base(pdev, "csid", true); - if (!new_csid_dev->base) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto csid_invalid_vreg_data; - } - new_csid_dev->irq = msm_camera_get_irq(pdev, "csid"); - if (!new_csid_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto csid_invalid_irq; - } - new_csid_dev->pdev = pdev; - new_csid_dev->msm_sd.sd.internal_ops = &msm_csid_internal_ops; - new_csid_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(new_csid_dev->msm_sd.sd.name, - ARRAY_SIZE(new_csid_dev->msm_sd.sd.name), "msm_csid"); - media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0); - new_csid_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - new_csid_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSID; - new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5; - msm_sd_register(&new_csid_dev->msm_sd); - -#ifdef CONFIG_COMPAT - msm_cam_copy_v4l2_subdev_fops(&msm_csid_v4l2_subdev_fops); - msm_csid_v4l2_subdev_fops.compat_ioctl32 = msm_csid_subdev_fops_ioctl32; - new_csid_dev->msm_sd.sd.devnode->fops = &msm_csid_v4l2_subdev_fops; -#endif - - rc = msm_camera_register_irq(pdev, new_csid_dev->irq, - msm_csid_irq, IRQF_TRIGGER_RISING, "csid", new_csid_dev); - if (rc < 0) { - pr_err("%s: irq request fail\n", __func__); - rc = -EBUSY; - goto csid_invalid_irq; - } - rc = msm_camera_enable_irq(new_csid_dev->irq, false); - if (rc < 0) { - pr_err("%s Error registering irq ", __func__); - rc = -EBUSY; - goto csid_invalid_irq; - } - - if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v2.0")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v2_0; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v2_0; - new_csid_dev->hw_dts_version = CSID_VERSION_V20; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v2.2")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v2_2; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v2_2; - new_csid_dev->hw_dts_version = CSID_VERSION_V22; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.0")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_0; - new_csid_dev->hw_dts_version = CSID_VERSION_V30; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v4.0")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_0; - new_csid_dev->hw_dts_version = CSID_VERSION_V40; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.1")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_1; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_1; - new_csid_dev->hw_dts_version = CSID_VERSION_V31; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.2")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_2; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_2; - new_csid_dev->hw_dts_version = CSID_VERSION_V32; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.4.1")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_4_1; - new_csid_dev->hw_dts_version = CSID_VERSION_V34_1; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_4_1; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.4.2")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_4_2; - new_csid_dev->hw_dts_version = CSID_VERSION_V34_2; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_4_2; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.4.3")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_4_3; - new_csid_dev->hw_dts_version = CSID_VERSION_V34_3; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_4_3; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.6.0")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_6_0; - new_csid_dev->hw_dts_version = CSID_VERSION_V36; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_6_0; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.5")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_5; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_5; - new_csid_dev->hw_dts_version = CSID_VERSION_V35; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.5.1")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_5_1; - new_csid_dev->ctrl_reg->csid_lane_assign = - csid_lane_assign_v3_5_1; - new_csid_dev->hw_dts_version = CSID_VERSION_V35_1; - } else { - pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, - new_csid_dev->hw_dts_version); - rc = -EINVAL; - goto csid_invalid_irq; - } - - new_csid_dev->csid_state = CSID_POWER_DOWN; - return 0; - -csid_invalid_irq: - msm_camera_put_reg_base(pdev, new_csid_dev->base, "csid", true); -csid_invalid_vreg_data: - kfree(new_csid_dev->csid_vreg); -csid_no_resource: - mutex_destroy(&new_csid_dev->mutex); - kfree(new_csid_dev->ctrl_reg); - kfree(new_csid_dev); - return rc; -} - -static int msm_csid_exit(struct platform_device *pdev) -{ - struct v4l2_subdev *subdev = platform_get_drvdata(pdev); - struct csid_device *csid_dev = - v4l2_get_subdevdata(subdev); - - msm_camera_put_clk_info(pdev, &csid_dev->csid_clk_info, - &csid_dev->csid_clk, csid_dev->num_clk); - msm_camera_put_reg_base(pdev, csid_dev->base, "csid", true); - kfree(csid_dev); - return 0; -} - -static const struct of_device_id msm_csid_dt_match[] = { - {.compatible = "qcom,csid"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_csid_dt_match); - -static struct platform_driver csid_driver = { - .probe = csid_probe, - .remove = msm_csid_exit, - .driver = { - .name = MSM_CSID_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_csid_dt_match, - }, -}; - -static int __init msm_csid_init_module(void) -{ - return platform_driver_register(&csid_driver); -} - -static void __exit msm_csid_exit_module(void) -{ - platform_driver_unregister(&csid_driver); -} - -module_init(msm_csid_init_module); -module_exit(msm_csid_exit_module); -MODULE_DESCRIPTION("MSM CSID driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.h b/drivers/media/platform/msm/ais/sensor/csid/msm_csid.h deleted file mode 100644 index 58fc9612448739cd43b4b016bcab1bca986ce23f..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSID_H -#define MSM_CSID_H - -#include -#include -#include -#include -#include -#include "msm_sd.h" -#include "cam_soc_api.h" - -#define CSID_SOF_DEBUG_COUNT 3 - -enum csiphy_lane_assign { - PHY_LANE_D0, - PHY_LANE_CLK, - PHY_LANE_D1, - PHY_LANE_D2, - PHY_LANE_D3, - PHY_LANE_MAX, -}; - -struct csid_reg_parms_t { -/* MIPI CSID registers */ - uint32_t csid_hw_version_addr; - uint32_t csid_core_ctrl_0_addr; - uint32_t csid_core_ctrl_1_addr; - uint32_t csid_rst_cmd_addr; - uint32_t csid_cid_lut_vc_0_addr; - uint32_t csid_cid_lut_vc_1_addr; - uint32_t csid_cid_lut_vc_2_addr; - uint32_t csid_cid_lut_vc_3_addr; - uint32_t csid_cid_n_cfg_addr; - uint32_t csid_irq_clear_cmd_addr; - uint32_t csid_irq_mask_addr; - uint32_t csid_irq_status_addr; - uint32_t csid_captured_unmapped_long_pkt_hdr_addr; - uint32_t csid_captured_mmaped_long_pkt_hdr_addr; - uint32_t csid_captured_short_pkt_addr; - uint32_t csid_captured_long_pkt_hdr_addr; - uint32_t csid_captured_long_pkt_ftr_addr; - uint32_t csid_pif_misr_dl0_addr; - uint32_t csid_pif_misr_dl1_addr; - uint32_t csid_pif_misr_dl2_addr; - uint32_t csid_pif_misr_dl3_addr; - uint32_t csid_stats_total_pkts_rcvd_addr; - uint32_t csid_stats_ecc_addr; - uint32_t csid_stats_crc_addr; - uint32_t csid_tg_ctrl_addr; - uint32_t csid_tg_vc_cfg_addr; - uint32_t csid_tg_dt_n_cfg_0_addr; - uint32_t csid_tg_dt_n_cfg_1_addr; - uint32_t csid_tg_dt_n_cfg_2_addr; - uint32_t csid_rst_done_irq_bitshift; - uint32_t csid_rst_stb_all; - uint32_t csid_dl_input_sel_shift; - uint32_t csid_phy_sel_shift; - uint32_t csid_version; - uint32_t csid_3p_ctrl_0_addr; - uint32_t csid_3p_pkt_hdr_addr; - uint32_t csid_test_bus_ctrl; - uint32_t csid_irq_mask_val; - uint32_t csid_err_lane_overflow_offset_2p; - uint32_t csid_err_lane_overflow_offset_3p; - uint32_t csid_phy_sel_shift_3p; -}; - -struct csid_ctrl_t { - struct csid_reg_parms_t csid_reg; - uint8_t *csid_lane_assign; -}; - -enum msm_csid_state_t { - CSID_POWER_UP, - CSID_POWER_DOWN, -}; - -struct csid_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct resource *irq; - struct regulator *csi_vdd; - void __iomem *base; - struct mutex mutex; - struct completion reset_complete; - uint32_t hw_version; - uint32_t hw_dts_version; - enum msm_csid_state_t csid_state; - struct csid_ctrl_t *ctrl_reg; - struct regulator *reg_ptr; - size_t num_clk; - struct clk **csid_clk; - struct msm_cam_clk_info *csid_clk_info; - uint32_t csid_clk_index; - uint32_t csid_max_clk; - uint32_t csid_3p_enabled; - struct camera_vreg_t *csid_vreg; - struct regulator *csid_reg_ptr[MAX_REGULATOR]; - int32_t regulator_count; - uint8_t is_testmode; - struct msm_camera_csid_testmode_parms testmode_params; - struct msm_camera_csid_params current_csid_params; - uint32_t csid_sof_debug; - uint32_t csid_lane_cnt; - uint32_t csid_sof_debug_count; - - void *csiphy_dev; -}; - -#define VIDIOC_MSM_CSID_RELEASE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct v4l2_subdev*) -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/Makefile b/drivers/media/platform/msm/ais/sensor/csiphy/Makefile deleted file mode 100644 index d3fd33252f8e0e43f4a4a72b9083a42410de76f4..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_csiphy.o diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h b/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h deleted file mode 100644 index 867aec2e0103d52231db3e767596d43a7759b406..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSIPHY_2_2_HWREG_H -#define MSM_CSIPHY_2_2_HWREG_H - -#include - -struct csiphy_reg_parms_t csiphy_v2_2 = { - /* MIPI CSI PHY registers */ - 0x17C, - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x180, - 0x1A0, - 0x6F, - 0x1A4, - 0x1C0, - 0x1C4, - 0x4, - 0x1E0, - 0x1E8, - 0x1, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h b/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h deleted file mode 100644 index 69efdcc71499f2dc8e0c3fb83fdca06f91a9a48c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSIPHY_3_0_HWREG_H -#define MSM_CSIPHY_3_0_HWREG_H - -#include - -struct csiphy_reg_parms_t csiphy_v3_0 = { - /* MIPI CSI PHY registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x188, - 0x18C, - 0x1AC, - 0x3F, - 0x1AC, - 0x1CC, - 0x1CC, - 0x4, - 0x1EC, - 0x1F4, - 0x10, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h b/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h deleted file mode 100644 index cdf62d46ee7d022317e538ff6e3e39fb3da44e9f..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSIPHY_3_2_HWREG_H -#define MSM_CSIPHY_3_2_HWREG_H - -#include - -struct csiphy_reg_parms_t csiphy_v3_2 = { - /* MIPI CSI PHY registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x188, - 0x18C, - 0x1AC, - 0x3F, - 0x1AC, - 0x1CC, - 0x1CC, - 0x4, - 0x1EC, - 0x1F4, - 0x32, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_4_2_1_hwreg.h b/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_4_2_1_hwreg.h deleted file mode 100644 index 5af1ded189a603635cd21db3a1fea9f431c18756..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_4_2_1_hwreg.h +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSIPHY_3_4_2_1_HWREG_H -#define MSM_CSIPHY_3_4_2_1_HWREG_H - -#define ULPM_WAKE_UP_TIMER_MODE 2 -#define GLITCH_ELIMINATION_NUM 0x12 /* bit [6:4] */ - -#include - -struct csiphy_reg_parms_t csiphy_v3_4_2_1 = { - .mipi_csiphy_interrupt_status0_addr = 0x8B0, - .mipi_csiphy_interrupt_clear0_addr = 0x858, - .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .combo_clk_mask = 0x10, -}; - -struct csiphy_reg_3ph_parms_t csiphy_v3_4_2_1_3ph = { - /* MIPI CSI PHY registers */ - {0x814, 0x0}, - {0x818, 0x1}, - {0x188, 0x7F}, - {0x18C, 0x7F}, - {0x190, 0x0}, - {0x104, 0x6}, - {0x108, 0x0}, - {0x10c, 0x0}, - {0x114, 0x20}, - {0x118, 0x3E}, - {0x11c, 0x41}, - {0x120, 0x41}, - {0x124, 0x7F}, - {0x128, 0x0}, - {0x12c, 0x0}, - {0x130, 0x1}, - {0x134, 0x0}, - {0x138, 0x0}, - {0x13C, 0x10}, - {0x140, 0x1}, - {0x144, GLITCH_ELIMINATION_NUM}, - {0x148, 0xFE}, - {0x14C, 0x1}, - {0x154, 0x0}, - {0x15C, 0x33}, - {0x160, ULPM_WAKE_UP_TIMER_MODE}, - {0x164, 0x48}, - {0x168, 0xA0}, - {0x16C, 0x17}, - {0x170, 0x41}, - {0x174, 0x41}, - {0x178, 0x3E}, - {0x17C, 0x0}, - {0x180, 0x0}, - {0x184, 0x7F}, - {0x1cc, 0x10}, - {0x81c, 0x6}, - {0x82c, 0xFF}, - {0x830, 0xFF}, - {0x834, 0xFB}, - {0x838, 0xFF}, - {0x83c, 0x7F}, - {0x840, 0xFF}, - {0x844, 0xFF}, - {0x848, 0xEF}, - {0x84c, 0xFF}, - {0x850, 0xFF}, - {0x854, 0xFF}, - {0x28, 0x0}, - {0x800, 0x2}, - {0x0, 0x88}, - {0x4, 0x8}, - {0x8, 0x0}, - {0xC, 0xFF}, - {0x10, 0x56}, - {0x2C, 0x1}, - {0x30, 0x0}, - {0x34, 0x3}, - {0x38, 0xfe}, - {0x3C, 0xB8}, - {0x1C, 0xE7}, - {0x14, 0x0}, - {0x14, 0x60}, - {0x700, 0x80} -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_4_2_hwreg.h b/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_4_2_hwreg.h deleted file mode 100644 index d85dd1ec3a484daf4e7b62763b03dba0c5458a5a..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_4_2_hwreg.h +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSIPHY_3_4_2_HWREG_H -#define MSM_CSIPHY_3_4_2_HWREG_H - -#define ULPM_WAKE_UP_TIMER_MODE 2 -#define GLITCH_ELIMINATION_NUM 0x12 /* bit [6:4] */ - -#include - -struct csiphy_reg_parms_t csiphy_v3_4_2 = { - .mipi_csiphy_interrupt_status0_addr = 0x8B0, - .mipi_csiphy_interrupt_clear0_addr = 0x858, - .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .combo_clk_mask = 0x10, -}; - -struct csiphy_reg_3ph_parms_t csiphy_v3_4_2_3ph = { - /* MIPI CSI PHY registers */ - {0x814, 0x0}, - {0x818, 0x1}, - {0x188, 0x7F}, - {0x18C, 0x7F}, - {0x190, 0x0}, - {0x104, 0x6}, - {0x108, 0x0}, - {0x10c, 0x0}, - {0x114, 0x20}, - {0x118, 0x3E}, - {0x11c, 0x41}, - {0x120, 0x41}, - {0x124, 0x7F}, - {0x128, 0x0}, - {0x12c, 0x0}, - {0x130, 0x1}, - {0x134, 0x0}, - {0x138, 0x0}, - {0x13C, 0x10}, - {0x140, 0x1}, - {0x144, GLITCH_ELIMINATION_NUM}, - {0x148, 0xFE}, - {0x14C, 0x1}, - {0x154, 0x0}, - {0x15C, 0x33}, - {0x160, ULPM_WAKE_UP_TIMER_MODE}, - {0x164, 0x48}, - {0x168, 0xA0}, - {0x16C, 0x17}, - {0x170, 0x41}, - {0x174, 0x41}, - {0x178, 0x3E}, - {0x17C, 0x0}, - {0x180, 0x0}, - {0x184, 0x7F}, - {0x1cc, 0x10}, - {0x81c, 0x6}, - {0x82c, 0xFF}, - {0x830, 0xFF}, - {0x834, 0xFB}, - {0x838, 0xFF}, - {0x83c, 0x7F}, - {0x840, 0xFF}, - {0x844, 0xFF}, - {0x848, 0xEF}, - {0x84c, 0xFF}, - {0x850, 0xFF}, - {0x854, 0xFF}, - {0x28, 0x0}, - {0x800, 0x2}, - {0x0, 0x8E}, - {0x4, 0x8}, - {0x8, 0x0}, - {0xC, 0xFF}, - {0x10, 0x56}, - {0x2C, 0x1}, - {0x30, 0x0}, - {0x34, 0x3}, - {0x38, 0xfe}, - {0x3C, 0xB8}, - {0x1C, 0xE7}, - {0x14, 0x0}, - {0x14, 0x60}, - {0x700, 0x80} -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h b/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h deleted file mode 100644 index 99b725a75c8fdbc4cf23241c3e1e18ebd205a63f..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSIPHY_3_5_HWREG_H -#define MSM_CSIPHY_3_5_HWREG_H - -#define ULPM_WAKE_UP_TIMER_MODE 2 -#define GLITCH_ELIMINATION_NUM 0x12 /* bit [6:4] */ - -#include - -struct csiphy_reg_parms_t csiphy_v3_5 = { - .mipi_csiphy_interrupt_status0_addr = 0x8B0, - .mipi_csiphy_interrupt_clear0_addr = 0x858, - .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .combo_clk_mask = 0x10, -}; - -struct csiphy_reg_3ph_parms_t csiphy_v3_5_3ph = { - /* MIPI CSI PHY registers */ - {0x814, 0x0}, - {0x818, 0x1}, - {0x188, 0x7F}, - {0x18C, 0x7F}, - {0x190, 0x0}, - {0x104, 0x6}, - {0x108, 0x0}, - {0x10c, 0x0}, - {0x114, 0x20}, - {0x118, 0x3E}, - {0x11c, 0x41}, - {0x120, 0x41}, - {0x124, 0x7F}, - {0x128, 0x0}, - {0x12c, 0x0}, - {0x130, 0x1}, - {0x134, 0x0}, - {0x138, 0x0}, - {0x13C, 0x10}, - {0x140, 0x1}, - {0x144, GLITCH_ELIMINATION_NUM}, - {0x148, 0xFE}, - {0x14C, 0x1}, - {0x154, 0x0}, - {0x15C, 0x33}, - {0x160, ULPM_WAKE_UP_TIMER_MODE}, - {0x164, 0x48}, - {0x168, 0xA0}, - {0x16C, 0x17}, - {0x170, 0x41}, - {0x174, 0x41}, - {0x178, 0x3E}, - {0x17C, 0x0}, - {0x180, 0x0}, - {0x184, 0x7F}, - {0x1cc, 0x10}, - {0x81c, 0x6}, - {0x82c, 0xFF}, - {0x830, 0xFF}, - {0x834, 0xFB}, - {0x838, 0xFF}, - {0x83c, 0x7F}, - {0x840, 0xFF}, - {0x844, 0xFF}, - {0x848, 0xEF}, - {0x84c, 0xFF}, - {0x850, 0xFF}, - {0x854, 0xFF}, - {0x28, 0x0}, - {0x800, 0x0}, - {0x0, 0xD7}, - {0x4, 0x8}, - {0x8, 0x0}, - {0xC, 0xA5}, - {0x10, 0x50}, - {0x2C, 0x1}, - {0x30, 0x2}, - {0x34, 0x3}, - {0x38, 0x1}, - {0x3C, 0xB8}, - {0x1C, 0xA}, - {0x14, 0x0}, - {0x0, 0x0}, - {0x700, 0xC0}, -}; -#endif diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c deleted file mode 100644 index 91aac313e597682ec47cf7805913798afbb0a2d1..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c +++ /dev/null @@ -1,1661 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include "msm_csiphy.h" -#include "msm_sd.h" -#include "include/msm_csiphy_2_0_hwreg.h" -#include "include/msm_csiphy_2_2_hwreg.h" -#include "include/msm_csiphy_3_0_hwreg.h" -#include "include/msm_csiphy_3_1_hwreg.h" -#include "include/msm_csiphy_3_2_hwreg.h" -#include "include/msm_csiphy_3_4_2_hwreg.h" -#include "include/msm_csiphy_3_4_2_1_hwreg.h" -#include "include/msm_csiphy_3_5_hwreg.h" -#include "cam_hw_ops.h" - -#define DBG_CSIPHY 0 -#define SOF_DEBUG_ENABLE 1 -#define SOF_DEBUG_DISABLE 0 - -#define V4L2_IDENT_CSIPHY 50003 -#define CSIPHY_VERSION_V22 0x01 -#define CSIPHY_VERSION_V20 0x00 -#define CSIPHY_VERSION_V30 0x10 -#define CSIPHY_VERSION_V31 0x31 -#define CSIPHY_VERSION_V32 0x32 -#define CSIPHY_VERSION_V342 0x342 -#define CSIPHY_VERSION_V342_1 0x3421 -#define CSIPHY_VERSION_V35 0x35 -#define MSM_CSIPHY_DRV_NAME "msm_csiphy" -#define CLK_LANE_OFFSET 1 -#define NUM_LANES_OFFSET 4 - -#define CSI_3PHASE_HW 1 -#define MAX_LANES 4 -#define CLOCK_OFFSET 0x700 -#define CSIPHY_SOF_DEBUG_COUNT 2 - -#undef CDBG -#ifdef CONFIG_MSM_AIS_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) -#endif - -static struct v4l2_file_operations msm_csiphy_v4l2_subdev_fops; - -static void msm_csiphy_cphy_irq_config( - struct csiphy_device *csiphy_dev, - struct msm_camera_csiphy_params *csiphy_params) -{ - void __iomem *csiphybase; - - csiphybase = csiphy_dev->base; - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl11.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl11.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl12.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl12.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl13.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl13.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl14.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl14.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl15.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl15.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl16.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl16.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl17.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl17.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl18.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl18.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl19.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl19.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl20.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl20.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl21.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl21.addr); -} - -static int msm_csiphy_3phase_lane_config( - struct csiphy_device *csiphy_dev, - struct msm_camera_csiphy_params *csiphy_params) -{ - uint8_t i = 0; - uint16_t lane_mask = 0, lane_enable = 0, temp; - void __iomem *csiphybase; - - csiphybase = csiphy_dev->base; - lane_mask = csiphy_params->lane_mask & 0x7; - while (lane_mask != 0) { - temp = (i << 1)+1; - lane_enable |= ((lane_mask & 0x1) << temp); - lane_mask >>= 1; - i++; - } - msm_camera_io_w(lane_enable, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl5.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.addr); - lane_mask = csiphy_params->lane_mask & 0x7; - i = 0; - while (lane_mask & 0x7) { - if (!(lane_mask & 0x1)) { - i++; - lane_mask >>= 1; - continue; - } - - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl21.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl21.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl23.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl23.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl26.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl26.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl27.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl27.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl1.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl1.addr + 0x200*i); - msm_camera_io_w(((csiphy_params->settle_cnt >> 8) & 0xff), - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl2.addr + 0x200*i); - msm_camera_io_w((csiphy_params->settle_cnt & 0xff), - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl3.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl5.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl5.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl6.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl6.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl7.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl7.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl8.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl8.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl9.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl9.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl10.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl10.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl11.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl11.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl12.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl12.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl15.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl15.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl16.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl16.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl17.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl17.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl18.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl18.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl19.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl19.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl23.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl23.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl24.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl24.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl28.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl28.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl29.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl29.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl30.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl30.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl33.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl33.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl34.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl34.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl35.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl35.addr + 0x200*i); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl36.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl36.addr + 0x200*i); - - if (ULPM_WAKE_UP_TIMER_MODE == 0x22) { - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl51.data, - csiphybase + csiphy_dev->ctrl_reg-> - csiphy_3ph_reg.mipi_csiphy_3ph_lnn_ctrl51.addr + - 0x200*i); - } - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl25.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnn_ctrl25.addr + 0x200*i); - - lane_mask >>= 1; - i++; - } - if (csiphy_params->combo_mode == 1) { - msm_camera_io_w(0x2, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl7.addr); - } else { - msm_camera_io_w(0x6, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl7.addr); - } - /* Delay for stabilizing the regulator*/ - usleep_range(10, 15); - msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params); - return 0; -} - -static int msm_csiphy_2phase_lane_config( - struct csiphy_device *csiphy_dev, - struct msm_camera_csiphy_params *csiphy_params) -{ - uint32_t val = 0, lane_enable = 0, clk_lane, mask = 1; - uint16_t lane_mask = 0, i = 0, offset; - void __iomem *csiphybase; - - csiphybase = csiphy_dev->base; - lane_mask = csiphy_params->lane_mask & 0x1f; - - lane_enable = msm_camera_io_r(csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl5.addr); - - for (i = 0; i < MAX_LANES; i++) { - if (mask == 0x2) { - if (lane_mask & mask) - lane_enable |= 0x80; - i--; - } else if (lane_mask & mask) - lane_enable |= 0x1 << (i<<1); - mask <<= 1; - } - CDBG("%s:%d lane_enable: %d\n", __func__, __LINE__, lane_enable); - - msm_camera_io_w(lane_enable, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl5.addr); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.addr); - - for (i = 0, mask = 0x1; i < MAX_LANES; i++) { - if (!(lane_mask & mask)) { - if (mask == 0x2) - i--; - mask <<= 0x1; - continue; - } - if (mask == 0x2) { - val = 4; - offset = CLOCK_OFFSET; - clk_lane = 1; - i--; - } else { - offset = 0x200*i; - val = 0; - clk_lane = 0; - } - - /* In combo mode setting the 4th lane - * as clk_lane for 1 lane sensor, checking - * the lane_mask == 0x18 for one lane sensor - */ - if ((csiphy_params->combo_mode == 1) && (lane_mask == 0x18)) { - val |= 0xA; - if (mask == csiphy_dev->ctrl_reg-> - csiphy_reg.combo_clk_mask) { - val |= 0x4; - clk_lane = 1; - } - } - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg7.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg7.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg6.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg6.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg8.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg8.addr + offset); - msm_camera_io_w(val, csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_misc1.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl15.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl15.addr + offset); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg2.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg2.addr + offset); - - msm_camera_io_w((csiphy_params->settle_cnt & 0xFF), - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg3.addr + offset); - - if (clk_lane == 1) { - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnck_cfg1.data, csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_lnck_cfg1.addr); - - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg4.data, csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg4.addr + offset); - if (lane_mask == 0x18) - msm_camera_io_w(0x80, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg1.addr + offset); - - } else { - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg1.data, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg1.addr + offset); - } - if ((csiphy_dev->hw_version == CSIPHY_VERSION_V342 || - csiphy_dev->hw_version == CSIPHY_VERSION_V342_1) && - csiphy_params->combo_mode == 1) { - msm_camera_io_w(0x52, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg5.addr + offset); - } else { - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg5.data, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg5.addr + offset); - } - if (clk_lane == 1 && lane_mask != 0x18 && - (csiphy_dev->hw_version == CSIPHY_VERSION_V342 || - csiphy_dev->hw_version == CSIPHY_VERSION_V342_1)) { - msm_camera_io_w(0x1f, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg9.addr + offset); - } else { - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg9.data, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_cfg9.addr + offset); - } - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_test_imp.data, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_test_imp.addr + offset); - if ((csiphy_dev->hw_version == CSIPHY_VERSION_V342 || - csiphy_dev->hw_version == CSIPHY_VERSION_V342_1)) { - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl5.data, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_2ph_lnn_ctrl5.addr + offset); - } - mask <<= 1; - } - if ((csiphy_dev->hw_version == CSIPHY_VERSION_V342 || - csiphy_dev->hw_version == CSIPHY_VERSION_V342_1) && - csiphy_params->combo_mode != 1) { - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl0.data, - csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl0.addr); - } - msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params); - return 0; -} - -static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, - struct msm_camera_csiphy_params *csiphy_params) -{ - int rc = 0; - int j = 0, curr_lane = 0; - uint32_t val = 0; - long clk_rate = 0; - uint8_t lane_cnt = 0; - uint16_t lane_mask = 0; - void __iomem *csiphybase; - uint8_t csiphy_id = csiphy_dev->pdev->id; - int32_t lane_val = 0, lane_right = 0, num_lanes = 0; - int ratio = 1; - - csiphybase = csiphy_dev->base; - if (!csiphybase) { - pr_err("%s: csiphybase NULL\n", __func__); - return -EINVAL; - } - - csiphy_dev->lane_mask[csiphy_id] |= csiphy_params->lane_mask; - lane_mask = csiphy_dev->lane_mask[csiphy_id]; - lane_cnt = csiphy_params->lane_cnt; - if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) { - pr_err("%s: unsupported lane cnt %d\n", - __func__, csiphy_params->lane_cnt); - return rc; - } - - clk_rate = (csiphy_params->csiphy_clk > 0) - ? csiphy_params->csiphy_clk : - csiphy_dev->csiphy_max_clk; - clk_rate = msm_camera_clk_set_rate(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_clk[csiphy_dev->csiphy_clk_index], - clk_rate); - if (clk_rate < 0) { - pr_err("csiphy_clk_set_rate failed\n"); - return -EINVAL; - } - - if (clk_rate < csiphy_dev->csiphy_max_clk && - clk_rate > 0) { - ratio = csiphy_dev->csiphy_max_clk/clk_rate; - csiphy_params->settle_cnt = csiphy_params->settle_cnt/ratio; - } - CDBG("%s csiphy_params, mask = 0x%x cnt = %d\n", - __func__, - csiphy_params->lane_mask, - csiphy_params->lane_cnt); - CDBG("%s csiphy_params, settle cnt = 0x%x csid %d\n", - __func__, csiphy_params->settle_cnt, - csiphy_params->csid_core); - - if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30) { - val = msm_camera_io_r(csiphy_dev->clk_mux_base); - if (csiphy_params->combo_mode && - (csiphy_params->lane_mask & 0x18) == 0x18) { - val &= ~0xf0; - val |= csiphy_params->csid_core << 4; - } else { - val &= ~0xf; - val |= csiphy_params->csid_core; - } - msm_camera_io_w(val, csiphy_dev->clk_mux_base); - CDBG("%s clk mux addr %pK val 0x%x\n", __func__, - csiphy_dev->clk_mux_base, val); - /* ensure write is done */ - mb(); - } - - csiphy_dev->csi_3phase = csiphy_params->csi_3phase; - if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) { - if (csiphy_dev->csi_3phase == 1) { - rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_3p_clk_info, - csiphy_dev->csiphy_3p_clk, 2, true); - rc = msm_csiphy_3phase_lane_config(csiphy_dev, - csiphy_params); - csiphy_dev->num_irq_registers = 20; - } else { - rc = msm_csiphy_2phase_lane_config(csiphy_dev, - csiphy_params); - csiphy_dev->num_irq_registers = 11; - } - if (rc < 0) { - pr_err("%s:%d: Error in setting lane configuration\n", - __func__, __LINE__); - } - return rc; - } - - msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_t_init_cfg0_addr); - msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_t_wakeup_cfg0_addr); - - if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { - val = 0x3; - msm_camera_io_w((lane_mask << 2) | val, - csiphybase + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); - msm_camera_io_w(0x10, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(csiphy_params->settle_cnt, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg3_addr); - msm_camera_io_w(0x24, - csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_interrupt_mask0_addr); - msm_camera_io_w(0x24, - csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_interrupt_clear0_addr); - } else { - val = 0x1; - msm_camera_io_w((lane_mask << 1) | val, - csiphybase + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); - msm_camera_io_w(csiphy_params->combo_mode << - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_mode_config_shift, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_glbl_reset_addr); - } - - lane_mask &= 0x1f; - while (lane_mask & 0x1f) { - if (!(lane_mask & 0x1)) { - j++; - lane_mask >>= 1; - continue; - } - msm_camera_io_w(0x10, - csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*j); - msm_camera_io_w(csiphy_params->settle_cnt, - csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg3_addr + 0x40*j); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_mask_val, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_mask_addr + 0x4*j); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_mask_val, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_clear_addr + 0x4*j); - if (csiphy_dev->is_3_1_20nm_hw == 1) { - if (j > CLK_LANE_OFFSET) { - lane_right = 0x8; - num_lanes = (lane_cnt - curr_lane) - << NUM_LANES_OFFSET; - if (lane_cnt < curr_lane) { - pr_err("%s: Lane_cnt is less than curr_lane number\n", - __func__); - return -EINVAL; - } - lane_val = lane_right|num_lanes; - } else if (j == 1) { - lane_val = 0x4; - } - if (csiphy_params->combo_mode == 1) { - /* - * In the case of combo mode, the clock is always - * 4th lane for the second sensor. - * So check whether the sensor is of one lane - * sensor and curr_lane for 0. - */ - if (curr_lane == 0 && - ((csiphy_params->lane_mask & - 0x18) == 0x18)) - lane_val = 0x4; - } - msm_camera_io_w(lane_val, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_misc1_addr + 0x40*j); - msm_camera_io_w(0x17, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_test_imp + 0x40*j); - curr_lane++; - } - j++; - lane_mask >>= 1; - } - return rc; -} - -void msm_csiphy_disable_irq( - struct csiphy_device *csiphy_dev) -{ - void __iomem *csiphybase; - - csiphybase = csiphy_dev->base; - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl11.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl12.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl13.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl14.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl15.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl16.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl17.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl18.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl19.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl20.addr); - msm_camera_io_w(0, - csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl21.addr); -} - -static irqreturn_t msm_csiphy_irq(int irq_num, void *data) -{ - uint32_t irq; - int i; - struct csiphy_device *csiphy_dev = data; - - if (csiphy_dev->csiphy_sof_debug == SOF_DEBUG_ENABLE) { - if (csiphy_dev->csiphy_sof_debug_count < CSIPHY_SOF_DEBUG_COUNT) - csiphy_dev->csiphy_sof_debug_count++; - else { - msm_csiphy_disable_irq(csiphy_dev); - return IRQ_HANDLED; - } - } - - for (i = 0; i < csiphy_dev->num_irq_registers; i++) { - irq = msm_camera_io_r( - csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_status0_addr + 0x4*i); - msm_camera_io_w(irq, - csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_clear0_addr + 0x4*i); - pr_err_ratelimited( - "%s CSIPHY%d_IRQ_STATUS_ADDR%d = 0x%x\n", - __func__, csiphy_dev->pdev->id, i, irq); - msm_camera_io_w(0x0, - csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_clear0_addr + 0x4*i); - } - msm_camera_io_w(0x1, csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); - return IRQ_HANDLED; -} - -static void msm_csiphy_reset(struct csiphy_device *csiphy_dev) -{ - msm_camera_io_w(0x1, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); - usleep_range(5000, 8000); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); -} - -static void msm_csiphy_3ph_reset(struct csiphy_device *csiphy_dev) -{ - msm_camera_io_w(0x1, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl0.addr); - usleep_range(5000, 8000); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl0.addr); -} - -#if DBG_CSIPHY -static int msm_csiphy_init(struct csiphy_device *csiphy_dev) -{ - int rc = 0; - - if (csiphy_dev == NULL) { - pr_err("%s: csiphy_dev NULL\n", __func__); - rc = -ENOMEM; - return rc; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - rc = -EINVAL; - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - csiphy_dev->ref_count--; - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - - rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d csiphy config_vreg failed\n", - __func__, __LINE__); - goto csiphy_vreg_config_fail; - } - rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d csiphy enable_vreg failed\n", - __func__, __LINE__); - goto top_vreg_enable_failed; - } - - rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, true); - - CDBG("%s:%d called\n", __func__, __LINE__); - if (rc < 0) { - pr_err("%s: csiphy clk enable failed\n", __func__); - csiphy_dev->ref_count--; - goto csiphy_enable_clk_fail; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - rc = msm_camera_enable_irq(csiphy_dev->irq, true); - if (rc < 0) - pr_err("%s: irq enable failed\n", __func__); - - if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) - msm_csiphy_3ph_reset(csiphy_dev); - else - msm_csiphy_reset(csiphy_dev); - - CDBG("%s:%d called\n", __func__, __LINE__); - - if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) - csiphy_dev->hw_version = - msm_camera_io_r(csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_hw_version_addr); - else - csiphy_dev->hw_version = csiphy_dev->hw_dts_version; - - CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, - csiphy_dev->hw_version); - csiphy_dev->csiphy_state = CSIPHY_POWER_UP; - return 0; - -csiphy_enable_clk_fail: - msm_camera_enable_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 0); -top_vreg_enable_failed: - msm_camera_config_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 0); -csiphy_vreg_config_fail: - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; -} -#else -static int msm_csiphy_init(struct csiphy_device *csiphy_dev) -{ - int rc = 0; - - CDBG("CSI_PHY: msm_csiphy_init\n"); - if (csiphy_dev == NULL) { - pr_err("%s: csiphy_dev NULL\n", __func__); - rc = -ENOMEM; - return rc; - } - csiphy_dev->csiphy_sof_debug_count = 0; - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } - - if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - rc = -EINVAL; - return rc; - } - - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - csiphy_dev->ref_count--; - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - - rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d csiphy config_vreg failed\n", - __func__, __LINE__); - goto csiphy_vreg_config_fail; - } - rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 1); - if (rc < 0) { - pr_err("%s:%d csiphy enable_vreg failed\n", - __func__, __LINE__); - goto top_vreg_enable_failed; - } - - rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, true); - if (rc < 0) { - pr_err("%s: csiphy clk enable failed\n", __func__); - csiphy_dev->ref_count--; - goto csiphy_enable_clk_fail; - } - CDBG("%s:%d clk enable success\n", __func__, __LINE__); - - if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) - msm_csiphy_3ph_reset(csiphy_dev); - else - msm_csiphy_reset(csiphy_dev); - - if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) - csiphy_dev->hw_version = - msm_camera_io_r(csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_hw_version_addr); - else - csiphy_dev->hw_version = csiphy_dev->hw_dts_version; - - csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE; - CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, - csiphy_dev->hw_version); - csiphy_dev->csiphy_state = CSIPHY_POWER_UP; - return 0; - -csiphy_enable_clk_fail: - msm_camera_enable_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 0); -top_vreg_enable_failed: - msm_camera_config_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 0); -csiphy_vreg_config_fail: - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; -} -#endif - -#if DBG_CSIPHY -static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) -{ - int i = 0; - int rc = 0; - struct msm_camera_csi_lane_params *csi_lane_params; - uint16_t csi_lane_mask; - - csi_lane_params = (struct msm_camera_csi_lane_params *)arg; - - if (!csiphy_dev || !csiphy_dev->ref_count) { - pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); - return 0; - } - - if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - return -EINVAL; - } - - if (--csiphy_dev->ref_count) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return 0; - } - - if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) { - msm_camera_io_w(0x0, - csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl5.addr); - msm_camera_io_w(0x0, - csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.addr); - } else if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { - csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; - for (i = 0; i < 4; i++) - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_glbl_pwr_cfg_addr); - } else { - if (!csi_lane_params) { - pr_err("%s:%d failed: csi_lane_params %pK\n", __func__, - __LINE__, csi_lane_params); - return -EINVAL; - } - csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); - - CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", - __func__, - csi_lane_params->csi_lane_assign, - csi_lane_params->csi_lane_mask); - - if (!csi_lane_mask) - csi_lane_mask = 0x1f; - - csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= - ~(csi_lane_mask); - i = 0; - while (csi_lane_mask) { - if (csi_lane_mask & 0x1) { - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_misc1_addr + 0x40*i); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_test_imp + 0x40*i); - } - csi_lane_mask >>= 1; - i++; - } - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_glbl_pwr_cfg_addr); - } - - rc = msm_camera_enable_irq(csiphy_dev->irq, false); - - msm_camera_clk_enable(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, false); - - if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW && - csiphy_dev->csi_3phase == 1) { - msm_camera_clk_enable(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_3p_clk_info, - csiphy_dev->csiphy_3p_clk, 2, false); - } - - msm_camera_enable_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, - csiphy_dev->regulator_count, NULL, 0, - &csiphy_dev->csiphy_reg_ptr[0], 0); - msm_camera_config_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count, - NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0); - - csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; - - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - return 0; -} -#else -static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) -{ - int i = 0, rc = 0; - struct msm_camera_csi_lane_params *csi_lane_params; - uint16_t csi_lane_mask; - - csi_lane_params = (struct msm_camera_csi_lane_params *)arg; - - if (!csiphy_dev || !csiphy_dev->ref_count) { - pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); - return 0; - } - - if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - return -EINVAL; - } - - if (--csiphy_dev->ref_count) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return 0; - } - - if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) { - msm_camera_io_w(0x0, - csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl5.addr); - msm_camera_io_w(0x0, - csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg. - mipi_csiphy_3ph_cmn_ctrl6.addr); - } else if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { - csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; - for (i = 0; i < 4; i++) - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_glbl_pwr_cfg_addr); - } else { - if (!csi_lane_params) { - pr_err("%s:%d failed: csi_lane_params %pK\n", __func__, - __LINE__, csi_lane_params); - return -EINVAL; - } - csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); - - CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", - __func__, - csi_lane_params->csi_lane_assign, - csi_lane_params->csi_lane_mask); - - if (!csi_lane_mask) - csi_lane_mask = 0x1f; - - csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= - ~(csi_lane_mask); - i = 0; - while (csi_lane_mask) { - if (csi_lane_mask & 0x1) { - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_misc1_addr + 0x40*i); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_test_imp + 0x40*i); - } - csi_lane_mask >>= 1; - i++; - } - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_glbl_pwr_cfg_addr); - } - if (csiphy_dev->csiphy_sof_debug == SOF_DEBUG_ENABLE) - rc = msm_camera_enable_irq(csiphy_dev->irq, false); - - msm_camera_clk_enable(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, false); - if ((csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) && - (csiphy_dev->csi_3phase == 1)) { - msm_camera_clk_enable(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_3p_clk_info, - csiphy_dev->csiphy_3p_clk, 2, false); - } - - msm_camera_enable_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count, - NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0); - msm_camera_config_vreg(&csiphy_dev->pdev->dev, - csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count, - NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0); - - csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; - - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); - return 0; -} - -#endif -static int32_t msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg) -{ - int rc = 0; - struct csiphy_cfg_data *cdata = (struct csiphy_cfg_data *)arg; - struct msm_camera_csiphy_params csiphy_params; - struct msm_camera_csi_lane_params csi_lane_params; - - if (!csiphy_dev || !cdata) { - pr_err("%s: csiphy_dev NULL\n", __func__); - return -EINVAL; - } - - CDBG("%s cfgtype = %d\n", __func__, cdata->cfgtype); - switch (cdata->cfgtype) { - case CSIPHY_INIT: - rc = msm_csiphy_init(csiphy_dev); - break; - case CSIPHY_CFG: - if (copy_from_user(&csiphy_params, - (void *)cdata->cfg.csiphy_params, - sizeof(struct msm_camera_csiphy_params))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE; - csiphy_dev->is_combo_mode = csiphy_params.combo_mode; - csiphy_dev->csiphy_params = csiphy_params; - rc = 0; - - CDBG("CSI_PHY: combo mode = %d\n", - csiphy_params.combo_mode); - CDBG("CSI_PHY: lane_cnt = %d\n", - csiphy_params.lane_cnt); - CDBG("CSI_PHY: settle_cnt = %d\n", - csiphy_params.settle_cnt); - CDBG("CSI_PHY: lane_mask = %d\n", - csiphy_params.lane_mask); - CDBG("CSI_PHY: csid_core = %d\n", - csiphy_params.csid_core); - CDBG("CSI_PHY: csiphy_clk = %d\n", - csiphy_params.csiphy_clk); - CDBG("CSI_PHY: csi_3phase = %d\n", - csiphy_params.csi_3phase); - break; - case CSIPHY_START: - rc = msm_csiphy_lane_config(csiphy_dev, - &csiphy_dev->csiphy_params); - break; - case CSIPHY_STOP: - csi_lane_params.csi_lane_assign = 0; - csi_lane_params.csi_lane_mask = csiphy_dev->csiphy_params. - lane_mask; - rc = msm_csiphy_release(csiphy_dev, &csi_lane_params); - break; - case CSIPHY_RELEASE: - csi_lane_params.csi_lane_assign = 0; - csi_lane_params.csi_lane_mask = csiphy_dev->csiphy_params. - lane_mask; - - CDBG("CSI_PHY: csi_lane_assign =%d\n", - csi_lane_params.csi_lane_assign); - CDBG("CSI_PHY: csi_lane_mask =%d\n", - csi_lane_params.csi_lane_mask); - - if ((csiphy_dev->is_combo_mode == 1) && - (csiphy_dev->ref_count == 2)) { - /* CSIPHY is running in Combo mode do - not power down core */ - csiphy_dev->ref_count--; - } else { - rc = msm_csiphy_release(csiphy_dev, &csi_lane_params); - } - - break; - default: - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -ENOIOCTLCMD; - break; - } - return rc; -} - -static int32_t msm_csiphy_get_subdev_id(struct csiphy_device *csiphy_dev, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - - if (!subdev_id) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -EINVAL; - } - *subdev_id = csiphy_dev->pdev->id; - CDBG("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); - return 0; -} - -static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = -ENOIOCTLCMD; - struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); - - if (!csiphy_dev) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -EINVAL; - } - mutex_lock(&csiphy_dev->mutex); - CDBG("%s:%d id %d\n", __func__, __LINE__, csiphy_dev->pdev->id); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - rc = msm_csiphy_get_subdev_id(csiphy_dev, arg); - break; - case VIDIOC_MSM_CSIPHY_IO_CFG: - rc = msm_csiphy_cmd(csiphy_dev, arg); - break; - case VIDIOC_MSM_CSIPHY_RELEASE: - case MSM_SD_SHUTDOWN: - rc = msm_csiphy_release(csiphy_dev, arg); - break; - case MSM_SD_NOTIFY_FREEZE: - if (!csiphy_dev || !csiphy_dev->ctrl_reg || - !csiphy_dev->ref_count) - break; - if (csiphy_dev->csiphy_sof_debug == SOF_DEBUG_DISABLE) { - csiphy_dev->csiphy_sof_debug = SOF_DEBUG_ENABLE; - rc = msm_camera_enable_irq(csiphy_dev->irq, true); - } - break; - case MSM_SD_UNNOTIFY_FREEZE: - if (!csiphy_dev || !csiphy_dev->ctrl_reg || - !csiphy_dev->ref_count) - break; - csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE; - rc = msm_camera_enable_irq(csiphy_dev->irq, false); - break; - default: - pr_err_ratelimited("%s: command not found\n", __func__); - } - mutex_unlock(&csiphy_dev->mutex); - CDBG("%s:%d\n", __func__, __LINE__); - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_csiphy_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct csiphy_cfg_data32 *u32 = - (struct csiphy_cfg_data32 *)arg; - struct csiphy_cfg_data csiphy_data; - - switch (cmd) { - case VIDIOC_MSM_CSIPHY_IO_CFG32: - cmd = VIDIOC_MSM_CSIPHY_IO_CFG; - csiphy_data.cfgtype = u32->cfgtype; - csiphy_data.cfg.csiphy_params = - compat_ptr(u32->cfg.csiphy_params); - return msm_csiphy_subdev_ioctl(sd, cmd, &csiphy_data); - default: - return msm_csiphy_subdev_ioctl(sd, cmd, arg); - } -} - -static long msm_csiphy_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_csiphy_subdev_do_ioctl); -} -#endif - -static const struct v4l2_subdev_internal_ops msm_csiphy_internal_ops; - -static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = { - .ioctl = &msm_csiphy_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = { - .core = &msm_csiphy_subdev_core_ops, -}; - -static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev, - struct platform_device *pdev) -{ - int i, rc = 0; - char *csi_3p_clk_name = "csi_phy_3p_clk"; - char *csi_3p_clk_src_name = "csiphy_3p_clk_src"; - uint32_t clk_cnt = 0; - - rc = msm_camera_get_clk_info(csiphy_dev->pdev, - &csiphy_dev->csiphy_all_clk_info, - &csiphy_dev->csiphy_all_clk, - &csiphy_dev->num_all_clk); - if (rc < 0) { - pr_err("%s:%d, failed\n", __func__, __LINE__); - return rc; - } - if (csiphy_dev->num_all_clk > CSIPHY_NUM_CLK_MAX) { - pr_err("%s: invalid count=%zu, max is %d\n", __func__, - csiphy_dev->num_all_clk, CSIPHY_NUM_CLK_MAX); - rc = -EINVAL; - goto MAX_CLK_ERROR; - } - - for (i = 0; i < csiphy_dev->num_all_clk; i++) { - if (!strcmp(csiphy_dev->csiphy_all_clk_info[i].clk_name, - csi_3p_clk_src_name)) { - csiphy_dev->csiphy_3p_clk_info[0].clk_name = - csiphy_dev->csiphy_all_clk_info[i].clk_name; - csiphy_dev->csiphy_3p_clk_info[0].clk_rate = - csiphy_dev->csiphy_all_clk_info[i].clk_rate; - csiphy_dev->csiphy_3p_clk[0] = - csiphy_dev->csiphy_all_clk[i]; - continue; - } else if (!strcmp(csiphy_dev->csiphy_all_clk_info[i].clk_name, - csi_3p_clk_name)) { - csiphy_dev->csiphy_3p_clk_info[1].clk_name = - csiphy_dev->csiphy_all_clk_info[i].clk_name; - csiphy_dev->csiphy_3p_clk_info[1].clk_rate = - csiphy_dev->csiphy_all_clk_info[i].clk_rate; - csiphy_dev->csiphy_3p_clk[1] = - csiphy_dev->csiphy_all_clk[i]; - continue; - } - csiphy_dev->csiphy_clk_info[clk_cnt].clk_name = - csiphy_dev->csiphy_all_clk_info[i].clk_name; - csiphy_dev->csiphy_clk_info[clk_cnt].clk_rate = - csiphy_dev->csiphy_all_clk_info[i].clk_rate; - csiphy_dev->csiphy_clk[clk_cnt] = - csiphy_dev->csiphy_all_clk[clk_cnt]; - if (!strcmp(csiphy_dev->csiphy_clk_info[clk_cnt].clk_name, - "csiphy_timer_src_clk")) { - CDBG("%s:%d, copy csiphy_timer_src_clk", - __func__, __LINE__); - csiphy_dev->csiphy_max_clk = - csiphy_dev->csiphy_clk_info[clk_cnt].clk_rate; - csiphy_dev->csiphy_clk_index = clk_cnt; - } - CDBG("%s: clk_rate[%d] = %ld\n", __func__, clk_cnt, - csiphy_dev->csiphy_clk_info[clk_cnt].clk_rate); - clk_cnt++; - } - - csiphy_dev->num_clk = clk_cnt; - return rc; -MAX_CLK_ERROR: - msm_camera_put_clk_info(csiphy_dev->pdev, - &csiphy_dev->csiphy_all_clk_info, - &csiphy_dev->csiphy_all_clk, - csiphy_dev->num_all_clk); - - return rc; -} - -static int csiphy_probe(struct platform_device *pdev) -{ - struct csiphy_device *new_csiphy_dev; - int rc = 0; - - new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL); - if (!new_csiphy_dev) - return -ENOMEM; - new_csiphy_dev->is_3_1_20nm_hw = 0; - new_csiphy_dev->ctrl_reg = NULL; - new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t), - GFP_KERNEL); - if (!new_csiphy_dev->ctrl_reg) { - kfree(new_csiphy_dev); - return -ENOMEM; - } - v4l2_subdev_init(&new_csiphy_dev->msm_sd.sd, &msm_csiphy_subdev_ops); - v4l2_set_subdevdata(&new_csiphy_dev->msm_sd.sd, new_csiphy_dev); - platform_set_drvdata(pdev, &new_csiphy_dev->msm_sd.sd); - - mutex_init(&new_csiphy_dev->mutex); - - if (pdev->dev.of_node) { - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - CDBG("%s: device id = %d\n", __func__, pdev->id); - } - - new_csiphy_dev->pdev = pdev; - new_csiphy_dev->msm_sd.sd.internal_ops = &msm_csiphy_internal_ops; - new_csiphy_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(new_csiphy_dev->msm_sd.sd.name, - ARRAY_SIZE(new_csiphy_dev->msm_sd.sd.name), "msm_csiphy"); - media_entity_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL, 0); - new_csiphy_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - new_csiphy_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSIPHY; - new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4; - msm_sd_register(&new_csiphy_dev->msm_sd); - - new_csiphy_dev->csiphy_3phase = 0; - new_csiphy_dev->num_irq_registers = 0x8; - - if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v2.0")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V20; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v2.2")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_2; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V22; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.0")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_0; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V30; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.1")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_1; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V31; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.1.1")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_1; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V31; - new_csiphy_dev->is_3_1_20nm_hw = 1; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.2")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_2; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V32; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.4.2")) { - new_csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_v3_4_2_3ph; - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_4_2; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V342; - new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.4.2.1")) { - new_csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_v3_4_2_1_3ph; - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_4_2_1; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V342_1; - new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.5")) { - new_csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_v3_5_3ph; - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_5; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V35; - new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW; - } else { - pr_err("%s:%d, invalid hw version : 0x%x\n", __func__, __LINE__, - new_csiphy_dev->hw_dts_version); - rc = -EINVAL; - goto csiphy_no_resource; - } - - rc = msm_camera_get_dt_vreg_data(pdev->dev.of_node, - &(new_csiphy_dev->csiphy_vreg), - &(new_csiphy_dev->regulator_count)); - if (rc < 0) { - pr_err("%s: get vreg data from dtsi fail\n", __func__); - rc = -EFAULT; - goto csiphy_no_resource; - } - /* ToDo: Enable 3phase clock for dynamic clock enable/disable */ - rc = msm_csiphy_get_clk_info(new_csiphy_dev, pdev); - if (rc < 0) { - pr_err("%s: msm_csiphy_get_clk_info() failed", __func__); - rc = -EFAULT; - goto csiphy_no_resource; - } - - new_csiphy_dev->base = msm_camera_get_reg_base(pdev, "csiphy", true); - if (!new_csiphy_dev->base) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto csiphy_no_resource; - } - - if (new_csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { - new_csiphy_dev->clk_mux_base = msm_camera_get_reg_base(pdev, - "csiphy_clk_mux", true); - if (!new_csiphy_dev->clk_mux_base) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto csiphy_no_mux_resource; - } - } - new_csiphy_dev->irq = msm_camera_get_irq(pdev, "csiphy"); - if (!new_csiphy_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto csiphy_no_irq_resource; - } - rc = msm_camera_register_irq(pdev, new_csiphy_dev->irq, - msm_csiphy_irq, IRQF_TRIGGER_RISING, "csiphy", new_csiphy_dev); - if (rc < 0) { - pr_err("%s: irq request fail\n", __func__); - rc = -EBUSY; - goto csiphy_no_irq_resource; - } - msm_camera_enable_irq(new_csiphy_dev->irq, false); - - msm_cam_copy_v4l2_subdev_fops(&msm_csiphy_v4l2_subdev_fops); -#ifdef CONFIG_COMPAT - msm_csiphy_v4l2_subdev_fops.compat_ioctl32 = - msm_csiphy_subdev_fops_ioctl; -#endif - new_csiphy_dev->msm_sd.sd.devnode->fops = - &msm_csiphy_v4l2_subdev_fops; - new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; - - return 0; - -csiphy_no_irq_resource: - if (new_csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { - msm_camera_put_reg_base(pdev, new_csiphy_dev->clk_mux_base, - "csiphy_clk_mux", true); - } -csiphy_no_mux_resource: - msm_camera_put_reg_base(pdev, new_csiphy_dev->base, "csiphy", true); -csiphy_no_resource: - mutex_destroy(&new_csiphy_dev->mutex); - kfree(new_csiphy_dev->ctrl_reg); - kfree(new_csiphy_dev); - return rc; -} - -static int msm_csiphy_exit(struct platform_device *pdev) -{ - struct v4l2_subdev *subdev = platform_get_drvdata(pdev); - struct csiphy_device *csiphy_dev = - v4l2_get_subdevdata(subdev); - - msm_camera_put_clk_info(pdev, - &csiphy_dev->csiphy_all_clk_info, - &csiphy_dev->csiphy_all_clk, - csiphy_dev->num_all_clk); - - msm_camera_put_reg_base(pdev, csiphy_dev->base, "csiphy", true); - if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { - msm_camera_put_reg_base(pdev, csiphy_dev->clk_mux_base, - "csiphy_clk_mux", true); - } - kfree(csiphy_dev); - return 0; -} - -static const struct of_device_id msm_csiphy_dt_match[] = { - {.compatible = "qcom,csiphy"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_csiphy_dt_match); - -static struct platform_driver csiphy_driver = { - .probe = csiphy_probe, - .remove = msm_csiphy_exit, - .driver = { - .name = MSM_CSIPHY_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_csiphy_dt_match, - }, -}; - -static int __init msm_csiphy_init_module(void) -{ - return platform_driver_register(&csiphy_driver); -} - -static void __exit msm_csiphy_exit_module(void) -{ - platform_driver_unregister(&csiphy_driver); -} - -module_init(msm_csiphy_init_module); -module_exit(msm_csiphy_exit_module); -MODULE_DESCRIPTION("MSM CSIPHY driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h deleted file mode 100644 index 025ce0d3e05ab0fddddcc37d7d75d55d8429e92f..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h +++ /dev/null @@ -1,181 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CSIPHY_H -#define MSM_CSIPHY_H - -#include -#include -#include -#include -#include -#include "msm_sd.h" -#include "msm_camera_io_util.h" -#include "msm_camera_dt_util.h" -#include "cam_soc_api.h" - -#define MAX_CSIPHY 3 -#define CSIPHY_NUM_CLK_MAX 16 - -struct csiphy_reg_t { - uint32_t addr; - uint32_t data; -}; - -struct csiphy_reg_parms_t { - /* MIPI CSI PHY registers */ - uint32_t mipi_csiphy_lnn_cfg1_addr; - uint32_t mipi_csiphy_lnn_cfg2_addr; - uint32_t mipi_csiphy_lnn_cfg3_addr; - uint32_t mipi_csiphy_lnn_cfg4_addr; - uint32_t mipi_csiphy_lnn_cfg5_addr; - uint32_t mipi_csiphy_lnck_cfg1_addr; - uint32_t mipi_csiphy_lnck_cfg2_addr; - uint32_t mipi_csiphy_lnck_cfg3_addr; - uint32_t mipi_csiphy_lnck_cfg4_addr; - uint32_t mipi_csiphy_lnn_test_imp; - uint32_t mipi_csiphy_lnn_misc1_addr; - uint32_t mipi_csiphy_glbl_reset_addr; - uint32_t mipi_csiphy_glbl_pwr_cfg_addr; - uint32_t mipi_csiphy_glbl_irq_cmd_addr; - uint32_t mipi_csiphy_hw_version_addr; - uint32_t mipi_csiphy_interrupt_status0_addr; - uint32_t mipi_csiphy_interrupt_mask0_addr; - uint32_t mipi_csiphy_interrupt_mask_val; - uint32_t mipi_csiphy_interrupt_mask_addr; - uint32_t mipi_csiphy_interrupt_clear0_addr; - uint32_t mipi_csiphy_interrupt_clear_addr; - uint32_t mipi_csiphy_mode_config_shift; - uint32_t mipi_csiphy_glbl_t_init_cfg0_addr; - uint32_t mipi_csiphy_t_wakeup_cfg0_addr; - uint32_t csiphy_version; - uint32_t combo_clk_mask; -}; - -struct csiphy_reg_3ph_parms_t { -/*MIPI CSI PHY registers*/ - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl5; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl6; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl34; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl35; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl36; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl1; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl2; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl3; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl5; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl6; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl7; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl8; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl9; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl10; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl11; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl12; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl13; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl14; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl15; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl16; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl17; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl18; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl19; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl21; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl23; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl24; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl25; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl26; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl27; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl28; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl29; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl30; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl31; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl32; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl33; - struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl51; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl7; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl11; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl12; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl13; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl14; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl15; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl16; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl17; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl18; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl19; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl20; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl21; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_misc1; - struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl0; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg1; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg2; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg3; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg4; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg5; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg6; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg7; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg8; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg9; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl15; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_test_imp; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_test_force; - struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl5; - struct csiphy_reg_t mipi_csiphy_3ph_lnck_cfg1; -}; - -struct csiphy_ctrl_t { - struct csiphy_reg_parms_t csiphy_reg; - struct csiphy_reg_3ph_parms_t csiphy_3ph_reg; -}; - -enum msm_csiphy_state_t { - CSIPHY_POWER_UP, - CSIPHY_POWER_DOWN, -}; - -struct csiphy_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *irq; - void __iomem *base; - void __iomem *clk_mux_base; - struct mutex mutex; - uint32_t hw_version; - uint32_t hw_dts_version; - enum msm_csiphy_state_t csiphy_state; - struct csiphy_ctrl_t *ctrl_reg; - size_t num_all_clk; - struct clk **csiphy_all_clk; - struct msm_cam_clk_info *csiphy_all_clk_info; - uint32_t num_clk; - struct clk *csiphy_clk[CSIPHY_NUM_CLK_MAX]; - struct msm_cam_clk_info csiphy_clk_info[CSIPHY_NUM_CLK_MAX]; - struct clk *csiphy_3p_clk[2]; - struct msm_cam_clk_info csiphy_3p_clk_info[2]; - unsigned char csi_3phase; - int32_t ref_count; - uint16_t lane_mask[MAX_CSIPHY]; - uint32_t is_3_1_20nm_hw; - uint32_t csiphy_clk_index; - uint32_t csiphy_max_clk; - uint8_t csiphy_3phase; - uint8_t num_irq_registers; - uint32_t csiphy_sof_debug; - uint32_t csiphy_sof_debug_count; - uint32_t is_combo_mode; - struct camera_vreg_t *csiphy_vreg; - struct regulator *csiphy_reg_ptr[MAX_REGULATOR]; - int32_t regulator_count; - struct msm_camera_csiphy_params csiphy_params; -}; - -#define VIDIOC_MSM_CSIPHY_RELEASE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *) -#endif diff --git a/drivers/media/platform/msm/ais/sensor/eeprom/Makefile b/drivers/media/platform/msm/ais/sensor/eeprom/Makefile deleted file mode 100644 index c93cfe564b3db0015ac7b44eee1bb6d8bec3a2a0..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/eeprom/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci -obj-$(CONFIG_MSM_AIS_EEPROM) += msm_eeprom.o diff --git a/drivers/media/platform/msm/ais/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/ais/sensor/eeprom/msm_eeprom.c deleted file mode 100644 index 438b90d5376c1641094b74f8b5dff39e6faf2747..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/eeprom/msm_eeprom.c +++ /dev/null @@ -1,1879 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include "msm_sd.h" -#include "msm_cci.h" -#include "msm_eeprom.h" - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -DEFINE_MSM_MUTEX(msm_eeprom_mutex); -#ifdef CONFIG_COMPAT -static struct v4l2_file_operations msm_eeprom_v4l2_subdev_fops; -#endif - -/** - * msm_get_read_mem_size - Get the total size for allocation - * @eeprom_map_array: mem map - * - * Returns size after computation size, returns error in case of error - */ -static int msm_get_read_mem_size - (struct msm_eeprom_memory_map_array *eeprom_map_array) { - int size = 0, i, j; - struct msm_eeprom_mem_map_t *eeprom_map; - - if (eeprom_map_array->msm_size_of_max_mappings > - MSM_EEPROM_MAX_MEM_MAP_CNT) { - pr_err("%s:%d Memory map cnt greter then expected: %d", - __func__, __LINE__, - eeprom_map_array->msm_size_of_max_mappings); - return -EINVAL; - } - for (j = 0; j < eeprom_map_array->msm_size_of_max_mappings; j++) { - eeprom_map = &(eeprom_map_array->memory_map[j]); - if (eeprom_map->memory_map_size > - MSM_EEPROM_MEMORY_MAP_MAX_SIZE) { - pr_err("%s:%d Memory map size greter then expected: %d", - __func__, __LINE__, - eeprom_map->memory_map_size); - return -EINVAL; - } - for (i = 0; i < eeprom_map->memory_map_size; i++) { - if (eeprom_map->mem_settings[i].i2c_operation == - MSM_CAM_READ) { - size += eeprom_map->mem_settings[i].reg_data; - } - } - } - CDBG("Total Data Size: %d\n", size); - return size; -} - -/** - * msm_eeprom_verify_sum - verify crc32 checksum - * @mem: data buffer - * @size: size of data buffer - * @sum: expected checksum - * - * Returns 0 if checksum match, -EINVAL otherwise. - */ -static int msm_eeprom_verify_sum(const char *mem, uint32_t size, uint32_t sum) -{ - uint32_t crc = ~0; - - /* check overflow */ - if (size > crc - sizeof(uint32_t)) - return -EINVAL; - - crc = crc32_le(crc, mem, size); - if (~crc != sum) { - CDBG("%s: expect 0x%x, result 0x%x\n", __func__, sum, ~crc); - return -EINVAL; - } - CDBG("%s: checksum pass 0x%x\n", __func__, sum); - return 0; -} - -/** - * msm_eeprom_match_crc - verify multiple regions using crc - * @data: data block to be verified - * - * Iterates through all regions stored in @data. Regions with odd index - * are treated as data, and its next region is treated as checksum. Thus - * regions of even index must have valid_size of 4 or 0 (skip verification). - * Returns a bitmask of verified regions, starting from LSB. 1 indicates - * a checksum match, while 0 indicates checksum mismatch or not verified. - */ -static uint32_t msm_eeprom_match_crc(struct msm_eeprom_memory_block_t *data) -{ - int j, rc; - uint32_t *sum; - uint32_t ret = 0; - uint8_t *memptr; - struct msm_eeprom_memory_map_t *map; - - if (!data) { - pr_err("%s data is NULL", __func__); - return -EINVAL; - } - map = data->map; - memptr = data->mapdata; - - for (j = 0; j + 1 < data->num_map; j += 2) { - /* empty table or no checksum */ - if (!map[j].mem.valid_size || !map[j+1].mem.valid_size) { - memptr += map[j].mem.valid_size - + map[j+1].mem.valid_size; - continue; - } - if (map[j+1].mem.valid_size != sizeof(uint32_t)) { - CDBG("%s: malformatted data mapping\n", __func__); - return -EINVAL; - } - sum = (uint32_t *) (memptr + map[j].mem.valid_size); - rc = msm_eeprom_verify_sum(memptr, map[j].mem.valid_size, - *sum); - if (!rc) - ret |= 1 << (j/2); - memptr += map[j].mem.valid_size + map[j+1].mem.valid_size; - } - return ret; -} - -/** - * read_eeprom_memory() - read map data into buffer - * @e_ctrl: eeprom control struct - * @block: block to be read - * - * This function iterates through blocks stored in block->map, reads each - * region and concatenate them into the pre-allocated block->mapdata - */ -static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_eeprom_memory_block_t *block) -{ - int rc = 0; - int j; - struct msm_eeprom_memory_map_t *emap = block->map; - struct msm_eeprom_board_info *eb_info; - uint8_t *memptr = block->mapdata; - - if (!e_ctrl) { - pr_err("%s e_ctrl is NULL", __func__); - return -EINVAL; - } - - eb_info = e_ctrl->eboard_info; - - for (j = 0; j < block->num_map; j++) { - if (emap[j].saddr.addr) { - eb_info->i2c_slaveaddr = emap[j].saddr.addr; - e_ctrl->i2c_client.cci_client->sid = - eb_info->i2c_slaveaddr >> 1; - pr_err("qcom,slave-addr = 0x%X\n", - eb_info->i2c_slaveaddr); - } - - if (emap[j].page.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].page.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &(e_ctrl->i2c_client), emap[j].page.addr, - emap[j].page.data, emap[j].page.data_t); - msleep(emap[j].page.delay); - if (rc < 0) { - pr_err("%s: page write failed\n", __func__); - return rc; - } - } - if (emap[j].pageen.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &(e_ctrl->i2c_client), emap[j].pageen.addr, - emap[j].pageen.data, emap[j].pageen.data_t); - msleep(emap[j].pageen.delay); - if (rc < 0) { - pr_err("%s: page enable failed\n", __func__); - return rc; - } - } - if (emap[j].poll.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].poll.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll( - &(e_ctrl->i2c_client), emap[j].poll.addr, - emap[j].poll.data, emap[j].poll.data_t, - emap[j].poll.delay); - if (rc < 0) { - pr_err("%s: poll failed\n", __func__); - return rc; - } - } - - if (emap[j].mem.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].mem.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq( - &(e_ctrl->i2c_client), emap[j].mem.addr, - memptr, emap[j].mem.valid_size); - if (rc < 0) { - pr_err("%s: read failed\n", __func__); - return rc; - } - memptr += emap[j].mem.valid_size; - } - if (emap[j].pageen.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &(e_ctrl->i2c_client), emap[j].pageen.addr, - 0, emap[j].pageen.data_t); - if (rc < 0) { - pr_err("%s: page disable failed\n", __func__); - return rc; - } - } - } - return rc; -} -/** - * msm_eeprom_parse_memory_map() - parse memory map in device node - * @of: device node - * @data: memory block for output - * - * This functions parses @of to fill @data. It allocates map itself, parses - * the @of node, calculate total data length, and allocates required buffer. - * It only fills the map, but does not perform actual reading. - */ -static int msm_eeprom_parse_memory_map(struct device_node *of, - struct msm_eeprom_memory_block_t *data) -{ - int i, rc = 0; - char property[PROPERTY_MAXSIZE]; - uint32_t count = 6; - struct msm_eeprom_memory_map_t *map; - - snprintf(property, PROPERTY_MAXSIZE, "qcom,num-blocks"); - rc = of_property_read_u32(of, property, &data->num_map); - CDBG("%s: %s %d\n", __func__, property, data->num_map); - if (rc < 0) { - pr_err("%s failed rc %d\n", __func__, rc); - return rc; - } - - map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); - if (!map) { - rc = -ENOMEM; - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - data->map = map; - - for (i = 0; i < data->num_map; i++) { - snprintf(property, PROPERTY_MAXSIZE, "qcom,page%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].page, count); - if (rc < 0) { - pr_err("%s: failed %d\n", __func__, __LINE__); - goto ERROR; - } - - snprintf(property, PROPERTY_MAXSIZE, - "qcom,pageen%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].pageen, count); - if (rc < 0) - CDBG("%s: pageen not needed\n", __func__); - - snprintf(property, PROPERTY_MAXSIZE, "qcom,saddr%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].saddr.addr, 1); - if (rc < 0) - CDBG("%s: saddr not needed - block %d\n", __func__, i); - - snprintf(property, PROPERTY_MAXSIZE, "qcom,poll%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].poll, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - - snprintf(property, PROPERTY_MAXSIZE, "qcom,mem%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].mem, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - data->num_data += map[i].mem.valid_size; - } - - CDBG("%s num_bytes %d\n", __func__, data->num_data); - - data->mapdata = kzalloc(data->num_data, GFP_KERNEL); - if (!data->mapdata) { - rc = -ENOMEM; - pr_err("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - return rc; - -ERROR: - kfree(data->map); - memset(data, 0, sizeof(*data)); - return rc; -} - -/** - * eeprom_parse_memory_map - Parse mem map - * @e_ctrl: ctrl structure - * @eeprom_map_array: eeprom map - * - * Returns success or failure - */ -static int eeprom_parse_memory_map(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_eeprom_memory_map_array *eeprom_map_array) -{ - int rc = 0, i, j; - uint8_t *memptr; - struct msm_eeprom_mem_map_t *eeprom_map; - - e_ctrl->cal_data.mapdata = NULL; - e_ctrl->cal_data.num_data = msm_get_read_mem_size(eeprom_map_array); - if (e_ctrl->cal_data.num_data <= 0) { - pr_err("%s:%d Error in reading mem size\n", - __func__, __LINE__); - e_ctrl->cal_data.num_data = 0; - return -EINVAL; - } - e_ctrl->cal_data.mapdata = - kzalloc(e_ctrl->cal_data.num_data, GFP_KERNEL); - if (!e_ctrl->cal_data.mapdata) - return -ENOMEM; - - memptr = e_ctrl->cal_data.mapdata; - for (j = 0; j < eeprom_map_array->msm_size_of_max_mappings; j++) { - eeprom_map = &(eeprom_map_array->memory_map[j]); - if (e_ctrl->i2c_client.cci_client) { - e_ctrl->i2c_client.cci_client->sid = - eeprom_map->slave_addr >> 1; - } else if (e_ctrl->i2c_client.client) { - e_ctrl->i2c_client.client->addr = - eeprom_map->slave_addr >> 1; - } - CDBG("Slave Addr: 0x%X\n", eeprom_map->slave_addr); - CDBG("Memory map Size: %d", - eeprom_map->memory_map_size); - for (i = 0; i < eeprom_map->memory_map_size; i++) { - switch (eeprom_map->mem_settings[i].i2c_operation) { - case MSM_CAM_WRITE: { - e_ctrl->i2c_client.addr_type = - eeprom_map->mem_settings[i].addr_type; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &(e_ctrl->i2c_client), - eeprom_map->mem_settings[i].reg_addr, - eeprom_map->mem_settings[i].reg_data, - eeprom_map->mem_settings[i].data_type); - msleep(eeprom_map->mem_settings[i].delay); - if (rc < 0) { - pr_err("%s: page write failed\n", - __func__); - goto clean_up; - } - } - break; - case MSM_CAM_POLL: { - e_ctrl->i2c_client.addr_type = - eeprom_map->mem_settings[i].addr_type; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll( - &(e_ctrl->i2c_client), - eeprom_map->mem_settings[i].reg_addr, - eeprom_map->mem_settings[i].reg_data, - eeprom_map->mem_settings[i].data_type, - eeprom_map->mem_settings[i].delay); - if (rc < 0) { - pr_err("%s: poll failed\n", - __func__); - goto clean_up; - } - } - break; - case MSM_CAM_READ: { - e_ctrl->i2c_client.addr_type = - eeprom_map->mem_settings[i].addr_type; - rc = e_ctrl->i2c_client.i2c_func_tbl-> - i2c_read_seq(&(e_ctrl->i2c_client), - eeprom_map->mem_settings[i].reg_addr, - memptr, - eeprom_map->mem_settings[i].reg_data); - msleep(eeprom_map->mem_settings[i].delay); - if (rc < 0) { - pr_err("%s: read failed\n", - __func__); - goto clean_up; - } - memptr += eeprom_map->mem_settings[i].reg_data; - } - break; - default: - pr_err("%s: %d Invalid i2c operation LC:%d\n", - __func__, __LINE__, i); - return -EINVAL; - } - } - } - memptr = e_ctrl->cal_data.mapdata; - for (i = 0; i < e_ctrl->cal_data.num_data; i++) - CDBG("memory_data[%d] = 0x%X\n", i, memptr[i]); - return rc; - -clean_up: - kfree(e_ctrl->cal_data.mapdata); - e_ctrl->cal_data.num_data = 0; - e_ctrl->cal_data.mapdata = NULL; - return rc; -} - -/** - * msm_eeprom_power_up - Do eeprom power up here - * @e_ctrl: ctrl structure - * @power_info: power up info for eeprom - * - * Returns success or failure - */ -static int msm_eeprom_power_up(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_camera_power_ctrl_t *power_info) { - int32_t rc = 0; - - rc = msm_camera_fill_vreg_params( - power_info->cam_vreg, power_info->num_vreg, - power_info->power_setting, power_info->power_setting_size); - if (rc < 0) { - pr_err("%s:%d failed in camera_fill_vreg_params rc %d", - __func__, __LINE__, rc); - return rc; - } - - /* Parse and fill vreg params for powerdown settings*/ - rc = msm_camera_fill_vreg_params( - power_info->cam_vreg, power_info->num_vreg, - power_info->power_down_setting, - power_info->power_down_setting_size); - if (rc < 0) { - pr_err("%s:%d failed msm_camera_fill_vreg_params for PDOWN rc %d", - __func__, __LINE__, rc); - return rc; - } - - rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc) { - pr_err("%s:%d failed in eeprom Power up rc %d\n", - __func__, __LINE__, rc); - return rc; - } - return rc; -} - -/** - * msm_eeprom_power_up - Do power up, parse and power down - * @e_ctrl: ctrl structure - * Returns success or failure - */ -static int eeprom_init_config(struct msm_eeprom_ctrl_t *e_ctrl, - void __user *argp) -{ - int rc = 0; - struct msm_eeprom_cfg_data *cdata = argp; - struct msm_sensor_power_setting_array *power_setting_array = NULL; - struct msm_camera_power_ctrl_t *power_info; - struct msm_eeprom_memory_map_array *memory_map_arr = NULL; - - power_setting_array = - kzalloc(sizeof(struct msm_sensor_power_setting_array), - GFP_KERNEL); - if (!power_setting_array) { - pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - memory_map_arr = kzalloc(sizeof(struct msm_eeprom_memory_map_array), - GFP_KERNEL); - if (!memory_map_arr) { - rc = -ENOMEM; - pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__); - goto free_mem; - } - - if (copy_from_user(power_setting_array, - cdata->cfg.eeprom_info.power_setting_array, - sizeof(struct msm_sensor_power_setting_array))) { - pr_err("%s copy_from_user failed %d\n", - __func__, __LINE__); - goto free_mem; - } - CDBG("%s:%d Size of power setting array: %d\n", - __func__, __LINE__, power_setting_array->size); - if (copy_from_user(memory_map_arr, - cdata->cfg.eeprom_info.mem_map_array, - sizeof(struct msm_eeprom_memory_map_array))) { - rc = -EINVAL; - pr_err("%s copy_from_user failed for memory map%d\n", - __func__, __LINE__); - goto free_mem; - } - - power_info = &(e_ctrl->eboard_info->power_info); - - power_info->power_setting = - power_setting_array->power_setting_a; - power_info->power_down_setting = - power_setting_array->power_down_setting_a; - - power_info->power_setting_size = - power_setting_array->size; - power_info->power_down_setting_size = - power_setting_array->size_down; - - if ((power_info->power_setting_size > - MAX_POWER_CONFIG) || - (power_info->power_down_setting_size > - MAX_POWER_CONFIG) || - (!power_info->power_down_setting_size) || - (!power_info->power_setting_size)) { - rc = -EINVAL; - pr_err("%s:%d Invalid power setting size :%d, %d\n", - __func__, __LINE__, - power_info->power_setting_size, - power_info->power_down_setting_size); - goto free_mem; - } - - if (e_ctrl->i2c_client.cci_client) { - e_ctrl->i2c_client.cci_client->i2c_freq_mode = - cdata->cfg.eeprom_info.i2c_freq_mode; - if (e_ctrl->i2c_client.cci_client->i2c_freq_mode > - I2C_MAX_MODES) { - pr_err("%s::%d Improper I2C freq mode\n", - __func__, __LINE__); - e_ctrl->i2c_client.cci_client->i2c_freq_mode = - I2C_STANDARD_MODE; - } - } - - /* Fill vreg power info and power up here */ - rc = msm_eeprom_power_up(e_ctrl, power_info); - if (rc < 0) { - pr_err("Power Up failed for eeprom\n"); - goto free_mem; - } - - rc = eeprom_parse_memory_map(e_ctrl, memory_map_arr); - if (rc < 0) - pr_err("%s::%d memory map parse failed\n", __func__, __LINE__); - - rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc < 0) { - pr_err("%s:%d Power down failed rc %d\n", - __func__, __LINE__, rc); - } - -free_mem: - kfree(power_setting_array); - kfree(memory_map_arr); - power_setting_array = NULL; - memory_map_arr = NULL; - return rc; -} - -static int msm_eeprom_get_cmm_data(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_eeprom_cfg_data *cdata) -{ - int rc = 0; - struct msm_eeprom_cmm_t *cmm_data = &e_ctrl->eboard_info->cmm_data; - - cdata->cfg.get_cmm_data.cmm_support = cmm_data->cmm_support; - cdata->cfg.get_cmm_data.cmm_compression = cmm_data->cmm_compression; - cdata->cfg.get_cmm_data.cmm_size = cmm_data->cmm_size; - return rc; -} - -static int eeprom_config_read_cal_data(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_eeprom_cfg_data *cdata) -{ - int rc; - - /* check range */ - if (cdata->cfg.read_data.num_bytes > - e_ctrl->cal_data.num_data) { - CDBG("%s: Invalid size. exp %u, req %u\n", __func__, - e_ctrl->cal_data.num_data, - cdata->cfg.read_data.num_bytes); - return -EINVAL; - } - - rc = copy_to_user(cdata->cfg.read_data.dbuffer, - e_ctrl->cal_data.mapdata, - cdata->cfg.read_data.num_bytes); - - return rc; -} - -static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl, - void __user *argp) -{ - struct msm_eeprom_cfg_data *cdata = - (struct msm_eeprom_cfg_data *)argp; - int rc = 0; - size_t length = 0; - - CDBG("%s E\n", __func__); - switch (cdata->cfgtype) { - case CFG_EEPROM_GET_INFO: - if (e_ctrl->userspace_probe == 1) { - pr_err("%s:%d Eeprom name should be module driver", - __func__, __LINE__); - rc = -EINVAL; - break; - } - CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); - cdata->is_supported = e_ctrl->is_supported; - length = strlen(e_ctrl->eboard_info->eeprom_name) + 1; - if (length > MAX_EEPROM_NAME) { - pr_err("%s:%d invalid eeprom_name length %d\n", - __func__, __LINE__, (int)length); - rc = -EINVAL; - break; - } - memcpy(cdata->cfg.eeprom_name, - e_ctrl->eboard_info->eeprom_name, length); - break; - case CFG_EEPROM_GET_CAL_DATA: - CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); - cdata->cfg.get_data.num_bytes = - e_ctrl->cal_data.num_data; - break; - case CFG_EEPROM_READ_CAL_DATA: - CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__); - rc = eeprom_config_read_cal_data(e_ctrl, cdata); - break; - case CFG_EEPROM_GET_MM_INFO: - CDBG("%s E CFG_EEPROM_GET_MM_INFO\n", __func__); - rc = msm_eeprom_get_cmm_data(e_ctrl, cdata); - break; - case CFG_EEPROM_INIT: - if (e_ctrl->userspace_probe == 0) { - pr_err("%s:%d Eeprom already probed at kernel boot", - __func__, __LINE__); - rc = -EINVAL; - break; - } - if (e_ctrl->cal_data.num_data == 0) { - rc = eeprom_init_config(e_ctrl, argp); - if (rc < 0) { - pr_err("%s:%d Eeprom init failed\n", - __func__, __LINE__); - return rc; - } - } else { - CDBG("%s:%d Already read eeprom\n", - __func__, __LINE__); - } - break; - default: - break; - } - - CDBG("%s X rc: %d\n", __func__, rc); - return rc; -} - -static int msm_eeprom_get_subdev_id(struct msm_eeprom_ctrl_t *e_ctrl, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - - CDBG("%s E\n", __func__); - if (!subdev_id) { - pr_err("%s failed\n", __func__); - return -EINVAL; - } - *subdev_id = e_ctrl->subdev_id; - CDBG("subdev_id %d\n", *subdev_id); - CDBG("%s X\n", __func__); - return 0; -} - -static long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - void __user *argp = (void __user *)arg; - - CDBG("%s E\n", __func__); - CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, e_ctrl, argp); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return msm_eeprom_get_subdev_id(e_ctrl, argp); - case VIDIOC_MSM_EEPROM_CFG: - return msm_eeprom_config(e_ctrl, argp); - default: - return -ENOIOCTLCMD; - } - - CDBG("%s X\n", __func__); -} - -static struct msm_camera_i2c_fn_t msm_eeprom_cci_func_tbl = { - .i2c_read = msm_camera_cci_i2c_read, - .i2c_read_seq = msm_camera_cci_i2c_read_seq, - .i2c_write = msm_camera_cci_i2c_write, - .i2c_write_seq = msm_camera_cci_i2c_write_seq, - .i2c_write_table = msm_camera_cci_i2c_write_table, - .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_cci_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_cci_i2c_util, - .i2c_poll = msm_camera_cci_i2c_poll, -}; - -static struct msm_camera_i2c_fn_t msm_eeprom_qup_func_tbl = { - .i2c_read = msm_camera_qup_i2c_read, - .i2c_read_seq = msm_camera_qup_i2c_read_seq, - .i2c_write = msm_camera_qup_i2c_write, - .i2c_write_table = msm_camera_qup_i2c_write_table, - .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_qup_i2c_write_table_w_microdelay, -}; - -static struct msm_camera_i2c_fn_t msm_eeprom_spi_func_tbl = { - .i2c_read = msm_camera_spi_read, - .i2c_read_seq = msm_camera_spi_read_seq, -}; - -static int msm_eeprom_open(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) { - int rc = 0; - struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - - CDBG("%s E\n", __func__); - if (!e_ctrl) { - pr_err("%s failed e_ctrl is NULL\n", __func__); - return -EINVAL; - } - CDBG("%s X\n", __func__); - return rc; -} - -static int msm_eeprom_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) { - int rc = 0; - struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - - CDBG("%s E\n", __func__); - if (!e_ctrl) { - pr_err("%s failed e_ctrl is NULL\n", __func__); - return -EINVAL; - } - CDBG("%s X\n", __func__); - return rc; -} - -static const struct v4l2_subdev_internal_ops msm_eeprom_internal_ops = { - .open = msm_eeprom_open, - .close = msm_eeprom_close, -}; - -static struct v4l2_subdev_core_ops msm_eeprom_subdev_core_ops = { - .ioctl = msm_eeprom_subdev_ioctl, -}; - -static struct v4l2_subdev_ops msm_eeprom_subdev_ops = { - .core = &msm_eeprom_subdev_core_ops, -}; - -static int msm_eeprom_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - struct msm_eeprom_ctrl_t *e_ctrl = NULL; - - CDBG("%s E\n", __func__); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s i2c_check_functionality failed\n", __func__); - goto probe_failure; - } - - e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); - if (!e_ctrl) - return -ENOMEM; - e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; - e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - CDBG("%s client = 0x%pK\n", __func__, client); - e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data); - if (!e_ctrl->eboard_info) { - pr_err("%s:%d board info NULL\n", __func__, __LINE__); - rc = -EINVAL; - goto ectrl_free; - } - e_ctrl->i2c_client.client = client; - e_ctrl->cal_data.mapdata = NULL; - e_ctrl->cal_data.map = NULL; - e_ctrl->userspace_probe = 0; - e_ctrl->is_supported = 1; - - /* Set device type as I2C */ - e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; - e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl; - - if (e_ctrl->eboard_info->i2c_slaveaddr != 0) - e_ctrl->i2c_client.client->addr = - e_ctrl->eboard_info->i2c_slaveaddr; - - /* Get clocks information */ - rc = msm_camera_i2c_dev_get_clk_info( - &e_ctrl->i2c_client.client->dev, - &e_ctrl->eboard_info->power_info.clk_info, - &e_ctrl->eboard_info->power_info.clk_ptr, - &e_ctrl->eboard_info->power_info.clk_info_size); - if (rc < 0) { - pr_err("failed: msm_camera_get_clk_info rc %d", rc); - goto ectrl_free; - } - - /* IMPLEMENT READING PART */ - /* Initialize sub device */ - v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd, - e_ctrl->i2c_client.client, - e_ctrl->eeprom_v4l2_subdev_ops); - v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); - e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; - e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); - e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; - msm_sd_register(&e_ctrl->msm_sd); - CDBG("%s success result=%d X\n", __func__, rc); - return rc; - -ectrl_free: - kfree(e_ctrl); -probe_failure: - pr_err("%s failed! rc = %d\n", __func__, rc); - return rc; -} - -static int msm_eeprom_i2c_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct msm_eeprom_ctrl_t *e_ctrl; - - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); - if (!e_ctrl) { - pr_err("%s: eeprom device is NULL\n", __func__); - return 0; - } - - if (!e_ctrl->eboard_info) { - pr_err("%s: eboard_info is NULL\n", __func__); - return 0; - } - - msm_camera_i2c_dev_put_clk_info(&e_ctrl->i2c_client.client->dev, - &e_ctrl->eboard_info->power_info.clk_info, - &e_ctrl->eboard_info->power_info.clk_ptr, - e_ctrl->eboard_info->power_info.clk_info_size); - - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); - if (e_ctrl->eboard_info) { - kfree(e_ctrl->eboard_info->power_info.gpio_conf); - kfree(e_ctrl->eboard_info); - } - e_ctrl->cal_data.mapdata = NULL; - kfree(e_ctrl); - e_ctrl = NULL; - - return 0; -} - -#define msm_eeprom_spi_parse_cmd(spic, str, name, out, size) \ - { \ - spic->cmd_tbl.name.opcode = out[0]; \ - spic->cmd_tbl.name.addr_len = out[1]; \ - spic->cmd_tbl.name.dummy_len = out[2]; \ - } - -static int msm_eeprom_spi_parse_of(struct msm_camera_spi_client *spic) -{ - int rc = -EFAULT; - uint32_t tmp[3]; - - if (of_property_read_u32_array(spic->spi_master->dev.of_node, - "qcom,spiop,read", tmp, 3)) - return -EFAULT; - msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,read", read, tmp, 3); - if (of_property_read_u32_array(spic->spi_master->dev.of_node, - "qcom,spiop,readseq", tmp, 3)) - return -EFAULT; - msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,readseq", read_seq, tmp, 3); - if (of_property_read_u32_array(spic->spi_master->dev.of_node, - "qcom,spiop,queryid", tmp, 3)) - return -EFAULT; - msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,queryid", query_id, tmp, 3); - - rc = of_property_read_u32_array(spic->spi_master->dev.of_node, - "qcom,eeprom-id", tmp, 2); - if (rc) { - pr_err("%s: Failed to get eeprom id\n", __func__); - return rc; - } - spic->mfr_id0 = tmp[0]; - spic->device_id0 = tmp[1]; - - return 0; -} - -static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl) -{ - int rc; - struct msm_camera_i2c_client *client = &e_ctrl->i2c_client; - uint8_t id[2]; - - rc = msm_camera_spi_query_id(client, 0, &id[0], 2); - if (rc < 0) - return rc; - CDBG("%s: read 0x%x 0x%x, check 0x%x 0x%x\n", __func__, id[0], - id[1], client->spi_client->mfr_id0, - client->spi_client->device_id0); - if (id[0] != client->spi_client->mfr_id0 - || id[1] != client->spi_client->device_id0) - return -ENODEV; - - return 0; -} - -static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) -{ - int rc = 0, i = 0; - struct msm_eeprom_board_info *eb_info; - struct msm_camera_power_ctrl_t *power_info = - &e_ctrl->eboard_info->power_info; - struct device_node *of_node = NULL; - struct msm_camera_gpio_conf *gconf = NULL; - int8_t gpio_array_size = 0; - uint16_t *gpio_array = NULL; - - eb_info = e_ctrl->eboard_info; - if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) - of_node = e_ctrl->i2c_client. - spi_client->spi_master->dev.of_node; - else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) - of_node = e_ctrl->pdev->dev.of_node; - - if (!of_node) { - pr_err("%s: %d of_node is NULL\n", __func__ , __LINE__); - return -ENOMEM; - } - rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, - &power_info->num_vreg); - if (rc < 0) - return rc; - - if (e_ctrl->userspace_probe == 0) { - rc = msm_camera_get_dt_power_setting_data(of_node, - power_info->cam_vreg, power_info->num_vreg, - power_info); - if (rc < 0) - goto ERROR1; - } - - power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!power_info->gpio_conf) { - rc = -ENOMEM; - goto ERROR2; - } - gconf = power_info->gpio_conf; - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size > 0) { - gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), - GFP_KERNEL); - if (!gpio_array) { - rc = -ENOMEM; - goto ERROR3; - } - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - kfree(gpio_array); - } - - return rc; -ERROR4: - kfree(gpio_array); -ERROR3: - kfree(power_info->gpio_conf); -ERROR2: - kfree(power_info->cam_vreg); -ERROR1: - kfree(power_info->power_setting); - return rc; -} - - -static int msm_eeprom_cmm_dts(struct msm_eeprom_board_info *eb_info, - struct device_node *of_node) -{ - int rc = 0; - struct msm_eeprom_cmm_t *cmm_data = &eb_info->cmm_data; - - cmm_data->cmm_support = - of_property_read_bool(of_node, "qcom,cmm-data-support"); - if (!cmm_data->cmm_support) - return -EINVAL; - cmm_data->cmm_compression = - of_property_read_bool(of_node, "qcom,cmm-data-compressed"); - if (!cmm_data->cmm_compression) - CDBG("No MM compression data\n"); - - rc = of_property_read_u32(of_node, "qcom,cmm-data-offset", - &cmm_data->cmm_offset); - if (rc < 0) - CDBG("No MM offset data\n"); - - rc = of_property_read_u32(of_node, "qcom,cmm-data-size", - &cmm_data->cmm_size); - if (rc < 0) - CDBG("No MM size data\n"); - - CDBG("cmm_support: cmm_compr %d, cmm_offset %d, cmm_size %d\n", - cmm_data->cmm_compression, - cmm_data->cmm_offset, - cmm_data->cmm_size); - return 0; -} - -static int msm_eeprom_spi_setup(struct spi_device *spi) -{ - struct msm_eeprom_ctrl_t *e_ctrl = NULL; - struct msm_camera_i2c_client *client = NULL; - struct msm_camera_spi_client *spi_client; - struct msm_eeprom_board_info *eb_info; - struct msm_camera_power_ctrl_t *power_info = NULL; - int rc = 0; - - e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); - if (!e_ctrl) - return -ENOMEM; - e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; - e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - client = &e_ctrl->i2c_client; - e_ctrl->is_supported = 0; - e_ctrl->userspace_probe = 0; - e_ctrl->cal_data.mapdata = NULL; - e_ctrl->cal_data.map = NULL; - - spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL); - if (!spi_client) { - kfree(e_ctrl); - return -ENOMEM; - } - - rc = of_property_read_u32(spi->dev.of_node, "cell-index", - &e_ctrl->subdev_id); - CDBG("cell-index %d, rc %d\n", e_ctrl->subdev_id, rc); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - return rc; - } - - eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL); - if (!eb_info) - goto spi_free; - e_ctrl->eboard_info = eb_info; - - rc = of_property_read_string(spi->dev.of_node, "qcom,eeprom-name", - &eb_info->eeprom_name); - CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, - eb_info->eeprom_name, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - e_ctrl->userspace_probe = 1; - goto board_free; - } - - e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE; - client->spi_client = spi_client; - spi_client->spi_master = spi; - client->i2c_func_tbl = &msm_eeprom_spi_func_tbl; - client->addr_type = MSM_CAMERA_I2C_3B_ADDR; - - rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, spi->dev.of_node); - if (rc < 0) - CDBG("%s MM data miss:%d\n", __func__, __LINE__); - - power_info = &eb_info->power_info; - power_info->dev = &spi->dev; - - /* Get clocks information */ - rc = msm_camera_i2c_dev_get_clk_info( - &spi->dev, - &power_info->clk_info, - &power_info->clk_ptr, - &power_info->clk_info_size); - if (rc < 0) { - pr_err("failed: msm_camera_get_clk_info rc %d", rc); - goto board_free; - } - - rc = msm_eeprom_get_dt_data(e_ctrl); - if (rc < 0) - goto board_free; - - /* set spi instruction info */ - spi_client->retry_delay = 1; - spi_client->retries = 0; - - rc = msm_eeprom_spi_parse_of(spi_client); - if (rc < 0) { - dev_err(&spi->dev, - "%s: Error parsing device properties\n", __func__); - goto board_free; - } - - if (e_ctrl->userspace_probe == 0) { - /* prepare memory buffer */ - rc = msm_eeprom_parse_memory_map(spi->dev.of_node, - &e_ctrl->cal_data); - if (rc < 0) - CDBG("%s: no cal memory map\n", __func__); - - /* power up eeprom for reading */ - rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto caldata_free; - } - - /* check eeprom id */ - rc = msm_eeprom_match_id(e_ctrl); - if (rc < 0) { - CDBG("%s: eeprom not matching %d\n", __func__, rc); - goto power_down; - } - /* read eeprom */ - if (e_ctrl->cal_data.map) { - rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); - if (rc < 0) { - pr_err("%s: read cal data failed\n", __func__); - goto power_down; - } - e_ctrl->is_supported |= msm_eeprom_match_crc( - &e_ctrl->cal_data); - } - - rc = msm_camera_power_down(power_info, - e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto caldata_free; - } - } else - e_ctrl->is_supported = 1; - - /* initiazlie subdev */ - v4l2_spi_subdev_init(&e_ctrl->msm_sd.sd, - e_ctrl->i2c_client.spi_client->spi_master, - e_ctrl->eeprom_v4l2_subdev_ops); - v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); - e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; - e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); - e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; - msm_sd_register(&e_ctrl->msm_sd); - e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; - CDBG("%s success result=%d supported=%x X\n", __func__, rc, - e_ctrl->is_supported); - - return 0; - -power_down: - msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); -caldata_free: - msm_camera_i2c_dev_put_clk_info( - &e_ctrl->i2c_client.spi_client->spi_master->dev, - &e_ctrl->eboard_info->power_info.clk_info, - &e_ctrl->eboard_info->power_info.clk_ptr, - e_ctrl->eboard_info->power_info.clk_info_size); - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); -board_free: - kfree(e_ctrl->eboard_info); -spi_free: - kfree(spi_client); - kfree(e_ctrl); - return rc; -} - -static int msm_eeprom_spi_probe(struct spi_device *spi) -{ - int irq, cs, cpha, cpol, cs_high; - - CDBG("%s\n", __func__); - spi->bits_per_word = 8; - spi->mode = SPI_MODE_0; - spi_setup(spi); - - irq = spi->irq; - cs = spi->chip_select; - cpha = (spi->mode & SPI_CPHA) ? 1 : 0; - cpol = (spi->mode & SPI_CPOL) ? 1 : 0; - cs_high = (spi->mode & SPI_CS_HIGH) ? 1 : 0; - CDBG("%s: irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n", - __func__, irq, cs, cpha, cpol, cs_high); - CDBG("%s: max_speed[%u]\n", __func__, spi->max_speed_hz); - - return msm_eeprom_spi_setup(spi); -} - -static int msm_eeprom_spi_remove(struct spi_device *sdev) -{ - struct v4l2_subdev *sd = spi_get_drvdata(sdev); - struct msm_eeprom_ctrl_t *e_ctrl; - - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); - if (!e_ctrl) { - pr_err("%s: eeprom device is NULL\n", __func__); - return 0; - } - - if (!e_ctrl->eboard_info) { - pr_err("%s: eboard_info is NULL\n", __func__); - return 0; - } - msm_camera_i2c_dev_put_clk_info( - &e_ctrl->i2c_client.spi_client->spi_master->dev, - &e_ctrl->eboard_info->power_info.clk_info, - &e_ctrl->eboard_info->power_info.clk_ptr, - e_ctrl->eboard_info->power_info.clk_info_size); - - kfree(e_ctrl->i2c_client.spi_client); - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); - if (e_ctrl->eboard_info) { - kfree(e_ctrl->eboard_info->power_info.gpio_conf); - kfree(e_ctrl->eboard_info); - } - e_ctrl->cal_data.mapdata = NULL; - kfree(e_ctrl); - e_ctrl = NULL; - - return 0; -} - -#ifdef CONFIG_COMPAT -static void msm_eeprom_copy_power_settings_compat( - struct msm_sensor_power_setting_array *ps, - struct msm_sensor_power_setting_array32 *ps32) -{ - uint16_t i = 0; - - ps->size = ps32->size; - for (i = 0; i < ps32->size; i++) { - ps->power_setting_a[i].config_val = - ps32->power_setting_a[i].config_val; - ps->power_setting_a[i].delay = - ps32->power_setting_a[i].delay; - ps->power_setting_a[i].seq_type = - ps32->power_setting_a[i].seq_type; - ps->power_setting_a[i].seq_val = - ps32->power_setting_a[i].seq_val; - } - - ps->size_down = ps32->size_down; - for (i = 0; i < ps32->size_down; i++) { - ps->power_down_setting_a[i].config_val = - ps32->power_down_setting_a[i].config_val; - ps->power_down_setting_a[i].delay = - ps32->power_down_setting_a[i].delay; - ps->power_down_setting_a[i].seq_type = - ps32->power_down_setting_a[i].seq_type; - ps->power_down_setting_a[i].seq_val = - ps32->power_down_setting_a[i].seq_val; - } -} - -static int eeprom_config_read_cal_data32(struct msm_eeprom_ctrl_t *e_ctrl, - void __user *arg) -{ - int rc; - uint8_t *ptr_dest = NULL; - struct msm_eeprom_cfg_data32 *cdata32 = - (struct msm_eeprom_cfg_data32 *) arg; - struct msm_eeprom_cfg_data cdata; - - cdata.cfgtype = cdata32->cfgtype; - cdata.is_supported = cdata32->is_supported; - cdata.cfg.read_data.num_bytes = cdata32->cfg.read_data.num_bytes; - /* check range */ - if (cdata.cfg.read_data.num_bytes > - e_ctrl->cal_data.num_data) { - CDBG("%s: Invalid size. exp %u, req %u\n", __func__, - e_ctrl->cal_data.num_data, - cdata.cfg.read_data.num_bytes); - return -EINVAL; - } - if (!e_ctrl->cal_data.mapdata) - return -EFAULT; - - ptr_dest = (uint8_t *) compat_ptr(cdata32->cfg.read_data.dbuffer); - - rc = copy_to_user(ptr_dest, e_ctrl->cal_data.mapdata, - cdata.cfg.read_data.num_bytes); - - return rc; -} - -static int eeprom_init_config32(struct msm_eeprom_ctrl_t *e_ctrl, - void __user *argp) -{ - int rc = 0; - struct msm_eeprom_cfg_data32 *cdata32 = argp; - struct msm_sensor_power_setting_array *power_setting_array = NULL; - struct msm_sensor_power_setting_array32 *power_setting_array32 = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - struct msm_eeprom_memory_map_array *mem_map_array = NULL; - - power_setting_array32 = - kzalloc(sizeof(struct msm_sensor_power_setting_array32), - GFP_KERNEL); - if (!power_setting_array32) { - pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - power_setting_array = - kzalloc(sizeof(struct msm_sensor_power_setting_array), - GFP_KERNEL); - if (power_setting_array == NULL) { - pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__); - rc = -ENOMEM; - goto free_mem; - } - mem_map_array = - kzalloc(sizeof(struct msm_eeprom_memory_map_array), - GFP_KERNEL); - if (mem_map_array == NULL) { - pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__); - rc = -ENOMEM; - goto free_mem; - } - - if (copy_from_user(power_setting_array32, - (void *)compat_ptr(cdata32->cfg.eeprom_info. - power_setting_array), - sizeof(struct msm_sensor_power_setting_array32))) { - pr_err("%s:%d copy_from_user failed\n", - __func__, __LINE__); - goto free_mem; - } - CDBG("%s:%d Size of power setting array: %d", - __func__, __LINE__, power_setting_array32->size); - if (copy_from_user(mem_map_array, - (void *)compat_ptr(cdata32->cfg.eeprom_info.mem_map_array), - sizeof(struct msm_eeprom_memory_map_array))) { - pr_err("%s:%d copy_from_user failed for memory map\n", - __func__, __LINE__); - goto free_mem; - } - - power_info = &(e_ctrl->eboard_info->power_info); - - if ((power_setting_array32->size > MAX_POWER_CONFIG) || - (power_setting_array32->size_down > MAX_POWER_CONFIG) || - (!power_setting_array32->size) || - (!power_setting_array32->size_down)) { - pr_err("%s:%d invalid power setting size=%d size_down=%d\n", - __func__, __LINE__, power_setting_array32->size, - power_setting_array32->size_down); - rc = -EINVAL; - goto free_mem; - } - msm_eeprom_copy_power_settings_compat( - power_setting_array, - power_setting_array32); - - power_info->power_setting = - power_setting_array->power_setting_a; - power_info->power_down_setting = - power_setting_array->power_down_setting_a; - - power_info->power_setting_size = - power_setting_array->size; - power_info->power_down_setting_size = - power_setting_array->size_down; - - if (e_ctrl->i2c_client.cci_client) { - e_ctrl->i2c_client.cci_client->i2c_freq_mode = - cdata32->cfg.eeprom_info.i2c_freq_mode; - if (e_ctrl->i2c_client.cci_client->i2c_freq_mode > - I2C_MAX_MODES) { - pr_err("%s::%d Improper I2C Freq Mode\n", - __func__, __LINE__); - e_ctrl->i2c_client.cci_client->i2c_freq_mode = - I2C_STANDARD_MODE; - } - CDBG("%s:%d Not CCI probe", __func__, __LINE__); - } - /* Fill vreg power info and power up here */ - rc = msm_eeprom_power_up(e_ctrl, power_info); - if (rc < 0) { - pr_err("%s:%d Power Up failed for eeprom\n", - __func__, __LINE__); - goto free_mem; - } - - rc = eeprom_parse_memory_map(e_ctrl, mem_map_array); - if (rc < 0) { - pr_err("%s:%d memory map parse failed\n", - __func__, __LINE__); - goto free_mem; - } - - rc = msm_camera_power_down(power_info, - e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); - if (rc < 0) - pr_err("%s:%d Power down failed rc %d\n", - __func__, __LINE__, rc); - -free_mem: - kfree(power_setting_array32); - kfree(power_setting_array); - kfree(mem_map_array); - power_setting_array32 = NULL; - power_setting_array = NULL; - mem_map_array = NULL; - return rc; -} - -static int msm_eeprom_config32(struct msm_eeprom_ctrl_t *e_ctrl, - void __user *argp) -{ - struct msm_eeprom_cfg_data32 *cdata = - (struct msm_eeprom_cfg_data32 *)argp; - int rc = 0; - size_t length = 0; - - CDBG("%s E\n", __func__); - switch (cdata->cfgtype) { - case CFG_EEPROM_GET_INFO: - if (e_ctrl->userspace_probe == 1) { - pr_err("%s:%d Eeprom name should be module driver", - __func__, __LINE__); - rc = -EINVAL; - break; - } - CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); - cdata->is_supported = e_ctrl->is_supported; - length = strlen(e_ctrl->eboard_info->eeprom_name) + 1; - if (length > MAX_EEPROM_NAME) { - pr_err("%s:%d invalid eeprom_name length %d\n", - __func__, __LINE__, (int)length); - rc = -EINVAL; - break; - } - memcpy(cdata->cfg.eeprom_name, - e_ctrl->eboard_info->eeprom_name, length); - break; - case CFG_EEPROM_GET_CAL_DATA: - CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); - cdata->cfg.get_data.num_bytes = - e_ctrl->cal_data.num_data; - break; - case CFG_EEPROM_READ_CAL_DATA: - CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__); - rc = eeprom_config_read_cal_data32(e_ctrl, argp); - break; - case CFG_EEPROM_INIT: - if (e_ctrl->userspace_probe == 0) { - pr_err("%s:%d Eeprom already probed at kernel boot", - __func__, __LINE__); - rc = -EINVAL; - break; - } - if (e_ctrl->cal_data.num_data == 0) { - rc = eeprom_init_config32(e_ctrl, argp); - if (rc < 0) - pr_err("%s:%d Eeprom init failed\n", - __func__, __LINE__); - } else { - CDBG("%s:%d Already read eeprom\n", - __func__, __LINE__); - } - break; - default: - break; - } - - CDBG("%s X rc: %d\n", __func__, rc); - return rc; -} - -static long msm_eeprom_subdev_ioctl32(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - void __user *argp = (void __user *)arg; - - CDBG("%s E\n", __func__); - CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, e_ctrl, argp); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return msm_eeprom_get_subdev_id(e_ctrl, argp); - case VIDIOC_MSM_EEPROM_CFG32: - return msm_eeprom_config32(e_ctrl, argp); - default: - return -ENOIOCTLCMD; - } - - CDBG("%s X\n", __func__); -} - -static long msm_eeprom_subdev_do_ioctl32( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - - return msm_eeprom_subdev_ioctl32(sd, cmd, arg); -} - -static long msm_eeprom_subdev_fops_ioctl32(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_eeprom_subdev_do_ioctl32); -} - -#endif - -static int msm_eeprom_platform_probe(struct platform_device *pdev) -{ - int rc = 0; - int j = 0; - uint32_t temp; - - struct msm_camera_cci_client *cci_client = NULL; - struct msm_eeprom_ctrl_t *e_ctrl = NULL; - struct msm_eeprom_board_info *eb_info = NULL; - struct device_node *of_node = pdev->dev.of_node; - struct msm_camera_power_ctrl_t *power_info = NULL; - - CDBG("%s E\n", __func__); - - e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); - if (!e_ctrl) - return -ENOMEM; - e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; - e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - - e_ctrl->cal_data.mapdata = NULL; - e_ctrl->cal_data.map = NULL; - e_ctrl->userspace_probe = 0; - e_ctrl->is_supported = 0; - if (!of_node) { - pr_err("%s dev.of_node NULL\n", __func__); - rc = -EINVAL; - goto ectrl_free; - } - - /* Set platform device handle */ - e_ctrl->pdev = pdev; - /* Set device type as platform device */ - e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE; - e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_cci_func_tbl; - e_ctrl->i2c_client.cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!e_ctrl->i2c_client.cci_client) { - rc = -ENOMEM; - goto ectrl_free; - } - - e_ctrl->eboard_info = kzalloc(sizeof( - struct msm_eeprom_board_info), GFP_KERNEL); - if (!e_ctrl->eboard_info) { - rc = -ENOMEM; - goto cciclient_free; - } - - eb_info = e_ctrl->eboard_info; - power_info = &eb_info->power_info; - cci_client = e_ctrl->i2c_client.cci_client; - cci_client->cci_subdev = msm_cci_get_subdev(); - cci_client->retries = 3; - cci_client->id_map = 0; - power_info->dev = &pdev->dev; - - /* Get clocks information */ - rc = msm_camera_get_clk_info(e_ctrl->pdev, - &power_info->clk_info, - &power_info->clk_ptr, - &power_info->clk_info_size); - if (rc < 0) { - pr_err("failed: msm_camera_get_clk_info rc %d", rc); - goto board_free; - } - - rc = of_property_read_u32(of_node, "cell-index", - &pdev->id); - CDBG("cell-index %d, rc %d\n", pdev->id, rc); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto board_free; - } - e_ctrl->subdev_id = pdev->id; - - rc = of_property_read_u32(of_node, "qcom,cci-master", - &e_ctrl->cci_master); - CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc); - if (rc < 0) { - pr_err("%s failed rc %d\n", __func__, rc); - goto board_free; - } - cci_client->cci_i2c_master = e_ctrl->cci_master; - - rc = of_property_read_string(of_node, "qcom,eeprom-name", - &eb_info->eeprom_name); - CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, - eb_info->eeprom_name, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - e_ctrl->userspace_probe = 1; - } - - rc = msm_eeprom_get_dt_data(e_ctrl); - if (rc < 0) - goto board_free; - - if (e_ctrl->userspace_probe == 0) { - rc = of_property_read_u32(of_node, "qcom,slave-addr", - &temp); - if (rc < 0) { - pr_err("%s failed rc %d\n", __func__, rc); - goto board_free; - } - - rc = of_property_read_u32(of_node, "qcom,i2c-freq-mode", - &e_ctrl->i2c_freq_mode); - CDBG("qcom,i2c_freq_mode %d, rc %d\n", - e_ctrl->i2c_freq_mode, rc); - if (rc < 0) { - pr_err("%s qcom,i2c-freq-mode read fail. Setting to 0 %d\n", - __func__, rc); - e_ctrl->i2c_freq_mode = 0; - } - if (e_ctrl->i2c_freq_mode >= I2C_MAX_MODES) { - pr_err("%s:%d invalid i2c_freq_mode = %d\n", - __func__, __LINE__, e_ctrl->i2c_freq_mode); - e_ctrl->i2c_freq_mode = 0; - } - eb_info->i2c_slaveaddr = temp; - CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr); - eb_info->i2c_freq_mode = e_ctrl->i2c_freq_mode; - cci_client->i2c_freq_mode = e_ctrl->i2c_freq_mode; - cci_client->sid = eb_info->i2c_slaveaddr >> 1; - - rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data); - if (rc < 0) - goto board_free; - - rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc) { - pr_err("failed rc %d\n", rc); - goto memdata_free; - } - rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); - if (rc < 0) { - pr_err("%s read_eeprom_memory failed\n", __func__); - goto power_down; - } - for (j = 0; j < e_ctrl->cal_data.num_data; j++) - CDBG("memory_data[%d] = 0x%X\n", j, - e_ctrl->cal_data.mapdata[j]); - - e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); - - rc = msm_camera_power_down(power_info, - e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); - if (rc) { - pr_err("failed rc %d\n", rc); - goto memdata_free; - } - } else - e_ctrl->is_supported = 1; - - v4l2_subdev_init(&e_ctrl->msm_sd.sd, - e_ctrl->eeprom_v4l2_subdev_ops); - v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); - platform_set_drvdata(pdev, &e_ctrl->msm_sd.sd); - e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; - e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(e_ctrl->msm_sd.sd.name, - ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom"); - media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); - e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; - msm_sd_register(&e_ctrl->msm_sd); - -#ifdef CONFIG_COMPAT - msm_cam_copy_v4l2_subdev_fops(&msm_eeprom_v4l2_subdev_fops); - msm_eeprom_v4l2_subdev_fops.compat_ioctl32 = - msm_eeprom_subdev_fops_ioctl32; - e_ctrl->msm_sd.sd.devnode->fops = &msm_eeprom_v4l2_subdev_fops; -#endif - - e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; - CDBG("%s X\n", __func__); - return rc; - -power_down: - msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); -memdata_free: - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); -board_free: - kfree(e_ctrl->eboard_info); -cciclient_free: - kfree(e_ctrl->i2c_client.cci_client); -ectrl_free: - kfree(e_ctrl); - return rc; -} - -static int msm_eeprom_platform_remove(struct platform_device *pdev) -{ - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct msm_eeprom_ctrl_t *e_ctrl; - - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); - if (!e_ctrl) { - pr_err("%s: eeprom device is NULL\n", __func__); - return 0; - } - - if (!e_ctrl->eboard_info) { - pr_err("%s: eboard_info is NULL\n", __func__); - return 0; - } - msm_camera_put_clk_info(e_ctrl->pdev, - &e_ctrl->eboard_info->power_info.clk_info, - &e_ctrl->eboard_info->power_info.clk_ptr, - e_ctrl->eboard_info->power_info.clk_info_size); - - kfree(e_ctrl->i2c_client.cci_client); - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); - if (e_ctrl->eboard_info) { - kfree(e_ctrl->eboard_info->power_info.gpio_conf); - kfree(e_ctrl->eboard_info); - } - kfree(e_ctrl); - return 0; -} - -static const struct of_device_id msm_eeprom_dt_match[] = { - { .compatible = "qcom,eeprom" }, - { } -}; - -MODULE_DEVICE_TABLE(of, msm_eeprom_dt_match); - -static struct platform_driver msm_eeprom_platform_driver = { - .driver = { - .name = "qcom,eeprom", - .owner = THIS_MODULE, - .of_match_table = msm_eeprom_dt_match, - }, - .probe = msm_eeprom_platform_probe, - .remove = msm_eeprom_platform_remove, -}; - -static const struct i2c_device_id msm_eeprom_i2c_id[] = { - { "msm_eeprom", (kernel_ulong_t)NULL}, - { } -}; - -static struct i2c_driver msm_eeprom_i2c_driver = { - .id_table = msm_eeprom_i2c_id, - .probe = msm_eeprom_i2c_probe, - .remove = msm_eeprom_i2c_remove, - .driver = { - .name = "msm_eeprom", - }, -}; - -static struct spi_driver msm_eeprom_spi_driver = { - .driver = { - .name = "qcom_eeprom", - .owner = THIS_MODULE, - .of_match_table = msm_eeprom_dt_match, - }, - .probe = msm_eeprom_spi_probe, - .remove = msm_eeprom_spi_remove, -}; - -static int __init msm_eeprom_init_module(void) -{ - int rc = 0; - - CDBG("%s E\n", __func__); - rc = platform_driver_register(&msm_eeprom_platform_driver); - CDBG("%s:%d platform rc %d\n", __func__, __LINE__, rc); - rc = spi_register_driver(&msm_eeprom_spi_driver); - CDBG("%s:%d spi rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&msm_eeprom_i2c_driver); -} - -static void __exit msm_eeprom_exit_module(void) -{ - platform_driver_unregister(&msm_eeprom_platform_driver); - spi_unregister_driver(&msm_eeprom_spi_driver); - i2c_del_driver(&msm_eeprom_i2c_driver); -} - -module_init(msm_eeprom_init_module); -module_exit(msm_eeprom_exit_module); -MODULE_DESCRIPTION("MSM EEPROM driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/eeprom/msm_eeprom.h b/drivers/media/platform/msm/ais/sensor/eeprom/msm_eeprom.h deleted file mode 100644 index 302a663cde9370148a2141110d292f4762fd596c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/eeprom/msm_eeprom.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_EEPROM_H -#define MSM_EEPROM_H - -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_camera_spi.h" -#include "msm_camera_io_util.h" -#include "msm_camera_dt_util.h" - -struct msm_eeprom_ctrl_t; - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -#define PROPERTY_MAXSIZE 32 - -struct msm_eeprom_ctrl_t { - struct platform_device *pdev; - struct mutex *eeprom_mutex; - - struct v4l2_subdev sdev; - struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops; - enum msm_camera_device_type_t eeprom_device_type; - struct msm_sd_subdev msm_sd; - enum cci_i2c_master_t cci_master; - enum i2c_freq_mode_t i2c_freq_mode; - - struct msm_camera_i2c_client i2c_client; - struct msm_eeprom_board_info *eboard_info; - uint32_t subdev_id; - int32_t userspace_probe; - struct msm_eeprom_memory_block_t cal_data; - uint8_t is_supported; -}; - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/flash/Makefile b/drivers/media/platform/msm/ais/sensor/flash/Makefile deleted file mode 100644 index fd6f381e6bdc09a4f167dac793b7b333cf153a38..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/flash/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_flash.o diff --git a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.h b/drivers/media/platform/msm/ais/sensor/flash/msm_flash.h deleted file mode 100644 index 6571b34f55fff0e427e2903ac62f408de5a776c9..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. - * - * 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. - * - */ - -#ifndef MSM_FLASH_H -#define MSM_FLASH_H - -#include -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_sd.h" - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -enum msm_camera_flash_state_t { - MSM_CAMERA_FLASH_INIT, - MSM_CAMERA_FLASH_OFF, - MSM_CAMERA_FLASH_LOW, - MSM_CAMERA_FLASH_HIGH, - MSM_CAMERA_FLASH_RELEASE, -}; - -struct msm_flash_ctrl_t; - -struct msm_flash_func_t { - int32_t (*camera_flash_init)(struct msm_flash_ctrl_t *, - struct msm_flash_cfg_data_t *); - int32_t (*camera_flash_release)(struct msm_flash_ctrl_t *); - int32_t (*camera_flash_off)(struct msm_flash_ctrl_t *, - struct msm_flash_cfg_data_t *); - int32_t (*camera_flash_low)(struct msm_flash_ctrl_t *, - struct msm_flash_cfg_data_t *); - int32_t (*camera_flash_high)(struct msm_flash_ctrl_t *, - struct msm_flash_cfg_data_t *); -}; - -struct msm_flash_table { - enum msm_flash_driver_type flash_driver_type; - struct msm_flash_func_t func_tbl; -}; - -struct msm_flash_reg_t { - struct msm_camera_i2c_reg_setting *init_setting; - struct msm_camera_i2c_reg_setting *off_setting; - struct msm_camera_i2c_reg_setting *release_setting; - struct msm_camera_i2c_reg_setting *low_setting; - struct msm_camera_i2c_reg_setting *high_setting; -}; - -struct msm_flash_ctrl_t { - struct msm_camera_i2c_client flash_i2c_client; - struct msm_sd_subdev msm_sd; - struct platform_device *pdev; - struct msm_flash_func_t *func_tbl; - struct msm_camera_power_ctrl_t power_info; - - /* Switch node to trigger led */ - const char *switch_trigger_name; - struct led_trigger *switch_trigger; - - /* Flash */ - uint32_t flash_num_sources; - const char *flash_trigger_name[MAX_LED_TRIGGERS]; - struct led_trigger *flash_trigger[MAX_LED_TRIGGERS]; - uint32_t flash_op_current[MAX_LED_TRIGGERS]; - uint32_t flash_max_current[MAX_LED_TRIGGERS]; - uint32_t flash_max_duration[MAX_LED_TRIGGERS]; - - /* Torch */ - uint32_t torch_num_sources; - const char *torch_trigger_name[MAX_LED_TRIGGERS]; - struct led_trigger *torch_trigger[MAX_LED_TRIGGERS]; - uint32_t torch_op_current[MAX_LED_TRIGGERS]; - uint32_t torch_max_current[MAX_LED_TRIGGERS]; - - void *data; - enum msm_camera_device_type_t flash_device_type; - enum cci_i2c_master_t cci_i2c_master; - uint32_t subdev_id; - struct mutex *flash_mutex; - struct msm_sensor_power_setting_array power_setting_array; - - /* flash driver type */ - enum msm_flash_driver_type flash_driver_type; - - /* flash state */ - enum msm_camera_flash_state_t flash_state; -}; - -int msm_flash_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id); - -int msm_flash_probe(struct platform_device *pdev, const void *data); - -int32_t msm_flash_create_v4lsubdev(struct platform_device *pdev, - void *data); -int32_t msm_led_i2c_flash_create_v4lsubdev(void *data); - -int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_flash_ctrl_t *fctrl, - void *arg); - -int32_t msm_led_i2c_trigger_config(struct msm_flash_ctrl_t *fctrl, - void *data); - -int msm_flash_led_init(struct msm_flash_ctrl_t *fctrl); -int msm_flash_led_release(struct msm_flash_ctrl_t *fctrl); -int msm_flash_led_off(struct msm_flash_ctrl_t *fctrl); -int msm_flash_led_low(struct msm_flash_ctrl_t *fctrl); -int msm_flash_led_high(struct msm_flash_ctrl_t *fctrl); -#endif diff --git a/drivers/media/platform/msm/ais/sensor/io/Makefile b/drivers/media/platform/msm/ais/sensor/io/Makefile deleted file mode 100644 index 86e3f9ad48f915b40fbfd493ab5eb10761b53765..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais/ -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci -ccflags-y += -Idrivers/misc/ -obj-$(CONFIG_MSM_AIS) += msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_spi.o msm_camera_dt_util.o msm_camera_tz_i2c.o diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_cci_i2c.c deleted file mode 100644 index da2ab2d334bb19776f35295fa089648369629f6c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_cci_i2c.c +++ /dev/null @@ -1,580 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include "msm_camera_i2c.h" -#include "msm_cci.h" - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) -#define MAX_I2C_ADDR_TYPE_SIZE (MSM_CAMERA_I2C_3B_ADDR + 1) -#define MAX_I2C_DATA_TYPE_SIZE (MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA + 1) - -int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - unsigned char buf[MAX_I2C_ADDR_TYPE_SIZE + MAX_I2C_DATA_TYPE_SIZE]; - struct msm_camera_cci_ctrl cci_ctrl; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR - && client->addr_type != MSM_CAMERA_I2C_3B_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - cci_ctrl.cmd = MSM_CCI_I2C_READ; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; - cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; - cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) - *data = buf[0]; - else - *data = buf[0] << 8 | buf[1]; - - S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); - return rc; -} - -int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - unsigned char *buf = NULL; - int i; - struct msm_camera_cci_ctrl cci_ctrl; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR - && client->addr_type != MSM_CAMERA_I2C_3B_ADDR) - || num_byte == 0) - return rc; - - if (num_byte > I2C_REG_DATA_MAX) { - S_I2C_DBG("%s: Error num_byte:0x%x exceeds 8K\n", - __func__, num_byte); - S_I2C_DBG("%s: max supported:0x%x\n", - __func__, I2C_REG_DATA_MAX); - return rc; - } - - buf = kzalloc(num_byte, GFP_KERNEL); - if (!buf) - return -ENOMEM; - cci_ctrl.cmd = MSM_CCI_I2C_READ; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; - cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; - cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; - cci_ctrl.status = -EFAULT; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); - rc = cci_ctrl.status; - - S_I2C_DBG("%s addr = 0x%x", __func__, addr); - for (i = 0; i < num_byte; i++) { - data[i] = buf[i]; - S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); - S_I2C_DBG("Data: 0x%x\n", data[i]); - } - kfree(buf); - return rc; -} - -int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - struct msm_camera_cci_ctrl cci_ctrl; - struct msm_camera_i2c_reg_array reg_conf_tbl; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - CDBG("%s:%d reg addr = 0x%x data type: %d\n", - __func__, __LINE__, addr, data_type); - reg_conf_tbl.reg_addr = addr; - reg_conf_tbl.reg_data = data; - reg_conf_tbl.delay = 0; - cci_ctrl.cmd = MSM_CCI_I2C_WRITE; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = ®_conf_tbl; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = 1; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - return rc; -} - -int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - uint32_t i = 0; - struct msm_camera_cci_ctrl cci_ctrl; - struct msm_camera_i2c_reg_array *reg_conf_tbl = NULL; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || num_byte == 0) - return rc; - - if (num_byte > I2C_SEQ_REG_DATA_MAX) { - pr_err("%s: num_byte=%d clamped to max supported %d\n", - __func__, num_byte, I2C_SEQ_REG_DATA_MAX); - return rc; - } - - S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", - __func__, addr, num_byte); - - reg_conf_tbl = kzalloc(num_byte * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_conf_tbl) - return -ENOMEM; - - reg_conf_tbl[0].reg_addr = addr; - for (i = 0; i < num_byte; i++) { - reg_conf_tbl[i].reg_data = data[i]; - reg_conf_tbl[i].delay = 0; - } - cci_ctrl.cmd = MSM_CCI_I2C_WRITE_SEQ; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte; - cci_ctrl.status = -EFAULT; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); - rc = cci_ctrl.status; - kfree(reg_conf_tbl); - reg_conf_tbl = NULL; - return rc; -} - -static int32_t msm_camera_cci_i2c_write_table_cmd( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting, - enum msm_cci_cmd_type cmd) -{ - int32_t rc = -EFAULT; - struct msm_camera_cci_ctrl cci_ctrl; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - cci_ctrl.cmd = cmd; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = - write_setting->reg_setting; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - return rc; -} - -int32_t msm_camera_cci_i2c_write_table_async( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - return msm_camera_cci_i2c_write_table_cmd(client, write_setting, - MSM_CCI_I2C_WRITE_ASYNC); -} - -int32_t msm_camera_cci_i2c_write_table_sync( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - return msm_camera_cci_i2c_write_table_cmd(client, write_setting, - MSM_CCI_I2C_WRITE_SYNC); -} - -int32_t msm_camera_cci_i2c_write_table_sync_block( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - return msm_camera_cci_i2c_write_table_cmd(client, write_setting, - MSM_CCI_I2C_WRITE_SYNC_BLOCK); -} - -int32_t msm_camera_cci_i2c_write_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - return msm_camera_cci_i2c_write_table_cmd(client, write_setting, - MSM_CCI_I2C_WRITE); -} - -int32_t msm_camera_cci_i2c_write_seq_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_seq_reg_array *reg_setting; - uint16_t client_addr_type; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { - pr_err("%s Invalid addr type %d\n", __func__, - write_setting->addr_type); - return rc; - } - - reg_setting = write_setting->reg_setting; - client_addr_type = client->addr_type; - client->addr_type = write_setting->addr_type; - - if (reg_setting->reg_data_size > I2C_SEQ_REG_DATA_MAX) { - pr_err("%s: number of bytes %u exceeding the max supported %d\n", - __func__, reg_setting->reg_data_size, I2C_SEQ_REG_DATA_MAX); - return rc; - } - - for (i = 0; i < write_setting->size; i++) { - rc = msm_camera_cci_i2c_write_seq(client, reg_setting->reg_addr, - reg_setting->reg_data, reg_setting->reg_data_size); - if (rc < 0) - return rc; - reg_setting++; - } - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - client->addr_type = client_addr_type; - return rc; -} - -int32_t msm_camera_cci_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - struct msm_camera_cci_ctrl cci_ctrl; - - if (!client || !write_setting) - return rc; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - cci_ctrl.cmd = MSM_CCI_I2C_WRITE; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = - write_setting->reg_setting; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - return rc; -} - -static int32_t msm_camera_cci_i2c_compare(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data = 0; - int data_len = 0; - - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - data_len = data_type; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - data_len = MSM_CAMERA_I2C_BYTE_DATA; - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - data_len = MSM_CAMERA_I2C_WORD_DATA; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_len); - if (rc < 0) - return rc; - - rc = I2C_COMPARE_MISMATCH; - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - if (data == reg_data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_SET_WORD_MASK: - if ((reg_data & data) == data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - if (!(reg_data & data)) - rc = I2C_COMPARE_MATCH; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - S_I2C_DBG("%s: Register and data match result %d\n", __func__, - rc); - return rc; -} - -int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type, uint32_t delay_ms) -{ - int32_t rc = -EFAULT; - int32_t i = 0; - - S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", - __func__, addr, data, data_type); - - if (delay_ms > MAX_POLL_DELAY_MS) { - pr_err("%s:%d invalid delay = %d max_delay = %d\n", - __func__, __LINE__, delay_ms, MAX_POLL_DELAY_MS); - return -EINVAL; - } - for (i = 0; i < delay_ms; i++) { - rc = msm_camera_cci_i2c_compare(client, - addr, data, data_type); - if (!rc) - return rc; - usleep_range(1000, 1010); - } - - /* If rc is 1 then read is successful but poll is failure */ - if (rc == 1) - pr_err("%s:%d poll failed rc=%d(non-fatal)\n", - __func__, __LINE__, rc); - - if (rc < 0) - pr_err("%s:%d poll failed rc=%d\n", __func__, __LINE__, rc); - - return rc; -} - -static int32_t msm_camera_cci_i2c_set_mask(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t mask, - enum msm_camera_i2c_data_type data_type, uint16_t set_mask) -{ - int32_t rc = -EFAULT; - uint16_t reg_data; - - rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_type); - if (rc < 0) { - S_I2C_DBG("%s read fail\n", __func__); - return rc; - } - S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", - __func__, addr, reg_data, mask); - - if (set_mask) - reg_data |= mask; - else - reg_data &= ~mask; - S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); - - rc = msm_camera_cci_i2c_write(client, addr, reg_data, data_type); - if (rc < 0) - S_I2C_DBG("%s write fail\n", __func__); - - return rc; -} - -static int32_t msm_camera_cci_i2c_set_write_mask_data( - struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, int16_t mask, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data; - - CDBG("%s\n", __func__); - if (mask == -1) - return 0; - if (mask == 0) { - rc = msm_camera_cci_i2c_write(client, addr, data, data_type); - } else { - rc = msm_camera_cci_i2c_read(client, addr, ®_data, - data_type); - if (rc < 0) { - CDBG("%s read fail\n", __func__); - return rc; - } - reg_data &= ~mask; - reg_data |= (data & mask); - rc = msm_camera_cci_i2c_write(client, addr, reg_data, - data_type); - if (rc < 0) - CDBG("%s write fail\n", __func__); - } - return rc; -} - -int32_t msm_camera_cci_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type) -{ - int i; - int32_t rc = -EFAULT; - - for (i = 0; i < size; i++) { - enum msm_camera_i2c_data_type dt; - - if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { - rc = msm_camera_cci_i2c_poll(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->dt, I2C_POLL_TIME_MS); - } else { - if (reg_conf_tbl->dt == 0) - dt = data_type; - else - dt = reg_conf_tbl->dt; - switch (dt) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - rc = msm_camera_cci_i2c_write( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, dt); - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: - rc = msm_camera_cci_i2c_set_write_mask_data( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->mask, - MSM_CAMERA_I2C_BYTE_DATA); - break; - default: - pr_err("%s: Unsupport data type: %d\n", - __func__, dt); - break; - } - } - if (rc < 0) - break; - reg_conf_tbl++; - } - return rc; -} - -int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, - uint16_t cci_cmd) -{ - int32_t rc = 0; - struct msm_camera_cci_ctrl cci_ctrl; - - CDBG("%s line %d\n", __func__, __LINE__); - cci_ctrl.cmd = cci_cmd; - cci_ctrl.cci_info = client->cci_client; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - return cci_ctrl.status; -} diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c deleted file mode 100644 index 071600ed522139995ea8c686525d0cfa8efbb8cf..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c +++ /dev/null @@ -1,1734 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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 "msm_camera_dt_util.h" -#include "msm_camera_io_util.h" -#include "msm_camera_i2c_mux.h" -#include "msm_cci.h" - -#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" -#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default" -/* #define CONFIG_MSM_CAMERA_DT_DEBUG */ - -#define VALIDATE_VOLTAGE(min, max, config_val) ((config_val) && \ - (config_val >= min) && (config_val <= max)) - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, - int num_vreg, struct msm_sensor_power_setting *power_setting, - uint16_t power_setting_size) -{ - uint16_t i = 0; - int j = 0; - - /* Validate input parameters */ - if (!cam_vreg || !power_setting) { - pr_err("%s:%d failed: cam_vreg %pK power_setting %pK", __func__, - __LINE__, cam_vreg, power_setting); - return -EINVAL; - } - - /* Validate size of num_vreg */ - if (num_vreg <= 0) { - pr_err("failed: num_vreg %d", num_vreg); - return -EINVAL; - } - - for (i = 0; i < power_setting_size; i++) { - if (power_setting[i].seq_type != SENSOR_VREG) - continue; - - switch (power_setting[i].seq_val) { - case CAM_VDIG: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vdig")) { - CDBG("%s:%d i %d j %d cam_vdig\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - if (VALIDATE_VOLTAGE( - cam_vreg[j].min_voltage, - cam_vreg[j].max_voltage, - power_setting[i].config_val)) { - cam_vreg[j].min_voltage = - cam_vreg[j].max_voltage = - power_setting[i].config_val; - } - break; - } - } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; - break; - - case CAM_VIO: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vio")) { - CDBG("%s:%d i %d j %d cam_vio\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - if (VALIDATE_VOLTAGE( - cam_vreg[j].min_voltage, - cam_vreg[j].max_voltage, - power_setting[i].config_val)) { - cam_vreg[j].min_voltage = - cam_vreg[j].max_voltage = - power_setting[i].config_val; - } - break; - } - } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; - break; - - case CAM_VANA: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vana")) { - CDBG("%s:%d i %d j %d cam_vana\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - if (VALIDATE_VOLTAGE( - cam_vreg[j].min_voltage, - cam_vreg[j].max_voltage, - power_setting[i].config_val)) { - cam_vreg[j].min_voltage = - cam_vreg[j].max_voltage = - power_setting[i].config_val; - } - break; - } - } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; - break; - - case CAM_VAF: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vaf")) { - CDBG("%s:%d i %d j %d cam_vaf\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - if (VALIDATE_VOLTAGE( - cam_vreg[j].min_voltage, - cam_vreg[j].max_voltage, - power_setting[i].config_val)) { - cam_vreg[j].min_voltage = - cam_vreg[j].max_voltage = - power_setting[i].config_val; - } - break; - } - } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; - break; - - case CAM_V_CUSTOM1: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, - "cam_v_custom1")) { - CDBG("%s:%d i %d j %d cam_vcustom1\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - if (VALIDATE_VOLTAGE( - cam_vreg[j].min_voltage, - cam_vreg[j].max_voltage, - power_setting[i].config_val)) { - cam_vreg[j].min_voltage = - cam_vreg[j].max_voltage = - power_setting[i].config_val; - } - break; - } - } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; - break; - case CAM_V_CUSTOM2: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, - "cam_v_custom2")) { - CDBG("%s:%d i %d j %d cam_vcustom2\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - if (VALIDATE_VOLTAGE( - cam_vreg[j].min_voltage, - cam_vreg[j].max_voltage, - power_setting[i].config_val)) { - cam_vreg[j].min_voltage = - cam_vreg[j].max_voltage = - power_setting[i].config_val; - } - break; - } - } - if (j == num_vreg) - power_setting[i].seq_val = INVALID_VREG; - break; - - default: - pr_err("%s:%d invalid seq_val %d\n", __func__, - __LINE__, power_setting[i].seq_val); - break; - } - } - return 0; -} - -int msm_sensor_get_sub_module_index(struct device_node *of_node, - struct msm_sensor_info_t **s_info) -{ - int rc = 0, i = 0; - uint32_t val = 0, count = 0; - uint32_t *val_array = NULL; - struct device_node *src_node = NULL; - struct msm_sensor_info_t *sensor_info; - - sensor_info = kzalloc(sizeof(*sensor_info), GFP_KERNEL); - if (!sensor_info) - return -ENOMEM; - for (i = 0; i < SUB_MODULE_MAX; i++) { - sensor_info->subdev_id[i] = -1; - /* Subdev expose additional interface for same sub module*/ - sensor_info->subdev_intf[i] = -1; - } - - src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - if (of_device_is_available(src_node)) - sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val; - else - CDBG("%s:%d actuator disabled!\n", __func__, __LINE__); - of_node_put(src_node); - src_node = NULL; - } - - src_node = of_parse_phandle(of_node, "qcom,ois-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,ois cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_OIS] = val; - of_node_put(src_node); - src_node = NULL; - } - - src_node = of_parse_phandle(of_node, "qcom,eeprom-src", 0); - if (!src_node) { - CDBG("%s:%d eeprom src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; - of_node_put(src_node); - src_node = NULL; - } - - rc = of_property_read_u32(of_node, "qcom,eeprom-sd-index", &val); - if (rc != -EINVAL) { - CDBG("%s qcom,eeprom-sd-index %d, rc %d\n", __func__, val, rc); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; - } else { - rc = 0; - } - - src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s:%d failed %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val; - of_node_put(src_node); - src_node = NULL; - } - - src_node = of_parse_phandle(of_node, "qcom,ir-led-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,ir led cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s:%d failed %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_IR_LED] = val; - of_node_put(src_node); - src_node = NULL; - } - - src_node = of_parse_phandle(of_node, "qcom,ir-cut-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,ir cut cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s:%d failed %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_IR_CUT] = val; - of_node_put(src_node); - src_node = NULL; - } - - rc = of_property_read_u32(of_node, "qcom,strobe-flash-sd-index", &val); - if (rc != -EINVAL) { - CDBG("%s qcom,strobe-flash-sd-index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_STROBE_FLASH] = val; - } else { - rc = 0; - } - - if (of_get_property(of_node, "qcom,csiphy-sd-index", &count)) { - count /= sizeof(uint32_t); - if (count > 2) { - pr_err("%s qcom,csiphy-sd-index count %d > 2\n", - __func__, count); - goto ERROR; - } - val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); - if (!val_array) { - rc = -ENOMEM; - goto ERROR; - } - - rc = of_property_read_u32_array(of_node, "qcom,csiphy-sd-index", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - kfree(val_array); - goto ERROR; - } - for (i = 0; i < count; i++) { - sensor_info->subdev_id[SUB_MODULE_CSIPHY + i] = - val_array[i]; - CDBG("%s csiphy_core[%d] = %d\n", - __func__, i, val_array[i]); - } - kfree(val_array); - } else { - pr_err("%s:%d qcom,csiphy-sd-index not present\n", __func__, - __LINE__); - rc = -EINVAL; - goto ERROR; - } - - if (of_get_property(of_node, "qcom,csid-sd-index", &count)) { - count /= sizeof(uint32_t); - if (count > 2) { - pr_err("%s qcom,csid-sd-index count %d > 2\n", - __func__, count); - rc = -EINVAL; - goto ERROR; - } - val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); - if (!val_array) { - rc = -ENOMEM; - goto ERROR; - } - - rc = of_property_read_u32_array(of_node, "qcom,csid-sd-index", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - kfree(val_array); - goto ERROR; - } - for (i = 0; i < count; i++) { - sensor_info->subdev_id - [SUB_MODULE_CSID + i] = val_array[i]; - CDBG("%s csid_core[%d] = %d\n", - __func__, i, val_array[i]); - } - kfree(val_array); - } else { - pr_err("%s:%d qcom,csid-sd-index not present\n", __func__, - __LINE__); - rc = -EINVAL; - goto ERROR; - } - - *s_info = sensor_info; - return rc; -ERROR: - kfree(sensor_info); - return rc; -} - -int msm_sensor_get_dt_actuator_data(struct device_node *of_node, - struct msm_actuator_info **act_info) -{ - int rc = 0; - uint32_t val = 0; - struct msm_actuator_info *actuator_info; - - rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val); - CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc); - if (rc < 0) - return 0; - - actuator_info = kzalloc(sizeof(*actuator_info), GFP_KERNEL); - if (!actuator_info) { - rc = -ENOMEM; - goto ERROR; - } - - actuator_info->cam_name = val; - - rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val); - CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc); - if (!rc) - actuator_info->vcm_pwd = val; - - rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val); - CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc); - if (!rc) - actuator_info->vcm_enable = val; - - *act_info = actuator_info; - return 0; -ERROR: - kfree(actuator_info); - return rc; -} - -int msm_sensor_get_dt_csi_data(struct device_node *of_node, - struct msm_camera_csi_lane_params **csi_lane_params) -{ - int rc = 0; - uint32_t val = 0; - struct msm_camera_csi_lane_params *clp; - - clp = kzalloc(sizeof(*clp), GFP_KERNEL); - if (!clp) - return -ENOMEM; - *csi_lane_params = clp; - - rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val); - CDBG("%s qcom,csi-lane-assign 0x%x, rc %d\n", __func__, val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - clp->csi_lane_assign = val; - - rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val); - CDBG("%s qcom,csi-lane-mask 0x%x, rc %d\n", __func__, val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - clp->csi_lane_mask = val; - - return rc; -ERROR: - kfree(clp); - return rc; -} - -int msm_camera_get_dt_power_setting_data(struct device_node *of_node, - struct camera_vreg_t *cam_vreg, int num_vreg, - struct msm_camera_power_ctrl_t *power_info) -{ - int rc = 0, i, j; - int count = 0; - const char *seq_name = NULL; - uint32_t *array = NULL; - struct msm_sensor_power_setting *ps; - - struct msm_sensor_power_setting *power_setting; - uint16_t *power_setting_size, size = 0; - bool need_reverse = 0; - - if (!power_info) - return -EINVAL; - - power_setting = power_info->power_setting; - power_setting_size = &power_info->power_setting_size; - - count = of_property_count_strings(of_node, "qcom,cam-power-seq-type"); - *power_setting_size = count; - - CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count); - - if (count <= 0) - return 0; - - ps = kcalloc(count, sizeof(*ps), GFP_KERNEL); - if (!ps) - return -ENOMEM; - power_setting = ps; - power_info->power_setting = ps; - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,cam-power-seq-type", i, - &seq_name); - CDBG("%s seq_name[%d] = %s\n", __func__, i, - seq_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - if (!strcmp(seq_name, "sensor_vreg")) { - ps[i].seq_type = SENSOR_VREG; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else if (!strcmp(seq_name, "sensor_gpio")) { - ps[i].seq_type = SENSOR_GPIO; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else if (!strcmp(seq_name, "sensor_clk")) { - ps[i].seq_type = SENSOR_CLK; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else if (!strcmp(seq_name, "sensor_i2c_mux")) { - ps[i].seq_type = SENSOR_I2C_MUX; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else { - CDBG("%s: unrecognized seq-type\n", __func__); - rc = -EILSEQ; - goto ERROR1; - } - } - - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,cam-power-seq-val", i, - &seq_name); - CDBG("%s seq_name[%d] = %s\n", __func__, i, - seq_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - switch (ps[i].seq_type) { - case SENSOR_VREG: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(seq_name, cam_vreg[j].reg_name)) - break; - } - if (j < num_vreg) - ps[i].seq_val = j; - else - rc = -EILSEQ; - break; - case SENSOR_GPIO: - if (!strcmp(seq_name, "sensor_gpio_reset")) - ps[i].seq_val = SENSOR_GPIO_RESET; - else if (!strcmp(seq_name, "sensor_gpio_standby")) - ps[i].seq_val = SENSOR_GPIO_STANDBY; - else if (!strcmp(seq_name, "sensor_gpio_vdig")) - ps[i].seq_val = SENSOR_GPIO_VDIG; - else if (!strcmp(seq_name, "sensor_gpio_vana")) - ps[i].seq_val = SENSOR_GPIO_VANA; - else if (!strcmp(seq_name, "sensor_gpio_vaf")) - ps[i].seq_val = SENSOR_GPIO_VAF; - else if (!strcmp(seq_name, "sensor_gpio_vio")) - ps[i].seq_val = SENSOR_GPIO_VIO; - else if (!strcmp(seq_name, "sensor_gpio_custom1")) - ps[i].seq_val = SENSOR_GPIO_CUSTOM1; - else if (!strcmp(seq_name, "sensor_gpio_custom2")) - ps[i].seq_val = SENSOR_GPIO_CUSTOM2; - else - rc = -EILSEQ; - break; - case SENSOR_CLK: - if (!strcmp(seq_name, "sensor_cam_mclk")) - ps[i].seq_val = SENSOR_CAM_MCLK; - else if (!strcmp(seq_name, "sensor_cam_clk")) - ps[i].seq_val = SENSOR_CAM_CLK; - else - rc = -EILSEQ; - break; - case SENSOR_I2C_MUX: - if (!strcmp(seq_name, "none")) - ps[i].seq_val = 0; - else - rc = -EILSEQ; - break; - default: - rc = -EILSEQ; - break; - } - if (rc < 0) { - CDBG("%s: unrecognized seq-val\n", __func__); - goto ERROR1; - } - } - - array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); - if (!array) { - rc = -ENOMEM; - goto ERROR1; - } - - - rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val", - array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - if (ps[i].seq_type == SENSOR_GPIO) { - if (array[i] == 0) - ps[i].config_val = GPIO_OUT_LOW; - else if (array[i] == 1) - ps[i].config_val = GPIO_OUT_HIGH; - } else { - ps[i].config_val = array[i]; - } - CDBG("%s power_setting[%d].config_val = %ld\n", __func__, i, - ps[i].config_val); - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay", - array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - ps[i].delay = array[i]; - CDBG("%s power_setting[%d].delay = %d\n", __func__, - i, ps[i].delay); - } - kfree(array); - - size = *power_setting_size; - - if (NULL != ps && 0 != size) - need_reverse = 1; - - power_info->power_down_setting = - kzalloc(sizeof(*ps) * size, GFP_KERNEL); - - if (!power_info->power_down_setting) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR1; - } - - memcpy(power_info->power_down_setting, - ps, sizeof(*ps) * size); - - power_info->power_down_setting_size = size; - - if (need_reverse) { - int c, end = size - 1; - struct msm_sensor_power_setting power_down_setting_t; - - for (c = 0; c < size/2; c++) { - power_down_setting_t = - power_info->power_down_setting[c]; - power_info->power_down_setting[c] = - power_info->power_down_setting[end]; - power_info->power_down_setting[end] = - power_down_setting_t; - end--; - } - } - return rc; -ERROR2: - kfree(array); -ERROR1: - kfree(ps); - power_setting_size = 0; - return rc; -} - -int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size) -{ - int rc = 0, i = 0; - uint32_t count = 0; - uint32_t *val_array = NULL; - - if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count)) - return 0; - - count /= sizeof(uint32_t); - if (!count) { - pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__); - return 0; - } - - val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); - if (!val_array) - return -ENOMEM; - - gconf->cam_gpio_req_tbl = kcalloc(count, sizeof(struct gpio), - GFP_KERNEL); - if (!gconf->cam_gpio_req_tbl) { - rc = -ENOMEM; - goto ERROR1; - } - gconf->cam_gpio_req_tbl_size = count; - - rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - if (val_array[i] >= gpio_array_size) { - pr_err("%s gpio req tbl index %d invalid\n", - __func__, val_array[i]); - return -EINVAL; - } - gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]]; - CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i, - gconf->cam_gpio_req_tbl[i].gpio); - } - - rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - gconf->cam_gpio_req_tbl[i].flags = val_array[i]; - CDBG("%s cam_gpio_req_tbl[%d].flags = %ld\n", __func__, i, - gconf->cam_gpio_req_tbl[i].flags); - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,gpio-req-tbl-label", i, - &gconf->cam_gpio_req_tbl[i].label); - CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i, - gconf->cam_gpio_req_tbl[i].label); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - } - - kfree(val_array); - return rc; - -ERROR2: - kfree(gconf->cam_gpio_req_tbl); -ERROR1: - kfree(val_array); - gconf->cam_gpio_req_tbl_size = 0; - return rc; -} - -int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size) -{ - int rc = 0, val = 0; - - gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info), - GFP_KERNEL); - if (!gconf->gpio_num_info) { - rc = -ENOMEM; - return rc; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-ir-p", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-ir-p failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-ir-p invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - - gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_P] = - gpio_array[val]; - gconf->gpio_num_info->valid[IR_CUT_FILTER_GPIO_P] = 1; - - CDBG("%s qcom,gpio-ir-p %d\n", __func__, - gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_P]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-ir-m", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-ir-m failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-ir-m invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - - gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M] = - gpio_array[val]; - - gconf->gpio_num_info->valid[IR_CUT_FILTER_GPIO_M] = 1; - - CDBG("%s qcom,gpio-ir-m %d\n", __func__, - gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-vana failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-vana invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_VANA] = 1; - CDBG("%s qcom,gpio-vana %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-vio", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-vio failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-vio invalid %d\n", - __func__, __LINE__, val); - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_VIO] = 1; - CDBG("%s qcom,gpio-vio %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-vaf", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-vaf failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-vaf invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_VAF] = 1; - CDBG("%s qcom,gpio-vaf %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-vdig failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-vdig invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_VDIG] = 1; - CDBG("%s qcom,gpio-vdig %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-reset failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-reset invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_RESET] = 1; - CDBG("%s qcom,gpio-reset %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-standby", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-standby failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-standby invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_STANDBY] = 1; - CDBG("%s qcom,gpio-standby %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-af-pwdm", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-af-pwdm failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_AF_PWDM] = 1; - CDBG("%s qcom,gpio-af-pwdm %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-flash-en invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_FL_EN] = 1; - CDBG("%s qcom,gpio-flash-en %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-flash-now invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_FL_NOW] = 1; - CDBG("%s qcom,gpio-flash-now %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-flash-reset", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%dread qcom,gpio-flash-reset failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-flash-reset invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_FL_RESET] = 1; - CDBG("%s qcom,gpio-flash-reset %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-custom1", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-custom1 failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-custom1 invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM1] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_CUSTOM1] = 1; - CDBG("%s qcom,gpio-custom1 %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM1]); - } else { - rc = 0; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-custom2", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-custom2 failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-custom2 invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM2] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_CUSTOM2] = 1; - CDBG("%s qcom,gpio-custom2 %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM2]); - } else { - rc = 0; - } - - return rc; - -ERROR: - kfree(gconf->gpio_num_info); - gconf->gpio_num_info = NULL; - return rc; -} - -int msm_camera_get_dt_vreg_data(struct device_node *of_node, - struct camera_vreg_t **cam_vreg, int *num_vreg) -{ - int rc = 0, i = 0; - int32_t count = 0; - uint32_t *vreg_array = NULL; - struct camera_vreg_t *vreg = NULL; - bool custom_vreg_name = false; - - count = of_property_count_strings(of_node, "qcom,cam-vreg-name"); - CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count); - - if (!count || (count == -EINVAL)) { - pr_err("%s:%d number of entries is 0 or not present in dts\n", - __func__, __LINE__); - *num_vreg = 0; - return 0; - } - - vreg = kcalloc(count, sizeof(*vreg), GFP_KERNEL); - if (!vreg) - return -ENOMEM; - *cam_vreg = vreg; - *num_vreg = count; - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,cam-vreg-name", i, - &vreg[i].reg_name); - CDBG("%s reg_name[%d] = %s\n", __func__, i, - vreg[i].reg_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - } - - custom_vreg_name = of_property_read_bool(of_node, - "qcom,cam-custom-vreg-name"); - if (custom_vreg_name) { - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,cam-custom-vreg-name", i, - &vreg[i].custom_vreg_name); - CDBG("%s sub reg_name[%d] = %s\n", __func__, i, - vreg[i].custom_vreg_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - } - } - - vreg_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); - if (!vreg_array) { - rc = -ENOMEM; - goto ERROR1; - } - - for (i = 0; i < count; i++) - vreg[i].type = VREG_TYPE_DEFAULT; - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type", - vreg_array, count); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } else { - for (i = 0; i < count; i++) { - vreg[i].type = vreg_array[i]; - CDBG("%s cam_vreg[%d].type = %d\n", - __func__, i, vreg[i].type); - } - } - } else { - CDBG("%s:%d no qcom,cam-vreg-type entries in dts\n", - __func__, __LINE__); - rc = 0; - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage", - vreg_array, count); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } else { - for (i = 0; i < count; i++) { - vreg[i].min_voltage = vreg_array[i]; - CDBG("%s cam_vreg[%d].min_voltage = %d\n", - __func__, i, vreg[i].min_voltage); - } - } - } else { - CDBG("%s:%d no qcom,cam-vreg-min-voltage entries in dts\n", - __func__, __LINE__); - rc = 0; - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage", - vreg_array, count); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } else { - for (i = 0; i < count; i++) { - vreg[i].max_voltage = vreg_array[i]; - CDBG("%s cam_vreg[%d].max_voltage = %d\n", - __func__, i, vreg[i].max_voltage); - } - } - } else { - CDBG("%s:%d no qcom,cam-vreg-max-voltage entries in dts\n", - __func__, __LINE__); - rc = 0; - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode", - vreg_array, count); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } else { - for (i = 0; i < count; i++) { - vreg[i].op_mode = vreg_array[i]; - CDBG("%s cam_vreg[%d].op_mode = %d\n", - __func__, i, vreg[i].op_mode); - } - } - } else { - CDBG("%s:%d no qcom,cam-vreg-op-mode entries in dts\n", - __func__, __LINE__); - rc = 0; - } - - kfree(vreg_array); - return rc; -ERROR2: - kfree(vreg_array); -ERROR1: - kfree(vreg); - *num_vreg = 0; - return rc; -} - -static int msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) -{ - struct v4l2_subdev *i2c_mux_sd = - dev_get_drvdata(&i2c_conf->mux_dev->dev); - v4l2_subdev_call(i2c_mux_sd, core, ioctl, - VIDIOC_MSM_I2C_MUX_INIT, NULL); - v4l2_subdev_call(i2c_mux_sd, core, ioctl, - VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode); - return 0; -} - -static int msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) -{ - struct v4l2_subdev *i2c_mux_sd = - dev_get_drvdata(&i2c_conf->mux_dev->dev); - v4l2_subdev_call(i2c_mux_sd, core, ioctl, - VIDIOC_MSM_I2C_MUX_RELEASE, NULL); - return 0; -} - -int msm_camera_pinctrl_init( - struct msm_pinctrl_info *sensor_pctrl, struct device *dev) { - - sensor_pctrl->pinctrl = devm_pinctrl_get(dev); - if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { - pr_err("%s:%d Getting pinctrl handle failed\n", - __func__, __LINE__); - return -EINVAL; - } - sensor_pctrl->gpio_state_active = - pinctrl_lookup_state(sensor_pctrl->pinctrl, - CAM_SENSOR_PINCTRL_STATE_DEFAULT); - if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) { - pr_err("%s:%d Failed to get the active state pinctrl handle\n", - __func__, __LINE__); - return -EINVAL; - } - sensor_pctrl->gpio_state_suspend - = pinctrl_lookup_state(sensor_pctrl->pinctrl, - CAM_SENSOR_PINCTRL_STATE_SLEEP); - if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) { - pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", - __func__, __LINE__); - return -EINVAL; - } - return 0; -} - -int msm_cam_sensor_handle_reg_gpio(int seq_val, - struct msm_camera_gpio_conf *gconf, int val) { - - int gpio_offset = -1; - - if (!gconf) { - pr_err("ERR:%s: Input Parameters are not proper\n", __func__); - return -EINVAL; - } - CDBG("%s: %d Seq val: %d, config: %d", __func__, __LINE__, - seq_val, val); - - switch (seq_val) { - case CAM_VDIG: - gpio_offset = SENSOR_GPIO_VDIG; - break; - - case CAM_VIO: - gpio_offset = SENSOR_GPIO_VIO; - break; - - case CAM_VANA: - gpio_offset = SENSOR_GPIO_VANA; - break; - - case CAM_VAF: - gpio_offset = SENSOR_GPIO_VAF; - break; - - case CAM_V_CUSTOM1: - gpio_offset = SENSOR_GPIO_CUSTOM1; - break; - - case CAM_V_CUSTOM2: - gpio_offset = SENSOR_GPIO_CUSTOM2; - break; - - default: - pr_err("%s:%d Invalid VREG seq val %d\n", __func__, - __LINE__, seq_val); - return -EINVAL; - } - - CDBG("%s: %d GPIO offset: %d, seq_val: %d\n", __func__, __LINE__, - gpio_offset, seq_val); - - if ((gconf->gpio_num_info->valid[gpio_offset] == 1)) { - gpio_set_value_cansleep( - gconf->gpio_num_info->gpio_num - [gpio_offset], val); - } - return 0; -} - -int32_t msm_sensor_driver_get_gpio_data( - struct msm_camera_gpio_conf **gpio_conf, - struct device_node *of_node) -{ - int32_t rc = 0, i = 0; - uint16_t *gpio_array = NULL; - int16_t gpio_array_size = 0; - struct msm_camera_gpio_conf *gconf = NULL; - - /* Validate input parameters */ - if (!of_node) { - pr_err("failed: invalid param of_node %pK", of_node); - return -EINVAL; - } - - gpio_array_size = of_gpio_count(of_node); - CDBG("gpio count %d\n", gpio_array_size); - if (gpio_array_size <= 0) - return -ENODEV; - - gconf = kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!gconf) - return -ENOMEM; - - *gpio_conf = gconf; - - gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL); - if (!gpio_array) - goto FREE_GPIO_CONF; - - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("gpio_array[%d] = %d", i, gpio_array[i]); - } - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, - gpio_array_size); - if (rc < 0) { - pr_err("failed in msm_camera_get_dt_gpio_req_tbl\n"); - goto FREE_GPIO_CONF; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array, - gpio_array_size); - if (rc < 0) { - pr_err("failed in msm_camera_init_gpio_pin_tbl\n"); - goto FREE_GPIO_REQ_TBL; - } - kfree(gpio_array); - return rc; - -FREE_GPIO_REQ_TBL: - kfree(gconf->cam_gpio_req_tbl); -FREE_GPIO_CONF: - kfree(gconf); - kfree(gpio_array); - *gpio_conf = NULL; - return rc; -} - -int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client) -{ - int rc = 0, index = 0, no_gpio = 0, ret = 0; - struct msm_sensor_power_setting *power_setting = NULL; - - CDBG("%s:%d\n", __func__, __LINE__); - if (!ctrl || !sensor_i2c_client) { - pr_err("failed ctrl %pK sensor_i2c_client %pK\n", ctrl, - sensor_i2c_client); - return -EINVAL; - } - if (ctrl->gpio_conf->cam_gpiomux_conf_tbl != NULL) - pr_err("%s:%d mux install\n", __func__, __LINE__); - - ret = msm_camera_pinctrl_init(&(ctrl->pinctrl_info), ctrl->dev); - if (ret < 0) { - pr_err("%s:%d Initialization of pinctrl failed\n", - __func__, __LINE__); - ctrl->cam_pinctrl_status = 0; - } else { - ctrl->cam_pinctrl_status = 1; - } - rc = msm_camera_request_gpio_table( - ctrl->gpio_conf->cam_gpio_req_tbl, - ctrl->gpio_conf->cam_gpio_req_tbl_size, 1); - if (rc < 0) - no_gpio = rc; - if (ctrl->cam_pinctrl_status) { - ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_active); - if (ret) - pr_err("%s:%d cannot set pin to active state", - __func__, __LINE__); - } - for (index = 0; index < ctrl->power_setting_size; index++) { - CDBG("%s index %d\n", __func__, index); - power_setting = &ctrl->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { - case SENSOR_CLK: - if (power_setting->seq_val >= ctrl->clk_info_size) { - pr_err("%s clk index %d >= max %zu\n", __func__, - power_setting->seq_val, - ctrl->clk_info_size); - goto power_up_failed; - } - if (power_setting->config_val) - ctrl->clk_info[power_setting->seq_val]. - clk_rate = power_setting->config_val; - rc = msm_camera_clk_enable(ctrl->dev, - ctrl->clk_info, ctrl->clk_ptr, - ctrl->clk_info_size, true); - if (rc < 0) { - pr_err("%s: clk enable failed\n", __func__); - goto power_up_failed; - } - break; - case SENSOR_GPIO: - if (no_gpio) { - pr_err("%s: request gpio failed\n", __func__); - return no_gpio; - } - if (power_setting->seq_val >= SENSOR_GPIO_MAX || - !ctrl->gpio_conf->gpio_num_info) { - pr_err("%s gpio index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - goto power_up_failed; - } - if (!ctrl->gpio_conf->gpio_num_info->valid - [power_setting->seq_val]) - continue; - CDBG("%s:%d gpio set val %d\n", __func__, __LINE__, - ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val]); - gpio_set_value_cansleep( - ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], - (int) power_setting->config_val); - break; - case SENSOR_VREG: - if (power_setting->seq_val == INVALID_VREG) - break; - - if (power_setting->seq_val >= CAM_VREG_MAX) { - pr_err("%s vreg index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - goto power_up_failed; - } - if (power_setting->seq_val < ctrl->num_vreg) - msm_camera_config_single_vreg(ctrl->dev, - &ctrl->cam_vreg - [power_setting->seq_val], - (struct regulator **) - &power_setting->data[0], - 1); - else - pr_err("%s: %d usr_idx:%d dts_idx:%d\n", - __func__, __LINE__, - power_setting->seq_val, ctrl->num_vreg); - - rc = msm_cam_sensor_handle_reg_gpio( - power_setting->seq_val, - ctrl->gpio_conf, 1); - if (rc < 0) { - pr_err("ERR:%s Error in handling VREG GPIO\n", - __func__); - goto power_up_failed; - } - break; - case SENSOR_I2C_MUX: - if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) - msm_camera_enable_i2c_mux(ctrl->i2c_conf); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); - break; - } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); - } - } - - if (device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = sensor_i2c_client->i2c_func_tbl->i2c_util( - sensor_i2c_client, MSM_CCI_INIT); - if (rc < 0) { - pr_err("%s cci_init failed\n", __func__); - goto power_up_failed; - } - } - CDBG("%s exit\n", __func__); - return 0; -power_up_failed: - pr_err("%s:%d failed\n", __func__, __LINE__); - for (index--; index >= 0; index--) { - CDBG("%s index %d\n", __func__, index); - power_setting = &ctrl->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { - case SENSOR_GPIO: - if (!ctrl->gpio_conf->gpio_num_info) - continue; - if (!ctrl->gpio_conf->gpio_num_info->valid - [power_setting->seq_val]) - continue; - gpio_set_value_cansleep( - ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], GPIOF_OUT_INIT_LOW); - break; - case SENSOR_VREG: - if (power_setting->seq_val < ctrl->num_vreg) - msm_camera_config_single_vreg(ctrl->dev, - &ctrl->cam_vreg - [power_setting->seq_val], - (struct regulator **) - &power_setting->data[0], - 0); - else - pr_err("%s:%d:seq_val: %d > num_vreg: %d\n", - __func__, __LINE__, - power_setting->seq_val, ctrl->num_vreg); - - msm_cam_sensor_handle_reg_gpio(power_setting->seq_val, - ctrl->gpio_conf, GPIOF_OUT_INIT_LOW); - break; - case SENSOR_I2C_MUX: - if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) - msm_camera_disable_i2c_mux(ctrl->i2c_conf); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); - break; - } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); - } - } - if (ctrl->cam_pinctrl_status) { - ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_suspend); - if (ret) - pr_err("%s:%d cannot set pin to suspend state\n", - __func__, __LINE__); - devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); - } - ctrl->cam_pinctrl_status = 0; - msm_camera_request_gpio_table( - ctrl->gpio_conf->cam_gpio_req_tbl, - ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); - return rc; -} - -static struct msm_sensor_power_setting* -msm_camera_get_power_settings(struct msm_camera_power_ctrl_t *ctrl, - enum msm_sensor_power_seq_type_t seq_type, - uint16_t seq_val) -{ - struct msm_sensor_power_setting *power_setting, *ps = NULL; - int idx; - - for (idx = 0; idx < ctrl->power_setting_size; idx++) { - power_setting = &ctrl->power_setting[idx]; - if ((power_setting->seq_type == seq_type) && - (power_setting->seq_val == seq_val)) { - ps = power_setting; - return ps; - } - - } - return ps; -} - -int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client) -{ - int index = 0, ret = 0; - struct msm_sensor_power_setting *pd = NULL; - struct msm_sensor_power_setting *ps; - - CDBG("%s:%d\n", __func__, __LINE__); - if (!ctrl || !sensor_i2c_client) { - pr_err("failed ctrl %pK sensor_i2c_client %pK\n", ctrl, - sensor_i2c_client); - return -EINVAL; - } - if (device_type == MSM_CAMERA_PLATFORM_DEVICE) - sensor_i2c_client->i2c_func_tbl->i2c_util( - sensor_i2c_client, MSM_CCI_RELEASE); - - for (index = 0; index < ctrl->power_down_setting_size; index++) { - CDBG("%s index %d\n", __func__, index); - pd = &ctrl->power_down_setting[index]; - ps = NULL; - CDBG("%s type %d\n", __func__, pd->seq_type); - switch (pd->seq_type) { - case SENSOR_CLK: - msm_camera_clk_enable(ctrl->dev, - ctrl->clk_info, ctrl->clk_ptr, - ctrl->clk_info_size, false); - break; - case SENSOR_GPIO: - if (pd->seq_val >= SENSOR_GPIO_MAX || - !ctrl->gpio_conf->gpio_num_info) { - pr_err("%s gpio index %d >= max %d\n", __func__, - pd->seq_val, - SENSOR_GPIO_MAX); - continue; - } - if (!ctrl->gpio_conf->gpio_num_info->valid - [pd->seq_val]) - continue; - gpio_set_value_cansleep( - ctrl->gpio_conf->gpio_num_info->gpio_num - [pd->seq_val], - (int) pd->config_val); - break; - case SENSOR_VREG: - if (pd->seq_val == INVALID_VREG) - break; - if (pd->seq_val >= CAM_VREG_MAX) { - pr_err("%s vreg index %d >= max %d\n", __func__, - pd->seq_val, - SENSOR_GPIO_MAX); - continue; - } - - ps = msm_camera_get_power_settings(ctrl, - pd->seq_type, - pd->seq_val); - if (ps) { - if (pd->seq_val < ctrl->num_vreg) - msm_camera_config_single_vreg(ctrl->dev, - &ctrl->cam_vreg - [pd->seq_val], - (struct regulator **) - &ps->data[0], - 0); - else - pr_err("%s:%d:seq_val:%d > num_vreg: %d\n", - __func__, __LINE__, pd->seq_val, - ctrl->num_vreg); - } else - pr_err("%s error in power up/down seq data\n", - __func__); - ret = msm_cam_sensor_handle_reg_gpio(pd->seq_val, - ctrl->gpio_conf, GPIOF_OUT_INIT_LOW); - if (ret < 0) - pr_err("ERR:%s Error while disabling VREG GPIO\n", - __func__); - break; - case SENSOR_I2C_MUX: - if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) - msm_camera_disable_i2c_mux(ctrl->i2c_conf); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - pd->seq_type); - break; - } - if (pd->delay > 20) { - msleep(pd->delay); - } else if (pd->delay) { - usleep_range(pd->delay * 1000, - (pd->delay * 1000) + 1000); - } - } - if (ctrl->cam_pinctrl_status) { - ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_suspend); - if (ret) - pr_err("%s:%d cannot set pin to suspend state", - __func__, __LINE__); - devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); - } - ctrl->cam_pinctrl_status = 0; - msm_camera_request_gpio_table( - ctrl->gpio_conf->cam_gpio_req_tbl, - ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); - CDBG("%s exit\n", __func__); - return 0; -} - diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.h deleted file mode 100644 index a29ef21274c289883107ee9082b6a1b359cb33be..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CAMERA_DT_UTIL_H__ -#define MSM_CAMERA_DT_UTIL_H__ - -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "cam_soc_api.h" - - -#define INVALID_VREG 100 - -int msm_sensor_get_sub_module_index(struct device_node *of_node, - struct msm_sensor_info_t **s_info); - -int msm_sensor_get_dt_actuator_data(struct device_node *of_node, - struct msm_actuator_info **act_info); - -int msm_sensor_get_dt_csi_data(struct device_node *of_node, - struct msm_camera_csi_lane_params **csi_lane_params); - -int msm_camera_get_dt_power_setting_data(struct device_node *of_node, - struct camera_vreg_t *cam_vreg, int num_vreg, - struct msm_camera_power_ctrl_t *power_info); - -int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int msm_camera_get_dt_vreg_data(struct device_node *of_node, - struct camera_vreg_t **cam_vreg, int *num_vreg); - -int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client); - -int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client); - -int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, - int num_vreg, struct msm_sensor_power_setting *power_setting, - uint16_t power_setting_size); - -int msm_camera_pinctrl_init - (struct msm_pinctrl_info *sensor_pctrl, struct device *dev); - -int32_t msm_sensor_driver_get_gpio_data( - struct msm_camera_gpio_conf **gpio_conf, - struct device_node *of_node); -#endif diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c.h deleted file mode 100644 index 043355195d91ed28cf7a3eb837dd53ec33ca064c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c.h +++ /dev/null @@ -1,211 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_CAMERA_CCI_I2C_H -#define MSM_CAMERA_CCI_I2C_H - -#include -#include -#include - -#define I2C_POLL_TIME_MS 5 -#define MAX_POLL_DELAY_MS 100 - -#define I2C_COMPARE_MATCH 0 -#define I2C_COMPARE_MISMATCH 1 - -struct msm_camera_i2c_client { - struct msm_camera_i2c_fn_t *i2c_func_tbl; - struct i2c_client *client; - struct msm_camera_cci_client *cci_client; - struct msm_camera_spi_client *spi_client; - enum msm_camera_i2c_reg_addr_type addr_type; -}; - -struct msm_camera_i2c_fn_t { - int (*i2c_read)(struct msm_camera_i2c_client *, uint32_t, uint16_t *, - enum msm_camera_i2c_data_type); - int32_t (*i2c_read_seq)(struct msm_camera_i2c_client *, uint32_t, - uint8_t *, uint32_t); - int (*i2c_write)(struct msm_camera_i2c_client *, uint32_t, uint16_t, - enum msm_camera_i2c_data_type); - int (*i2c_write_seq)(struct msm_camera_i2c_client *, uint32_t , - uint8_t *, uint32_t); - int32_t (*i2c_write_table)(struct msm_camera_i2c_client *, - struct msm_camera_i2c_reg_setting *); - int32_t (*i2c_write_seq_table)(struct msm_camera_i2c_client *, - struct msm_camera_i2c_seq_reg_setting *); - int32_t (*i2c_write_table_w_microdelay) - (struct msm_camera_i2c_client *, - struct msm_camera_i2c_reg_setting *); - int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t); - int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type); - int32_t (*i2c_poll)(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type, uint32_t delay_ms); - int32_t (*i2c_read_burst)(struct msm_camera_i2c_client *client, - uint32_t read_byte, uint8_t *buffer, uint32_t addr, - enum msm_camera_i2c_data_type data_type); - int32_t (*i2c_write_burst)(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size, - uint32_t buf_len, uint32_t addr, - enum msm_camera_i2c_data_type data_type); - int32_t (*i2c_write_table_async)(struct msm_camera_i2c_client *, - struct msm_camera_i2c_reg_setting *); - int32_t (*i2c_write_table_sync)(struct msm_camera_i2c_client *, - struct msm_camera_i2c_reg_setting *); - int32_t (*i2c_write_table_sync_block)(struct msm_camera_i2c_client *, - struct msm_camera_i2c_reg_setting *); -}; - -int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_cci_i2c_write_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_table_async( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_table_sync( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_table_sync_block( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_seq_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, - uint16_t cci_cmd); - -int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type, uint32_t delay_ms); - -int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting); - -int32_t msm_camera_qup_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_qup_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type, uint32_t delay_ms); - -int32_t msm_camera_tz_i2c_register_sensor(void *s_ctrl_p); - -int32_t msm_camera_tz_i2c_power_up(struct msm_camera_i2c_client *client); - -int32_t msm_camera_tz_i2c_power_down(struct msm_camera_i2c_client *client); - -int32_t msm_camera_tz_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_tz_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_tz_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_tz_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_tz_i2c_write_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_tz_i2c_write_table_async( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_tz_i2c_write_table_sync( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_tz_i2c_write_table_sync_block( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_tz_i2c_write_seq_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting); - -int32_t msm_camera_tz_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_tz_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_sensor_tz_i2c_util(struct msm_camera_i2c_client *client, - uint16_t cci_cmd); - -int32_t msm_camera_tz_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c_mux.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c_mux.c deleted file mode 100644 index d0d1e4003de6f6021b3cdad16f5b21eaa0c39b0e..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c_mux.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include "msm_camera_i2c_mux.h" - -/* TODO move this somewhere else */ -#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux" -static int msm_i2c_mux_config(struct i2c_mux_device *mux_device, uint8_t *mode) -{ - uint32_t val; - - val = msm_camera_io_r(mux_device->ctl_base); - if (*mode == MODE_DUAL) { - msm_camera_io_w(val | 0x3, mux_device->ctl_base); - } else if (*mode == MODE_L) { - msm_camera_io_w(((val | 0x2) & ~(0x1)), mux_device->ctl_base); - val = msm_camera_io_r(mux_device->ctl_base); - CDBG("the camio mode config left value is %d\n", val); - } else { - msm_camera_io_w(((val | 0x1) & ~(0x2)), mux_device->ctl_base); - val = msm_camera_io_r(mux_device->ctl_base); - CDBG("the camio mode config right value is %d\n", val); - } - return 0; -} - -static int msm_i2c_mux_init(struct i2c_mux_device *mux_device) -{ - int rc = 0, val = 0; - - if (mux_device->use_count == 0) { - val = msm_camera_io_r(mux_device->rw_base); - msm_camera_io_w((val | 0x200), mux_device->rw_base); - } - mux_device->use_count++; - return 0; -}; - -static int msm_i2c_mux_release(struct i2c_mux_device *mux_device) -{ - int val = 0; - - mux_device->use_count--; - if (mux_device->use_count == 0) { - val = msm_camera_io_r(mux_device->rw_base); - msm_camera_io_w((val & ~0x200), mux_device->rw_base); - } - return 0; -} - -static long msm_i2c_mux_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct i2c_mux_device *mux_device; - int rc = 0; - - mux_device = v4l2_get_subdevdata(sd); - if (mux_device == NULL) { - rc = -ENOMEM; - return rc; - } - mutex_lock(&mux_device->mutex); - switch (cmd) { - case VIDIOC_MSM_I2C_MUX_CFG: - rc = msm_i2c_mux_config(mux_device, (uint8_t *) arg); - break; - case VIDIOC_MSM_I2C_MUX_INIT: - rc = msm_i2c_mux_init(mux_device); - break; - case VIDIOC_MSM_I2C_MUX_RELEASE: - rc = msm_i2c_mux_release(mux_device); - break; - default: - rc = -ENOIOCTLCMD; - } - mutex_unlock(&mux_device->mutex); - return rc; -} - -static struct v4l2_subdev_core_ops msm_i2c_mux_subdev_core_ops = { - .ioctl = &msm_i2c_mux_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_i2c_mux_subdev_ops = { - .core = &msm_i2c_mux_subdev_core_ops, -}; - -static int i2c_mux_probe(struct platform_device *pdev) -{ - struct i2c_mux_device *mux_device; - int rc = 0; - - CDBG("%s: device id = %d\n", __func__, pdev->id); - mux_device = kzalloc(sizeof(struct i2c_mux_device), GFP_KERNEL); - if (!mux_device) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - - v4l2_subdev_init(&mux_device->subdev, &msm_i2c_mux_subdev_ops); - v4l2_set_subdevdata(&mux_device->subdev, mux_device); - platform_set_drvdata(pdev, &mux_device->subdev); - mutex_init(&mux_device->mutex); - - mux_device->ctl_base = msm_camera_get_reg_base(pdev, - "i2c_mux_ctl", true); - if (!mux_device->ctl_base) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto ctl_base_failed; - } - mux_device->rw_base = msm_camera_get_reg_base(pdev, "i2c_mux_rw", true); - if (!mux_device->rw_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto rw_base_failed; - } - mux_device->pdev = pdev; - return 0; - -rw_base_failed: - msm_camera_put_reg_base(pdev, mux_device->ctl_base, - "i2c_mux_ctl", true); -ctl_base_failed: - mutex_destroy(&mux_device->mutex); - kfree(mux_device); - return 0; -} - -static int i2c_mux_remove(struct platform_device *pdev) -{ - struct v4l2_subdev *sub_dev = platform_get_drvdata(pdev); - struct i2c_mux_device *mux_device; - - if (!sub_dev) { - pr_err("%s: sub device is NULL\n", __func__); - return 0; - } - - mux_device = (struct mux_device *)v4l2_get_subdevdata(sub_dev); - if (!mux_device) { - pr_err("%s: sub device is NULL\n", __func__); - return 0; - } - - msm_camera_put_reg_base(pdev, mux_device->rw_base, "i2c_mux_ctl", true); - msm_camera_put_reg_base(pdev, mux_device->ctl_base, "i2c_mux_rw", true); -} - -static struct platform_driver i2c_mux_driver = { - .probe = i2c_mux_probe, - .remove = i2c_mux_remove, - .driver = { - .name = MSM_I2C_MUX_DRV_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init msm_camera_i2c_mux_init_module(void) -{ - return platform_driver_register(&i2c_mux_driver); -} - -static void __exit msm_camera_i2c_mux_exit_module(void) -{ - platform_driver_unregister(&i2c_mux_driver); -} - -module_init(msm_camera_i2c_mux_init_module); -module_exit(msm_camera_i2c_mux_exit_module); -MODULE_DESCRIPTION("MSM Camera I2C mux driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c_mux.h b/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c_mux.h deleted file mode 100644 index 706fd9298630f42d9ec46ed41324d68d989cbf4c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_i2c_mux.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_I2C_MUX_H -#define MSM_I2C_MUX_H - -#include -#include - -struct i2c_mux_device { - struct platform_device *pdev; - struct v4l2_subdev subdev; - void __iomem *ctl_base; - void __iomem *rw_base; - struct mutex mutex; - unsigned use_count; -}; - -struct i2c_mux_cfg_params { - struct v4l2_subdev *subdev; - void *parms; -}; - -#define VIDIOC_MSM_I2C_MUX_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct i2c_mux_cfg_params) - -#define VIDIOC_MSM_I2C_MUX_INIT \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct v4l2_subdev*) - -#define VIDIOC_MSM_I2C_MUX_RELEASE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct v4l2_subdev*) - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_qup_i2c.c deleted file mode 100644 index 9098b23dbc677eb79a0596cc9d1a738c5ff4a0fc..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_qup_i2c.c +++ /dev/null @@ -1,608 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include "msm_camera_i2c.h" - -#undef CDBG -#ifdef CONFIG_MSM_AIS_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) -#define S_I2C_DBG(fmt, args...) -#endif - -static int32_t msm_camera_qup_i2c_rxdata( - struct msm_camera_i2c_client *dev_client, unsigned char *rxdata, - int data_length) -{ - int32_t rc = 0; - uint16_t saddr = dev_client->client->addr >> 1; - struct i2c_msg msgs[] = { - { - .addr = saddr, - .flags = 0, - .len = dev_client->addr_type, - .buf = rxdata, - }, - { - .addr = saddr, - .flags = I2C_M_RD, - .len = data_length, - .buf = rxdata, - }, - }; - - rc = i2c_transfer(dev_client->client->adapter, msgs, 2); - if (rc < 0) - S_I2C_DBG("msm_camera_qup_i2c_rxdata failed 0x%x\n", saddr); - return rc; -} - -static int32_t msm_camera_qup_i2c_txdata( - struct msm_camera_i2c_client *dev_client, unsigned char *txdata, - int length) -{ - int32_t rc = 0; - uint16_t saddr = dev_client->client->addr >> 1; - struct i2c_msg msg[] = { - { - .addr = saddr, - .flags = 0, - .len = length, - .buf = txdata, - }, - }; - - rc = i2c_transfer(dev_client->client->adapter, msg, 1); - if (rc < 0) - S_I2C_DBG("msm_camera_qup_i2c_txdata failed 0x%x\n", saddr); - return rc; -} - -int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - unsigned char *buf = NULL; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - if (client->addr_type > UINT_MAX - data_type) { - S_I2C_DBG("%s: integer overflow prevented\n", __func__); - return rc; - } - - buf = kzalloc(client->addr_type+data_type, GFP_KERNEL); - if (!buf) { - S_I2C_DBG("%s:%d no memory\n", __func__, __LINE__); - return -ENOMEM; - } - - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - } - rc = msm_camera_qup_i2c_rxdata(client, buf, data_type); - if (rc < 0) { - S_I2C_DBG("%s fail\n", __func__); - kfree(buf); - buf = NULL; - return rc; - } - - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) - *data = buf[0]; - else - *data = buf[0] << 8 | buf[1]; - - S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); - kfree(buf); - buf = NULL; - return rc; -} - -int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - unsigned char *buf = NULL; - int i; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || num_byte == 0) - return rc; - - if (num_byte > I2C_REG_DATA_MAX) { - S_I2C_DBG("%s: Error num_byte:0x%x exceeds 8K\n", - __func__, num_byte); - S_I2C_DBG("%s: max supported:0x%x\n", - __func__, I2C_REG_DATA_MAX); - return rc; - } - if (client->addr_type > UINT_MAX - num_byte) { - S_I2C_DBG("%s: integer overflow prevented\n", __func__); - return rc; - } - - buf = kzalloc(client->addr_type+num_byte, GFP_KERNEL); - if (!buf) { - S_I2C_DBG("%s:%d no memory\n", __func__, __LINE__); - return -ENOMEM; - } - - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - } - rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte); - if (rc < 0) { - S_I2C_DBG("%s fail\n", __func__); - kfree(buf); - buf = NULL; - return rc; - } - - S_I2C_DBG("%s addr = 0x%x", __func__, addr); - for (i = 0; i < num_byte; i++) { - data[i] = buf[i]; - S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); - S_I2C_DBG("Data: 0x%x\n", data[i]); - } - kfree(buf); - buf = NULL; - return rc; -} - -int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+data_type]; - uint8_t len = 0; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - S_I2C_DBG("%s reg addr = 0x%x data type: %d\n", - __func__, addr, data_type); - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - len = 1; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len+1, buf[len+1]); - len = 2; - } - S_I2C_DBG("Data: 0x%x\n", data); - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) { - buf[len] = data; - S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); - len += 1; - } else if (data_type == MSM_CAMERA_I2C_WORD_DATA) { - buf[len] = data >> BITS_PER_BYTE; - buf[len+1] = data; - S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); - S_I2C_DBG("Byte %d: 0x%x\n", len+1, buf[len+1]); - len += 2; - } - rc = msm_camera_qup_i2c_txdata(client, buf, len); - if (rc < 0) - S_I2C_DBG("%s fail\n", __func__); - return rc; -} - -int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+num_byte]; - uint8_t len = 0, i = 0; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || num_byte == 0) - return rc; - - S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", - __func__, addr, num_byte); - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - len = 1; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len+1, buf[len+1]); - len = 2; - } - if (num_byte > I2C_SEQ_REG_DATA_MAX) { - pr_err("%s: num_byte=%d clamped to max supported %d\n", - __func__, num_byte, I2C_SEQ_REG_DATA_MAX); - num_byte = I2C_SEQ_REG_DATA_MAX; - } - for (i = 0; i < num_byte; i++) { - buf[i+len] = data[i]; - S_I2C_DBG("Byte %d: 0x%x\n", i+len, buf[i+len]); - S_I2C_DBG("Data: 0x%x\n", data[i]); - } - rc = msm_camera_qup_i2c_txdata(client, buf, len+num_byte); - if (rc < 0) - S_I2C_DBG("%s fail\n", __func__); - return rc; -} - -int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_reg_array *reg_setting; - uint16_t client_addr_type; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - reg_setting = write_setting->reg_setting; - client_addr_type = client->addr_type; - client->addr_type = write_setting->addr_type; - - for (i = 0; i < write_setting->size; i++) { - CDBG("%s addr 0x%x data 0x%x\n", __func__, - reg_setting->reg_addr, reg_setting->reg_data); - - rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, - reg_setting->reg_data, write_setting->data_type); - if (rc < 0) - break; - reg_setting++; - } - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - client->addr_type = client_addr_type; - return rc; -} - -int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_seq_reg_array *reg_setting; - uint16_t client_addr_type; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { - pr_err("%s Invalid addr type %d\n", __func__, - write_setting->addr_type); - return rc; - } - - reg_setting = write_setting->reg_setting; - client_addr_type = client->addr_type; - client->addr_type = write_setting->addr_type; - - if (reg_setting->reg_data_size > I2C_SEQ_REG_DATA_MAX) { - pr_err("%s: number of bytes %u exceeding the max supported %d\n", - __func__, reg_setting->reg_data_size, I2C_SEQ_REG_DATA_MAX); - return rc; - } - - for (i = 0; i < write_setting->size; i++) { - rc = msm_camera_qup_i2c_write_seq(client, reg_setting->reg_addr, - reg_setting->reg_data, reg_setting->reg_data_size); - if (rc < 0) - break; - reg_setting++; - } - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - client->addr_type = client_addr_type; - return rc; -} - -int32_t msm_camera_qup_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (!client || !write_setting) - return rc; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - reg_setting = write_setting->reg_setting; - for (i = 0; i < write_setting->size; i++) { - rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, - reg_setting->reg_data, write_setting->data_type); - if (rc < 0) - break; - if (reg_setting->delay) - usleep_range(reg_setting->delay, - reg_setting->delay + 1000); - reg_setting++; - } - return rc; -} - -static int32_t msm_camera_qup_i2c_compare( - struct msm_camera_i2c_client *client, uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data = 0; - int data_len = 0; - - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - data_len = data_type; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - data_len = MSM_CAMERA_I2C_BYTE_DATA; - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - data_len = MSM_CAMERA_I2C_WORD_DATA; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_len); - if (rc < 0) - return rc; - - rc = I2C_COMPARE_MISMATCH; - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - if (data == reg_data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_SET_WORD_MASK: - if ((reg_data & data) == data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - if (!(reg_data & data)) - rc = I2C_COMPARE_MATCH; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - S_I2C_DBG("%s: Register and data match result %d\n", __func__, - rc); - return rc; -} - -int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type, uint32_t delay_ms) -{ - int32_t rc = 0; - int i; - - S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", - __func__, addr, data, data_type); - - if (delay_ms > MAX_POLL_DELAY_MS) { - pr_err("%s:%d invalid delay = %d max_delay = %d\n", - __func__, __LINE__, delay_ms, MAX_POLL_DELAY_MS); - return -EINVAL; - } - - for (i = 0; i < delay_ms; i++) { - rc = msm_camera_qup_i2c_compare(client, - addr, data, data_type); - if (rc < 0) { - pr_err("%s:%d qup_i2c_compare failed rc = %d", __func__, - __LINE__, rc); - break; - } - if (rc == I2C_COMPARE_MISMATCH) - break; - usleep_range(1000, 1010); - } - return rc; -} - -static int32_t msm_camera_qup_i2c_set_mask(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t mask, - enum msm_camera_i2c_data_type data_type, uint16_t set_mask) -{ - int32_t rc; - uint16_t reg_data; - - rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_type); - if (rc < 0) { - S_I2C_DBG("%s read fail\n", __func__); - return rc; - } - S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", - __func__, addr, reg_data, mask); - - if (set_mask) - reg_data |= mask; - else - reg_data &= ~mask; - S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); - - rc = msm_camera_qup_i2c_write(client, addr, reg_data, data_type); - if (rc < 0) - S_I2C_DBG("%s write fail\n", __func__); - - return rc; -} - -static int32_t msm_camera_qup_i2c_set_write_mask_data( - struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, int16_t mask, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data; - - CDBG("%s\n", __func__); - if (mask == -1) - return 0; - if (mask == 0) { - rc = msm_camera_qup_i2c_write(client, addr, data, data_type); - } else { - rc = msm_camera_qup_i2c_read(client, addr, ®_data, - data_type); - if (rc < 0) { - CDBG("%s read fail\n", __func__); - return rc; - } - reg_data &= ~mask; - reg_data |= (data & mask); - rc = msm_camera_qup_i2c_write(client, addr, reg_data, - data_type); - if (rc < 0) - CDBG("%s write fail\n", __func__); - } - return rc; -} - - -int32_t msm_camera_qup_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type) -{ - int i; - int32_t rc = -EFAULT; - - pr_err("%s, E. ", __func__); - for (i = 0; i < size; i++) { - enum msm_camera_i2c_data_type dt; - - if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { - rc = msm_camera_qup_i2c_poll(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->dt, I2C_POLL_TIME_MS); - } else { - if (reg_conf_tbl->dt == 0) - dt = data_type; - else - dt = reg_conf_tbl->dt; - switch (dt) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - rc = msm_camera_qup_i2c_write( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, dt); - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: - rc = msm_camera_qup_i2c_set_write_mask_data( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->mask, - MSM_CAMERA_I2C_BYTE_DATA); - break; - default: - pr_err("%s: Unsupport data type: %d\n", - __func__, dt); - break; - } - } - if (rc < 0) - break; - reg_conf_tbl++; - } - return rc; -} - diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_spi.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_spi.c deleted file mode 100644 index 0975d12c389828171e42336c537d6d3c7cfdab16..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_spi.c +++ /dev/null @@ -1,851 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include "msm_camera_spi.h" - -#undef SPIDBG -#ifdef CONFIG_MSM_AIS_DEBUG -#define SPIDBG(fmt, args...) pr_debug(fmt, ##args) -#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define SPIDBG(fmt, args...) -#define S_I2C_DBG(fmt, args...) -#endif - -static int msm_camera_spi_txfr(struct spi_device *spi, char *txbuf, - char *rxbuf, int num_byte) -{ - struct spi_transfer t; - struct spi_message m; - - memset(&t, 0, sizeof(t)); - t.tx_buf = txbuf; - t.rx_buf = rxbuf; - t.len = num_byte; - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - return spi_sync(spi, &m); -} - -static int msm_camera_spi_txfr_read(struct spi_device *spi, char *txbuf, - char *rxbuf, int txlen, int rxlen) -{ - struct spi_transfer tx; - struct spi_transfer rx; - struct spi_message m; - - memset(&tx, 0, sizeof(tx)); - memset(&rx, 0, sizeof(rx)); - tx.tx_buf = txbuf; - rx.rx_buf = rxbuf; - tx.len = txlen; - rx.len = rxlen; - spi_message_init(&m); - spi_message_add_tail(&tx, &m); - spi_message_add_tail(&rx, &m); - return spi_sync(spi, &m); -} - - -/** - * msm_camera_set_addr() - helper function to set transfer address - * @addr: device address - * @addr_len: the addr field length of an instruction - * @type: type (i.e. byte-length) of @addr - * @str: shifted address output, must be zeroed when passed in - * - * This helper function sets @str based on the addr field length of an - * instruction and the data length. - */ -static void msm_camera_set_addr(uint32_t addr, uint8_t addr_len, - enum msm_camera_i2c_reg_addr_type type, - char *str) -{ - int i, len; - - if (!addr_len) - return; - - if (addr_len < type) - SPIDBG("%s: omitting higher bits in address\n", __func__); - - /* only support transfer MSB first for now */ - len = addr_len - type; - for (i = len; i < addr_len; i++) { - if (i >= 0) - str[i] = (addr >> (BITS_PER_BYTE * (addr_len - i - 1))) - & 0xFF; - } - -} - -/** - * msm_camera_spi_tx_helper() - wrapper for SPI transaction - * @client: io client - * @inst: inst of this transaction - * @addr: device addr following the inst - * @data: output byte array (could be NULL) - * @num_byte: size of @data - * @tx, rx: optional transfer buffer. It must be at least header - * + @num_byte long. - * - * This is the core function for SPI transaction, except for writes. It first - * checks address type, then allocates required memory for tx/rx buffers. - * It sends out , and optionally receives @num_byte of response, - * if @data is not NULL. This function does not check for wait conditions, - * and will return immediately once bus transaction finishes. - * - * This function will allocate buffers of header + @num_byte long. For - * large transfers, the allocation could fail. External buffer @tx, @rx - * should be passed in to bypass allocation. The size of buffer should be - * at least header + num_byte long. Since buffer is managed externally, - * @data will be ignored, and read results will be in @rx. - * @tx, @rx also can be used for repeated transfers to improve performance. - */ -int32_t msm_camera_spi_tx_helper(struct msm_camera_i2c_client *client, - struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data, - uint32_t num_byte, char *tx, char *rx) -{ - int32_t rc = -EINVAL; - struct spi_device *spi = client->spi_client->spi_master; - char *ctx = NULL, *crx = NULL; - uint32_t len, hlen; - uint8_t retries = client->spi_client->retries; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) - return rc; - - hlen = msm_camera_spi_get_hlen(inst); - len = hlen + num_byte; - - if (tx) - ctx = tx; - else - ctx = kzalloc(len, GFP_KERNEL | GFP_DMA); - if (!ctx) - return -ENOMEM; - - if (num_byte) { - if (rx) - crx = rx; - else - crx = kzalloc(len, GFP_KERNEL | GFP_DMA); - if (!crx) { - if (!tx) - kfree(ctx); - return -ENOMEM; - } - } else { - crx = NULL; - } - - ctx[0] = inst->opcode; - msm_camera_set_addr(addr, inst->addr_len, client->addr_type, ctx + 1); - while ((rc = msm_camera_spi_txfr(spi, ctx, crx, len)) && retries) { - retries--; - msleep(client->spi_client->retry_delay); - } - if (rc < 0) { - SPIDBG("%s: failed %d\n", __func__, rc); - goto out; - } - if (data && num_byte && !rx) - memcpy(data, crx + hlen, num_byte); - -out: - if (!tx) - kfree(ctx); - if (!rx) - kfree(crx); - return rc; -} - -int32_t msm_camera_spi_tx_read(struct msm_camera_i2c_client *client, - struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data, - uint32_t num_byte, char *tx, char *rx) -{ - int32_t rc = -EINVAL; - struct spi_device *spi = client->spi_client->spi_master; - char *ctx = NULL, *crx = NULL; - uint32_t hlen; - uint8_t retries = client->spi_client->retries; - - if ((client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) - return rc; - - hlen = msm_camera_spi_get_hlen(inst); - if (tx) - ctx = tx; - else - ctx = kzalloc(hlen, GFP_KERNEL | GFP_DMA); - if (!ctx) - return -ENOMEM; - if (num_byte) { - if (rx) - crx = rx; - else - crx = kzalloc(num_byte, GFP_KERNEL | GFP_DMA); - if (!crx) { - if (!tx) - kfree(ctx); - return -ENOMEM; - } - } else { - crx = NULL; - } - - ctx[0] = inst->opcode; - if (client->addr_type == MSM_CAMERA_I2C_3B_ADDR) { - msm_camera_set_addr(addr, inst->addr_len, client->addr_type, - ctx + 1); - } else { - ctx[1] = (addr >> BITS_PER_BYTE) & 0xFF; - ctx[2] = (addr & 0xFF); - ctx[3] = 0; - } - SPIDBG("%s: tx(%u): %02x %02x %02x %02x\n", __func__, - hlen, ctx[0], ctx[1], ctx[2], ctx[3]); - while ((rc = msm_camera_spi_txfr_read(spi, ctx, crx, hlen, num_byte)) - && retries) { - retries--; - msleep(client->spi_client->retry_delay); - } - if (rc < 0) { - pr_err("%s: failed %d\n", __func__, rc); - goto out; - } - if (data && num_byte && !rx) - memcpy(data, crx, num_byte); -out: - if (!tx) - kfree(ctx); - if (!rx) - kfree(crx); - return rc; -} - -int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EINVAL; - uint8_t temp[2]; - - if ((data_type != MSM_CAMERA_I2C_BYTE_DATA) - && (data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - rc = msm_camera_spi_tx_read(client, - &client->spi_client->cmd_tbl.read, addr, &temp[0], - data_type, NULL, NULL); - if (rc < 0) { - pr_err("%s: failed %d\n", __func__, rc); - return rc; - } - - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) - *data = temp[0]; - else - *data = (temp[0] << BITS_PER_BYTE) | temp[1]; - - SPIDBG("%s: addr 0x%x, data %u\n", __func__, addr, *data); - return rc; -} - -int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - return msm_camera_spi_tx_helper(client, - &client->spi_client->cmd_tbl.read_seq, addr, data, num_byte, - NULL, NULL); -} - -/** - * msm_camera_spi_read_seq_l()- function for large SPI reads - * @client: io client - * @addr: device address to read - * @num_byte: read length - * @tx,rx: pre-allocated SPI buffer. Its size must be at least - * header + num_byte - * - * This function is used for large transactions. Instead of allocating SPI - * buffer each time, caller is responsible for pre-allocating memory buffers. - * Memory buffer must be at least header + num_byte. Header length can be - * obtained by msm_camera_spi_get_hlen(). - */ -int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, - uint32_t addr, uint32_t num_byte, char *tx, char *rx) -{ - return msm_camera_spi_tx_helper(client, - &client->spi_client->cmd_tbl.read_seq, addr, NULL, num_byte, - tx, rx); -} - -int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - return msm_camera_spi_tx_helper(client, - &client->spi_client->cmd_tbl.query_id, addr, data, num_byte, - NULL, NULL); -} - -static int32_t msm_camera_spi_read_status_reg( - struct msm_camera_i2c_client *client, uint8_t *status) -{ - struct msm_camera_spi_inst *rs = - &client->spi_client->cmd_tbl.read_status; - - if (rs->addr_len != 0) { - pr_err("%s: not implemented yet\n", __func__); - return -EINVAL; - } - return msm_camera_spi_tx_helper(client, rs, 0, status, 1, NULL, NULL); -} - -static int32_t msm_camera_spi_device_busy(struct msm_camera_i2c_client *client, - uint8_t *busy) -{ - int rc; - uint8_t st = 0; - - rc = msm_camera_spi_read_status_reg(client, &st); - if (rc < 0) { - pr_err("%s: failed to read status reg\n", __func__); - return rc; - } - *busy = st & client->spi_client->busy_mask; - return 0; -} - -static int32_t msm_camera_spi_wait(struct msm_camera_i2c_client *client, - struct msm_camera_spi_inst *inst) -{ - uint8_t busy; - int i, rc; - - SPIDBG("%s: op 0x%x wait start\n", __func__, inst->opcode); - for (i = 0; i < inst->delay_count; i++) { - rc = msm_camera_spi_device_busy(client, &busy); - if (rc < 0) - return rc; - if (!busy) - break; - msleep(inst->delay_intv); - SPIDBG("%s: op 0x%x wait\n", __func__, inst->opcode); - } - if (i > inst->delay_count) { - pr_err("%s: op %x timed out\n", __func__, inst->opcode); - return -ETIMEDOUT; - } - SPIDBG("%s: op %x finished\n", __func__, inst->opcode); - return 0; -} - -static int32_t msm_camera_spi_write_enable( - struct msm_camera_i2c_client *client) -{ - struct msm_camera_spi_inst *we = - &client->spi_client->cmd_tbl.write_enable; - int rc; - - if (0 == we->opcode) - return 0; - if (we->addr_len != 0) { - pr_err("%s: not implemented yet\n", __func__); - return -EINVAL; - } - rc = msm_camera_spi_tx_helper(client, we, 0, NULL, 0, NULL, NULL); - if (rc < 0) - pr_err("%s: write enable failed\n", __func__); - return rc; -} - -int32_t msm_camera_spi_erase(struct msm_camera_i2c_client *client, - uint32_t addr, uint32_t size) -{ - struct msm_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase; - int rc = 0; - uint32_t cur; - uint32_t end = addr + size; - uint32_t erase_size = client->spi_client->erase_size; - - end = addr + size; - for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) { - SPIDBG("%s: erasing 0x%x\n", __func__, cur); - rc = msm_camera_spi_write_enable(client); - if (rc < 0) - return rc; - rc = msm_camera_spi_tx_helper(client, se, cur, NULL, 0, - NULL, NULL); - if (rc < 0) { - pr_err("%s: erase failed\n", __func__); - return rc; - } - rc = msm_camera_spi_wait(client, se); - if (rc < 0) { - pr_err("%s: erase timedout\n", __func__); - return rc; - } - } - return rc; -} - -/** - * msm_camera_spi_page_program() - core function to perform write - * @client: need for obtaining SPI device - * @addr: address to program on device - * @data: data to write - * @len: size of data - * @tx: tx buffer, size >= header + len - * - * This function performs SPI write, and has no boundary check. Writing range - * should not cross page boundary, or data will be corrupted. Transaction is - * guaranteed to be finished when it returns. This function should never be - * used outside msm_camera_spi_write_seq(). - */ -static int32_t msm_camera_spi_page_program(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint16_t len, uint8_t *tx) -{ - int rc; - struct msm_camera_spi_inst *pg = - &client->spi_client->cmd_tbl.page_program; - struct spi_device *spi = client->spi_client->spi_master; - uint8_t retries = client->spi_client->retries; - uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; - - SPIDBG("%s: addr 0x%x, size 0x%x\n", __func__, addr, len); - rc = msm_camera_spi_write_enable(client); - if (rc < 0) - return rc; - memset(tx, 0, header_len); - tx[0] = pg->opcode; - msm_camera_set_addr(addr, pg->addr_len, client->addr_type, tx + 1); - memcpy(tx + header_len, data, len); - SPIDBG("%s: tx(%u): %02x %02x %02x %02x\n", __func__, - len, tx[0], tx[1], tx[2], tx[3]); - while ((rc = spi_write(spi, tx, len + header_len)) && retries) { - rc = msm_camera_spi_wait(client, pg); - msleep(client->spi_client->retry_delay); - retries--; - } - if (rc < 0) { - pr_err("%s: failed %d\n", __func__, rc); - return rc; - } - rc = msm_camera_spi_wait(client, pg); - return rc; -} - -int32_t msm_camera_spi_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - struct msm_camera_spi_inst *pg = - &client->spi_client->cmd_tbl.page_program; - const uint32_t page_size = client->spi_client->page_size; - uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; - uint16_t len; - uint32_t cur_len, end; - char *tx, *pdata = data; - int rc = -EINVAL; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) - return rc; - /* single page write */ - if ((addr % page_size) + num_byte <= page_size) { - len = header_len + num_byte; - tx = kmalloc(len, GFP_KERNEL | GFP_DMA); - if (!tx) - goto NOMEM; - rc = msm_camera_spi_page_program(client, addr, data, - num_byte, tx); - if (rc < 0) - goto ERROR; - goto OUT; - } - /* multi page write */ - len = header_len + page_size; - tx = kmalloc(len, GFP_KERNEL | GFP_DMA); - if (!tx) - goto NOMEM; - while (num_byte) { - end = min(page_size, (addr % page_size) + num_byte); - cur_len = end - (addr % page_size); - rc = msm_camera_spi_page_program(client, addr, pdata, - cur_len, tx); - if (rc < 0) - goto ERROR; - addr += cur_len; - pdata += cur_len; - num_byte -= cur_len; - } - goto OUT; -NOMEM: - pr_err("%s: memory allocation failed\n", __func__); - return -ENOMEM; -ERROR: - pr_err("%s: error write\n", __func__); -OUT: - kfree(tx); - return rc; -} - -int32_t msm_camera_spi_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, enum msm_camera_i2c_data_type data_type) -{ - struct msm_camera_spi_inst *pg = - &client->spi_client->cmd_tbl.page_program; - uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; - uint16_t len = 0; - char buf[data_type]; - char *tx; - int rc = -EINVAL; - - if (((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - S_I2C_DBG("Data: 0x%x\n", data); - len = header_len + (uint8_t)data_type; - tx = kmalloc(len, GFP_KERNEL | GFP_DMA); - if (!tx) - goto NOMEM; - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) { - buf[0] = data; - SPIDBG("Byte %d: 0x%x\n", len, buf[0]); - } else if (data_type == MSM_CAMERA_I2C_WORD_DATA) { - buf[0] = (data >> BITS_PER_BYTE) & 0x00FF; - buf[1] = (data & 0x00FF); - } - rc = msm_camera_spi_page_program(client, addr, buf, - (uint16_t)data_type, tx); - if (rc < 0) - goto ERROR; - goto OUT; -NOMEM: - pr_err("%s: memory allocation failed\n", __func__); - return -ENOMEM; -ERROR: - pr_err("%s: error write\n", __func__); -OUT: - kfree(tx); - return rc; -} -int32_t msm_camera_spi_write_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_reg_array *reg_setting; - uint16_t client_addr_type; - - if (!client || !write_setting) - return rc; - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - reg_setting = write_setting->reg_setting; - client_addr_type = client->addr_type; - client->addr_type = write_setting->addr_type; - for (i = 0; i < write_setting->size; i++) { - SPIDBG("%s addr %x data %x\n", __func__, - reg_setting->reg_addr, reg_setting->reg_data); - rc = msm_camera_spi_write(client, reg_setting->reg_addr, - reg_setting->reg_data, write_setting->data_type); - if (rc < 0) - break; - reg_setting++; - } - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, - (write_setting->delay - * 1000) + 1000); - client->addr_type = client_addr_type; - return rc; -} -uint32_t msm_get_burst_size(struct msm_camera_i2c_reg_array *reg_setting, - uint32_t reg_size, uint32_t index, uint16_t burst_addr) -{ - uint32_t i; - uint32_t cnt = 0; - - for (i = index; i < reg_size; i++) { - if (reg_setting[i].reg_addr == burst_addr) - cnt++; - else - break; - } - return cnt; -} - -#ifdef SPI_DYNAMIC_ALLOC -int32_t msm_camera_spi_send_burst(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size, - struct msm_camera_burst_info *info, - enum msm_camera_i2c_data_type data_type) -{ - uint32_t i, j, k; - int32_t rc = 0; - uint32_t chunk_num, residue; - struct msm_camera_spi_inst *pg = - &client->spi_client->cmd_tbl.page_program; - uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; - uint8_t *ctx, *data; - uint32_t len; - - if (info->burst_len == 0 || info->chunk_size == 0) { - pr_err("%s:%d Invalid argument\n", __func__, __LINE__); - return rc; - } - if (info->burst_start + info->burst_len > reg_size) { - pr_err("%s too big burst size, index=%d, size=%d\n", __func__, - info->burst_start, info->burst_len); - return rc; - } - chunk_num = info->burst_len / info->chunk_size; - residue = info->burst_len % info->chunk_size; - SPIDBG("%s header_len=%d, chunk nb=%d, residue=%d\n", - __func__, header_len, chunk_num, residue); - len = info->chunk_size * data_type + header_len; - SPIDBG("buffer allocation size = %d\n", len); - ctx = kmalloc(len, GFP_KERNEL | GFP_DMA); - if (!ctx) { - pr_err("%s %d memory alloc fail!\n", __func__, __LINE__); - return rc; - } - ctx[0] = pg->opcode; - ctx[1] = (info->burst_addr >> 8) & 0xff; - ctx[2] = info->burst_addr & 0xff; - k = info->burst_start; - for (i = 0; i < chunk_num; i++) { - data = ctx + header_len; - for (j = 0; j < info->chunk_size; j++) { - *data++ = (reg_setting[k+j].reg_data >> 8) & 0xff; - *data++ = reg_setting[k+j].reg_data & 0xff; - } - rc = msm_camera_spi_txfr(client->spi_client->spi_master, - (void *) ctx, NULL, - info->chunk_size * data_type + header_len); - if (rc < 0) { - pr_err("%s %d spi sending error = %d!!\n", - __func__, __LINE__, rc); - goto fail; - } - k += info->chunk_size; - } - SPIDBG("%s burst chunk start=%d, residue=%d\n", - __func__, k, residue); - if (residue) { - data = ctx + header_len; - for (j = 0; j < residue; j++) { - *data++ = (reg_setting[k+j].reg_data >> 8) & 0xff; - *data++ = reg_setting[k+j].reg_data & 0xff; - } - rc = msm_camera_spi_txfr(client->spi_client->spi_master, - (void *)ctx, NULL, - residue*data_type+header_len); - if (rc < 0) { - pr_err("%s %d spi sending error = %d!!\n", __func__, - __LINE__, rc); - goto fail; - } - } -fail: - kfree(ctx); - return rc; -} -#else /* SPI_DYNAMIC_ALLOC */ -int32_t msm_camera_spi_send_burst(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size, - struct msm_camera_burst_info *info, - enum msm_camera_i2c_data_type data_type) -{ - uint32_t i, j, k; - int32_t rc = 0; - uint32_t chunk_num, residue; - struct msm_camera_spi_inst *pg = - &client->spi_client->cmd_tbl.page_program; - uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; - struct msm_spi_write_burst_packet tx_buf; - - if (info->burst_len == 0 || info->burst_len == 0 - || info->chunk_size == 0) { - pr_err("%s %d Invalid argument\n", __func__, __LINE__); - return rc; - } - if (info->burst_start + info->burst_len > reg_size) { - pr_err("%s too big burst size, index=%d, size=%d\n", __func__, - info->burst_start, info->burst_len); - return rc; - } - chunk_num = info->burst_len / info->chunk_size; - residue = info->burst_len % info->chunk_size; - SPIDBG("%s header_len=%d, chunk nb=%d, residue=%d\n", - __func__, header_len, chunk_num, residue); - tx_buf.cmd = pg->opcode; - tx_buf.addr_msb = (info->burst_addr >> 8) & 0xff; - tx_buf.addr_lsb = info->burst_addr & 0xff; - SPIDBG("%s cmd=%d, addr_msb=0x%x, addr_lsb=0x%x\n", __func__, - tx_buf.cmd, tx_buf.addr_msb, tx_buf.addr_lsb); - k = info->burst_start; - for (i = 0; i < chunk_num; i++) { - SPIDBG("%s burst chunk start=%d, chunk_size=%d, chunk_num=%d\n", - __func__, - k, info->chunk_size, i); - for (j = 0; j < info->chunk_size; j++) { - tx_buf.data_arr[j].data_msb = - (reg_setting[k+j].reg_data >> 8) & 0xff; - tx_buf.data_arr[j].data_lsb = - reg_setting[k+j].reg_data & 0xff; - } - rc = msm_camera_spi_txfr(client->spi_client->spi_master, - (void *)&tx_buf, NULL, - info->chunk_size * data_type+header_len); - if (rc < 0) { - pr_err("%s %d spi sending error = %d!!\n", __func__, - __LINE__, rc); - goto fail; - } - k += info->chunk_size; - } - SPIDBG("%s burst chunk start=%d, residue=%d\n", __func__, k, residue); - if (residue) { - for (j = 0; j < residue; j++) { - tx_buf.data_arr[j].data_msb = (reg_setting[k+j].reg_data - >> 8) & 0xff; - tx_buf.data_arr[j].data_lsb = reg_setting[k+j].reg_data - & 0xff; - } - rc = msm_camera_spi_txfr(client->spi_client->spi_master, - (void *)&tx_buf, NULL, - residue * data_type+header_len); - if (rc < 0) { - pr_err("%s %d spi sending error = %d!!\n", __func__, - __LINE__, rc); - goto fail; - } - } -fail: - return rc; -} -#endif /* SPI_DYNAMIC_ALLOC */ - -int32_t msm_camera_spi_write_burst(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size, - uint32_t buf_len, uint32_t burst_addr, - enum msm_camera_i2c_data_type data_type) -{ - int k = 0; - int32_t rc = -EFAULT; - struct msm_camera_burst_info burst_info; - - SPIDBG(" %s: start\n", __func__); - if (buf_len <= 0) { - pr_err("%s Invalid parameter, buf_len = %d\n", - __func__, buf_len); - return rc; - } - if (reg_size <= 0 || reg_setting == NULL) { - pr_err("%s Invalid parameter, array_size = %d\n", - __func__, reg_size); - return rc; - } - - if ((client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - SPIDBG(" %s: buf_len=%d, reg_size=%d\n", __func__, buf_len, reg_size); - while (k < reg_size) { - if (reg_setting[k].reg_addr == burst_addr) { - memset(&burst_info, 0x00, - sizeof(struct msm_camera_burst_info)); - burst_info.burst_addr = burst_addr; - burst_info.burst_start = k; - burst_info.chunk_size = buf_len; - burst_info.burst_len = - msm_get_burst_size(reg_setting, reg_size, k, - burst_addr); - SPIDBG("%s burst start = %d, length = %d\n", __func__, - k, burst_info.burst_len); - rc = msm_camera_spi_send_burst(client, reg_setting, - reg_size, &burst_info, data_type); - if (rc < 0) { - pr_err("[%s::%d][spi_sync Error::%d]\n", - __func__, __LINE__, rc); - return rc; - } - k += burst_info.burst_len; - } else { - SPIDBG("%s word write, start = %d\n", __func__, k); - msm_camera_spi_write(client, reg_setting[k].reg_addr, - reg_setting[k].reg_data, data_type); - k++; - } - } - SPIDBG("%s: end\n", __func__); - return rc; -} - -int32_t msm_camera_spi_read_burst(struct msm_camera_i2c_client *client, - uint32_t read_byte, uint8_t *buffer, uint32_t burst_addr, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - struct msm_camera_spi_inst *pg = - &client->spi_client->cmd_tbl.read; - uint32_t len = msm_camera_spi_get_hlen(pg); - uint8_t *tx_buf = NULL; - uint8_t *r = buffer; - - SPIDBG("%s: start\n", __func__); - - if (buffer == NULL || read_byte == 0 || len == 0) { - pr_err("%s %d Invalid parameters!!\n", __func__, __LINE__); - return rc; - } - - if ((client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - tx_buf = kzalloc(len, GFP_KERNEL | GFP_DMA); - if (!tx_buf) - return -ENOMEM; - - tx_buf[0] = pg->opcode; - tx_buf[1] = (burst_addr >> 8) & 0xff; - tx_buf[2] = burst_addr & 0xff; - tx_buf[3] = 0; /* dummy */ - rc = msm_camera_spi_txfr_read(client->spi_client->spi_master, - &tx_buf[0], r, len, read_byte); - if (rc < 0) - pr_err("[%s::%d][spi_sync Error::%d]\n", __func__, - __LINE__, rc); - - kfree(tx_buf); - - SPIDBG("%s: end\n", __func__); - return rc; -} diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_spi.h b/drivers/media/platform/msm/ais/sensor/io/msm_camera_spi.h deleted file mode 100644 index 28aa184ce6309a776be4164b55635ccd0cbb8985..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_spi.h +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __MSM_CAMERA_SPI_H -#define __MSM_CAMERA_SPI_H - -#include -#include -#include "msm_camera_i2c.h" - -#define MAX_SPI_SIZE 110 -#define SPI_DYNAMIC_ALLOC - -/** - * Common SPI communication scheme - * tx: [addr][wait][write buffer] - * rx: [read buffer] - * Some inst require polling busy reg until it's done - */ -struct msm_camera_spi_inst { - uint8_t opcode; /* one-byte opcode */ - uint8_t addr_len; /* addr len in bytes */ - uint8_t dummy_len; /* setup cycles */ - uint8_t delay_intv; /* delay intv for this inst (ms) */ - uint8_t delay_count; /* total delay count for this inst */ -}; - -struct msm_spi_write_burst_data { - u8 data_msb; - u8 data_lsb; -}; - -struct msm_spi_write_burst_packet { - u8 cmd; - u8 addr_msb; - u8 addr_lsb; - struct msm_spi_write_burst_data data_arr[MAX_SPI_SIZE]; -}; - -struct msm_camera_burst_info { - uint32_t burst_addr; - uint32_t burst_start; - uint32_t burst_len; - uint32_t chunk_size; -}; - -struct msm_camera_spi_inst_tbl { - struct msm_camera_spi_inst read; - struct msm_camera_spi_inst read_seq; - struct msm_camera_spi_inst query_id; - struct msm_camera_spi_inst page_program; - struct msm_camera_spi_inst write_enable; - struct msm_camera_spi_inst read_status; - struct msm_camera_spi_inst erase; -}; - -struct msm_camera_spi_client { - struct spi_device *spi_master; - struct msm_camera_spi_inst_tbl cmd_tbl; - uint8_t device_id0; - uint8_t device_id1; - uint8_t mfr_id0; - uint8_t mfr_id1; - uint8_t retry_delay; /* ms */ - uint8_t retries; /* retry times upon failure */ - uint8_t busy_mask; /* busy bit in status reg */ - uint16_t page_size; /* page size for page program */ - uint32_t erase_size; /* minimal erase size */ -}; - -static __always_inline -uint16_t msm_camera_spi_get_hlen(struct msm_camera_spi_inst *inst) -{ - return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len; -} - -int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, - uint32_t addr, uint32_t num_byte, char *tx, char *rx); - -int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_spi_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_spi_erase(struct msm_camera_i2c_client *client, - uint32_t addr, uint32_t size); - -int32_t msm_camera_spi_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_spi_write_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_spi_write_burst(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size, - uint32_t buf_len, uint32_t addr, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_spi_read_burst(struct msm_camera_i2c_client *client, - uint32_t read_byte, uint8_t *buffer, uint32_t addr, - enum msm_camera_i2c_data_type data_type); - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_tz_i2c.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_tz_i2c.c deleted file mode 100644 index 75589c176e22f5584517f66d3738197a44cc40ef..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_tz_i2c.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include "qseecom_kernel.h" -#include "msm_camera_i2c.h" -#include "msm_camera_io_util.h" -#include "msm_cci.h" -#include "msm_sensor.h" - -#define QSEECOM_SBUFF_SIZE SZ_128K -#define MAX_TA_NAME 32 -#define EMPTY_QSEECOM_HANDLE NULL - -#ifndef CONFIG_MSM_AIS_SEC_CCI_TA_NAME - #define CONFIG_MSM_AIS_SEC_CCI_TA_NAME "seccamdemo64" -#endif /* CONFIG_MSM_SEC_CCI_TA_NAME */ - -/* Update version major number in case the HLOS-TA interface is changed*/ -#define TA_IF_VERSION_MAJ 0 -#define TA_IF_VERSION_MIN 1 - -#undef CDBG -#ifdef CONFIG_MSM_AIS_SEC_CCI_DEBUG - -#define CDBG(fmt, args...) \ - pr_info(CONFIG_MSM_AIS_SEC_CCI_TA_NAME "::%s:%d - " fmt,\ - __func__, __LINE__, ##args) -#define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \ - ((ret < 0) ? i2c_fn(__VA_ARGS__):ret) - -#else /* CONFIG_MSM_AIS_SEC_CCI_DEBUG */ - -#define CDBG(fmt, args...) \ - pr_info("%s:%d - " fmt, __func__, __LINE__, ##args) -#define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \ - ((ret < 0) ? -EFAULT:ret) - -#endif /* CONFIG_MSM_AIS_SEC_CCI_DEBUG */ - -#pragma pack(push, msm_camera_tz_i2c, 1) - -enum msm_camera_tz_i2c_cmd_id_t { - TZ_I2C_CMD_GET_NONE, - TZ_I2C_CMD_GET_IF_VERSION, - TZ_I2C_CMD_POWER_UP, - TZ_I2C_CMD_POWER_DOWN, - TZ_I2C_CMD_CCI_GENERIC, - TZ_I2C_CMD_CCI_READ, - TZ_I2C_CMD_CCI_READ_SEQ, - TZ_I2C_CMD_CCI_WRITE, - TZ_I2C_CMD_CCI_WRITE_SEQ, - TZ_I2C_CMD_CCI_WRITE_TABLE_ASYNC, - TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC, - TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC_BLOCK, - TZ_I2C_CMD_CCI_WRITE_TABLE, - TZ_I2C_CMD_CCI_WRITE_SEQ_TABLE, - TZ_I2C_CMD_CCI_WRITE_TABLE_W_MICRODELAY, - TZ_I2C_CMD_CCI_POLL, - TZ_I2C_CMD_CCI_WRITE_CONF_TBL, - TZ_I2C_CMD_CCI_UTIL, -}; - -enum msm_camera_tz_i2c_status_t { - TZ_I2C_STATUS_SUCCESS = 0, - TZ_I2C_STATUS_GENERAL_FAILURE = -1, - TZ_I2C_STATUS_INVALID_INPUT_PARAMS = -2, - TZ_I2C_STATUS_INVALID_SENSOR_ID = -3, - TZ_I2C_STATUS_BYPASS = -4, - TZ_I2C_STATUS_ERR_SIZE = 0x7FFFFFFF -}; - -struct msm_camera_tz_i2c_generic_req_t { - enum msm_camera_tz_i2c_cmd_id_t cmd_id; -}; - -struct msm_camera_tz_i2c_generic_rsp_t { - enum msm_camera_tz_i2c_status_t rc; -}; - -#define msm_camera_tz_i2c_get_if_version_req_t msm_camera_tz_i2c_generic_req_t - -struct msm_camera_tz_i2c_get_if_version_rsp_t { - enum msm_camera_tz_i2c_status_t rc; - uint32_t if_version_maj; - uint32_t if_version_min; -}; - -struct msm_camera_tz_i2c_power_up_req_t { - enum msm_camera_tz_i2c_cmd_id_t cmd_id; - int32_t sensor_id; -}; - -#define msm_camera_tz_i2c_power_up_rsp_t msm_camera_tz_i2c_generic_rsp_t - -struct msm_camera_tz_i2c_power_down_req_t { - enum msm_camera_tz_i2c_cmd_id_t cmd_id; - int32_t sensor_id; -}; - -#define msm_camera_tz_i2c_power_down_rsp_t msm_camera_tz_i2c_generic_rsp_t - -struct msm_camera_tz_i2c_cci_generic_req_t { - enum msm_camera_tz_i2c_cmd_id_t cmd_id; - int32_t sensor_id; - enum msm_camera_tz_i2c_cmd_id_t cci_cmd_id; - uint32_t cci_i2c_master; - uint16_t sid; - uint16_t cid; -}; - -#define msm_camera_tz_i2c_cci_generic_rsp_t msm_camera_tz_i2c_generic_rsp_t - -struct msm_camera_tz_i2c_cci_read_req_t { - enum msm_camera_tz_i2c_cmd_id_t cmd_id; - int32_t sensor_id; - uint32_t cci_i2c_master; - uint16_t sid; - uint16_t cid; - uint32_t addr; - uint32_t data_type; -}; - -struct msm_camera_tz_i2c_cci_read_rsp_t { - enum msm_camera_tz_i2c_status_t rc; - uint16_t data; -}; - -struct msm_camera_tz_i2c_cci_write_req_t { - enum msm_camera_tz_i2c_cmd_id_t cmd_id; - int32_t sensor_id; - uint32_t cci_i2c_master; - uint16_t sid; - uint16_t cid; - uint32_t addr; - uint16_t data; - uint32_t data_type; -}; - -#define msm_camera_tz_i2c_cci_write_rsp_t msm_camera_tz_i2c_generic_rsp_t - -struct msm_camera_tz_i2c_cci_util_req_t { - enum msm_camera_tz_i2c_cmd_id_t cmd_id; - int32_t sensor_id; - uint32_t cci_i2c_master; - uint16_t sid; - uint16_t cid; - uint16_t cci_cmd; -}; - -#define msm_camera_tz_i2c_cci_util_rsp_t msm_camera_tz_i2c_generic_rsp_t - -#pragma pack(pop, msm_camera_tz_i2c) - -struct msm_camera_tz_i2c_sensor_info_t { - struct msm_sensor_ctrl_t *s_ctrl; - struct msm_camera_i2c_fn_t *saved_sensor_i2c_fn; - uint32_t secure; - uint32_t ta_enabled; - struct qseecom_handle *ta_qseecom_handle; - const char *ta_name; -}; - -struct msm_camera_tz_i2c_ctrl_t { - struct mutex lock; - uint32_t lock_ready; - uint32_t secure_mode; -}; - -static struct msm_camera_tz_i2c_ctrl_t msm_camera_tz_i2c_ctrl; - -static struct msm_camera_tz_i2c_sensor_info_t sensor_info[MAX_CAMERAS] = { - {NULL, NULL, 0, 0, NULL, CONFIG_MSM_AIS_SEC_CCI_TA_NAME}, - {NULL, NULL, 0, 0, NULL, CONFIG_MSM_AIS_SEC_CCI_TA_NAME}, - {NULL, NULL, 0, 0, NULL, CONFIG_MSM_AIS_SEC_CCI_TA_NAME}, - {NULL, NULL, 0, 0, NULL, CONFIG_MSM_AIS_SEC_CCI_TA_NAME}, -}; - -static int32_t msm_camera_tz_i2c_is_sensor_secure( - struct msm_camera_i2c_client *client) -{ - uint32_t index; - - if (client == NULL) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - CDBG("Enter\n"); - for (index = 0; index < MAX_CAMERAS; index++) { - if ((sensor_info[index].s_ctrl != NULL) && - sensor_info[index].secure && - (sensor_info[index].s_ctrl->sensor_i2c_client == - client)) { - CDBG("Found secure sensor ID = %d\n", - sensor_info[index].s_ctrl->id); - return sensor_info[index].s_ctrl->id; - } - } - return -EINVAL; -} - -static int32_t get_cmd_rsp_buffers( - struct qseecom_handle *ta_qseecom_handle, - void **cmd, int *cmd_len, - void **rsp, int *rsp_len) -{ - - CDBG("Enter\n"); - if ((ta_qseecom_handle == NULL) || - (cmd == NULL) || (cmd_len == NULL) || - (rsp == NULL) || (rsp_len == NULL)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - if (*cmd_len & QSEECOM_ALIGN_MASK) - *cmd_len = QSEECOM_ALIGN(*cmd_len); - - if (*rsp_len & QSEECOM_ALIGN_MASK) - *rsp_len = QSEECOM_ALIGN(*rsp_len); - - if ((*rsp_len + *cmd_len) > QSEECOM_SBUFF_SIZE) { - pr_err("%s:%d - Shared buffer too small to hold cmd=%d and rsp=%d\n", - __func__, __LINE__, - *cmd_len, *rsp_len); - return -ENOMEM; - } - - *cmd = ta_qseecom_handle->sbuf; - *rsp = ta_qseecom_handle->sbuf + *cmd_len; - return 0; -} - -static int32_t msm_camera_tz_i2c_ta_get_if_version( - struct qseecom_handle *ta_qseecom_handle, - uint32_t *if_version_maj, - uint32_t *if_version_min) -{ - int32_t cmd_len, rsp_len; - struct msm_camera_tz_i2c_get_if_version_req_t *cmd; - struct msm_camera_tz_i2c_get_if_version_rsp_t *rsp; - int32_t rc = 0; - - CDBG("Enter\n"); - if ((ta_qseecom_handle == NULL) || - (if_version_maj == NULL) || (if_version_min == NULL)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - cmd_len = sizeof(struct msm_camera_tz_i2c_get_if_version_req_t); - rsp_len = sizeof(struct msm_camera_tz_i2c_get_if_version_rsp_t); - - rc = get_cmd_rsp_buffers(ta_qseecom_handle, - (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); - if (!rc) { - cmd->cmd_id = TZ_I2C_CMD_GET_IF_VERSION; - - rc = qseecom_send_command(ta_qseecom_handle, - (void *)cmd, cmd_len, (void *)rsp, rsp_len); - - if (rc < 0) { - pr_err("%s:%d - Unable to get if version info, rc=%d\n", - __func__, __LINE__, - rc); - return rc; - } - - if (rsp->rc < 0) { - CDBG("TZ I2C App error, rc=%d\n", rsp->rc); - rc = -EFAULT; - } else { - *if_version_maj = rsp->if_version_maj; - *if_version_min = rsp->if_version_min; - CDBG("TZ I2C If version %d.%d\n", *if_version_maj, - *if_version_min); - } - } - return rc; -} - -static int32_t msm_camera_tz_i2c_ta_power_up( - struct qseecom_handle *ta_qseecom_handle, - int32_t sensor_id, - uint32_t *sensor_secure) -{ - int32_t cmd_len, rsp_len; - struct msm_camera_tz_i2c_power_up_req_t *cmd; - struct msm_camera_tz_i2c_power_up_rsp_t *rsp; - int32_t rc = 0; - - CDBG("Enter\n"); - - if (sensor_secure == NULL) - return -EINVAL; - - *sensor_secure = 0; - if ((ta_qseecom_handle == NULL) || - (sensor_secure == NULL) || - (sensor_id < 0) || - (sensor_id >= MAX_CAMERAS)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - cmd_len = sizeof(struct msm_camera_tz_i2c_power_up_req_t); - rsp_len = sizeof(struct msm_camera_tz_i2c_power_up_rsp_t); - - rc = get_cmd_rsp_buffers(ta_qseecom_handle, - (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); - if (!rc) { - cmd->cmd_id = TZ_I2C_CMD_POWER_UP; - cmd->sensor_id = sensor_id; - - rc = qseecom_send_command(ta_qseecom_handle, - (void *)cmd, cmd_len, (void *)rsp, rsp_len); - - if (rc < 0) { - pr_err("%s:%d - Unable to get sensor secure status, rc=%d\n", - __func__, __LINE__, - rc); - return rc; - } - - if (rsp->rc == TZ_I2C_STATUS_SUCCESS) - *sensor_secure = 1; - CDBG("Sensor %d is %s\n", sensor_id, - (*sensor_secure)?"SECURE":"NON-SECURE"); - } - return rc; -} - -static int32_t msm_camera_tz_i2c_ta_power_down( - struct qseecom_handle *ta_qseecom_handle, - int32_t sensor_id) -{ - int32_t cmd_len, rsp_len; - struct msm_camera_tz_i2c_power_down_req_t *cmd; - struct msm_camera_tz_i2c_power_down_rsp_t *rsp; - int32_t rc = 0; - - CDBG("Enter\n"); - - if ((ta_qseecom_handle == NULL) || - (sensor_id < 0) || - (sensor_id >= MAX_CAMERAS)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - cmd_len = sizeof(struct msm_camera_tz_i2c_power_down_req_t); - rsp_len = sizeof(struct msm_camera_tz_i2c_power_down_rsp_t); - - rc = get_cmd_rsp_buffers(ta_qseecom_handle, - (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); - if (!rc) { - cmd->cmd_id = TZ_I2C_CMD_POWER_DOWN; - cmd->sensor_id = sensor_id; - - rc = qseecom_send_command(ta_qseecom_handle, - (void *)cmd, cmd_len, (void *)rsp, rsp_len); - - if (rc < 0) { - pr_err("%s:%d - Failed: rc=%d\n", - __func__, __LINE__, - rc); - return rc; - } - } - return rc; -} - -static int32_t msm_camera_tz_i2c_ta_cci_generic( - struct msm_camera_i2c_client *client, - enum msm_camera_tz_i2c_cmd_id_t cci_cmd_id) -{ - int32_t cmd_len, rsp_len; - struct msm_camera_tz_i2c_cci_generic_req_t *cmd; - struct msm_camera_tz_i2c_cci_generic_rsp_t *rsp; - int32_t rc = 0; - struct qseecom_handle *ta_qseecom_handle; - int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); - - if ((client == NULL) || - (sensor_id < 0) || - (sensor_id >= MAX_CAMERAS)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, cci_cmd_id=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - cci_cmd_id); - - ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; - cmd_len = sizeof(struct msm_camera_tz_i2c_cci_generic_req_t); - rsp_len = sizeof(struct msm_camera_tz_i2c_cci_generic_rsp_t); - - rc = get_cmd_rsp_buffers(ta_qseecom_handle, - (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); - if (!rc) { - cmd->cmd_id = TZ_I2C_CMD_CCI_GENERIC; - cmd->sensor_id = sensor_id; - cmd->cci_cmd_id = cci_cmd_id; - cmd->cci_i2c_master = client->cci_client->cci_i2c_master; - cmd->sid = client->cci_client->sid; - cmd->cid = client->cci_client->cid; - - rc = qseecom_send_command(ta_qseecom_handle, - (void *)cmd, cmd_len, (void *)rsp, rsp_len); - - if (rc < 0) { - pr_err("%s:%d - Failed: rc=%d\n", - __func__, __LINE__, - rc); - return rc; - } - rc = rsp->rc; - CDBG("Done: rc=%d, cci_cmd_id=%d\n", rc, cci_cmd_id); - } - return rc; -} - -static int32_t msm_camera_tz_i2c_ta_cci_read( - struct msm_camera_i2c_client *client, - uint32_t addr, - uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t cmd_len, rsp_len; - struct msm_camera_tz_i2c_cci_read_req_t *cmd; - struct msm_camera_tz_i2c_cci_read_rsp_t *rsp; - int32_t rc = 0; - struct qseecom_handle *ta_qseecom_handle; - int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); - - if ((client == NULL) || - (data == NULL) || - (sensor_id < 0) || - (sensor_id >= MAX_CAMERAS)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, Addr=0x%X, Type=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - addr, - data_type); - - ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; - cmd_len = sizeof(struct msm_camera_tz_i2c_cci_read_req_t); - rsp_len = sizeof(struct msm_camera_tz_i2c_cci_read_rsp_t); - - rc = get_cmd_rsp_buffers(ta_qseecom_handle, - (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); - if (!rc) { - cmd->cmd_id = TZ_I2C_CMD_CCI_READ; - cmd->sensor_id = sensor_id; - cmd->cci_i2c_master = client->cci_client->cci_i2c_master; - cmd->sid = client->cci_client->sid; - cmd->cid = client->cci_client->cid; - cmd->addr = addr; - cmd->data_type = data_type; - - rc = qseecom_send_command(ta_qseecom_handle, - (void *)cmd, cmd_len, (void *)rsp, rsp_len); - - if (rc < 0) { - pr_err("%s:%d - Failed: rc=%d\n", - __func__, __LINE__, - rc); - return rc; - } - rc = rsp->rc; - *data = rsp->data; - - CDBG("Done: rc=%d, addr=0x%X, data=0x%X\n", rc, - addr, *data); - } - return rc; -} - -static int32_t msm_camera_tz_i2c_ta_cci_write( - struct msm_camera_i2c_client *client, - uint32_t addr, - uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t cmd_len, rsp_len; - struct msm_camera_tz_i2c_cci_write_req_t *cmd; - struct msm_camera_tz_i2c_cci_write_rsp_t *rsp; - int32_t rc = 0; - struct qseecom_handle *ta_qseecom_handle; - int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); - - if ((client == NULL) || - (sensor_id < 0) || - (sensor_id >= MAX_CAMERAS)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, Addr=0x%X, Data=0x%X Type=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - addr, - data, - data_type); - - ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; - cmd_len = sizeof(struct msm_camera_tz_i2c_cci_write_req_t); - rsp_len = sizeof(struct msm_camera_tz_i2c_cci_write_rsp_t); - - rc = get_cmd_rsp_buffers(ta_qseecom_handle, - (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); - if (!rc) { - cmd->cmd_id = TZ_I2C_CMD_CCI_WRITE; - cmd->sensor_id = sensor_id; - cmd->cci_i2c_master = client->cci_client->cci_i2c_master; - cmd->sid = client->cci_client->sid; - cmd->cid = client->cci_client->cid; - cmd->addr = addr; - cmd->data = data; - cmd->data_type = data_type; - - rc = qseecom_send_command(ta_qseecom_handle, - (void *)cmd, cmd_len, (void *)rsp, rsp_len); - - if (rc < 0) { - pr_err("%s:%d - Failed:, rc=%d\n", - __func__, __LINE__, - rc); - return rc; - } - rc = rsp->rc; - - CDBG("Done: rc=%d, addr=0x%X, data=0x%X\n", rc, - addr, data); - } - return rc; -} - -static int32_t msm_camera_tz_i2c_ta_cci_util( - struct msm_camera_i2c_client *client, - uint16_t cci_cmd) -{ - int32_t cmd_len, rsp_len; - struct msm_camera_tz_i2c_cci_util_req_t *cmd; - struct msm_camera_tz_i2c_cci_util_rsp_t *rsp; - int32_t rc = 0; - struct qseecom_handle *ta_qseecom_handle; - int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); - - if ((client == NULL) || - (sensor_id < 0) || - (sensor_id >= MAX_CAMERAS)) { - pr_err("%s:%d - Bad parameters\n", - __func__, __LINE__); - return -EINVAL; - } - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, cci_cmd=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - cci_cmd); - - ta_qseecom_handle = sensor_info[sensor_id].ta_qseecom_handle; - cmd_len = sizeof(struct msm_camera_tz_i2c_cci_util_req_t); - rsp_len = sizeof(struct msm_camera_tz_i2c_cci_util_rsp_t); - - rc = get_cmd_rsp_buffers(ta_qseecom_handle, - (void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len); - if (!rc) { - cmd->cmd_id = TZ_I2C_CMD_CCI_UTIL; - cmd->sensor_id = sensor_id; - cmd->cci_i2c_master = client->cci_client->cci_i2c_master; - cmd->sid = client->cci_client->sid; - cmd->cid = client->cci_client->cid; - cmd->cci_cmd = cci_cmd; - - rc = qseecom_send_command(ta_qseecom_handle, - (void *)cmd, cmd_len, (void *)rsp, rsp_len); - - if (rc < 0) { - pr_err("%s:%d - Failed: rc=%d\n", - __func__, __LINE__, - rc); - return rc; - } - rc = rsp->rc; - CDBG("Done: rc=%d, cci_cmd=%d\n", rc, cci_cmd); - } - return rc; -} - -static int32_t msm_camera_tz_i2c_ta_probe( - struct msm_camera_i2c_client *client) -{ - int32_t sensor_id = -1; - - CDBG("Enter\n"); - sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); - if ((sensor_id >= 0) && sensor_info[sensor_id].ta_enabled - && msm_camera_tz_i2c_ctrl.lock_ready) { - mutex_lock(&msm_camera_tz_i2c_ctrl.lock); - return sensor_id; - } - return -EINVAL; -} - -static int32_t msm_camera_tz_i2c_ta_done(void) -{ - int32_t rc = 0; - - CDBG("Enter\n"); - if (msm_camera_tz_i2c_ctrl.lock_ready) - mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); - return rc; -} - -int32_t msm_camera_tz_i2c_power_up( - struct msm_camera_i2c_client *client) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); - - if (!msm_camera_tz_i2c_ctrl.lock_ready) { - msm_camera_tz_i2c_ctrl.lock_ready = 1; - mutex_init(&msm_camera_tz_i2c_ctrl.lock); - } - - CDBG("Enter (sensor_id=%d)\n", sensor_id); - if (sensor_id >= 0) { - ktime_t startTime; - - mutex_lock(&msm_camera_tz_i2c_ctrl.lock); - if (msm_camera_tz_i2c_ctrl.secure_mode) { - mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); - return rc; - } - startTime = ktime_get(); - - CDBG("Switch to secure mode (secure sensor=%d)\n", - sensor_id); - /* Start the TA */ - if ((sensor_info[sensor_id].ta_qseecom_handle == NULL) - && (sensor_info[sensor_id].ta_name != NULL) && - ('\0' != sensor_info[sensor_id].ta_name[0])) { - uint32_t if_version_maj = 0; - uint32_t if_version_min = 0; - - sensor_info[sensor_id].ta_enabled = 0; - rc = qseecom_start_app( - &sensor_info[sensor_id].ta_qseecom_handle, - (char *)sensor_info[sensor_id].ta_name, - QSEECOM_SBUFF_SIZE); - if (!rc) { - rc = msm_camera_tz_i2c_ta_get_if_version( - sensor_info[sensor_id]. - ta_qseecom_handle, - &if_version_maj, &if_version_min); - } - - if (!rc) { - if (if_version_maj != TA_IF_VERSION_MAJ) { - CDBG("TA ver mismatch %d.%d != %d.%d\n", - if_version_maj, if_version_min, - TA_IF_VERSION_MAJ, - TA_IF_VERSION_MIN); - rc = qseecom_shutdown_app( - &sensor_info[sensor_id]. - ta_qseecom_handle); - sensor_info[sensor_id].ta_qseecom_handle - = EMPTY_QSEECOM_HANDLE; - rc = -EFAULT; - } else { - uint32_t sensor_secure = 0; - /* Notify TA */ - /* Get sensor secure status */ - rc = msm_camera_tz_i2c_ta_power_up( - sensor_info[sensor_id]. - ta_qseecom_handle, - sensor_id, - &sensor_secure); - if (!rc && sensor_secure) - /* Sensor validated by TA*/ - sensor_info[sensor_id]. - ta_enabled = 1; - else { - qseecom_shutdown_app( - &sensor_info[sensor_id]. - ta_qseecom_handle); - sensor_info[sensor_id]. - ta_qseecom_handle - = EMPTY_QSEECOM_HANDLE; - rc = -EFAULT; - } - } - } - } - CDBG("Init TA %s - %s(%d) - %llu\n", - sensor_info[sensor_id].ta_name, - (sensor_info[sensor_id].ta_enabled)?"Ok" : - "Failed", rc, ktime_us_delta(ktime_get(), - startTime)); - if (!rc) - msm_camera_tz_i2c_ctrl.secure_mode++; - mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); - } - return rc; -} - -int32_t msm_camera_tz_i2c_power_down( - struct msm_camera_i2c_client *client) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client); - - if (!msm_camera_tz_i2c_ctrl.lock_ready) { - msm_camera_tz_i2c_ctrl.lock_ready = 1; - mutex_init(&msm_camera_tz_i2c_ctrl.lock); - } - - CDBG("Enter (sensor_id=%d)\n", sensor_id); - if ((sensor_id >= 0) && (msm_camera_tz_i2c_ctrl.secure_mode != 0)) { - mutex_lock(&msm_camera_tz_i2c_ctrl.lock); - if (msm_camera_tz_i2c_ctrl.secure_mode == 1) { - ktime_t startTime = ktime_get(); - - CDBG("Switch to non-secure mode (secure sensor=%d)\n", - sensor_id); - /* Shutdown the TA */ - if (sensor_info[sensor_id].ta_qseecom_handle != NULL) { - msm_camera_tz_i2c_ta_power_down( - sensor_info[sensor_id]. - ta_qseecom_handle, - sensor_id); - rc = qseecom_shutdown_app(&sensor_info[ - sensor_id].ta_qseecom_handle); - sensor_info[sensor_id].ta_qseecom_handle - = EMPTY_QSEECOM_HANDLE; - } - CDBG("Unload TA %s - %s(%d) - %llu\n", - sensor_info[sensor_id].ta_name, - (!rc)?"Ok":"Failed", rc, - ktime_us_delta(ktime_get(), startTime)); - } - msm_camera_tz_i2c_ctrl.secure_mode--; - mutex_unlock(&msm_camera_tz_i2c_ctrl.lock); - } - return rc; -} - -int32_t msm_camera_tz_i2c_register_sensor( - void *s_ctrl_p) -{ - struct msm_sensor_ctrl_t *s_ctrl = (struct msm_sensor_ctrl_t *)s_ctrl_p; - - if (s_ctrl == NULL) { - pr_err("%s:%d - invalid parameter)\n", - __func__, __LINE__); - return -EINVAL; - } - if (s_ctrl->id >= MAX_CAMERAS) { - pr_err("%s:%d - invalid ID: %d\n", - __func__, __LINE__, s_ctrl->id); - return -EINVAL; - } - - CDBG("id=%d, client=%pK\n", s_ctrl->id, s_ctrl); - sensor_info[s_ctrl->id].s_ctrl = s_ctrl; - sensor_info[s_ctrl->id].secure = s_ctrl->is_secure; - return 0; -} - -int32_t msm_camera_tz_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - addr); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_read( - client, addr, data, data_type); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_read, client, addr, data, data_type); -} - -int32_t msm_camera_tz_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X, num=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - addr, - num_byte); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_READ_SEQ); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_read_seq, client, addr, data, num_byte); -} - -int32_t msm_camera_tz_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - addr); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_write( - client, addr, data, data_type); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write, client, addr, data, data_type); -} - -int32_t msm_camera_tz_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X, num=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, - addr, - num_byte); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_SEQ); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_seq, client, addr, data, num_byte); -} - -int32_t msm_camera_tz_i2c_write_table_async( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_TABLE_ASYNC); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_table_async, client, write_setting); -} - -int32_t msm_camera_tz_i2c_write_table_sync( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_table_sync, client, write_setting); -} - -int32_t msm_camera_tz_i2c_write_table_sync_block( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_TABLE_SYNC_BLOCK); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_table_sync_block, client, - write_setting); -} - -int32_t msm_camera_tz_i2c_write_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_TABLE); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_table, client, write_setting); -} - -int32_t msm_camera_tz_i2c_write_seq_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_SEQ_TABLE); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_seq_table, client, write_setting); -} - -int32_t msm_camera_tz_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_TABLE_W_MICRODELAY); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_table_w_microdelay, client, - write_setting); -} - -int32_t msm_camera_tz_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_POLL); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_poll, client, addr, data, data_type); -} - -int32_t msm_camera_tz_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_generic( - client, TZ_I2C_CMD_CCI_WRITE_CONF_TBL); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_camera_cci_i2c_write_conf_tbl, client, reg_conf_tbl, size, - data_type); -} - -int32_t msm_sensor_tz_i2c_util(struct msm_camera_i2c_client *client, - uint16_t cci_cmd) -{ - int32_t rc = -EFAULT; - int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client); - - CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, cci_cmd=%d\n", - sensor_id, - client->cci_client->cci_i2c_master, - client->cci_client->sid, - client->cci_client->cid, cci_cmd); - - if (sensor_id >= 0) { - rc = msm_camera_tz_i2c_ta_cci_util(client, cci_cmd); - msm_camera_tz_i2c_ta_done(); - } - return TZ_I2C_FN_RETURN(rc, - msm_sensor_cci_i2c_util, client, cci_cmd); -} diff --git a/drivers/media/platform/msm/ais/sensor/ir_cut/Makefile b/drivers/media/platform/msm/ais/sensor/ir_cut/Makefile deleted file mode 100644 index 32ce6226088a06332d8b23e21ae4aad89a07841c..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ir_cut/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_ir_cut.o diff --git a/drivers/media/platform/msm/ais/sensor/ir_cut/msm_ir_cut.c b/drivers/media/platform/msm/ais/sensor/ir_cut/msm_ir_cut.c deleted file mode 100644 index 4a7faccbaea8933e189c9b7843284d9b3d5e4112..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ir_cut/msm_ir_cut.c +++ /dev/null @@ -1,662 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - * - */ - -#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ - -#include -#include -#include "msm_ir_cut.h" -#include "msm_camera_dt_util.h" - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -DEFINE_MSM_MUTEX(msm_ir_cut_mutex); - -static struct v4l2_file_operations msm_ir_cut_v4l2_subdev_fops; - -static const struct of_device_id msm_ir_cut_dt_match[] = { - {.compatible = "qcom,ir-cut", .data = NULL}, - {} -}; - -static struct msm_ir_cut_table msm_gpio_ir_cut_table; - -static struct msm_ir_cut_table *ir_cut_table[] = { - &msm_gpio_ir_cut_table, -}; - -static int32_t msm_ir_cut_get_subdev_id( - struct msm_ir_cut_ctrl_t *ir_cut_ctrl, void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - - CDBG("Enter\n"); - if (!subdev_id) { - pr_err("failed\n"); - return -EINVAL; - } - if (MSM_CAMERA_PLATFORM_DEVICE != ir_cut_ctrl->ir_cut_device_type) { - pr_err("failed\n"); - return -EINVAL; - } - - *subdev_id = ir_cut_ctrl->pdev->id; - - CDBG("subdev_id %d\n", *subdev_id); - CDBG("Exit\n"); - return 0; -} - -static int32_t msm_ir_cut_init( - struct msm_ir_cut_ctrl_t *ir_cut_ctrl, - struct msm_ir_cut_cfg_data_t *ir_cut_data) -{ - int32_t rc = 0; - - CDBG("Enter"); - - rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on(ir_cut_ctrl, ir_cut_data); - - CDBG("Exit"); - return rc; -} - -static int32_t msm_ir_cut_release( - struct msm_ir_cut_ctrl_t *ir_cut_ctrl) -{ - int32_t rc = 0; - - if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_RELEASE) { - pr_err("%s:%d Invalid ir_cut state = %d", - __func__, __LINE__, ir_cut_ctrl->ir_cut_state); - return 0; - } - - if (rc < 0) { - pr_err("%s:%d camera_ir_cut_on failed rc = %d", - __func__, __LINE__, rc); - return rc; - } - ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_RELEASE; - return 0; -} - -static int32_t msm_ir_cut_off(struct msm_ir_cut_ctrl_t *ir_cut_ctrl, - struct msm_ir_cut_cfg_data_t *ir_cut_data) -{ - int rc = 0; - - CDBG("Enter cut off\n"); - - if (ir_cut_ctrl->gconf) { - rc = msm_camera_request_gpio_table( - ir_cut_ctrl->gconf->cam_gpio_req_tbl, - ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 1); - - if (rc < 0) { - pr_err("ERR:%s:Failed in selecting state: %d\n", - __func__, rc); - - return rc; - } - } else { - pr_err("%s: No IR CUT GPIOs\n", __func__); - return 0; - } - - if (ir_cut_ctrl->cam_pinctrl_status) { - rc = pinctrl_select_state( - ir_cut_ctrl->pinctrl_info.pinctrl, - ir_cut_ctrl->pinctrl_info.gpio_state_active); - - if (rc < 0) - pr_err("ERR:%s:%d cannot set pin to active state: %d", - __func__, __LINE__, rc); - } - - CDBG("ERR:%s:gpio_conf->gpio_num_info->gpio_num[0] = %d", - __func__, - ir_cut_ctrl->gconf->gpio_num_info-> - gpio_num[IR_CUT_FILTER_GPIO_P]); - - CDBG("ERR:%s:gpio_conf->gpio_num_info->gpio_num[1] = %d", - __func__, - ir_cut_ctrl->gconf->gpio_num_info-> - gpio_num[IR_CUT_FILTER_GPIO_M]); - - gpio_set_value_cansleep( - ir_cut_ctrl->gconf->gpio_num_info-> - gpio_num[IR_CUT_FILTER_GPIO_P], - 0); - - gpio_set_value_cansleep( - ir_cut_ctrl->gconf->gpio_num_info-> - gpio_num[IR_CUT_FILTER_GPIO_M], - 1); - - if (ir_cut_ctrl->gconf) { - rc = msm_camera_request_gpio_table( - ir_cut_ctrl->gconf->cam_gpio_req_tbl, - ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 0); - - if (rc < 0) { - pr_err("ERR:%s:Failed in selecting state: %d\n", - __func__, rc); - - return rc; - } - } else { - pr_err("%s: No IR CUT GPIOs\n", __func__); - return 0; - } - - CDBG("Exit\n"); - return 0; -} - -static int32_t msm_ir_cut_on( - struct msm_ir_cut_ctrl_t *ir_cut_ctrl, - struct msm_ir_cut_cfg_data_t *ir_cut_data) -{ - int rc = 0; - - CDBG("Enter ir cut on\n"); - - if (ir_cut_ctrl->gconf) { - rc = msm_camera_request_gpio_table( - ir_cut_ctrl->gconf->cam_gpio_req_tbl, - ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 1); - - if (rc < 0) { - pr_err("ERR:%s:Failed in selecting state: %d\n", - __func__, rc); - - return rc; - } - } else { - pr_err("%s: No IR CUT GPIOs\n", __func__); - return 0; - } - - if (ir_cut_ctrl->cam_pinctrl_status) { - rc = pinctrl_select_state( - ir_cut_ctrl->pinctrl_info.pinctrl, - ir_cut_ctrl->pinctrl_info.gpio_state_active); - - if (rc < 0) - pr_err("ERR:%s:%d cannot set pin to active state: %d", - __func__, __LINE__, rc); - } - - CDBG("ERR:%s: gpio_conf->gpio_num_info->gpio_num[0] = %d", - __func__, - ir_cut_ctrl->gconf->gpio_num_info-> - gpio_num[IR_CUT_FILTER_GPIO_P]); - - CDBG("ERR:%s: gpio_conf->gpio_num_info->gpio_num[1] = %d", - __func__, - ir_cut_ctrl->gconf->gpio_num_info-> - gpio_num[IR_CUT_FILTER_GPIO_M]); - - gpio_set_value_cansleep( - ir_cut_ctrl->gconf->gpio_num_info-> - gpio_num[IR_CUT_FILTER_GPIO_P], - 1); - - gpio_set_value_cansleep( - ir_cut_ctrl->gconf-> - gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M], - 1); - - if (ir_cut_ctrl->gconf) { - rc = msm_camera_request_gpio_table( - ir_cut_ctrl->gconf->cam_gpio_req_tbl, - ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 0); - - if (rc < 0) { - pr_err("ERR:%s:Failed in selecting state: %d\n", - __func__, rc); - - return rc; - } - } else { - pr_err("%s: No IR CUT GPIOs\n", __func__); - return 0; - } - CDBG("Exit\n"); - return 0; -} - -static int32_t msm_ir_cut_handle_init( - struct msm_ir_cut_ctrl_t *ir_cut_ctrl, - struct msm_ir_cut_cfg_data_t *ir_cut_data) -{ - uint32_t i = 0; - int32_t rc = -EFAULT; - enum msm_ir_cut_driver_type ir_cut_driver_type = - ir_cut_ctrl->ir_cut_driver_type; - - CDBG("Enter"); - - if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT) { - pr_err("%s:%d Invalid ir_cut state = %d", - __func__, __LINE__, ir_cut_ctrl->ir_cut_state); - return 0; - } - - for (i = 0; i < ARRAY_SIZE(ir_cut_table); i++) { - if (ir_cut_driver_type == ir_cut_table[i]->ir_cut_driver_type) { - ir_cut_ctrl->func_tbl = &ir_cut_table[i]->func_tbl; - rc = 0; - break; - } - } - - if (rc < 0) { - pr_err("%s:%d failed invalid ir_cut_driver_type %d\n", - __func__, __LINE__, ir_cut_driver_type); - return -EINVAL; - } - - if (rc < 0) { - pr_err("%s:%d camera_ir_cut_init failed rc = %d", - __func__, __LINE__, rc); - return rc; - } - - ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_INIT; - - CDBG("Exit"); - return 0; -} - -static int32_t msm_ir_cut_config(struct msm_ir_cut_ctrl_t *ir_cut_ctrl, - void __user *argp) -{ - int32_t rc = -EINVAL; - struct msm_ir_cut_cfg_data_t *ir_cut_data = - (struct msm_ir_cut_cfg_data_t *) argp; - - mutex_lock(ir_cut_ctrl->ir_cut_mutex); - - CDBG("Enter %s type %d\n", __func__, ir_cut_data->cfg_type); - - switch (ir_cut_data->cfg_type) { - case CFG_IR_CUT_INIT: - rc = msm_ir_cut_handle_init(ir_cut_ctrl, ir_cut_data); - break; - case CFG_IR_CUT_RELEASE: - if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT) - rc = ir_cut_ctrl->func_tbl->camera_ir_cut_release( - ir_cut_ctrl); - break; - case CFG_IR_CUT_OFF: - if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT) - rc = ir_cut_ctrl->func_tbl->camera_ir_cut_off( - ir_cut_ctrl, ir_cut_data); - break; - case CFG_IR_CUT_ON: - if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT) - rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on( - ir_cut_ctrl, ir_cut_data); - break; - default: - rc = -EFAULT; - break; - } - - mutex_unlock(ir_cut_ctrl->ir_cut_mutex); - - CDBG("Exit %s type %d\n", __func__, ir_cut_data->cfg_type); - - return rc; -} - -static long msm_ir_cut_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_ir_cut_ctrl_t *fctrl = NULL; - void __user *argp = (void __user *)arg; - - CDBG("Enter\n"); - - if (!sd) { - pr_err("sd NULL\n"); - return -EINVAL; - } - fctrl = v4l2_get_subdevdata(sd); - if (!fctrl) { - pr_err("fctrl NULL\n"); - return -EINVAL; - } - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return msm_ir_cut_get_subdev_id(fctrl, argp); - case VIDIOC_MSM_IR_CUT_CFG: - return msm_ir_cut_config(fctrl, argp); - case MSM_SD_NOTIFY_FREEZE: - return 0; - case MSM_SD_SHUTDOWN: - if (!fctrl->func_tbl) { - pr_err("fctrl->func_tbl NULL\n"); - return -EINVAL; - } else { - return fctrl->func_tbl->camera_ir_cut_release(fctrl); - } - default: - pr_err_ratelimited("invalid cmd %d\n", cmd); - return -ENOIOCTLCMD; - } - CDBG("Exit\n"); -} - -static struct v4l2_subdev_core_ops msm_ir_cut_subdev_core_ops = { - .ioctl = msm_ir_cut_subdev_ioctl, -}; - -static struct v4l2_subdev_ops msm_ir_cut_subdev_ops = { - .core = &msm_ir_cut_subdev_core_ops, -}; -static int msm_ir_cut_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) { - - int rc = 0; - struct msm_ir_cut_ctrl_t *ir_cut_ctrl = v4l2_get_subdevdata(sd); - - CDBG("Enter\n"); - - if (!ir_cut_ctrl) { - pr_err("%s: failed\n", __func__); - return -EINVAL; - } - - if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT) - rc = ir_cut_ctrl->func_tbl->camera_ir_cut_release( - ir_cut_ctrl); - - CDBG("Exit\n"); - - return rc; -}; - -static const struct v4l2_subdev_internal_ops msm_ir_cut_internal_ops = { - .close = msm_ir_cut_close, -}; - -static int32_t msm_ir_cut_get_gpio_dt_data(struct device_node *of_node, - struct msm_ir_cut_ctrl_t *fctrl) -{ - int32_t rc = 0, i = 0; - uint16_t *gpio_array = NULL; - int16_t gpio_array_size = 0; - struct msm_camera_gpio_conf *gconf = NULL; - - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size > 0) { - fctrl->power_info.gpio_conf = - kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!fctrl->power_info.gpio_conf) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - gconf = fctrl->power_info.gpio_conf; - - gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), - GFP_KERNEL); - if (!gpio_array) - return -ENOMEM; - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - if (((int16_t)gpio_array[i]) < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -EINVAL; - goto free_gpio_array; - } - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto free_gpio_array; - } - kfree(gpio_array); - - if (fctrl->ir_cut_driver_type == IR_CUT_DRIVER_DEFAULT) - fctrl->ir_cut_driver_type = IR_CUT_DRIVER_GPIO; - CDBG("%s:%d fctrl->ir_cut_driver_type = %d", __func__, __LINE__, - fctrl->ir_cut_driver_type); - } - - return rc; - -free_gpio_array: - kfree(gpio_array); - return rc; -} - -static int32_t msm_ir_cut_get_dt_data(struct device_node *of_node, - struct msm_ir_cut_ctrl_t *fctrl) -{ - int32_t rc = 0; - - CDBG("called\n"); - - if (!of_node) { - pr_err("of_node NULL\n"); - return -EINVAL; - } - - /* Read the sub device */ - rc = of_property_read_u32(of_node, "cell-index", &fctrl->pdev->id); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - return rc; - } - - fctrl->ir_cut_driver_type = IR_CUT_DRIVER_DEFAULT; - - /* Read the gpio information from device tree */ - rc = msm_ir_cut_get_gpio_dt_data(of_node, fctrl); - if (rc < 0) { - pr_err("%s:%d msm_ir_cut_get_gpio_dt_data failed rc %d\n", - __func__, __LINE__, rc); - return rc; - } - - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_ir_cut_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - int32_t rc = 0; - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct msm_ir_cut_cfg_data_t32 *u32 = - (struct msm_ir_cut_cfg_data_t32 *)arg; - struct msm_ir_cut_cfg_data_t ir_cut_data; - - CDBG("Enter"); - ir_cut_data.cfg_type = u32->cfg_type; - - switch (cmd) { - case VIDIOC_MSM_IR_CUT_CFG32: - cmd = VIDIOC_MSM_IR_CUT_CFG; - break; - default: - return msm_ir_cut_subdev_ioctl(sd, cmd, arg); - } - - rc = msm_ir_cut_subdev_ioctl(sd, cmd, &ir_cut_data); - - CDBG("Exit"); - return rc; -} - -static long msm_ir_cut_subdev_fops_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_ir_cut_subdev_do_ioctl); -} -#endif - -static int32_t msm_ir_cut_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0, i = 0; - struct msm_ir_cut_ctrl_t *ir_cut_ctrl = NULL; - - CDBG("Enter"); - if (!pdev->dev.of_node) { - pr_err("of_node NULL\n"); - return -EINVAL; - } - - ir_cut_ctrl = kzalloc(sizeof(struct msm_ir_cut_ctrl_t), GFP_KERNEL); - if (!ir_cut_ctrl) - return -ENOMEM; - - memset(ir_cut_ctrl, 0, sizeof(struct msm_ir_cut_ctrl_t)); - - ir_cut_ctrl->pdev = pdev; - - rc = msm_ir_cut_get_dt_data(pdev->dev.of_node, ir_cut_ctrl); - - if (rc < 0) { - pr_err("%s:%d msm_ir_cut_get_dt_data failed\n", - __func__, __LINE__); - kfree(ir_cut_ctrl); - return -EINVAL; - } - - rc = msm_sensor_driver_get_gpio_data(&(ir_cut_ctrl->gconf), - (&pdev->dev)->of_node); - - if ((rc < 0) || (ir_cut_ctrl->gconf == NULL)) { - pr_err("%s: No IR CUT GPIOs\n", __func__); - - kfree(ir_cut_ctrl); - return -EINVAL; - } - - CDBG("%s: gpio_request_table_size = %d\n", - __func__, - ir_cut_ctrl->gconf->cam_gpio_req_tbl_size); - - for (i = 0; - i < ir_cut_ctrl->gconf->cam_gpio_req_tbl_size; i++) { - CDBG("%s: gpio = %d\n", __func__, - ir_cut_ctrl->gconf->cam_gpio_req_tbl[i].gpio); - CDBG("%s: gpio-flags = %lu\n", __func__, - ir_cut_ctrl->gconf->cam_gpio_req_tbl[i].flags); - CDBG("%s: gconf->gpio_num_info->gpio_num[%d] = %d\n", - __func__, i, - ir_cut_ctrl->gconf->gpio_num_info->gpio_num[i]); - } - - ir_cut_ctrl->cam_pinctrl_status = 1; - - rc = msm_camera_pinctrl_init( - &(ir_cut_ctrl->pinctrl_info), &(pdev->dev)); - - if (rc < 0) { - pr_err("ERR:%s: Error in reading IR CUT pinctrl\n", - __func__); - ir_cut_ctrl->cam_pinctrl_status = 0; - } - - ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_RELEASE; - ir_cut_ctrl->power_info.dev = &ir_cut_ctrl->pdev->dev; - ir_cut_ctrl->ir_cut_device_type = MSM_CAMERA_PLATFORM_DEVICE; - ir_cut_ctrl->ir_cut_mutex = &msm_ir_cut_mutex; - - /* Initialize sub device */ - v4l2_subdev_init(&ir_cut_ctrl->msm_sd.sd, &msm_ir_cut_subdev_ops); - v4l2_set_subdevdata(&ir_cut_ctrl->msm_sd.sd, ir_cut_ctrl); - - ir_cut_ctrl->msm_sd.sd.internal_ops = &msm_ir_cut_internal_ops; - ir_cut_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(ir_cut_ctrl->msm_sd.sd.name, - ARRAY_SIZE(ir_cut_ctrl->msm_sd.sd.name), - "msm_camera_ir_cut"); - media_entity_init(&ir_cut_ctrl->msm_sd.sd.entity, 0, NULL, 0); - ir_cut_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - ir_cut_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_IR_CUT; - ir_cut_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; - msm_sd_register(&ir_cut_ctrl->msm_sd); - - CDBG("%s:%d ir_cut sd name = %s", __func__, __LINE__, - ir_cut_ctrl->msm_sd.sd.entity.name); - msm_ir_cut_v4l2_subdev_fops = v4l2_subdev_fops; -#ifdef CONFIG_COMPAT - msm_ir_cut_v4l2_subdev_fops.compat_ioctl32 = - msm_ir_cut_subdev_fops_ioctl; -#endif - ir_cut_ctrl->msm_sd.sd.devnode->fops = &msm_ir_cut_v4l2_subdev_fops; - - CDBG("probe success\n"); - return rc; -} - -MODULE_DEVICE_TABLE(of, msm_ir_cut_dt_match); - -static struct platform_driver msm_ir_cut_platform_driver = { - .probe = msm_ir_cut_platform_probe, - .driver = { - .name = "qcom,ir-cut", - .owner = THIS_MODULE, - .of_match_table = msm_ir_cut_dt_match, - }, -}; - -static int __init msm_ir_cut_init_module(void) -{ - int32_t rc = 0; - - CDBG("Enter\n"); - rc = platform_driver_register(&msm_ir_cut_platform_driver); - if (!rc) - return rc; - - pr_err("platform probe for ir_cut failed"); - - return rc; -} - -static void __exit msm_ir_cut_exit_module(void) -{ - platform_driver_unregister(&msm_ir_cut_platform_driver); -} - -static struct msm_ir_cut_table msm_gpio_ir_cut_table = { - .ir_cut_driver_type = IR_CUT_DRIVER_GPIO, - .func_tbl = { - .camera_ir_cut_init = msm_ir_cut_init, - .camera_ir_cut_release = msm_ir_cut_release, - .camera_ir_cut_off = msm_ir_cut_off, - .camera_ir_cut_on = msm_ir_cut_on, - }, -}; - -module_init(msm_ir_cut_init_module); -module_exit(msm_ir_cut_exit_module); -MODULE_DESCRIPTION("MSM IR CUT"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/ir_cut/msm_ir_cut.h b/drivers/media/platform/msm/ais/sensor/ir_cut/msm_ir_cut.h deleted file mode 100644 index e74af5b3c2e41f7f1a8df2665489d64c9e702ab1..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ir_cut/msm_ir_cut.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - * - */ - -#ifndef MSM_IR_CUT_H -#define MSM_IR_CUT_H - -#include -#include "msm_camera_dt_util.h" -#include "msm_camera_io_util.h" -#include "msm_sd.h" - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -enum msm_camera_ir_cut_state_t { - MSM_CAMERA_IR_CUT_INIT, - MSM_CAMERA_IR_CUT_RELEASE, -}; - -enum msm_ir_cut_driver_type { - IR_CUT_DRIVER_GPIO, - IR_CUT_DRIVER_DEFAULT, -}; - -struct msm_ir_cut_ctrl_t; - -struct msm_ir_cut_func_t { - int32_t (*camera_ir_cut_init)(struct msm_ir_cut_ctrl_t *, - struct msm_ir_cut_cfg_data_t *); - int32_t (*camera_ir_cut_release)(struct msm_ir_cut_ctrl_t *); - int32_t (*camera_ir_cut_off)(struct msm_ir_cut_ctrl_t *, - struct msm_ir_cut_cfg_data_t *); - int32_t (*camera_ir_cut_on)(struct msm_ir_cut_ctrl_t *, - struct msm_ir_cut_cfg_data_t *); -}; - -struct msm_ir_cut_table { - enum msm_ir_cut_driver_type ir_cut_driver_type; - struct msm_ir_cut_func_t func_tbl; -}; - -struct msm_ir_cut_ctrl_t { - struct msm_sd_subdev msm_sd; - struct platform_device *pdev; - struct msm_ir_cut_func_t *func_tbl; - struct msm_camera_power_ctrl_t power_info; - - enum msm_camera_device_type_t ir_cut_device_type; - struct mutex *ir_cut_mutex; - - /* ir_cut driver type */ - enum msm_ir_cut_driver_type ir_cut_driver_type; - - /* ir_cut state */ - enum msm_camera_ir_cut_state_t ir_cut_state; - - struct msm_camera_gpio_conf *gconf; - struct msm_pinctrl_info pinctrl_info; - uint8_t cam_pinctrl_status; -}; - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/ir_led/Makefile b/drivers/media/platform/msm/ais/sensor/ir_led/Makefile deleted file mode 100644 index bb3cc3ce40b4213253b17692edd4f4822618944f..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ir_led/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -obj-$(CONFIG_MSM_AIS) += msm_ir_led.o diff --git a/drivers/media/platform/msm/ais/sensor/ir_led/msm_ir_led.c b/drivers/media/platform/msm/ais/sensor/ir_led/msm_ir_led.c deleted file mode 100644 index 6ead05d4fe38596c3369998e76e69a5e6b212c9a..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ir_led/msm_ir_led.c +++ /dev/null @@ -1,456 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - * - */ - -#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ - -#include -#include -#include -#include "msm_ir_led.h" -#include "msm_camera_dt_util.h" - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -DEFINE_MSM_MUTEX(msm_ir_led_mutex); - -static struct v4l2_file_operations msm_ir_led_v4l2_subdev_fops; - -static const struct of_device_id msm_ir_led_dt_match[] = { - {.compatible = "qcom,ir-led", .data = NULL}, - {} -}; - -static struct msm_ir_led_table msm_default_ir_led_table; - -static struct msm_ir_led_table *ir_led_table[] = { - &msm_default_ir_led_table, -}; - -static int32_t msm_ir_led_get_subdev_id( - struct msm_ir_led_ctrl_t *ir_led_ctrl, void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - - if (!subdev_id) { - pr_err("subdevice ID is not valid\n"); - return -EINVAL; - } - if (MSM_CAMERA_PLATFORM_DEVICE != ir_led_ctrl->ir_led_device_type) { - pr_err("device type is not matching\n"); - return -EINVAL; - } - - *subdev_id = ir_led_ctrl->pdev->id; - - CDBG("subdev_id %d\n", *subdev_id); - return 0; -} - -static int32_t msm_ir_led_init( - struct msm_ir_led_ctrl_t *ir_led_ctrl, - struct msm_ir_led_cfg_data_t *ir_led_data) -{ - int32_t rc = 0; - - rc = ir_led_ctrl->func_tbl->camera_ir_led_off(ir_led_ctrl, ir_led_data); - - return rc; -} - -static int32_t msm_ir_led_release( - struct msm_ir_led_ctrl_t *ir_led_ctrl, - struct msm_ir_led_cfg_data_t *ir_led_data) -{ - int32_t rc = -EFAULT; - - if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_RELEASE) { - pr_err("Invalid ir_led state = %d\n", - ir_led_ctrl->ir_led_state); - return rc; - } - - rc = ir_led_ctrl->func_tbl->camera_ir_led_off(ir_led_ctrl, ir_led_data); - if (rc < 0) { - pr_err("camera_ir_led_off failed (%d)\n", rc); - return rc; - } - ir_led_ctrl->ir_led_state = MSM_CAMERA_IR_LED_RELEASE; - - return rc; -} - -static int32_t msm_ir_led_off(struct msm_ir_led_ctrl_t *ir_led_ctrl, - struct msm_ir_led_cfg_data_t *ir_led_data) -{ - int32_t rc = 0; - - CDBG("pwm duty on(ns) %d, pwm period(ns) %d\n", - ir_led_data->pwm_duty_on_ns, ir_led_data->pwm_period_ns); - - if (ir_led_data->pwm_period_ns <= 0) - ir_led_data->pwm_period_ns = DEFAULT_PWM_TIME_PERIOD_NS; - - if (ir_led_data->pwm_duty_on_ns != 0) - ir_led_data->pwm_duty_on_ns = DEFAULT_PWM_DUTY_CYCLE_NS; - - if (ir_led_ctrl->pwm_dev) { - rc = pwm_config(ir_led_ctrl->pwm_dev, - ir_led_data->pwm_duty_on_ns, - ir_led_data->pwm_period_ns); - - if (rc) { - pr_err("PWM config failed (%d)\n", rc); - return rc; - } - /* workaround to disable pwm_module */ - udelay(50); - - pwm_disable(ir_led_ctrl->pwm_dev); - } else { - CDBG("pwm device is null\n"); - } - - return 0; -} - -static int32_t msm_ir_led_on( - struct msm_ir_led_ctrl_t *ir_led_ctrl, - struct msm_ir_led_cfg_data_t *ir_led_data) -{ - int32_t rc = 0; - - CDBG("pwm duty on(ns) %d, pwm period(ns) %d\n", - ir_led_data->pwm_duty_on_ns, ir_led_data->pwm_period_ns); - - if (ir_led_ctrl->pwm_dev) { - rc = pwm_config(ir_led_ctrl->pwm_dev, - ir_led_data->pwm_duty_on_ns, - ir_led_data->pwm_period_ns); - if (rc) { - pr_err("PWM config failed (%d)\n", rc); - return rc; - } - - rc = pwm_enable(ir_led_ctrl->pwm_dev); - if (rc) { - pr_err("PWM enable failed(%d)\n", rc); - return rc; - } - } else { - CDBG("pwm device is null\n"); - } - return 0; -} - -static int32_t msm_ir_led_handle_init( - struct msm_ir_led_ctrl_t *ir_led_ctrl, - struct msm_ir_led_cfg_data_t *ir_led_data) -{ - uint32_t i = 0; - int32_t rc = -EFAULT; - enum msm_ir_led_driver_type ir_led_driver_type = - ir_led_ctrl->ir_led_driver_type; - - if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT) { - pr_err("Invalid ir_led state = %d\n", - ir_led_ctrl->ir_led_state); - return rc; - } - - for (i = 0; i < ARRAY_SIZE(ir_led_table); i++) { - if (ir_led_driver_type == ir_led_table[i]->ir_led_driver_type) { - ir_led_ctrl->func_tbl = &ir_led_table[i]->func_tbl; - rc = 0; - break; - } - } - - if (rc < 0) { - pr_err("failed invalid ir_led_driver_type %d\n", - ir_led_driver_type); - return -EINVAL; - } - - rc = ir_led_ctrl->func_tbl->camera_ir_led_init( - ir_led_ctrl, ir_led_data); - if (rc < 0) { - pr_err("camera_ir_led_init failed (%d)\n", rc); - return rc; - } - - ir_led_ctrl->ir_led_state = MSM_CAMERA_IR_LED_INIT; - - CDBG("IR LED STATE intialised Successfully\n"); - return rc; -} - -static int32_t msm_ir_led_config(struct msm_ir_led_ctrl_t *ir_led_ctrl, - void __user *argp) -{ - int32_t rc = -EINVAL; - struct msm_ir_led_cfg_data_t *ir_led_data = - (struct msm_ir_led_cfg_data_t *) argp; - - CDBG("type %d\n", ir_led_data->cfg_type); - - mutex_lock(ir_led_ctrl->ir_led_mutex); - - switch (ir_led_data->cfg_type) { - case CFG_IR_LED_INIT: - rc = msm_ir_led_handle_init(ir_led_ctrl, ir_led_data); - break; - case CFG_IR_LED_RELEASE: - if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT) - rc = ir_led_ctrl->func_tbl->camera_ir_led_release( - ir_led_ctrl, ir_led_data); - break; - case CFG_IR_LED_OFF: - if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT) - rc = ir_led_ctrl->func_tbl->camera_ir_led_off( - ir_led_ctrl, ir_led_data); - break; - case CFG_IR_LED_ON: - if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT) - rc = ir_led_ctrl->func_tbl->camera_ir_led_on( - ir_led_ctrl, ir_led_data); - break; - default: - rc = -EFAULT; - break; - } - - mutex_unlock(ir_led_ctrl->ir_led_mutex); - - CDBG("Exit (%d): type %d\n", rc, ir_led_data->cfg_type); - - return rc; -} - -static long msm_ir_led_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_ir_led_ctrl_t *fctrl = NULL; - void __user *argp = (void __user *)arg; - struct msm_ir_led_cfg_data_t ir_led_data = {0}; - - if (!sd) { - pr_err(" v4l2 ir led subdevice is NULL\n"); - return -EINVAL; - } - fctrl = v4l2_get_subdevdata(sd); - if (!fctrl) { - pr_err("fctrl NULL\n"); - return -EINVAL; - } - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return msm_ir_led_get_subdev_id(fctrl, argp); - case VIDIOC_MSM_IR_LED_CFG: - return msm_ir_led_config(fctrl, argp); - case MSM_SD_NOTIFY_FREEZE: - return 0; - case MSM_SD_SHUTDOWN: - if (!fctrl->func_tbl) { - pr_err("No call back funcions\n"); - return -EINVAL; - } else { - return fctrl->func_tbl->camera_ir_led_release(fctrl, - &ir_led_data); - } - default: - pr_err_ratelimited("invalid cmd %d\n", cmd); - return -ENOIOCTLCMD; - } -} - -static struct v4l2_subdev_core_ops msm_ir_led_subdev_core_ops = { - .ioctl = msm_ir_led_subdev_ioctl, -}; - -static struct v4l2_subdev_ops msm_ir_led_subdev_ops = { - .core = &msm_ir_led_subdev_core_ops, -}; - -static const struct v4l2_subdev_internal_ops msm_ir_led_internal_ops; - -static int32_t msm_ir_led_get_dt_data(struct device_node *of_node, - struct msm_ir_led_ctrl_t *fctrl) -{ - int32_t rc = 0; - - /* Read the sub device */ - rc = of_property_read_u32(of_node, "cell-index", &fctrl->pdev->id); - if (rc < 0) { - pr_err("reading cell-index for ir-led node is failed(rc) %d\n", - rc); - return rc; - } - - fctrl->ir_led_driver_type = IR_LED_DRIVER_DEFAULT; - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_ir_led_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - int32_t rc = 0; - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct msm_ir_led_cfg_data_t32 *u32 = - (struct msm_ir_led_cfg_data_t32 *)arg; - struct msm_ir_led_cfg_data_t ir_led_data; - - ir_led_data.cfg_type = u32->cfg_type; - ir_led_data.pwm_duty_on_ns = u32->pwm_duty_on_ns; - ir_led_data.pwm_period_ns = u32->pwm_period_ns; - - switch (cmd) { - case VIDIOC_MSM_IR_LED_CFG32: - cmd = VIDIOC_MSM_IR_LED_CFG; - break; - default: - return msm_ir_led_subdev_ioctl(sd, cmd, arg); - } - - rc = msm_ir_led_subdev_ioctl(sd, cmd, &ir_led_data); - - return rc; -} - -static long msm_ir_led_subdev_fops_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_ir_led_subdev_do_ioctl); -} -#endif - -static int32_t msm_ir_led_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - struct msm_ir_led_ctrl_t *ir_led_ctrl = NULL; - - if (!pdev->dev.of_node) { - pr_err("IR LED device node is not present in device tree\n"); - return -EINVAL; - } - - ir_led_ctrl = devm_kzalloc(&pdev->dev, sizeof(struct msm_ir_led_ctrl_t), - GFP_KERNEL); - if (!ir_led_ctrl) - return -ENOMEM; - - ir_led_ctrl->pdev = pdev; - - /* Reading PWM device node */ - ir_led_ctrl->pwm_dev = of_pwm_get(pdev->dev.of_node, NULL); - - if (PTR_ERR(ir_led_ctrl->pwm_dev) == -EPROBE_DEFER) { - pr_info("Deferring probe...Cannot get PWM device\n"); - return -EPROBE_DEFER; - } - - if (IS_ERR(ir_led_ctrl->pwm_dev)) { - rc = PTR_ERR(ir_led_ctrl->pwm_dev); - CDBG("Cannot get PWM device (%d)\n", rc); - ir_led_ctrl->pwm_dev = NULL; - } - - rc = msm_ir_led_get_dt_data(pdev->dev.of_node, ir_led_ctrl); - if (rc < 0) { - pr_err("msm_ir_led_get_dt_data failed\n"); - return -EINVAL; - } - - ir_led_ctrl->ir_led_state = MSM_CAMERA_IR_LED_RELEASE; - ir_led_ctrl->power_info.dev = &ir_led_ctrl->pdev->dev; - ir_led_ctrl->ir_led_device_type = MSM_CAMERA_PLATFORM_DEVICE; - ir_led_ctrl->ir_led_mutex = &msm_ir_led_mutex; - - /* Initialize sub device */ - v4l2_subdev_init(&ir_led_ctrl->msm_sd.sd, &msm_ir_led_subdev_ops); - v4l2_set_subdevdata(&ir_led_ctrl->msm_sd.sd, ir_led_ctrl); - - ir_led_ctrl->msm_sd.sd.internal_ops = &msm_ir_led_internal_ops; - ir_led_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(ir_led_ctrl->msm_sd.sd.name, - ARRAY_SIZE(ir_led_ctrl->msm_sd.sd.name), - "msm_camera_ir_led"); - media_entity_init(&ir_led_ctrl->msm_sd.sd.entity, 0, NULL, 0); - ir_led_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - ir_led_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_IR_LED; - ir_led_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; - - rc = msm_sd_register(&ir_led_ctrl->msm_sd); - if (rc < 0) { - pr_err("sub dev register failed for ir_led device\n"); - return rc; - } - - CDBG("ir_led sd name = %s\n", - ir_led_ctrl->msm_sd.sd.entity.name); - msm_ir_led_v4l2_subdev_fops = v4l2_subdev_fops; -#ifdef CONFIG_COMPAT - msm_ir_led_v4l2_subdev_fops.compat_ioctl32 = - msm_ir_led_subdev_fops_ioctl; -#endif - ir_led_ctrl->msm_sd.sd.devnode->fops = &msm_ir_led_v4l2_subdev_fops; - - CDBG("probe success\n"); - return rc; -} - -MODULE_DEVICE_TABLE(of, msm_ir_led_dt_match); - -static struct platform_driver msm_ir_led_platform_driver = { - .probe = msm_ir_led_platform_probe, - .driver = { - .name = "qcom,ir-led", - .owner = THIS_MODULE, - .of_match_table = msm_ir_led_dt_match, - }, -}; - -static int __init msm_ir_led_init_module(void) -{ - int32_t rc = 0; - - rc = platform_driver_register(&msm_ir_led_platform_driver); - if (!rc) - return rc; - - pr_err("ir-led driver register failed (%d)\n", rc); - - return rc; -} - -static void __exit msm_ir_led_exit_module(void) -{ - platform_driver_unregister(&msm_ir_led_platform_driver); -} - -static struct msm_ir_led_table msm_default_ir_led_table = { - .ir_led_driver_type = IR_LED_DRIVER_DEFAULT, - .func_tbl = { - .camera_ir_led_init = msm_ir_led_init, - .camera_ir_led_release = msm_ir_led_release, - .camera_ir_led_off = msm_ir_led_off, - .camera_ir_led_on = msm_ir_led_on, - }, -}; - -module_init(msm_ir_led_init_module); -module_exit(msm_ir_led_exit_module); -MODULE_DESCRIPTION("MSM IR LED"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/ir_led/msm_ir_led.h b/drivers/media/platform/msm/ais/sensor/ir_led/msm_ir_led.h deleted file mode 100644 index 15141b97affbe6127149c70096c0623db89d7b77..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ir_led/msm_ir_led.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - * - */ - -#ifndef MSM_IR_LED_H -#define MSM_IR_LED_H - -#include -#include -#include -#include -#include -#include "msm_sd.h" - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -/* Default frequency is taken as 15KHz*/ -#define DEFAULT_PWM_TIME_PERIOD_NS 66667 -#define DEFAULT_PWM_DUTY_CYCLE_NS 0 - -enum msm_camera_ir_led_state_t { - MSM_CAMERA_IR_LED_INIT, - MSM_CAMERA_IR_LED_RELEASE, -}; - -enum msm_ir_led_driver_type { - IR_LED_DRIVER_GPIO, - IR_LED_DRIVER_DEFAULT, -}; - -struct msm_ir_led_ctrl_t; - -struct msm_ir_led_func_t { - int32_t (*camera_ir_led_init)(struct msm_ir_led_ctrl_t *, - struct msm_ir_led_cfg_data_t *); - int32_t (*camera_ir_led_release)(struct msm_ir_led_ctrl_t *, - struct msm_ir_led_cfg_data_t *); - int32_t (*camera_ir_led_off)(struct msm_ir_led_ctrl_t *, - struct msm_ir_led_cfg_data_t *); - int32_t (*camera_ir_led_on)(struct msm_ir_led_ctrl_t *, - struct msm_ir_led_cfg_data_t *); -}; - -struct msm_ir_led_table { - enum msm_ir_led_driver_type ir_led_driver_type; - struct msm_ir_led_func_t func_tbl; -}; - -struct msm_ir_led_ctrl_t { - struct msm_sd_subdev msm_sd; - struct platform_device *pdev; - struct pwm_device *pwm_dev; - struct msm_ir_led_func_t *func_tbl; - struct msm_camera_power_ctrl_t power_info; - - enum msm_camera_device_type_t ir_led_device_type; - struct mutex *ir_led_mutex; - - /* ir_led driver type */ - enum msm_ir_led_driver_type ir_led_driver_type; - - /* ir_led state */ - enum msm_camera_ir_led_state_t ir_led_state; -}; - -#endif diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor.c b/drivers/media/platform/msm/ais/sensor/msm_sensor.c deleted file mode 100644 index 229b58bd62d48ffe510479e2ee26c9a084926f29..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/msm_sensor.c +++ /dev/null @@ -1,1719 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include "msm_sensor.h" -#include "msm_sd.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" -#include "msm_camera_i2c_mux.h" -#include -#include - -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -#define MAX_SENSOR_V4l2_EVENTS 100 -static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl; -static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl; - -static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl) -{ - int idx; - struct msm_sensor_power_setting *power_setting; - - for (idx = 0; idx < ctrl->power_setting_size; idx++) { - power_setting = &ctrl->power_setting[idx]; - if ((power_setting->seq_type == SENSOR_CLK) && - (power_setting->seq_val == SENSOR_CAM_MCLK)) { - if (power_setting->config_val == 24000000) { - power_setting->config_val = 23880000; - CDBG("%s MCLK request adjusted to 23.88MHz\n" - , __func__); - } - break; - } - } -} - -static void msm_sensor_misc_regulator( - struct msm_sensor_ctrl_t *sctrl, uint32_t enable) -{ - int32_t rc = 0; - - if (enable) { - sctrl->misc_regulator = (void *)rpm_regulator_get( - &sctrl->pdev->dev, sctrl->sensordata->misc_regulator); - if (sctrl->misc_regulator) { - rc = rpm_regulator_set_mode(sctrl->misc_regulator, - RPM_REGULATOR_MODE_HPM); - if (rc < 0) { - pr_err("%s: Failed to set for rpm regulator on %s: %d\n", - __func__, - sctrl->sensordata->misc_regulator, rc); - rpm_regulator_put(sctrl->misc_regulator); - } - } else { - pr_err("%s: Failed to vote for rpm regulator on %s: %d\n", - __func__, - sctrl->sensordata->misc_regulator, rc); - } - } else { - if (sctrl->misc_regulator) { - rc = rpm_regulator_set_mode( - (struct rpm_regulator *)sctrl->misc_regulator, - RPM_REGULATOR_MODE_AUTO); - if (rc < 0) - pr_err("%s: Failed to set for rpm regulator on %s: %d\n", - __func__, - sctrl->sensordata->misc_regulator, rc); - rpm_regulator_put(sctrl->misc_regulator); - } - } -} - -int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl) -{ - if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client) - return 0; - kfree(s_ctrl->sensordata->slave_info); - kfree(s_ctrl->sensordata->cam_slave_info); - kfree(s_ctrl->sensordata->actuator_info); - kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); - kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); - kfree(s_ctrl->sensordata->power_info.gpio_conf); - kfree(s_ctrl->sensordata->power_info.cam_vreg); - kfree(s_ctrl->sensordata->power_info.power_setting); - kfree(s_ctrl->sensordata->power_info.power_down_setting); - kfree(s_ctrl->sensordata->csi_lane_params); - kfree(s_ctrl->sensordata->sensor_info); - if (s_ctrl->sensor_device_type == MSM_CAMERA_I2C_DEVICE) { - msm_camera_i2c_dev_put_clk_info( - &s_ctrl->sensor_i2c_client->client->dev, - &s_ctrl->sensordata->power_info.clk_info, - &s_ctrl->sensordata->power_info.clk_ptr, - s_ctrl->sensordata->power_info.clk_info_size); - } else { - msm_camera_put_clk_info(s_ctrl->pdev, - &s_ctrl->sensordata->power_info.clk_info, - &s_ctrl->sensordata->power_info.clk_ptr, - s_ctrl->sensordata->power_info.clk_info_size); - } - - kfree(s_ctrl->sensordata); - return 0; -} - -int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) -{ - struct msm_camera_power_ctrl_t *power_info; - enum msm_camera_device_type_t sensor_device_type; - struct msm_camera_i2c_client *sensor_i2c_client; - - if (!s_ctrl) { - pr_err("%s:%d failed: s_ctrl %pK\n", - __func__, __LINE__, s_ctrl); - return -EINVAL; - } - - if (s_ctrl->is_csid_tg_mode) - return 0; - - power_info = &s_ctrl->sensordata->power_info; - sensor_device_type = s_ctrl->sensor_device_type; - sensor_i2c_client = s_ctrl->sensor_i2c_client; - - if (!power_info || !sensor_i2c_client) { - pr_err("%s:%d failed: power_info %pK sensor_i2c_client %pK\n", - __func__, __LINE__, power_info, sensor_i2c_client); - return -EINVAL; - } - - /* Power down secure session if it exist*/ - if (s_ctrl->is_secure) - msm_camera_tz_i2c_power_down(sensor_i2c_client); - - return msm_camera_power_down(power_info, sensor_device_type, - sensor_i2c_client); -} - -int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) -{ - int rc; - struct msm_camera_power_ctrl_t *power_info; - struct msm_camera_i2c_client *sensor_i2c_client; - struct msm_camera_slave_info *slave_info; - const char *sensor_name; - uint32_t retry = 0; - - if (!s_ctrl) { - pr_err("%s:%d failed: %pK\n", - __func__, __LINE__, s_ctrl); - return -EINVAL; - } - - if (s_ctrl->is_csid_tg_mode) - return 0; - - power_info = &s_ctrl->sensordata->power_info; - sensor_i2c_client = s_ctrl->sensor_i2c_client; - slave_info = s_ctrl->sensordata->slave_info; - sensor_name = s_ctrl->sensordata->sensor_name; - - if (!power_info || !sensor_i2c_client || !slave_info || - !sensor_name) { - pr_err("%s:%d failed: %pK %pK %pK %pK\n", - __func__, __LINE__, power_info, - sensor_i2c_client, slave_info, sensor_name); - return -EINVAL; - } - - if (s_ctrl->set_mclk_23880000) - msm_sensor_adjust_mclk(power_info); - - CDBG("Sensor %d tagged as %s\n", s_ctrl->id, - (s_ctrl->is_secure)?"SECURE":"NON-SECURE"); - - for (retry = 0; retry < 3; retry++) { - if (s_ctrl->is_secure) { - rc = msm_camera_tz_i2c_power_up(sensor_i2c_client); - if (rc < 0) { -#ifdef CONFIG_MSM_AIS_SEC_CCI_DEBUG - CDBG("Secure Sensor %d use cci\n", s_ctrl->id); - /* session is not secure */ - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_cci_func_tbl; -#else /* CONFIG_MSM_AIS_SEC_CCI_DEBUG */ - return rc; -#endif /* CONFIG_MSM_AIS_SEC_CCI_DEBUG */ - } else { - /* session is secure */ - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_secure_func_tbl; - } - } - rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type, - sensor_i2c_client); - if (rc < 0) - return rc; - rc = msm_sensor_check_id(s_ctrl); - if (rc < 0) { - msm_camera_power_down(power_info, - s_ctrl->sensor_device_type, sensor_i2c_client); - msleep(20); - continue; - } else { - break; - } - } - - return rc; -} - -static uint16_t msm_sensor_id_by_mask(struct msm_sensor_ctrl_t *s_ctrl, - uint16_t chipid) -{ - uint16_t sensor_id = chipid; - int16_t sensor_id_mask = s_ctrl->sensordata->slave_info->sensor_id_mask; - - if (!sensor_id_mask) - sensor_id_mask = ~sensor_id_mask; - - sensor_id &= sensor_id_mask; - sensor_id_mask &= -sensor_id_mask; - sensor_id_mask -= 1; - while (sensor_id_mask) { - sensor_id_mask >>= 1; - sensor_id >>= 1; - } - return sensor_id; -} - -int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) -{ - int rc = 0; - uint16_t chipid = 0; - struct msm_camera_i2c_client *sensor_i2c_client; - struct msm_camera_slave_info *slave_info; - const char *sensor_name; - - if (!s_ctrl) { - pr_err("%s:%d failed: %pK\n", - __func__, __LINE__, s_ctrl); - return -EINVAL; - } - sensor_i2c_client = s_ctrl->sensor_i2c_client; - slave_info = s_ctrl->sensordata->slave_info; - sensor_name = s_ctrl->sensordata->sensor_name; - - if (!sensor_i2c_client || !slave_info || !sensor_name) { - pr_err("%s:%d failed: %pK %pK %pK\n", - __func__, __LINE__, sensor_i2c_client, slave_info, - sensor_name); - return -EINVAL; - } - - rc = sensor_i2c_client->i2c_func_tbl->i2c_read( - sensor_i2c_client, slave_info->sensor_id_reg_addr, - &chipid, MSM_CAMERA_I2C_WORD_DATA); - if (rc < 0) { - pr_err("%s: %s: read id failed\n", __func__, sensor_name); - return rc; - } - - pr_debug("%s: read id: 0x%x expected id 0x%x:\n", - __func__, chipid, slave_info->sensor_id); - if (msm_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) { - pr_err("%s chip id %x does not match %x\n", - __func__, chipid, slave_info->sensor_id); - return -ENODEV; - } - return rc; -} - -static struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd) -{ - return container_of(container_of(sd, struct msm_sd_subdev, sd), - struct msm_sensor_ctrl_t, msm_sd); -} - -static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - - mutex_lock(s_ctrl->msm_sensor_mutex); - if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { - s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting); - kfree(s_ctrl->stop_setting.reg_setting); - s_ctrl->stop_setting.reg_setting = NULL; - - if (s_ctrl->func_tbl->sensor_power_down) { - if (s_ctrl->sensordata->misc_regulator) - msm_sensor_misc_regulator(s_ctrl, 0); - - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, - __LINE__, rc); - } - s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; - CDBG("%s:%d sensor state %d\n", __func__, __LINE__, - s_ctrl->sensor_state); - } else { - pr_err("s_ctrl->func_tbl NULL\n"); - } - } - mutex_unlock(s_ctrl->msm_sensor_mutex); -} - -static int msm_sensor_get_af_status(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - /* TO-DO: Need to set AF status register address and expected value - We need to check the AF status in the sensor register and - set the status in the *status variable accordingly*/ - return 0; -} - -static int32_t msm_sensor_get_subdev_id( - struct msm_sensor_ctrl_t *s_ctrl, void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - - if (!subdev_id) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -EINVAL; - } - *subdev_id = s_ctrl->id; - pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); - return 0; -} - -static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); - void __user *argp = (void __user *)arg; - - if (!s_ctrl) { - pr_err("%s s_ctrl NULL\n", __func__); - return -EBADF; - } - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - rc = msm_sensor_get_subdev_id(s_ctrl, arg); - return rc; - case VIDIOC_MSM_SENSOR_INIT_CFG: -#ifdef CONFIG_COMPAT - case VIDIOC_MSM_SENSOR_INIT_CFG32: - if (is_compat_task()) { - struct sensor_init_cfg_data32 *u32 = - (struct sensor_init_cfg_data32 *)argp; - struct sensor_init_cfg_data sensor_init_data; - - memset(&sensor_init_data, 0, sizeof(sensor_init_data)); - sensor_init_data.cfgtype = u32->cfgtype; - sensor_init_data.cfg.setting = compat_ptr(u32->cfg. - setting); - cmd = VIDIOC_MSM_SENSOR_INIT_CFG; - rc = msm_sensor_driver_cmd(&s_ctrl->s_init, - &sensor_init_data); - } else -#endif - { - rc = msm_sensor_driver_cmd(&s_ctrl->s_init, argp); - } - return rc; - - case VIDIOC_MSM_SENSOR_CFG: -#ifdef CONFIG_COMPAT - if (is_compat_task()) - rc = s_ctrl->func_tbl->sensor_config32(s_ctrl, argp); - else -#endif - rc = s_ctrl->func_tbl->sensor_config(s_ctrl, argp); - return rc; - case VIDIOC_MSM_SENSOR_GET_AF_STATUS: - return msm_sensor_get_af_status(s_ctrl, argp); - case VIDIOC_MSM_SENSOR_RELEASE: - case MSM_SD_SHUTDOWN: - msm_sensor_stop_stream(s_ctrl); - return 0; - case MSM_SD_NOTIFY_FREEZE: - return 0; - case MSM_SD_UNNOTIFY_FREEZE: - return 0; - default: - pr_err("%s unknown command %d\n", __func__, cmd); - return -ENOIOCTLCMD; - } -} - -#ifdef CONFIG_COMPAT -static long msm_sensor_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; - switch (cmd) { - case VIDIOC_MSM_SENSOR_CFG32: - cmd = VIDIOC_MSM_SENSOR_CFG; - case VIDIOC_DQEVENT: { - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return -ENOIOCTLCMD; - return v4l2_event_dequeue(vfh, arg, - file->f_flags & O_NONBLOCK); - } - break; - case VIDIOC_SUBSCRIBE_EVENT: - pr_debug("msm_sensor_subdev_do_ioctl:VIDIOC_SUBSCRIBE_EVENT"); - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); - default: - pr_debug("msm_sensor.c msm_sensor_subdev_do_ioctl"); - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); - } -} - -long msm_sensor_subdev_fops_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_sensor_subdev_do_ioctl); -} - -static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - struct sensorb_cfg_data32 *cdata = (struct sensorb_cfg_data32 *)argp; - int32_t rc = 0; - int32_t i = 0; - - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) { - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.subdev_intf[i] = - s_ctrl->sensordata->sensor_info->subdev_intf[i]; - } - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - cdata->cfg.sensor_info.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_info.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) { - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d subdev_intf[%d] %d\n", __func__, __LINE__, - i, cdata->cfg.sensor_info.subdev_intf[i]); - } - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_WRITE_I2C_ARRAY: - case CFG_WRITE_I2C_ARRAY_SYNC: - case CFG_WRITE_I2C_ARRAY_SYNC_BLOCK: - case CFG_WRITE_I2C_ARRAY_ASYNC: { - struct msm_camera_i2c_reg_setting32 conf_array32; - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - - if (copy_from_user(&conf_array32, - (void *)compat_ptr(cdata->cfg.setting), - sizeof(struct msm_camera_i2c_reg_setting32))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - conf_array.addr_type = conf_array32.addr_type; - conf_array.data_type = conf_array32.data_type; - conf_array.delay = conf_array32.delay; - conf_array.size = conf_array32.size; - conf_array.reg_setting = compat_ptr(conf_array32.reg_setting); - - if (!conf_array.size || - conf_array.size > I2C_REG_DATA_MAX) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, - (void *)(conf_array.reg_setting), - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - - if (CFG_WRITE_I2C_ARRAY == cdata->cfgtype) - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table(s_ctrl->sensor_i2c_client, - &conf_array); - else if (CFG_WRITE_I2C_ARRAY_ASYNC == cdata->cfgtype) - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table_async(s_ctrl->sensor_i2c_client, - &conf_array); - else if (CFG_WRITE_I2C_ARRAY_SYNC_BLOCK == cdata->cfgtype) - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table_sync_block( - s_ctrl->sensor_i2c_client, - &conf_array); - else - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table_sync(s_ctrl->sensor_i2c_client, - &conf_array); - - kfree(reg_setting); - break; - } - case CFG_SLAVE_READ_I2C: { - struct msm_camera_i2c_read_config read_config; - struct msm_camera_i2c_read_config *read_config_ptr = NULL; - uint16_t local_data = 0; - uint16_t orig_slave_addr = 0, read_slave_addr = 0; - uint16_t orig_addr_type = 0, read_addr_type = 0; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - read_config_ptr = - (struct msm_camera_i2c_read_config *) - compat_ptr(cdata->cfg.setting); - - if (copy_from_user(&read_config, read_config_ptr, - sizeof(struct msm_camera_i2c_read_config))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - read_slave_addr = read_config.slave_addr; - read_addr_type = read_config.addr_type; - - CDBG("%s:CFG_SLAVE_READ_I2C:", __func__); - CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n", - __func__, read_config.slave_addr, - read_config.reg_addr, read_config.data_type); - if (s_ctrl->sensor_i2c_client->cci_client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->cci_client->sid; - s_ctrl->sensor_i2c_client->cci_client->sid = - read_slave_addr >> 1; - } else if (s_ctrl->sensor_i2c_client->client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->client->addr; - s_ctrl->sensor_i2c_client->client->addr = - read_slave_addr >> 1; - } else { - pr_err("%s: error: no i2c/cci client found.", __func__); - rc = -EFAULT; - break; - } - CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", - __func__, orig_slave_addr, - read_slave_addr >> 1); - - orig_addr_type = s_ctrl->sensor_i2c_client->addr_type; - s_ctrl->sensor_i2c_client->addr_type = read_addr_type; - - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( - s_ctrl->sensor_i2c_client, - read_config.reg_addr, - &local_data, read_config.data_type); - if (s_ctrl->sensor_i2c_client->cci_client) { - s_ctrl->sensor_i2c_client->cci_client->sid = - orig_slave_addr; - } else if (s_ctrl->sensor_i2c_client->client) { - s_ctrl->sensor_i2c_client->client->addr = - orig_slave_addr; - } - s_ctrl->sensor_i2c_client->addr_type = orig_addr_type; - - pr_debug("slave_read %x %x %x\n", read_slave_addr, - read_config.reg_addr, local_data); - - if (rc < 0) { - pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__); - break; - } - read_config_ptr->data = local_data; - break; - } - case CFG_SLAVE_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_array_write_config32 write_config32; - struct msm_camera_i2c_array_write_config write_config; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - uint16_t orig_slave_addr = 0, write_slave_addr = 0; - uint16_t orig_addr_type = 0, write_addr_type = 0; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (copy_from_user(&write_config32, - (void *)compat_ptr(cdata->cfg.setting), - sizeof( - struct msm_camera_i2c_array_write_config32))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - write_config.slave_addr = write_config32.slave_addr; - write_config.conf_array.addr_type = - write_config32.conf_array.addr_type; - write_config.conf_array.data_type = - write_config32.conf_array.data_type; - write_config.conf_array.delay = - write_config32.conf_array.delay; - write_config.conf_array.size = - write_config32.conf_array.size; - write_config.conf_array.reg_setting = - compat_ptr(write_config32.conf_array.reg_setting); - - pr_debug("%s:CFG_SLAVE_WRITE_I2C_ARRAY:\n", __func__); - pr_debug("%s:slave_addr=0x%x, array_size=%d addr_type=%d data_type=%d\n", - __func__, - write_config.slave_addr, - write_config.conf_array.size, - write_config.conf_array.addr_type, - write_config.conf_array.data_type); - - if (!write_config.conf_array.size || - write_config.conf_array.size > I2C_REG_DATA_MAX) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(write_config.conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, - (void *)(write_config.conf_array.reg_setting), - write_config.conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - write_config.conf_array.reg_setting = reg_setting; - write_slave_addr = write_config.slave_addr; - write_addr_type = write_config.conf_array.addr_type; - - if (s_ctrl->sensor_i2c_client->cci_client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->cci_client->sid; - s_ctrl->sensor_i2c_client->cci_client->sid = - write_slave_addr >> 1; - } else if (s_ctrl->sensor_i2c_client->client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->client->addr; - s_ctrl->sensor_i2c_client->client->addr = - write_slave_addr >> 1; - } else { - pr_err("%s: error: no i2c/cci client found.", - __func__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - pr_debug("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x\n", - __func__, orig_slave_addr, - write_slave_addr >> 1); - orig_addr_type = s_ctrl->sensor_i2c_client->addr_type; - s_ctrl->sensor_i2c_client->addr_type = write_addr_type; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &(write_config.conf_array)); - - s_ctrl->sensor_i2c_client->addr_type = orig_addr_type; - if (s_ctrl->sensor_i2c_client->cci_client) { - s_ctrl->sensor_i2c_client->cci_client->sid = - orig_slave_addr; - } else if (s_ctrl->sensor_i2c_client->client) { - s_ctrl->sensor_i2c_client->client->addr = - orig_slave_addr; - } else { - pr_err("%s: error: no i2c/cci client found.\n", - __func__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting32 conf_array32; - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - - if (copy_from_user(&conf_array32, - (void *)compat_ptr(cdata->cfg.setting), - sizeof(struct msm_camera_i2c_seq_reg_setting32))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - conf_array.addr_type = conf_array32.addr_type; - conf_array.delay = conf_array32.delay; - conf_array.size = conf_array32.size; - conf_array.reg_setting = compat_ptr(conf_array32.reg_setting); - - if (!conf_array.size || - conf_array.size > I2C_SEQ_REG_DATA_MAX) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - if (s_ctrl->func_tbl->sensor_power_up) { - if (s_ctrl->sensordata->misc_regulator) - msm_sensor_misc_regulator(s_ctrl, 1); - - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, - __LINE__, rc); - break; - } - s_ctrl->sensor_state = MSM_SENSOR_POWER_UP; - CDBG("%s:%d sensor state %d\n", __func__, __LINE__, - s_ctrl->sensor_state); - } else { - rc = -EFAULT; - } - break; - case CFG_POWER_DOWN: - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - kfree(s_ctrl->stop_setting.reg_setting); - s_ctrl->stop_setting.reg_setting = NULL; - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - if (s_ctrl->func_tbl->sensor_power_down) { - if (s_ctrl->sensordata->misc_regulator) - msm_sensor_misc_regulator(s_ctrl, 0); - - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, - __LINE__, rc); - break; - } - s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; - CDBG("%s:%d sensor state %d\n", __func__, __LINE__, - s_ctrl->sensor_state); - } else { - rc = -EFAULT; - } - break; - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting32 stop_setting32; - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (copy_from_user(&stop_setting32, - (void *)compat_ptr((cdata->cfg.setting)), - sizeof(struct msm_camera_i2c_reg_setting32))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - stop_setting->addr_type = stop_setting32.addr_type; - stop_setting->data_type = stop_setting32.data_type; - stop_setting->delay = stop_setting32.delay; - stop_setting->size = stop_setting32.size; - - reg_setting = compat_ptr(stop_setting32.reg_setting); - - if ((!stop_setting->size) || - (stop_setting->size > I2C_SEQ_REG_DATA_MAX)) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, - stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - - case CFG_SET_I2C_SYNC_PARAM: { - struct msm_camera_cci_ctrl cci_ctrl; - - s_ctrl->sensor_i2c_client->cci_client->cid = - cdata->cfg.sensor_i2c_sync_params.cid; - s_ctrl->sensor_i2c_client->cci_client->id_map = - cdata->cfg.sensor_i2c_sync_params.csid; - - CDBG("I2C_SYNC_PARAM CID:%d, line:%d delay:%d, cdid:%d\n", - s_ctrl->sensor_i2c_client->cci_client->cid, - cdata->cfg.sensor_i2c_sync_params.line, - cdata->cfg.sensor_i2c_sync_params.delay, - cdata->cfg.sensor_i2c_sync_params.csid); - - cci_ctrl.cmd = MSM_CCI_SET_SYNC_CID; - cci_ctrl.cfg.cci_wait_sync_cfg.line = - cdata->cfg.sensor_i2c_sync_params.line; - cci_ctrl.cfg.cci_wait_sync_cfg.delay = - cdata->cfg.sensor_i2c_sync_params.delay; - cci_ctrl.cfg.cci_wait_sync_cfg.cid = - cdata->cfg.sensor_i2c_sync_params.cid; - cci_ctrl.cfg.cci_wait_sync_cfg.csid = - cdata->cfg.sensor_i2c_sync_params.csid; - rc = v4l2_subdev_call(s_ctrl->sensor_i2c_client-> - cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - rc = -EFAULT; - break; - } - break; - } - - default: - rc = -EFAULT; - break; - } - -DONE: - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} -#endif - -int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - int32_t rc = 0; - int32_t i = 0; - - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) { - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.subdev_intf[i] = - s_ctrl->sensordata->sensor_info->subdev_intf[i]; - } - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - cdata->cfg.sensor_info.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_info.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) { - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d subdev_intf[%d] %d\n", __func__, __LINE__, - i, cdata->cfg.sensor_info.subdev_intf[i]); - } - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - - case CFG_WRITE_I2C_ARRAY: - case CFG_WRITE_I2C_ARRAY_SYNC: - case CFG_WRITE_I2C_ARRAY_SYNC_BLOCK: - case CFG_WRITE_I2C_ARRAY_ASYNC: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (!conf_array.size || - conf_array.size > I2C_REG_DATA_MAX) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY) - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table(s_ctrl->sensor_i2c_client, - &conf_array); - else if (CFG_WRITE_I2C_ARRAY_ASYNC == cdata->cfgtype) - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table_async(s_ctrl->sensor_i2c_client, - &conf_array); - else if (CFG_WRITE_I2C_ARRAY_SYNC_BLOCK == cdata->cfgtype) - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table_sync_block( - s_ctrl->sensor_i2c_client, - &conf_array); - else - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_table_sync(s_ctrl->sensor_i2c_client, - &conf_array); - - kfree(reg_setting); - break; - } - case CFG_SLAVE_READ_I2C: { - struct msm_camera_i2c_read_config read_config; - struct msm_camera_i2c_read_config *read_config_ptr = NULL; - uint16_t local_data = 0; - uint16_t orig_slave_addr = 0, read_slave_addr = 0; - uint16_t orig_addr_type = 0, read_addr_type = 0; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - read_config_ptr = - (struct msm_camera_i2c_read_config *)cdata->cfg.setting; - if (copy_from_user(&read_config, read_config_ptr, - sizeof(struct msm_camera_i2c_read_config))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - read_slave_addr = read_config.slave_addr; - read_addr_type = read_config.addr_type; - CDBG("%s:CFG_SLAVE_READ_I2C:", __func__); - CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n", - __func__, read_config.slave_addr, - read_config.reg_addr, read_config.data_type); - if (s_ctrl->sensor_i2c_client->cci_client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->cci_client->sid; - s_ctrl->sensor_i2c_client->cci_client->sid = - read_slave_addr >> 1; - } else if (s_ctrl->sensor_i2c_client->client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->client->addr; - s_ctrl->sensor_i2c_client->client->addr = - read_slave_addr >> 1; - } else { - pr_err("%s: error: no i2c/cci client found.", __func__); - rc = -EFAULT; - break; - } - CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", - __func__, orig_slave_addr, - read_slave_addr >> 1); - - orig_addr_type = s_ctrl->sensor_i2c_client->addr_type; - s_ctrl->sensor_i2c_client->addr_type = read_addr_type; - - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( - s_ctrl->sensor_i2c_client, - read_config.reg_addr, - &local_data, read_config.data_type); - if (s_ctrl->sensor_i2c_client->cci_client) { - s_ctrl->sensor_i2c_client->cci_client->sid = - orig_slave_addr; - } else if (s_ctrl->sensor_i2c_client->client) { - s_ctrl->sensor_i2c_client->client->addr = - orig_slave_addr; - } - s_ctrl->sensor_i2c_client->addr_type = orig_addr_type; - - if (rc < 0) { - pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__); - break; - } - read_config_ptr->data = local_data; - break; - } - case CFG_SLAVE_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_array_write_config write_config; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - uint16_t orig_slave_addr = 0, write_slave_addr = 0; - uint16_t orig_addr_type = 0, write_addr_type = 0; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (copy_from_user(&write_config, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_array_write_config))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__); - CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__, - write_config.slave_addr, - write_config.conf_array.size); - - if (!write_config.conf_array.size || - write_config.conf_array.size > I2C_REG_DATA_MAX) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(write_config.conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, - (void *)(write_config.conf_array.reg_setting), - write_config.conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - write_config.conf_array.reg_setting = reg_setting; - write_slave_addr = write_config.slave_addr; - write_addr_type = write_config.conf_array.addr_type; - if (s_ctrl->sensor_i2c_client->cci_client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->cci_client->sid; - s_ctrl->sensor_i2c_client->cci_client->sid = - write_slave_addr >> 1; - } else if (s_ctrl->sensor_i2c_client->client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->client->addr; - s_ctrl->sensor_i2c_client->client->addr = - write_slave_addr >> 1; - } else { - pr_err("%s: error: no i2c/cci client found.", __func__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", - __func__, orig_slave_addr, - write_slave_addr >> 1); - orig_addr_type = s_ctrl->sensor_i2c_client->addr_type; - s_ctrl->sensor_i2c_client->addr_type = write_addr_type; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &(write_config.conf_array)); - s_ctrl->sensor_i2c_client->addr_type = orig_addr_type; - if (s_ctrl->sensor_i2c_client->cci_client) { - s_ctrl->sensor_i2c_client->cci_client->sid = - orig_slave_addr; - } else if (s_ctrl->sensor_i2c_client->client) { - s_ctrl->sensor_i2c_client->client->addr = - orig_slave_addr; - } else { - pr_err("%s: error: no i2c/cci client found.", __func__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (!conf_array.size || - conf_array.size > I2C_SEQ_REG_DATA_MAX) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - if (s_ctrl->func_tbl->sensor_power_up) { - if (s_ctrl->sensordata->misc_regulator) - msm_sensor_misc_regulator(s_ctrl, 1); - - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, - __LINE__, rc); - break; - } - s_ctrl->sensor_state = MSM_SENSOR_POWER_UP; - CDBG("%s:%d sensor state %d\n", __func__, __LINE__, - s_ctrl->sensor_state); - } else { - rc = -EFAULT; - } - break; - - case CFG_POWER_DOWN: - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - kfree(s_ctrl->stop_setting.reg_setting); - s_ctrl->stop_setting.reg_setting = NULL; - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - if (s_ctrl->func_tbl->sensor_power_down) { - if (s_ctrl->sensordata->misc_regulator) - msm_sensor_misc_regulator(s_ctrl, 0); - - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, - __LINE__, rc); - break; - } - s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; - CDBG("%s:%d sensor state %d\n", __func__, __LINE__, - s_ctrl->sensor_state); - } else { - rc = -EFAULT; - } - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (s_ctrl->is_csid_tg_mode) - goto DONE; - - if (copy_from_user(stop_setting, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - - if ((!stop_setting->size) || - (stop_setting->size > I2C_SEQ_REG_DATA_MAX)) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, - stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - - case CFG_SET_I2C_SYNC_PARAM: { - struct msm_camera_cci_ctrl cci_ctrl; - - s_ctrl->sensor_i2c_client->cci_client->cid = - cdata->cfg.sensor_i2c_sync_params.cid; - s_ctrl->sensor_i2c_client->cci_client->id_map = - cdata->cfg.sensor_i2c_sync_params.csid; - - CDBG("I2C_SYNC_PARAM CID:%d, line:%d delay:%d, cdid:%d\n", - s_ctrl->sensor_i2c_client->cci_client->cid, - cdata->cfg.sensor_i2c_sync_params.line, - cdata->cfg.sensor_i2c_sync_params.delay, - cdata->cfg.sensor_i2c_sync_params.csid); - - cci_ctrl.cmd = MSM_CCI_SET_SYNC_CID; - cci_ctrl.cfg.cci_wait_sync_cfg.line = - cdata->cfg.sensor_i2c_sync_params.line; - cci_ctrl.cfg.cci_wait_sync_cfg.delay = - cdata->cfg.sensor_i2c_sync_params.delay; - cci_ctrl.cfg.cci_wait_sync_cfg.cid = - cdata->cfg.sensor_i2c_sync_params.cid; - cci_ctrl.cfg.cci_wait_sync_cfg.csid = - cdata->cfg.sensor_i2c_sync_params.csid; - rc = v4l2_subdev_call(s_ctrl->sensor_i2c_client-> - cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - rc = -EFAULT; - break; - } - break; - } - - default: - rc = -EFAULT; - break; - } - -DONE: - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} - -int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl) -{ - int rc; - - if (s_ctrl->func_tbl->sensor_match_id) - rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); - else - rc = msm_sensor_match_id(s_ctrl); - if (rc < 0) - pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc); - return rc; -} - -static int msm_sensor_power(struct v4l2_subdev *sd, int on) -{ - int rc = 0; - struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); - - mutex_lock(s_ctrl->msm_sensor_mutex); - if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { - s_ctrl->func_tbl->sensor_power_down(s_ctrl); - s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; - } - mutex_unlock(s_ctrl->msm_sensor_mutex); - return rc; -} - -static int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, - unsigned int index, enum v4l2_mbus_pixelcode *code) -{ - struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); - - if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size) - return -EINVAL; - - *code = s_ctrl->sensor_v4l2_subdev_info[index].code; - return 0; -} - -static u32 msm_sensor_evt_mask_to_sensor_event(u32 evt_mask) -{ - u32 evt_id = SENSOR_EVENT_SUBS_MASK_NONE; - - switch (evt_mask) { - case SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS: - evt_id = SENSOR_EVENT_SIGNAL_STATUS; - break; - default: - evt_id = SENSOR_EVENT_SUBS_MASK_NONE; - break; - } - - return evt_id; -} - -static int msm_sensor_subscribe_event_mask(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub, int evt_mask_index, - u32 evt_id, bool subscribe_flag) -{ - int rc = 0; - - sub->type = evt_id; - - if (subscribe_flag) - rc = v4l2_event_subscribe(fh, sub, - MAX_SENSOR_V4l2_EVENTS, NULL); - else - rc = v4l2_event_unsubscribe(fh, sub); - if (rc != 0) { - pr_err("%s: Subs event_type =0x%x failed\n", - __func__, sub->type); - return rc; - } - return rc; -} - -static int msm_sensor_process_event_subscription(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub, bool subscribe_flag) -{ - int rc = 0, evt_mask_index = 0; - u32 evt_mask = sub->type; - u32 evt_id = 0; - - if (SENSOR_EVENT_SUBS_MASK_NONE == evt_mask) { - pr_err("%s: Subs event_type is None=0x%x\n", - __func__, evt_mask); - return 0; - } - - evt_mask_index = SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS; - if (evt_mask & (1<msm_sd.sd.devnode, &sensor_event); - return 0; -} - -static int msm_sensor_subscribe_event(struct v4l2_subdev *sd, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return msm_sensor_process_event_subscription(fh, sub, true); -} - -static int msm_sensor_unsubscribe_event(struct v4l2_subdev *sd, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return msm_sensor_process_event_subscription(fh, sub, false); -} - -static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = { - .ioctl = msm_sensor_subdev_ioctl, - .subscribe_event = msm_sensor_subscribe_event, - .unsubscribe_event = msm_sensor_unsubscribe_event, - .s_power = msm_sensor_power, -}; - -static struct v4l2_subdev_video_ops msm_sensor_subdev_video_ops = { - .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, -}; - -static struct v4l2_subdev_ops msm_sensor_subdev_ops = { - .core = &msm_sensor_subdev_core_ops, - .video = &msm_sensor_subdev_video_ops, -}; - -static struct msm_sensor_fn_t msm_sensor_func_tbl = { - .sensor_config = msm_sensor_config, -#ifdef CONFIG_COMPAT - .sensor_config32 = msm_sensor_config32, -#endif - .sensor_power_up = msm_sensor_power_up, - .sensor_power_down = msm_sensor_power_down, - .sensor_match_id = msm_sensor_match_id, -}; - -static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { - .i2c_read = msm_camera_cci_i2c_read, - .i2c_read_seq = msm_camera_cci_i2c_read_seq, - .i2c_write = msm_camera_cci_i2c_write, - .i2c_write_table = msm_camera_cci_i2c_write_table, - .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_cci_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_cci_i2c_util, - .i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl, - .i2c_write_table_async = msm_camera_cci_i2c_write_table_async, - .i2c_write_table_sync = msm_camera_cci_i2c_write_table_sync, - .i2c_write_table_sync_block = msm_camera_cci_i2c_write_table_sync_block, - -}; - -static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { - .i2c_read = msm_camera_qup_i2c_read, - .i2c_read_seq = msm_camera_qup_i2c_read_seq, - .i2c_write = msm_camera_qup_i2c_write, - .i2c_write_table = msm_camera_qup_i2c_write_table, - .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_qup_i2c_write_table_w_microdelay, - .i2c_write_conf_tbl = msm_camera_qup_i2c_write_conf_tbl, - .i2c_write_table_async = msm_camera_qup_i2c_write_table, - .i2c_write_table_sync = msm_camera_qup_i2c_write_table, - .i2c_write_table_sync_block = msm_camera_qup_i2c_write_table, -}; - -static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl = { - .i2c_read = msm_camera_tz_i2c_read, - .i2c_read_seq = msm_camera_tz_i2c_read_seq, - .i2c_write = msm_camera_tz_i2c_write, - .i2c_write_table = msm_camera_tz_i2c_write_table, - .i2c_write_seq_table = msm_camera_tz_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_tz_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_tz_i2c_util, - .i2c_write_conf_tbl = msm_camera_tz_i2c_write_conf_tbl, - .i2c_write_table_async = msm_camera_tz_i2c_write_table_async, - .i2c_write_table_sync = msm_camera_tz_i2c_write_table_sync, - .i2c_write_table_sync_block = msm_camera_tz_i2c_write_table_sync_block, -}; - -int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) -{ - struct msm_camera_cci_client *cci_client = NULL; - unsigned long mount_pos = 0; - - /* Validate input parameters */ - if (!s_ctrl) { - pr_err("%s:%d failed: invalid params s_ctrl %pK\n", __func__, - __LINE__, s_ctrl); - return -EINVAL; - } - - if (!s_ctrl->sensor_i2c_client) { - pr_err("%s:%d failed: invalid params sensor_i2c_client %pK\n", - __func__, __LINE__, s_ctrl->sensor_i2c_client); - return -EINVAL; - } - - /* Initialize cci_client */ - s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!s_ctrl->sensor_i2c_client->cci_client) - return -ENOMEM; - - if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - cci_client = s_ctrl->sensor_i2c_client->cci_client; - - /* Get CCI subdev */ - cci_client->cci_subdev = msm_cci_get_subdev(); - - if (s_ctrl->is_secure) - msm_camera_tz_i2c_register_sensor((void *)s_ctrl); - - /* Update CCI / I2C function table */ - if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_cci_func_tbl; - } else { - if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) { - CDBG("%s:%d\n", __func__, __LINE__); - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_qup_func_tbl; - } - } - - /* Update function table driven by ioctl */ - if (!s_ctrl->func_tbl) - s_ctrl->func_tbl = &msm_sensor_func_tbl; - - /* Update v4l2 subdev ops table */ - if (!s_ctrl->sensor_v4l2_subdev_ops) - s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; - - /* Update sensor mount angle and position in media entity flag */ - mount_pos = s_ctrl->sensordata->sensor_info->position << 16; - mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> - sensor_mount_angle / 90) << 8); - s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; - - return 0; -} diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor.h b/drivers/media/platform/msm/ais/sensor/msm_sensor.h deleted file mode 100644 index 1ec54b8eb548476d9488a8bc1b08b1c1c8893b32..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/msm_sensor.h +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_SENSOR_H -#define MSM_SENSOR_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_camera_dt_util.h" -#include "msm_sd.h" -#include "msm_sensor_init.h" - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -enum msm_sensor_sensor_slave_info_type { - MSM_SENSOR_SLAVEADDR_DATA, - MSM_SENSOR_IDREGADDR_DATA, - MSM_SENSOR_SENSOR_ID_DATA, - MSM_SENSOR_SENIDMASK_DATA, - MSM_SENSOR_NUM_ID_INFO_DATA, -}; - -struct msm_sensor_ctrl_t; - -enum msm_sensor_state_t { - MSM_SENSOR_POWER_DOWN, - MSM_SENSOR_POWER_UP, -}; - -struct msm_sensor_fn_t { - int (*sensor_config)(struct msm_sensor_ctrl_t *, void __user *); -#ifdef CONFIG_COMPAT - int (*sensor_config32)(struct msm_sensor_ctrl_t *, void __user *); -#endif - int (*sensor_power_down)(struct msm_sensor_ctrl_t *); - int (*sensor_power_up)(struct msm_sensor_ctrl_t *); - int (*sensor_match_id)(struct msm_sensor_ctrl_t *); -}; - -struct msm_sensor_ctrl_t { - struct platform_device *pdev; - struct mutex *msm_sensor_mutex; - - enum msm_camera_device_type_t sensor_device_type; - struct msm_camera_sensor_board_info *sensordata; - struct msm_sensor_power_setting_array power_setting_array; - struct msm_sensor_packed_cfg_t *cfg_override; - struct msm_sd_subdev msm_sd; - enum cci_i2c_master_t cci_i2c_master; - - struct msm_camera_i2c_client *sensor_i2c_client; - struct v4l2_subdev_info *sensor_v4l2_subdev_info; - uint8_t sensor_v4l2_subdev_info_size; - struct v4l2_subdev_ops *sensor_v4l2_subdev_ops; - struct msm_sensor_fn_t *func_tbl; - struct msm_camera_i2c_reg_setting stop_setting; - void *misc_regulator; - enum msm_sensor_state_t sensor_state; - uint8_t is_probe_succeed; - uint32_t id; - struct device_node *of_node; - enum msm_camera_stream_type_t camera_stream_type; - uint32_t set_mclk_23880000; - uint8_t is_csid_tg_mode; - uint32_t is_secure; - /* Interrupt GPIOs */ - struct gpio gpio_array[1]; - /* device status and Flags */ - int irq; - struct msm_sensor_init_t s_init; - /* worker to handle interrupts */ - struct delayed_work irq_delayed_work; -}; - -int msm_sensor_send_event(struct msm_sensor_ctrl_t *s_ctrl, - uint32_t event_type, struct msm_sensor_event_data *event_data); - -int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp); - -int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_update_cfg(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl); - -int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl); - -int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); -#ifdef CONFIG_COMPAT -long msm_sensor_subdev_fops_ioctl(struct file *file, - unsigned int cmd, - unsigned long arg); -#endif -#endif diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor_init.c b/drivers/media/platform/msm/ais/sensor/msm_sensor_init.c deleted file mode 100644 index ffbf963e819eedfec0223ecfae8f4de2e72d65c5..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/msm_sensor_init.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "MSM-SENSOR-INIT %s:%d " fmt "\n", __func__, __LINE__ - -/* Header files */ -#include "msm_sensor_driver.h" -#include "msm_sensor.h" -#include "msm_sd.h" -#include "msm_camera_io_util.h" -#include "msm_early_cam.h" - -/* Logging macro */ -#undef CDBG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) - -#define EARLY_CAMERA_SIGNAL_DONE 0xa5a5a5a5 -#define EARLY_CAMERA_SIGNAL_DISABLED 0 - -static bool early_camera_clock_off; -static struct msm_sensor_init_t *s_init; - -static int msm_sensor_wait_for_probe_done(struct msm_sensor_init_t *s_init) -{ - int rc; - int tm = 10000; - - if (s_init->module_init_status == 1) { - CDBG("msm_cam_get_module_init_status -2\n"); - return 0; - } - rc = wait_event_timeout(s_init->state_wait, - (s_init->module_init_status == 1), msecs_to_jiffies(tm)); - if (rc == 0) { - pr_err("%s:%d wait timeout\n", __func__, __LINE__); - rc = -1; - } - - return rc; -} - -#define MMSS_A_VFE_0_SPARE 0xC84 - -/* Static function definition */ -int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init, void *arg) -{ - int32_t rc = 0; - u32 val = 0; - void __iomem *base; - struct sensor_init_cfg_data *cfg = (struct sensor_init_cfg_data *)arg; - - /* Validate input parameters */ - if (!s_init || !cfg) { - pr_err("failed: s_init %pK cfg %pK", s_init, cfg); - return -EINVAL; - } - - pr_debug("%s : %d", __func__, cfg->cfgtype); - switch (cfg->cfgtype) { - case CFG_SINIT_PROBE: - mutex_lock(&s_init->imutex); - s_init->module_init_status = 0; - rc = msm_sensor_driver_probe(cfg->cfg.setting, - &cfg->probed_info, - cfg->entity_name); - mutex_unlock(&s_init->imutex); - if (rc < 0) - pr_err("%s failed (non-fatal) rc %d", __func__, rc); - break; - - case CFG_SINIT_PROBE_DONE: - if (early_camera_clock_off == false) { - base = ioremap(0x00A10000, 0x1000); - val = msm_camera_io_r_mb(base + MMSS_A_VFE_0_SPARE); - while (val != EARLY_CAMERA_SIGNAL_DONE) { - if (val == EARLY_CAMERA_SIGNAL_DISABLED) - break; - msleep(1000); - val = msm_camera_io_r_mb( - base + MMSS_A_VFE_0_SPARE); - pr_err("Waiting for signal from LK val = %u\n", - val); - } - rc = msm_early_cam_disable_clocks(); - if (rc < 0) { - pr_err("Failed to disable early camera :%d\n", - rc); - } else { - early_camera_clock_off = true; - pr_debug("Voted OFF early camera clocks\n"); - } - } - - s_init->module_init_status = 1; - wake_up(&s_init->state_wait); - break; - - case CFG_SINIT_PROBE_WAIT_DONE: - rc = msm_sensor_wait_for_probe_done(s_init); - break; - - default: - pr_err("default"); - break; - } - - return rc; -} - -static int __init msm_sensor_init_module(void) -{ - int ret = 0; - - /* Allocate memory for msm_sensor_init control structure */ - s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL); - if (!s_init) - return -ENOMEM; - - CDBG("MSM_SENSOR_INIT_MODULE %pK", NULL); - - /* Initialize mutex */ - mutex_init(&s_init->imutex); - - init_waitqueue_head(&s_init->state_wait); - early_camera_clock_off = false; - return ret; -} - -static void __exit msm_sensor_exit_module(void) -{ - mutex_destroy(&s_init->imutex); - kfree(s_init); -} - -module_init(msm_sensor_init_module); -module_exit(msm_sensor_exit_module); -MODULE_DESCRIPTION("msm_sensor_init"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/ois/Makefile b/drivers/media/platform/msm/ais/sensor/ois/Makefile deleted file mode 100644 index 9e08ea0f3c8d317714c1c0a36eac33382e996ca0..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ois/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/ais -ccflags-y += -Idrivers/media/platform/msm/ais/common -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io -ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci -obj-$(CONFIG_MSM_AIS) += msm_ois.o diff --git a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c deleted file mode 100644 index 4b529bc6c0a6e24a72c42e93f75d0fdd9bc43fcb..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c +++ /dev/null @@ -1,1020 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ - -#include -#include -#include "msm_sd.h" -#include "msm_ois.h" -#include "msm_cci.h" - -DEFINE_MSM_MUTEX(msm_ois_mutex); -/* #define MSM_OIS_DEBUG */ -#undef CDBG -#ifdef MSM_OIS_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -static struct v4l2_file_operations msm_ois_v4l2_subdev_fops; -static int32_t msm_ois_power_up(struct msm_ois_ctrl_t *o_ctrl); -static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl); - -static struct i2c_driver msm_ois_i2c_driver; - -static int32_t msm_ois_download(struct msm_ois_ctrl_t *o_ctrl) -{ - uint16_t bytes_in_tx = 0; - uint16_t total_bytes = 0; - uint8_t *ptr = NULL; - int32_t rc = 0; - const struct firmware *fw = NULL; - const char *fw_name_prog = NULL; - const char *fw_name_coeff = NULL; - char name_prog[MAX_SENSOR_NAME] = {0}; - char name_coeff[MAX_SENSOR_NAME] = {0}; - struct device *dev = &(o_ctrl->pdev->dev); - enum msm_camera_i2c_reg_addr_type save_addr_type; - - CDBG("Enter\n"); - save_addr_type = o_ctrl->i2c_client.addr_type; - o_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR; - - snprintf(name_coeff, MAX_SENSOR_NAME, "%s.coeff", - o_ctrl->oboard_info->ois_name); - - snprintf(name_prog, MAX_SENSOR_NAME, "%s.prog", - o_ctrl->oboard_info->ois_name); - - /* cast pointer as const pointer*/ - fw_name_prog = name_prog; - fw_name_coeff = name_coeff; - - /* Load FW */ - rc = request_firmware(&fw, fw_name_prog, dev); - if (rc) { - dev_err(dev, "Failed to locate %s\n", fw_name_prog); - o_ctrl->i2c_client.addr_type = save_addr_type; - return rc; - } - - total_bytes = fw->size; - for (ptr = (uint8_t *)fw->data; total_bytes; - total_bytes -= bytes_in_tx, ptr += bytes_in_tx) { - bytes_in_tx = (total_bytes > 10) ? 10 : total_bytes; - rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq( - &o_ctrl->i2c_client, o_ctrl->oboard_info->opcode.prog, - ptr, bytes_in_tx); - if (rc < 0) { - pr_err("Failed: remaining bytes to be downloaded: %d", - bytes_in_tx); - /* abort download fw and return error*/ - goto release_firmware; - } - } - release_firmware(fw); - - rc = request_firmware(&fw, fw_name_coeff, dev); - if (rc) { - dev_err(dev, "Failed to locate %s\n", fw_name_coeff); - o_ctrl->i2c_client.addr_type = save_addr_type; - return rc; - } - total_bytes = fw->size; - for (ptr = (uint8_t *)fw->data; total_bytes; - total_bytes -= bytes_in_tx, ptr += bytes_in_tx) { - bytes_in_tx = (total_bytes > 10) ? 10 : total_bytes; - rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq( - &o_ctrl->i2c_client, o_ctrl->oboard_info->opcode.coeff, - ptr, bytes_in_tx); - if (rc < 0) { - pr_err("Failed: remaining bytes to be downloaded: %d", - total_bytes); - /* abort download fw*/ - break; - } - } -release_firmware: - release_firmware(fw); - o_ctrl->i2c_client.addr_type = save_addr_type; - - return rc; -} - -static int32_t msm_ois_data_config(struct msm_ois_ctrl_t *o_ctrl, - struct msm_ois_slave_info *slave_info) -{ - int rc = 0; - struct msm_camera_cci_client *cci_client = NULL; - - CDBG("Enter\n"); - if (!slave_info) { - pr_err("failed : invalid slave_info "); - return -EINVAL; - } - /* fill ois slave info*/ - if (strlcpy(o_ctrl->oboard_info->ois_name, slave_info->ois_name, - sizeof(o_ctrl->oboard_info->ois_name)) < 0) { - pr_err("failed: copy_from_user"); - return -EFAULT; - } - memcpy(&(o_ctrl->oboard_info->opcode), &(slave_info->opcode), - sizeof(struct msm_ois_opcode)); - o_ctrl->oboard_info->i2c_slaveaddr = slave_info->i2c_addr; - - /* config cci_client*/ - if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - cci_client = o_ctrl->i2c_client.cci_client; - cci_client->sid = - o_ctrl->oboard_info->i2c_slaveaddr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - cci_client->cci_i2c_master = o_ctrl->cci_master; - } else { - o_ctrl->i2c_client.client->addr = - o_ctrl->oboard_info->i2c_slaveaddr; - } - o_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_WORD_ADDR; - - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_ois_write_settings(struct msm_ois_ctrl_t *o_ctrl, - uint16_t size, struct reg_settings_ois_t *settings) -{ - int32_t rc = -EFAULT; - int32_t i = 0; - struct msm_camera_i2c_seq_reg_array *reg_setting; - - CDBG("Enter\n"); - - for (i = 0; i < size; i++) { - switch (settings[i].i2c_operation) { - case MSM_OIS_WRITE: { - switch (settings[i].data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &o_ctrl->i2c_client, - settings[i].reg_addr, - settings[i].reg_data, - settings[i].data_type); - break; - case MSM_CAMERA_I2C_DWORD_DATA: - reg_setting = - kzalloc(sizeof(struct msm_camera_i2c_seq_reg_array), - GFP_KERNEL); - if (!reg_setting) - return -ENOMEM; - - reg_setting->reg_addr = settings[i].reg_addr; - reg_setting->reg_data[0] = (uint8_t) - ((settings[i].reg_data & - 0xFF000000) >> 24); - reg_setting->reg_data[1] = (uint8_t) - ((settings[i].reg_data & - 0x00FF0000) >> 16); - reg_setting->reg_data[2] = (uint8_t) - ((settings[i].reg_data & - 0x0000FF00) >> 8); - reg_setting->reg_data[3] = (uint8_t) - (settings[i].reg_data & 0x000000FF); - reg_setting->reg_data_size = 4; - rc = o_ctrl->i2c_client.i2c_func_tbl-> - i2c_write_seq(&o_ctrl->i2c_client, - reg_setting->reg_addr, - reg_setting->reg_data, - reg_setting->reg_data_size); - kfree(reg_setting); - reg_setting = NULL; - if (rc < 0) - return rc; - break; - - default: - pr_err("Unsupport data type: %d\n", - settings[i].data_type); - break; - } - if (settings[i].delay > 20) - msleep(settings[i].delay); - else if (0 != settings[i].delay) - usleep_range(settings[i].delay * 1000, - (settings[i].delay * 1000) + 1000); - } - break; - - case MSM_OIS_POLL: { - switch (settings[i].data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - - rc = o_ctrl->i2c_client.i2c_func_tbl - ->i2c_poll(&o_ctrl->i2c_client, - settings[i].reg_addr, - settings[i].reg_data, - settings[i].data_type, - settings[i].delay); - break; - - default: - pr_err("Unsupport data type: %d\n", - settings[i].data_type); - break; - } - } - } - - if (rc < 0) - break; - } - - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_ois_vreg_control(struct msm_ois_ctrl_t *o_ctrl, - int config) -{ - int rc = 0, i, cnt; - struct msm_ois_vreg *vreg_cfg; - - vreg_cfg = &o_ctrl->vreg_cfg; - cnt = vreg_cfg->num_vreg; - if (!cnt) - return 0; - - if (cnt >= MSM_OIS_MAX_VREGS) { - pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt); - return -EINVAL; - } - - for (i = 0; i < cnt; i++) { - rc = msm_camera_config_single_vreg(&(o_ctrl->pdev->dev), - &vreg_cfg->cam_vreg[i], - (struct regulator **)&vreg_cfg->data[i], - config); - } - return rc; -} - -static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl) -{ - int32_t rc = 0; - enum msm_sensor_power_seq_gpio_t gpio; - - CDBG("Enter\n"); - if (o_ctrl->ois_state != OIS_DISABLE_STATE) { - - rc = msm_ois_vreg_control(o_ctrl, 0); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - - for (gpio = SENSOR_GPIO_AF_PWDM; gpio < SENSOR_GPIO_MAX; - gpio++) { - if (o_ctrl->gconf && - o_ctrl->gconf->gpio_num_info && - o_ctrl->gconf-> - gpio_num_info->valid[gpio] == 1) { - gpio_set_value_cansleep( - o_ctrl->gconf->gpio_num_info - ->gpio_num[gpio], - GPIOF_OUT_INIT_LOW); - - if (o_ctrl->cam_pinctrl_status) { - rc = pinctrl_select_state( - o_ctrl->pinctrl_info.pinctrl, - o_ctrl->pinctrl_info. - gpio_state_suspend); - if (rc < 0) - pr_err("ERR:%s:%d cannot set pin to suspend state: %d", - __func__, __LINE__, rc); - devm_pinctrl_put( - o_ctrl->pinctrl_info.pinctrl); - } - o_ctrl->cam_pinctrl_status = 0; - rc = msm_camera_request_gpio_table( - o_ctrl->gconf->cam_gpio_req_tbl, - o_ctrl->gconf->cam_gpio_req_tbl_size, - 0); - if (rc < 0) - pr_err("ERR:%s:Failed in selecting state in ois power down: %d\n", - __func__, rc); - } - } - - o_ctrl->i2c_tbl_index = 0; - o_ctrl->ois_state = OIS_OPS_INACTIVE; - } - CDBG("Exit\n"); - return rc; -} - -static int msm_ois_init(struct msm_ois_ctrl_t *o_ctrl) -{ - int rc = 0; - - CDBG("Enter\n"); - - if (!o_ctrl) { - pr_err("failed\n"); - return -EINVAL; - } - - if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_util( - &o_ctrl->i2c_client, MSM_CCI_INIT); - if (rc < 0) - pr_err("cci_init failed\n"); - } - o_ctrl->ois_state = OIS_OPS_ACTIVE; - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl, - struct msm_ois_set_info_t *set_info) -{ - struct reg_settings_ois_t *settings = NULL; - int32_t rc = 0; - struct msm_camera_cci_client *cci_client = NULL; - - CDBG("Enter\n"); - - if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - cci_client = o_ctrl->i2c_client.cci_client; - cci_client->sid = - set_info->ois_params.i2c_addr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - cci_client->cci_i2c_master = o_ctrl->cci_master; - cci_client->i2c_freq_mode = set_info->ois_params.i2c_freq_mode; - } else { - o_ctrl->i2c_client.client->addr = - set_info->ois_params.i2c_addr; - } - o_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_WORD_ADDR; - - - if (set_info->ois_params.setting_size > 0 && - set_info->ois_params.setting_size - < MAX_OIS_REG_SETTINGS) { - settings = kmalloc( - sizeof(struct reg_settings_ois_t) * - (set_info->ois_params.setting_size), - GFP_KERNEL); - if (settings == NULL) { - pr_err("Error allocating memory\n"); - return -EFAULT; - } - if (copy_from_user(settings, - (void *)set_info->ois_params.settings, - set_info->ois_params.setting_size * - sizeof(struct reg_settings_ois_t))) { - kfree(settings); - pr_err("Error copying\n"); - return -EFAULT; - } - - rc = msm_ois_write_settings(o_ctrl, - set_info->ois_params.setting_size, - settings); - kfree(settings); - if (rc < 0) { - pr_err("Error\n"); - return -EFAULT; - } - } - - CDBG("Exit\n"); - - return rc; -} - - -static int32_t msm_ois_config(struct msm_ois_ctrl_t *o_ctrl, - void __user *argp) -{ - struct msm_ois_cfg_data *cdata = - (struct msm_ois_cfg_data *)argp; - int32_t rc = 0; - - mutex_lock(o_ctrl->ois_mutex); - CDBG("Enter\n"); - CDBG("%s type %d\n", __func__, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_OIS_INIT: - rc = msm_ois_init(o_ctrl); - if (rc < 0) - pr_err("msm_ois_init failed %d\n", rc); - break; - case CFG_OIS_POWERDOWN: - rc = msm_ois_power_down(o_ctrl); - if (rc < 0) - pr_err("msm_ois_power_down failed %d\n", rc); - break; - case CFG_OIS_POWERUP: - rc = msm_ois_power_up(o_ctrl); - if (rc < 0) - pr_err("Failed ois power up%d\n", rc); - break; - case CFG_OIS_CONTROL: - rc = msm_ois_control(o_ctrl, &cdata->cfg.set_info); - if (rc < 0) - pr_err("Failed ois control%d\n", rc); - break; - case CFG_OIS_I2C_WRITE_SEQ_TABLE: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - memcpy(&conf_array, - (void *)cdata->cfg.settings, - sizeof(struct msm_camera_i2c_seq_reg_setting)); - } else -#endif - if (copy_from_user(&conf_array, - (void *)cdata->cfg.settings, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (!conf_array.size || - conf_array.size > I2C_SEQ_REG_DATA_MAX) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = o_ctrl->i2c_client.i2c_func_tbl-> - i2c_write_seq_table(&o_ctrl->i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - default: - break; - } - mutex_unlock(o_ctrl->ois_mutex); - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_ois_config_download(struct msm_ois_ctrl_t *o_ctrl, - void __user *argp) -{ - struct msm_ois_cfg_download_data *cdata = - (struct msm_ois_cfg_download_data *)argp; - int32_t rc = 0; - - if (!o_ctrl || !cdata) { - pr_err("failed: Invalid data\n"); - return -EINVAL; - } - mutex_lock(o_ctrl->ois_mutex); - CDBG("Enter\n"); - CDBG("%s type %d\n", __func__, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_OIS_DATA_CONFIG: - rc = msm_ois_data_config(o_ctrl, &cdata->slave_info); - if (rc < 0) - pr_err("Failed ois data config %d\n", rc); - break; - case CFG_OIS_DOWNLOAD: - rc = msm_ois_download(o_ctrl); - if (rc < 0) - pr_err("Failed ois download %d\n", rc); - break; - default: - break; - } - mutex_unlock(o_ctrl->ois_mutex); - CDBG("Exit\n"); - return rc; -} - - -static int32_t msm_ois_get_subdev_id(struct msm_ois_ctrl_t *o_ctrl, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - - CDBG("Enter\n"); - if (!subdev_id) { - pr_err("failed\n"); - return -EINVAL; - } - if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) - *subdev_id = o_ctrl->pdev->id; - else - *subdev_id = o_ctrl->subdev_id; - - CDBG("subdev_id %d\n", *subdev_id); - CDBG("Exit\n"); - return 0; -} - -static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { - .i2c_read = msm_camera_cci_i2c_read, - .i2c_read_seq = msm_camera_cci_i2c_read_seq, - .i2c_write = msm_camera_cci_i2c_write, - .i2c_write_table = msm_camera_cci_i2c_write_table, - .i2c_write_seq = msm_camera_cci_i2c_write_seq, - .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_cci_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_cci_i2c_util, - .i2c_poll = msm_camera_cci_i2c_poll, -}; - -static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { - .i2c_read = msm_camera_qup_i2c_read, - .i2c_read_seq = msm_camera_qup_i2c_read_seq, - .i2c_write = msm_camera_qup_i2c_write, - .i2c_write_table = msm_camera_qup_i2c_write_table, - .i2c_write_seq = msm_camera_qup_i2c_write_seq, - .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_qup_i2c_write_table_w_microdelay, - .i2c_poll = msm_camera_qup_i2c_poll, -}; - -static int msm_ois_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) { - int rc = 0; - struct msm_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); - - CDBG("Enter\n"); - if (!o_ctrl) { - pr_err("failed\n"); - return -EINVAL; - } - mutex_lock(o_ctrl->ois_mutex); - if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE && - o_ctrl->ois_state != OIS_DISABLE_STATE) { - rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_util( - &o_ctrl->i2c_client, MSM_CCI_RELEASE); - if (rc < 0) - pr_err("cci_init failed\n"); - } - o_ctrl->ois_state = OIS_DISABLE_STATE; - mutex_unlock(o_ctrl->ois_mutex); - CDBG("Exit\n"); - return rc; -} - -static const struct v4l2_subdev_internal_ops msm_ois_internal_ops = { - .close = msm_ois_close, -}; - -static long msm_ois_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc; - struct msm_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); - void __user *argp = (void __user *)arg; - - CDBG("Enter\n"); - CDBG("%s:%d o_ctrl %pK argp %pK\n", __func__, __LINE__, o_ctrl, argp); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return msm_ois_get_subdev_id(o_ctrl, argp); - case VIDIOC_MSM_OIS_CFG: - return msm_ois_config(o_ctrl, argp); - case VIDIOC_MSM_OIS_CFG_DOWNLOAD: - return msm_ois_config_download(o_ctrl, argp); - case MSM_SD_SHUTDOWN: - if (!o_ctrl->i2c_client.i2c_func_tbl) { - pr_err("o_ctrl->i2c_client.i2c_func_tbl NULL\n"); - return -EINVAL; - } - mutex_lock(o_ctrl->ois_mutex); - rc = msm_ois_power_down(o_ctrl); - if (rc < 0) { - pr_err("%s:%d OIS Power down failed\n", - __func__, __LINE__); - } - mutex_unlock(o_ctrl->ois_mutex); - return msm_ois_close(sd, NULL); - default: - return -ENOIOCTLCMD; - } -} - -static int32_t msm_ois_power_up(struct msm_ois_ctrl_t *o_ctrl) -{ - int rc = 0; - enum msm_sensor_power_seq_gpio_t gpio; - - CDBG("%s called\n", __func__); - - rc = msm_ois_vreg_control(o_ctrl, 1); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - - for (gpio = SENSOR_GPIO_AF_PWDM; - gpio < SENSOR_GPIO_MAX; gpio++) { - if (o_ctrl->gconf && o_ctrl->gconf->gpio_num_info && - o_ctrl->gconf->gpio_num_info->valid[gpio] == 1) { - rc = msm_camera_request_gpio_table( - o_ctrl->gconf->cam_gpio_req_tbl, - o_ctrl->gconf->cam_gpio_req_tbl_size, 1); - if (rc < 0) { - pr_err("ERR:%s:Failed in selecting state for ois: %d\n", - __func__, rc); - return rc; - } - if (o_ctrl->cam_pinctrl_status) { - rc = pinctrl_select_state( - o_ctrl->pinctrl_info.pinctrl, - o_ctrl->pinctrl_info.gpio_state_active); - if (rc < 0) - pr_err("ERR:%s:%d cannot set pin to active state: %d", - __func__, __LINE__, rc); - } - - gpio_set_value_cansleep( - o_ctrl->gconf->gpio_num_info->gpio_num[gpio], - 1); - } - } - - o_ctrl->ois_state = OIS_ENABLE_STATE; - CDBG("Exit\n"); - return rc; -} - -static struct v4l2_subdev_core_ops msm_ois_subdev_core_ops = { - .ioctl = msm_ois_subdev_ioctl, -}; - -static struct v4l2_subdev_ops msm_ois_subdev_ops = { - .core = &msm_ois_subdev_core_ops, -}; - -static const struct i2c_device_id msm_ois_i2c_id[] = { - {"qcom,ois", (kernel_ulong_t)NULL}, - { } -}; - -static int32_t msm_ois_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - struct msm_ois_ctrl_t *ois_ctrl_t = NULL; - - CDBG("Enter\n"); - - if (client == NULL) { - pr_err("msm_ois_i2c_probe: client is null\n"); - return -EINVAL; - } - - ois_ctrl_t = kzalloc(sizeof(struct msm_ois_ctrl_t), - GFP_KERNEL); - if (!ois_ctrl_t) - return -ENOMEM; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("i2c_check_functionality failed\n"); - rc = -EINVAL; - goto probe_failure; - } - - CDBG("client = 0x%pK\n", client); - - rc = of_property_read_u32(client->dev.of_node, "cell-index", - &ois_ctrl_t->subdev_id); - CDBG("cell-index %d, rc %d\n", ois_ctrl_t->subdev_id, rc); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto probe_failure; - } - - ois_ctrl_t->i2c_driver = &msm_ois_i2c_driver; - ois_ctrl_t->i2c_client.client = client; - /* Set device type as I2C */ - ois_ctrl_t->ois_device_type = MSM_CAMERA_I2C_DEVICE; - ois_ctrl_t->i2c_client.i2c_func_tbl = &msm_sensor_qup_func_tbl; - ois_ctrl_t->ois_v4l2_subdev_ops = &msm_ois_subdev_ops; - ois_ctrl_t->ois_mutex = &msm_ois_mutex; - - /* Assign name for sub device */ - snprintf(ois_ctrl_t->msm_sd.sd.name, sizeof(ois_ctrl_t->msm_sd.sd.name), - "%s", ois_ctrl_t->i2c_driver->driver.name); - - /* Initialize sub device */ - v4l2_i2c_subdev_init(&ois_ctrl_t->msm_sd.sd, - ois_ctrl_t->i2c_client.client, - ois_ctrl_t->ois_v4l2_subdev_ops); - v4l2_set_subdevdata(&ois_ctrl_t->msm_sd.sd, ois_ctrl_t); - ois_ctrl_t->msm_sd.sd.internal_ops = &msm_ois_internal_ops; - ois_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&ois_ctrl_t->msm_sd.sd.entity, 0, NULL, 0); - ois_ctrl_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - ois_ctrl_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_OIS; - ois_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; - msm_sd_register(&ois_ctrl_t->msm_sd); - ois_ctrl_t->ois_state = OIS_DISABLE_STATE; - pr_info("msm_ois_i2c_probe: succeeded\n"); - CDBG("Exit\n"); - -probe_failure: - kfree(ois_ctrl_t); - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_ois_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - long rc = 0; - struct video_device *vdev; - struct v4l2_subdev *sd; - struct msm_ois_cfg_data32 *u32; - struct msm_ois_cfg_data ois_data; - void *parg; - struct msm_camera_i2c_seq_reg_setting settings; - struct msm_camera_i2c_seq_reg_setting32 settings32; - - if (!file || !arg) { - pr_err("%s:failed NULL parameter\n", __func__); - return -EINVAL; - } - vdev = video_devdata(file); - sd = vdev_to_v4l2_subdev(vdev); - u32 = (struct msm_ois_cfg_data32 *)arg; - parg = arg; - - - switch (cmd) { - case VIDIOC_MSM_OIS_CFG32: - cmd = VIDIOC_MSM_OIS_CFG; - ois_data.cfgtype = u32->cfgtype; - - switch (u32->cfgtype) { - case CFG_OIS_CONTROL: - ois_data.cfg.set_info.ois_params.setting_size = - u32->cfg.set_info.ois_params.setting_size; - ois_data.cfg.set_info.ois_params.i2c_addr = - u32->cfg.set_info.ois_params.i2c_addr; - ois_data.cfg.set_info.ois_params.i2c_freq_mode = - u32->cfg.set_info.ois_params.i2c_freq_mode; - ois_data.cfg.set_info.ois_params.i2c_addr_type = - u32->cfg.set_info.ois_params.i2c_addr_type; - ois_data.cfg.set_info.ois_params.i2c_data_type = - u32->cfg.set_info.ois_params.i2c_data_type; - ois_data.cfg.set_info.ois_params.settings = - compat_ptr(u32->cfg.set_info.ois_params. - settings); - parg = &ois_data; - break; - case CFG_OIS_I2C_WRITE_SEQ_TABLE: - if (copy_from_user(&settings32, - (void *)compat_ptr(u32->cfg.settings), - sizeof( - struct msm_camera_i2c_seq_reg_setting32))) { - pr_err("copy_from_user failed\n"); - return -EFAULT; - } - - settings.addr_type = settings32.addr_type; - settings.delay = settings32.delay; - settings.size = settings32.size; - settings.reg_setting = - compat_ptr(settings32.reg_setting); - - ois_data.cfg.settings = &settings; - parg = &ois_data; - break; - default: - parg = &ois_data; - break; - } - break; - case VIDIOC_MSM_OIS_CFG: - pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd); - return -EINVAL; - } - rc = msm_ois_subdev_ioctl(sd, cmd, parg); - - return rc; -} - -static long msm_ois_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_ois_subdev_do_ioctl); -} -#endif - -static int32_t msm_ois_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - struct msm_camera_cci_client *cci_client = NULL; - struct msm_ois_ctrl_t *msm_ois_t = NULL; - struct msm_ois_vreg *vreg_cfg; - - CDBG("Enter\n"); - - if (!pdev->dev.of_node) { - pr_err("of_node NULL\n"); - return -EINVAL; - } - - msm_ois_t = kzalloc(sizeof(struct msm_ois_ctrl_t), - GFP_KERNEL); - if (!msm_ois_t) - return -ENOMEM; - - msm_ois_t->oboard_info = kzalloc(sizeof( - struct msm_ois_board_info), GFP_KERNEL); - if (!msm_ois_t->oboard_info) { - kfree(msm_ois_t); - return -ENOMEM; - } - - rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index", - &pdev->id); - CDBG("cell-index %d, rc %d\n", pdev->id, rc); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto release_memory; - } - - rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master", - &msm_ois_t->cci_master); - CDBG("qcom,cci-master %d, rc %d\n", msm_ois_t->cci_master, rc); - if (rc < 0 || msm_ois_t->cci_master >= MASTER_MAX) { - pr_err("failed rc %d\n", rc); - goto release_memory; - } - - if (of_find_property((&pdev->dev)->of_node, - "qcom,cam-vreg-name", NULL)) { - vreg_cfg = &msm_ois_t->vreg_cfg; - rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node, - &vreg_cfg->cam_vreg, &vreg_cfg->num_vreg); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto release_memory; - } - } - - rc = msm_sensor_driver_get_gpio_data(&(msm_ois_t->gconf), - (&pdev->dev)->of_node); - if (-ENODEV == rc) { - pr_notice("No valid OIS GPIOs data\n"); - } else if (rc < 0) { - pr_err("Error OIS GPIO\n"); - } else { - msm_ois_t->cam_pinctrl_status = 1; - rc = msm_camera_pinctrl_init( - &(msm_ois_t->pinctrl_info), &(pdev->dev)); - if (rc < 0) { - pr_err("ERR: Error in reading OIS pinctrl\n"); - msm_ois_t->cam_pinctrl_status = 0; - } - } - - msm_ois_t->ois_v4l2_subdev_ops = &msm_ois_subdev_ops; - msm_ois_t->ois_mutex = &msm_ois_mutex; - - /* Set platform device handle */ - msm_ois_t->pdev = pdev; - /* Set device type as platform device */ - msm_ois_t->ois_device_type = MSM_CAMERA_PLATFORM_DEVICE; - msm_ois_t->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl; - msm_ois_t->i2c_client.cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!msm_ois_t->i2c_client.cci_client) { - kfree(msm_ois_t->vreg_cfg.cam_vreg); - rc = -ENOMEM; - goto release_memory; - } - - cci_client = msm_ois_t->i2c_client.cci_client; - cci_client->cci_subdev = msm_cci_get_subdev(); - cci_client->cci_i2c_master = msm_ois_t->cci_master; - v4l2_subdev_init(&msm_ois_t->msm_sd.sd, - msm_ois_t->ois_v4l2_subdev_ops); - v4l2_set_subdevdata(&msm_ois_t->msm_sd.sd, msm_ois_t); - msm_ois_t->msm_sd.sd.internal_ops = &msm_ois_internal_ops; - msm_ois_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(msm_ois_t->msm_sd.sd.name, - ARRAY_SIZE(msm_ois_t->msm_sd.sd.name), "msm_ois"); - media_entity_init(&msm_ois_t->msm_sd.sd.entity, 0, NULL, 0); - msm_ois_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - msm_ois_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_OIS; - msm_ois_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; - msm_sd_register(&msm_ois_t->msm_sd); - msm_ois_t->ois_state = OIS_DISABLE_STATE; - msm_cam_copy_v4l2_subdev_fops(&msm_ois_v4l2_subdev_fops); -#ifdef CONFIG_COMPAT - msm_ois_v4l2_subdev_fops.compat_ioctl32 = - msm_ois_subdev_fops_ioctl; -#endif - msm_ois_t->msm_sd.sd.devnode->fops = - &msm_ois_v4l2_subdev_fops; - - CDBG("Exit\n"); - return rc; -release_memory: - kfree(msm_ois_t->oboard_info); - kfree(msm_ois_t->gconf); - kfree(msm_ois_t); - return rc; -} - -static const struct of_device_id msm_ois_i2c_dt_match[] = { - {.compatible = "qcom,ois"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_ois_i2c_dt_match); - -static struct i2c_driver msm_ois_i2c_driver = { - .id_table = msm_ois_i2c_id, - .probe = msm_ois_i2c_probe, - .remove = __exit_p(msm_ois_i2c_remove), - .driver = { - .name = "qcom,ois", - .owner = THIS_MODULE, - .of_match_table = msm_ois_i2c_dt_match, - }, -}; - -static const struct of_device_id msm_ois_dt_match[] = { - {.compatible = "qcom,ois", .data = NULL}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_ois_dt_match); - -static struct platform_driver msm_ois_platform_driver = { - .probe = msm_ois_platform_probe, - .driver = { - .name = "qcom,ois", - .owner = THIS_MODULE, - .of_match_table = msm_ois_dt_match, - }, -}; - -static int __init msm_ois_init_module(void) -{ - int32_t rc = 0; - - CDBG("Enter\n"); - rc = platform_driver_register(&msm_ois_platform_driver); - if (!rc) - return rc; - CDBG("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&msm_ois_i2c_driver); -} - -static void __exit msm_ois_exit_module(void) -{ - platform_driver_unregister(&msm_ois_platform_driver); - i2c_del_driver(&msm_ois_i2c_driver); -} - -module_init(msm_ois_init_module); -module_exit(msm_ois_exit_module); -MODULE_DESCRIPTION("MSM OIS"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.h b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.h deleted file mode 100644 index 4b269e5f29f8177d437886318d5dd51e2e54e69b..0000000000000000000000000000000000000000 --- a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef MSM_OIS_H -#define MSM_OIS_H - -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_camera_dt_util.h" -#include "msm_camera_io_util.h" - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -#define MSM_OIS_MAX_VREGS (10) - -struct msm_ois_ctrl_t; - -enum msm_ois_state_t { - OIS_ENABLE_STATE, - OIS_OPS_ACTIVE, - OIS_OPS_INACTIVE, - OIS_DISABLE_STATE, -}; - -struct msm_ois_vreg { - struct camera_vreg_t *cam_vreg; - void *data[MSM_OIS_MAX_VREGS]; - int num_vreg; -}; - -struct msm_ois_board_info { - char ois_name[MAX_OIS_NAME_SIZE]; - uint32_t i2c_slaveaddr; - struct msm_ois_opcode opcode; -}; - -struct msm_ois_ctrl_t { - struct i2c_driver *i2c_driver; - struct platform_driver *pdriver; - struct platform_device *pdev; - struct msm_camera_i2c_client i2c_client; - enum msm_camera_device_type_t ois_device_type; - struct msm_sd_subdev msm_sd; - struct mutex *ois_mutex; - enum msm_camera_i2c_data_type i2c_data_type; - struct v4l2_subdev sdev; - struct v4l2_subdev_ops *ois_v4l2_subdev_ops; - void *user_data; - uint16_t i2c_tbl_index; - enum cci_i2c_master_t cci_master; - uint32_t subdev_id; - enum msm_ois_state_t ois_state; - struct msm_ois_vreg vreg_cfg; - struct msm_camera_gpio_conf *gconf; - struct msm_pinctrl_info pinctrl_info; - uint8_t cam_pinctrl_status; - struct msm_ois_board_info *oboard_info; -}; - -#endif diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c index 6160c0afafa90d83fd10db7b9dc85c9b52ccd9af..cdd433cda81c9f5816610a2cbca91555f1645f52 100644 --- a/drivers/media/platform/msm/camera_v2/camera/camera.c +++ b/drivers/media/platform/msm/camera_v2/camera/camera.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -365,38 +365,44 @@ static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh, if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (WARN_ON(!sp->vb2_q.drv_priv)) - return -ENOMEM; - + mutex_lock(sp->vb2_q.lock); + if (WARN_ON(!sp->vb2_q.drv_priv)) { + rc = -ENOMEM; + mutex_unlock(sp->vb2_q.lock); + goto done; + } memcpy(sp->vb2_q.drv_priv, pfmt->fmt.raw_data, sizeof(struct msm_v4l2_format_data)); user_fmt = (struct msm_v4l2_format_data *)sp->vb2_q.drv_priv; pr_debug("%s: num planes :%c\n", __func__, user_fmt->num_planes); - /*num_planes need to bound checked, otherwise for loop - can execute forever */ - if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES)) - return -EINVAL; + /* num_planes need to bound checked, otherwise for loop + * can execute forever + */ + if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES)) { + rc = -EINVAL; + mutex_unlock(sp->vb2_q.lock); + goto done; + } for (i = 0; i < user_fmt->num_planes; i++) pr_debug("%s: plane size[%d]\n", __func__, user_fmt->plane_sizes[i]); - + mutex_unlock(sp->vb2_q.lock); if (msm_is_daemon_present() != false) { camera_pack_event(filep, MSM_CAMERA_SET_PARM, MSM_CAMERA_PRIV_S_FMT, -1, &event); rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); if (rc < 0) - return rc; - + goto done; rc = camera_check_event_status(&event); if (rc < 0) - return rc; + goto done; } sp->is_vb2_valid = 1; } - +done: return rc; } @@ -596,6 +602,12 @@ static int camera_v4l2_vb2_q_init(struct file *filep) pr_err("%s : memory not available\n", __func__); return -ENOMEM; } + q->lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); + if (!q->lock) { + kzfree(q->drv_priv); + return -ENOMEM; + } + mutex_init(q->lock); q->mem_ops = msm_vb2_get_q_mem_ops(); q->ops = msm_vb2_get_q_ops(); @@ -616,6 +628,8 @@ static void camera_v4l2_vb2_q_release(struct file *filep) kzfree(sp->vb2_q.drv_priv); mutex_lock(&sp->lock); vb2_queue_release(&sp->vb2_q); + mutex_destroy(sp->vb2_q.lock); + kzfree(sp->vb2_q.lock); mutex_unlock(&sp->lock); } diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c index d82b2eb602f9a8ce73ef6b65b1fb7d4d4b203d47..f45adabe829a7cb8ad1c915283eb313e40c82b90 100644 --- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2011-2014, 2017 The Linux Foundataion. All rights reserved. +/* Copyright (c) 2011-2014, 2017, 2019 The Linux Foundataion. + * All rights reserved. * * 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 @@ -354,12 +355,13 @@ int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, } } else { for (i = num_clk - 1; i >= 0; i--) { - if (clk_ptr[i] != NULL) { + if (!IS_ERR_OR_NULL(clk_ptr[i])) { CDBG("%s disable %s\n", __func__, clk_info[i].clk_name); clk_disable(clk_ptr[i]); clk_unprepare(clk_ptr[i]); clk_put(clk_ptr[i]); + clk_ptr[i] = NULL; } } } @@ -373,10 +375,11 @@ cam_clk_set_err: clk_put(clk_ptr[i]); cam_clk_get_err: for (i--; i >= 0; i--) { - if (clk_ptr[i] != NULL) { + if (!IS_ERR_OR_NULL(clk_ptr[i])) { clk_disable(clk_ptr[i]); clk_unprepare(clk_ptr[i]); clk_put(clk_ptr[i]); + clk_ptr[i] = NULL; } } return rc; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index 97c34528868ef6caa30bd12e32ef9d682df60f35..7a16e335dd283d38fa2215e0f7158d59a883825f 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -28,7 +28,7 @@ #define VFE32_EQUAL_SLICE_UB 194 #define VFE32_AXI_SLICE_UB 792 #define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx) -#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC) +#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x70 * (idx - 1) : 0x06FC) #define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4)) #define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8) #define VFE32_PING_PONG_BASE(wm, ping_pong) \ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index f25d8d8181999c8675a9b6c541c4a42fd4adcf81..6b698d667f9170e072b0967f6252374dd59288c0 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -1533,6 +1533,7 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, msm_camera_io_w_mb((update_state == DISABLE_CAMIF ? 0x0 : 0x6), vfe_dev->vfe_base + 0x2F4); vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + vfe_dev->axi_data.src_info[VFE_PIX_0].flag = 0; /* testgen OFF*/ if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) msm_camera_io_w(1 << 1, vfe_dev->vfe_base + 0x93C); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 4170257b7e7e1df185614e1ddab70f72120c8979..b7bf00eebeb19a9ebce12c78ed337f06f2425b8b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1712,26 +1712,21 @@ void msm_vfe47_cfg_axi_ub_equal_default( uint32_t prop_size = 0; uint32_t wm_ub_size; uint64_t delta; - uint32_t rdi_ub_offset; - - if (frame_src == VFE_PIX_0) { - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i] && - SRC_TO_INTF( - HANDLE_TO_IDX(axi_data->free_wm[i])) == - VFE_PIX_0) { - num_used_wms++; - total_image_size += - axi_data->wm_image_size[i]; - } + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + num_used_wms++; + total_image_size += + axi_data->wm_image_size[i]; } - ub_offset = (axi_data->hw_info->num_rdi * 2) * - axi_data->hw_info->min_wm_ub; - prop_size = vfe_dev->hw_info->vfe_ops.axi_ops. - get_ub_size(vfe_dev) - - axi_data->hw_info->min_wm_ub * (num_used_wms + - axi_data->hw_info->num_rdi * 2); } + if (!total_image_size) { + pr_err("%s: Error total_image_size is 0\n", __func__); + return; + } + prop_size = vfe_dev->hw_info->vfe_ops.axi_ops. + get_ub_size(vfe_dev) - + axi_data->hw_info->min_wm_ub * num_used_wms; for (i = 0; i < axi_data->hw_info->num_wm; i++) { if (!axi_data->free_wm[i]) { msm_camera_io_w(0, @@ -1739,34 +1734,23 @@ void msm_vfe47_cfg_axi_ub_equal_default( vfe_dev->hw_info->vfe_ops.axi_ops. ub_reg_offset(vfe_dev, i)); } - if (!axi_data->free_wm[i] || frame_src != SRC_TO_INTF( - HANDLE_TO_IDX(axi_data->free_wm[i]))) + if (!axi_data->free_wm[i]) continue; - if (frame_src == VFE_PIX_0) { - delta = (uint64_t)axi_data->wm_image_size[i] * - (uint64_t)prop_size; - do_div(delta, total_image_size); - wm_ub_size = axi_data->hw_info->min_wm_ub + - (uint32_t)delta; - msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), - vfe_dev->vfe_base + - vfe_dev->hw_info->vfe_ops.axi_ops. - ub_reg_offset(vfe_dev, i)); - ub_offset += wm_ub_size; - } else { - - rdi_ub_offset = (SRC_TO_INTF( - HANDLE_TO_IDX(axi_data->free_wm[i])) - - VFE_RAW_0) * 2 * - axi_data->hw_info->min_wm_ub; - wm_ub_size = axi_data->hw_info->min_wm_ub * 2; - msm_camera_io_w((rdi_ub_offset << 16 | - (wm_ub_size - 1)), - vfe_dev->vfe_base + - vfe_dev->hw_info->vfe_ops.axi_ops. - ub_reg_offset(vfe_dev, i)); + delta = (uint64_t)axi_data->wm_image_size[i] * + (uint64_t)prop_size; + do_div(delta, total_image_size); + if (frame_src != VFE_PIX_0) { + if (delta <= axi_data->hw_info->min_wm_ub) + delta = axi_data->hw_info->min_wm_ub; } + wm_ub_size = axi_data->hw_info->min_wm_ub + + (uint32_t)delta; + msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), + vfe_dev->vfe_base + + vfe_dev->hw_info->vfe_ops.axi_ops. + ub_reg_offset(vfe_dev, i)); + ub_offset += wm_ub_size; } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 13beb519403f70dd146f699d6c9bc4481bb0d353..f008fe89da354f96bf0f452f5c58e79b2a1a84b8 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1624,6 +1624,13 @@ static int msm_isp_update_deliver_count(struct vfe_device *vfe_dev, goto done; } temp_stream_info->sw_ping_pong_bit ^= 1; + if (temp_stream_info->undelivered_request_cnt == 0) { + temp_stream_info->current_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + temp_stream_info->activated_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + msm_isp_cfg_framedrop_reg(vfe_dev, temp_stream_info); + } } done: return rc; @@ -2240,6 +2247,10 @@ static void msm_isp_get_camif_update_state_and_halt( cur_pix_stream_cnt = axi_data->src_info[VFE_PIX_0].pix_stream_count + axi_data->src_info[VFE_PIX_0].raw_stream_count; + + if (stream_cfg_cmd->num_streams > VFE_AXI_SRC_MAX) + return; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { stream_info = &axi_data->stream_info[ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c index c7578b587812fcb8321b7ade153a862cc501d1ab..022d6a05e3e1bd83fa177dbd8421f12a269c2b39 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * 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 @@ -1127,6 +1127,10 @@ static enum msm_isp_camif_update_state cur_pix_stream_cnt = axi_data->src_info[VFE_PIX_0].pix_stream_count + axi_data->src_info[VFE_PIX_0].raw_stream_count; + + if (stream_cfg_cmd->num_streams > VFE_AXI_SRC_MAX) + return NO_UPDATE; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { stream_info = &axi_data->stream_info[ @@ -1210,7 +1214,7 @@ static void msm_isp_update_rdi_output_count( for (i = 0; i < stream_cfg_cmd->num_streams; i++) { if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) + >= MAX_NUM_STREAM) return; stream_info = &axi_data->stream_info[ diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 61cf0d811edb002fecf4efff721703118b3b23aa..27b64776a34acf33fb1b8d2762249acafd373774 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -229,32 +229,34 @@ static long msm_ispif_cmd_ext(struct v4l2_subdev *sd, long rc = 0; struct ispif_device *ispif = (struct ispif_device *)v4l2_get_subdevdata(sd); - struct ispif_cfg_data_ext pcdata; + struct ispif_cfg_data_ext pcdata = {0}; struct msm_ispif_param_data_ext *params = NULL; -#ifdef CONFIG_COMPAT - struct ispif_cfg_data_ext_32 *pcdata32 = - (struct ispif_cfg_data_ext_32 *)arg; - if (pcdata32 == NULL) { - pr_err("Invalid params passed from user\n"); - return -EINVAL; - } - pcdata.cfg_type = pcdata32->cfg_type; - pcdata.size = pcdata32->size; - pcdata.data = compat_ptr(pcdata32->data); + if (is_compat_task()) { +#ifdef CONFIG_COMPAT + struct ispif_cfg_data_ext_32 *pcdata32 = + (struct ispif_cfg_data_ext_32 *)arg; -#else - struct ispif_cfg_data_ext *pcdata64 = + if (pcdata32 == NULL) { + pr_err("Invalid params passed from user\n"); + return -EINVAL; + } + pcdata.cfg_type = pcdata32->cfg_type; + pcdata.size = pcdata32->size; + pcdata.data = compat_ptr(pcdata32->data); +#endif + } else { + struct ispif_cfg_data_ext *pcdata64 = (struct ispif_cfg_data_ext *)arg; - if (pcdata64 == NULL) { - pr_err("Invalid params passed from user\n"); - return -EINVAL; + if (pcdata64 == NULL) { + pr_err("Invalid params passed from user\n"); + return -EINVAL; + } + pcdata.cfg_type = pcdata64->cfg_type; + pcdata.size = pcdata64->size; + pcdata.data = pcdata64->data; } - pcdata.cfg_type = pcdata64->cfg_type; - pcdata.size = pcdata64->size; - pcdata.data = pcdata64->data; -#endif if (pcdata.size != sizeof(struct msm_ispif_param_data_ext)) { pr_err("%s: payload size mismatch\n", __func__); return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c index de27e585f63dfc190704b3a7767645f97fdd8b90..48f53f171da1c61bfbb1de70c7d6bdb1241fcd88 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c @@ -32,6 +32,8 @@ #define MSM_JPEG_NAME "jpeg" #define DEV_NAME_LEN 10 +static char devname[DEV_NAME_LEN]; + static int msm_jpeg_open(struct inode *inode, struct file *filp) { int rc = 0; @@ -185,7 +187,6 @@ static int msm_jpeg_init_dev(struct platform_device *pdev) struct msm_jpeg_device *msm_jpeg_device_p; const struct of_device_id *device_id; const struct msm_jpeg_priv_data *priv_data; - char devname[DEV_NAME_LEN]; msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); if (!msm_jpeg_device_p) { diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c index ebae1501118e087b5aff8918e5bc2bba95780a1c..178e8031aab65628814f55519905226c16d000ba 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -797,8 +797,12 @@ static int msm_jpegdma_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh); + int ret; - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + mutex_lock(&ctx->lock); + ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + mutex_unlock(&ctx->lock); + return ret; } /* @@ -813,17 +817,15 @@ static int msm_jpegdma_streamon(struct file *file, struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh); int ret; - if (!msm_jpegdma_config_ok(ctx)) - return -EINVAL; - mutex_lock(&ctx->lock); - + if (!msm_jpegdma_config_ok(ctx)) { + mutex_unlock(&ctx->lock); + return -EINVAL; + } ret = v4l2_m2m_streamon(file, ctx->m2m_ctx, buf_type); if (ret < 0) dev_err(ctx->jdma_device->dev, "Stream on fail\n"); - mutex_unlock(&ctx->lock); - return ret; } diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 098f113029d895b16739dc834ca71a7b6b9973d8..b00e8883d86284d4e02da977599c6426c392ee70 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -37,6 +37,7 @@ static struct list_head ordered_sd_list; static struct mutex ordered_sd_mtx; static struct mutex v4l2_event_mtx; +static atomic_t qos_add_request_done = ATOMIC_INIT(0); static struct pm_qos_request msm_v4l2_pm_qos_request; static struct msm_queue_head *msm_session_q; @@ -216,9 +217,11 @@ static inline int __msm_queue_find_command_ack_q(void *d1, void *d2) return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0; } -static void msm_pm_qos_add_request(void) +static inline void msm_pm_qos_add_request(void) { pr_info("%s: add request", __func__); + if (atomic_cmpxchg(&qos_add_request_done, 0, 1)) + return; pm_qos_add_request(&msm_v4l2_pm_qos_request, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); } @@ -232,6 +235,7 @@ static void msm_pm_qos_remove_request(void) void msm_pm_qos_update_request(int val) { pr_info("%s: update request %d", __func__, val); + msm_pm_qos_add_request(); pm_qos_update_request(&msm_v4l2_pm_qos_request, val); } diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c index 994d9de0e64357ebfa9946c822885d8f6d8cd197..12f9f1012450d3b8ff9f360a22f6d4671c9da3d0 100644 --- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c @@ -555,14 +555,17 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, return -EINVAL; if (!k_ioctl.ioctl_ptr) return -EINVAL; - - MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr, - sizeof(tmp)); - if (copy_from_user(&buf_info, tmp, - sizeof(struct msm_buf_mngr_info))) { - return -EFAULT; + if (!is_compat_task()) { + MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, + &k_ioctl.ioctl_ptr, sizeof(tmp)); + if (copy_from_user(&buf_info, + (void __user *)tmp, + sizeof(struct msm_buf_mngr_info))) { + return -EFAULT; + } + k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; } - k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; + argp = &k_ioctl; rc = msm_cam_buf_mgr_ops(cmd, argp); } diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c index 69d3a2ba1cba8320af7633253da8363b260e7184..b65a9e09e3b3c93006aaf196882faf007512135e 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, 2019, The Linux Foundation. All rights reserved. * * 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 @@ -19,15 +19,19 @@ static int msm_vb2_queue_setup(struct vb2_queue *q, unsigned int sizes[], void *alloc_ctxs[]) { int i; - struct msm_v4l2_format_data *data = q->drv_priv; + struct msm_v4l2_format_data *data = NULL; + int rc = -EINVAL; + + mutex_lock(q->lock); + data = q->drv_priv; if (!data) { pr_err("%s: drv_priv NULL\n", __func__); - return -EINVAL; + goto done; } if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES)) - return -EINVAL; + goto done; *num_planes = data->num_planes; @@ -36,12 +40,16 @@ static int msm_vb2_queue_setup(struct vb2_queue *q, } else { pr_err("%s: Unsupported buf type :%d\n", __func__, data->type); - return -EINVAL; + goto done; } - return 0; + rc = 0; + +done: + mutex_unlock(q->lock); + return rc; } -int msm_vb2_buf_init(struct vb2_buffer *vb) +static int msm_vb2_buf_init(struct vb2_buffer *vb) { struct msm_stream *stream; struct msm_session *session; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 4c00276c376f4ad8aac291a115c9c0dcd7f2654b..71cbc3cec43ffc7eaa02feae06e9a5fc18f67e84 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * 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 @@ -833,9 +833,14 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) if (irq_status & 0x8) { tx_level = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_FIFO_TX_STAT) >> 2; - for (i = 0; i < tx_level; i++) { - tx_fifo[i] = msm_camera_io_r(cpp_dev->base + - MSM_CPP_MICRO_FIFO_TX_DATA); + if (tx_level < MSM_CPP_TX_FIFO_LEVEL) { + for (i = 0; i < tx_level; i++) { + tx_fifo[i] = msm_camera_io_r(cpp_dev->base + + MSM_CPP_MICRO_FIFO_TX_DATA); + } + } else { + pr_err("Fatal invalid tx level %d", tx_level); + goto err; } spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx]; @@ -890,6 +895,7 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) pr_debug("DEBUG_R1: 0x%x\n", msm_camera_io_r(cpp_dev->base + 0x8C)); } +err: msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); return IRQ_HANDLED; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 0bfc34455465c1b429c7afc38969d71f5af42746..d3e6e22e4e53afc87d50a10c1ba8896348372358 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * 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 @@ -29,11 +29,6 @@ DEFINE_MSM_MUTEX(msm_actuator_mutex); #define PARK_LENS_LONG_STEP 7 #define PARK_LENS_MID_STEP 5 #define PARK_LENS_SMALL_STEP 3 -#ifdef CONFIG_MACH_XIAOMI_MIDO -#define PARK_LENS_QUIET_UPPER_CODE 400 -#define PARK_LENS_QUIET_LOWER_CODE 200 -#define PARK_LENS_QUIET_STEP 25 -#endif #define MAX_QVALUE 4096 static struct v4l2_file_operations msm_actuator_v4l2_subdev_fops; @@ -765,6 +760,9 @@ static int32_t msm_actuator_bivcm_move_focus( a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); while (a_ctrl->curr_step_pos != dest_step_pos) { + if (a_ctrl->curr_region_index >= a_ctrl->region_size) + break; + step_boundary = a_ctrl->region_params[a_ctrl->curr_region_index]. step_bound[dir]; @@ -838,16 +836,6 @@ static int32_t msm_actuator_park_lens(struct msm_actuator_ctrl_t *a_ctrl) next_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos]; while (next_lens_pos) { /* conditions which help to reduce park lens time */ -#ifdef CONFIG_MACH_XIAOMI_MIDO - if (next_lens_pos > PARK_LENS_QUIET_UPPER_CODE) - next_lens_pos = PARK_LENS_QUIET_UPPER_CODE; - else { - if (next_lens_pos > PARK_LENS_QUIET_LOWER_CODE) - next_lens_pos -= PARK_LENS_QUIET_STEP; - else - next_lens_pos = 0; - } -#else if (next_lens_pos > (a_ctrl->park_lens.max_step * PARK_LENS_LONG_STEP)) { next_lens_pos = next_lens_pos - @@ -869,7 +857,6 @@ static int32_t msm_actuator_park_lens(struct msm_actuator_ctrl_t *a_ctrl) (next_lens_pos - a_ctrl->park_lens. max_step) : 0; } -#endif a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, next_lens_pos, a_ctrl->park_lens.hw_params, a_ctrl->park_lens.damping_delay); diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c index 7c31e13c7f4419b1b128c7a2d1ffaf24bcdbf051..2d067a241884132b45942b01a352a20e1708a639 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * 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 @@ -37,25 +37,13 @@ static long msm_led_flash_subdev_ioctl(struct v4l2_subdev *sd, } switch (cmd) { case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - if (fctrl->func_tbl->flash_get_subdev_id) - return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp); - else - pr_err("NULL flash_get_subdev function\n"); - return -EINVAL; + return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp); case VIDIOC_MSM_FLASH_LED_DATA_CFG: - if (fctrl->func_tbl->flash_led_config) - return fctrl->func_tbl->flash_led_config(fctrl, argp); - else - pr_err("NULL flash_led_config function\n"); - return -EINVAL; + return fctrl->func_tbl->flash_led_config(fctrl, argp); case MSM_SD_NOTIFY_FREEZE: return 0; case MSM_SD_SHUTDOWN: - if (fctrl->func_tbl->flash_led_release) - return fctrl->func_tbl->flash_led_release(fctrl); - else - pr_err("NULL flash_led_release function\n"); - return -EINVAL; + return fctrl->func_tbl->flash_led_release(fctrl); default: pr_err_ratelimited("invalid cmd %d\n", cmd); return -ENOIOCTLCMD; @@ -94,7 +82,7 @@ int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev, void *data) "msm_flash"); media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0); fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH; + fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_FLASH; fctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; msm_sd_register(&fctrl->msm_sd); diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c index cc3373fd3012b848915cf48aa142009a832d3b85..68ac3aedcced9ee3bfb62a1ff5f64efe866874f8 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c @@ -408,13 +408,10 @@ static int32_t msm_led_get_dt_data(struct device_node *of_node, return -EINVAL; } - fctrl->flashdata = kzalloc(sizeof( - struct msm_camera_sensor_board_info), - GFP_KERNEL); - if (!fctrl->flashdata) { - pr_err("%s failed %d\n", __func__, __LINE__); + fctrl->flashdata = kzalloc(sizeof(fctrl->flashdata), + GFP_KERNEL); + if (!fctrl->flashdata) return -ENOMEM; - } flashdata = fctrl->flashdata; power_info = &flashdata->power_info; @@ -446,7 +443,6 @@ static int32_t msm_led_get_dt_data(struct device_node *of_node, rc = 0; } - fctrl->pinctrl_info.use_pinctrl = false; fctrl->pinctrl_info.use_pinctrl = of_property_read_bool(of_node, "qcom,enable_pinctrl"); if (of_get_property(of_node, "qcom,flash-source", &count)) { @@ -494,15 +490,12 @@ static int32_t msm_led_get_dt_data(struct device_node *of_node, fctrl->flash_trigger_name[i], &fctrl->flash_trigger[i]); } - } else { /*Handle LED Flash Ctrl by GPIO*/ power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); - if (!power_info->gpio_conf) { - rc = -ENOMEM; - return rc; - } + if (!power_info->gpio_conf) + return -ENOMEM; gconf = power_info->gpio_conf; gpio_array_size = of_gpio_count(of_node); @@ -510,8 +503,8 @@ static int32_t msm_led_get_dt_data(struct device_node *of_node, if (gpio_array_size) { gpio_array = - kzalloc((sizeof(uint16_t) * gpio_array_size), - GFP_KERNEL); + kcalloc(gpio_array_size, sizeof(uint16_t), + GFP_KERNEL); if (!gpio_array) { rc = -ENOMEM; goto ERROR4; diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c index 310f99cf22474d1445db10ab6eabccb42bc53a39..ff80801a21cd86a69e2e9f4b55f10fad608ad6be 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c @@ -38,27 +38,6 @@ static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, return 0; } -static int32_t msm_led_trigger_release(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - uint32_t i; - - if (!fctrl) { - pr_err("failed\n"); - return -EINVAL; - } - - /* Flash off */ - for (i = 0; i < fctrl->flash_num_sources; i++) - if (fctrl->flash_trigger[i]) - led_trigger_event(fctrl->flash_trigger[i], 0); - /* Torch off */ - for (i = 0; i < fctrl->torch_num_sources; i++) - if (fctrl->torch_trigger[i]) - led_trigger_event(fctrl->torch_trigger[i], 0); - return rc; -} - static int32_t msm_led_trigger_config(struct msm_led_flash_ctrl_t *fctrl, void *data) { @@ -339,7 +318,6 @@ static int __init msm_led_trigger_add_driver(void) static struct msm_flash_fn_t msm_led_trigger_func_tbl = { .flash_get_subdev_id = msm_led_trigger_get_subdev_id, .flash_led_config = msm_led_trigger_config, - .flash_led_release = msm_led_trigger_release, }; static struct msm_led_flash_ctrl_t fctrl = { diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c index 8652bacb8e6b751d4f4e340c945dfe02857b68af..7d7969f36adbd1df89d1fc7a7f25c74ed1e7e54e 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c @@ -789,8 +789,11 @@ int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, uint32_t count = 0; uint32_t *val_array = NULL; - if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count)) + rc = of_property_read_u32(of_node, "qcom,gpio-set-tbl-num", &count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); return 0; + } count /= sizeof(uint32_t); if (!count) { @@ -1425,7 +1428,7 @@ int msm_cam_sensor_handle_reg_gpio(int seq_val, CDBG("%s: %d GPIO offset: %d, seq_val: %d\n", __func__, __LINE__, gpio_offset, seq_val); - if (gconf->gpio_num_info->valid[gpio_offset] == 1) { + if ((gconf->gpio_num_info->valid[gpio_offset] == 1)) { gpio_set_value_cansleep( gconf->gpio_num_info->gpio_num [gpio_offset], val); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index febb3e716974942d899267bf0a6f4c0f0c89de85..1bf39d4c874d9c395414f3fc38b11ee9f81847a1 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -2019,6 +2019,18 @@ static long sde_rotator_compat_ioctl32(struct file *file, } #endif +static int sde_rotator_ctrl_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return -EINVAL; +} + +static int sde_rotator_event_unsubscribe(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return -EINVAL; +} + /* V4l2 ioctl handlers */ static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = { .vidioc_querycap = sde_rotator_querycap, @@ -2045,8 +2057,8 @@ static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = { .vidioc_s_priority = sde_rotator_s_priority, .vidioc_default = sde_rotator_private_ioctl, .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_subscribe_event = sde_rotator_ctrl_subscribe_event, + .vidioc_unsubscribe_event = sde_rotator_event_unsubscribe, }; /* diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index 54db53d82e14588bdb38b3631debbe65deeb0a0f..236ece8a13b43701fc9c164b6a437dff57a50649 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017,2019 The Linux Foundation. All rights reserved. * * 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 @@ -99,12 +99,22 @@ static enum msm_vidc_pixel_depth get_hal_pixel_depth(u32 hfi_bit_depth) return MSM_VIDC_BIT_DEPTH_UNSUPPORTED; } +static inline int validate_pkt_size(u32 rem_size, u32 msg_size) +{ + if (rem_size < msg_size) { + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", + __func__, rem_size); + return false; + } + return true; +} + static int hfi_process_sess_evt_seq_changed(u32 device_id, struct hfi_msg_event_notify_packet *pkt, struct msm_vidc_cb_info *info) { struct msm_vidc_cb_event event_notify = {0}; - int num_properties_changed; + u32 num_properties_changed, rem_size; struct hfi_frame_size *frame_sz; struct hfi_profile_level *profile_level; struct hfi_bit_depth *pixel_depth; @@ -116,12 +126,9 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, /* Initialize pic_struct to unknown as default */ event_notify.pic_struct = MSM_VIDC_PIC_STRUCT_UNKNOWN; - - if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) { - dprintk(VIDC_ERR, - "hal_process_session_init_done: bad_pkt_size\n"); + if (!validate_pkt_size(pkt->size, + sizeof(struct hfi_msg_event_notify_packet))) return -E2BIG; - } event_notify.device_id = device_id; event_notify.session_id = (void *)(uintptr_t)pkt->session_id; @@ -142,10 +149,18 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, if (num_properties_changed) { data_ptr = (u8 *) &pkt->rg_ext_event_data[0]; + rem_size = pkt->size - sizeof(struct + hfi_msg_event_notify_packet) + sizeof(u32); do { + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = (int) *((u32 *)data_ptr); + rem_size -= sizeof(u32); switch (prop_id) { case HFI_PROPERTY_PARAM_FRAME_SIZE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_frame_size))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); frame_sz = (struct hfi_frame_size *) data_ptr; @@ -155,8 +170,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, frame_sz->height, frame_sz->width); data_ptr += sizeof(struct hfi_frame_size); + rem_size -= sizeof(struct hfi_frame_size); break; case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_profile_level))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); profile_level = (struct hfi_profile_level *) data_ptr; @@ -165,8 +184,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, profile_level->level); data_ptr += sizeof(struct hfi_profile_level); + rem_size -= sizeof(struct hfi_profile_level); break; case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_bit_depth))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pixel_depth = (struct hfi_bit_depth *) data_ptr; /* @@ -197,8 +220,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, event_notify.bit_depth, luma_bit_depth, chroma_bit_depth); data_ptr += sizeof(struct hfi_bit_depth); + rem_size -= sizeof(struct hfi_bit_depth); break; case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_pic_struct))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pic_struct = (struct hfi_pic_struct *) data_ptr; event_notify.pic_struct = @@ -208,8 +235,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, pic_struct->progressive_only); data_ptr += sizeof(struct hfi_pic_struct); + rem_size -= sizeof(struct hfi_pic_struct); break; case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_colour_space))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); colour_info = (struct hfi_colour_space *) data_ptr; @@ -220,6 +251,7 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, colour_info->colour_space); data_ptr += sizeof(struct hfi_colour_space); + rem_size -= sizeof(struct hfi_colour_space); break; default: dprintk(VIDC_ERR, @@ -254,6 +286,12 @@ static int hfi_process_evt_release_buffer_ref(u32 device_id, "hal_process_session_init_done: bad_pkt_size\n"); return -E2BIG; } + if (pkt->size < sizeof(struct hfi_msg_event_notify_packet) - sizeof(u32) + + sizeof(struct hfi_msg_release_buffer_ref_event_packet)) { + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", + __func__, pkt->size); + return -E2BIG; + } data = (struct hfi_msg_release_buffer_ref_event_packet *) pkt->rg_ext_event_data; @@ -319,9 +357,10 @@ static int hfi_process_session_error(u32 device_id, } static int hfi_process_event_notify(u32 device_id, - struct hfi_msg_event_notify_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_event_notify_packet *pkt = _pkt; dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n"); if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) { @@ -360,9 +399,10 @@ static int hfi_process_event_notify(u32 device_id, } static int hfi_process_sys_init_done(u32 device_id, - struct hfi_msg_sys_init_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_init_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; enum vidc_status status = VIDC_ERR_NONE; @@ -399,9 +439,10 @@ err_no_prop: } static int hfi_process_sys_rel_resource_done(u32 device_id, - struct hfi_msg_sys_release_resource_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_release_resource_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; enum vidc_status status = VIDC_ERR_NONE; u32 pkt_size; @@ -574,7 +615,7 @@ static inline void copy_cap_prop( } static int hfi_fill_codec_info(u8 *data_ptr, - struct vidc_hal_sys_init_done *sys_init_done) { + struct vidc_hal_sys_init_done *sys_init_done, u32 rem_size) { u32 i; u32 codecs = 0, codec_count = 0, size = 0; struct msm_vidc_capability *capability; @@ -584,6 +625,9 @@ static int hfi_fill_codec_info(u8 *data_ptr, if (prop_id == HFI_PROPERTY_PARAM_CODEC_SUPPORTED) { struct hfi_codec_supported *prop; + if (!validate_pkt_size(rem_size - sizeof(u32), + sizeof(struct hfi_codec_supported))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); prop = (struct hfi_codec_supported *) data_ptr; sys_init_done->dec_codec_supported = @@ -591,6 +635,8 @@ static int hfi_fill_codec_info(u8 *data_ptr, sys_init_done->enc_codec_supported = prop->encoder_codec_supported; size = sizeof(struct hfi_codec_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_codec_supported) + sizeof(u32); } else { dprintk(VIDC_WARN, "%s: prop_id %#x, expected codec_supported property\n", @@ -606,6 +652,11 @@ static int hfi_fill_codec_info(u8 *data_ptr, vidc_get_hal_codec((1 << i) & codecs); capability->domain = vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER); + if (codec_count == VIDC_MAX_DECODE_SESSIONS) { + dprintk(VIDC_ERR, + "Max supported decoder sessions reached"); + break; + } } } codecs = sys_init_done->enc_codec_supported; @@ -617,18 +668,31 @@ static int hfi_fill_codec_info(u8 *data_ptr, vidc_get_hal_codec((1 << i) & codecs); capability->domain = vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER); + if (codec_count == VIDC_MAX_SESSIONS) { + dprintk(VIDC_ERR, + "Max supported sessions reached"); + break; + } } } sys_init_done->codec_count = codec_count; + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = *((u32 *)(orig_data_ptr + size)); if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) { - struct hfi_max_sessions_supported *prop = - (struct hfi_max_sessions_supported *) + struct hfi_max_sessions_supported *prop; + + if (!validate_pkt_size(rem_size - sizeof(u32), sizeof(struct + hfi_max_sessions_supported))) + return -E2BIG; + prop = (struct hfi_max_sessions_supported *) (orig_data_ptr + size + sizeof(u32)); sys_init_done->max_sessions_supported = prop->max_sessions; size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_max_sessions_supported) + sizeof(u32); dprintk(VIDC_DBG, "max_sessions_supported %d\n", prop->max_sessions); } @@ -783,6 +847,20 @@ static enum vidc_status hfi_parse_init_done_properties( { enum vidc_status status = VIDC_ERR_NONE; u32 prop_id, next_offset; +#define VALIDATE_PROPERTY_STRUCTURE_SIZE(pkt_size, property_size) ({\ + if (pkt_size < property_size) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + +#define VALIDATE_PROPERTY_PAYLOAD_SIZE(pkt_size, payload_size, \ + property_count) ({\ + if (pkt_size/payload_size < property_count) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) while (status == VIDC_ERR_NONE && num_properties && rem_bytes >= sizeof(u32)) { @@ -796,6 +874,9 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_codec_mask_supported *prop = (struct hfi_codec_mask_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); codecs = prop->codecs; domain = prop->video_domains; @@ -809,11 +890,14 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_capability_supported_info *) (data_ptr + next_offset); - if ((rem_bytes - next_offset) < prop->num_capabilities * - sizeof(struct hfi_capability_supported)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(u32), + sizeof(struct hfi_capability_supported), + prop->num_capabilities); + next_offset += sizeof(u32) + prop->num_capabilities * sizeof(struct hfi_capability_supported); @@ -834,10 +918,10 @@ static enum vidc_status hfi_parse_init_done_properties( char *fmt_ptr; struct hfi_uncompressed_plane_info *plane_info; - if ((rem_bytes - next_offset) < sizeof(*prop)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + num_format_entries = prop->format_entries; next_offset = sizeof(*prop); fmt_ptr = (char *)&prop->rg_format_info[0]; @@ -847,17 +931,19 @@ static enum vidc_status hfi_parse_init_done_properties( plane_info = (struct hfi_uncompressed_plane_info *) fmt_ptr; - if ((rem_bytes - next_offset) < - sizeof(*plane_info)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*plane_info)); + bytes_to_skip = sizeof(*plane_info) - sizeof(struct hfi_uncompressed_plane_constraints) + plane_info->num_planes * sizeof(struct hfi_uncompressed_plane_constraints); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + bytes_to_skip); fmt_ptr += bytes_to_skip; next_offset += bytes_to_skip; @@ -871,6 +957,13 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_properties_supported *prop = (struct hfi_properties_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(*prop) + + sizeof(u32), sizeof(u32), + prop->num_properties); next_offset += sizeof(*prop) - sizeof(u32) + prop->num_properties * sizeof(u32); num_properties--; @@ -887,6 +980,9 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_profile_level_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); ptr = (char *) &prop->rg_profile_level[0]; prof_count = prop->profile_count; next_offset += sizeof(u32); @@ -899,6 +995,9 @@ static enum vidc_status hfi_parse_init_done_properties( } while (prof_count) { prof_level = (struct hfi_profile_level *)ptr; + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prof_level)); capability. profile_level.profile_level[count].profile = prof_level->profile; @@ -915,6 +1014,9 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_interlace_format_supported)); next_offset += sizeof(struct hfi_interlace_format_supported); num_properties--; @@ -922,6 +1024,9 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_nal_stream_format_supported)); next_offset += sizeof(struct hfi_nal_stream_format_supported); num_properties--; @@ -929,18 +1034,27 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); next_offset += sizeof(u32); num_properties--; break; } case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); next_offset += sizeof(u32); num_properties--; break; } case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_intra_refresh)); next_offset += sizeof(struct hfi_intra_refresh); num_properties--; @@ -951,13 +1065,21 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_buffer_alloc_mode_supported *prop = (struct hfi_buffer_alloc_mode_supported *) (data_ptr + next_offset); - + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); if (prop->num_entries >= 32) { dprintk(VIDC_ERR, "%s - num_entries: %d from f/w seems suspect\n", __func__, prop->num_entries); break; } + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - + sizeof(struct hfi_buffer_alloc_mode_supported) + + sizeof(u32), + sizeof(u32), + prop->num_entries); next_offset += sizeof(struct hfi_buffer_alloc_mode_supported) - sizeof(u32) + prop->num_entries * sizeof(u32); @@ -975,8 +1097,12 @@ static enum vidc_status hfi_parse_init_done_properties( __func__, data_ptr, prop_id); break; } - rem_bytes -= next_offset; - data_ptr += next_offset; + if (rem_bytes > next_offset) { + rem_bytes -= next_offset; + data_ptr += next_offset; + } else { + rem_bytes = 0; + } } return status; @@ -987,7 +1113,8 @@ enum vidc_status hfi_process_sys_init_done_prop_read( struct vidc_hal_sys_init_done *sys_init_done) { enum vidc_status status = VIDC_ERR_NONE; - u32 rem_bytes, bytes_read, num_properties; + int bytes_read; + u32 rem_bytes, num_properties; u8 *data_ptr; u32 codecs = 0, domain = 0; @@ -996,6 +1123,11 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "hfi_msg_sys_init_done: Invalid input\n"); return VIDC_ERR_FAIL; } + if (pkt->size < sizeof(struct hfi_msg_sys_init_done_packet)) { + dprintk(VIDC_ERR, "%s: bad packet size: %d\n", + __func__, pkt->size); + return VIDC_ERR_FAIL; + } rem_bytes = pkt->size - sizeof(struct hfi_msg_sys_init_done_packet) + sizeof(u32); @@ -1023,7 +1155,9 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "Venus didn't set any properties in SYS_INIT_DONE"); return status; } - bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done); + bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done, rem_bytes); + if (bytes_read < 0) + return VIDC_ERR_FAIL; data_ptr += bytes_read; rem_bytes -= bytes_read; num_properties--; @@ -1214,9 +1348,10 @@ static void hfi_process_sess_get_prop_buf_req( } static int hfi_process_session_prop_info(u32 device_id, - struct hfi_msg_session_property_info_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_property_info_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; struct hfi_profile_level profile_level = {0}; enum hal_h264_entropy entropy; @@ -1289,9 +1424,10 @@ static int hfi_process_session_prop_info(u32 device_id, } static int hfi_process_session_init_done(u32 device_id, - struct hfi_msg_sys_session_init_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_init_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; struct vidc_hal_session_init_done session_init_done = { {0} }; @@ -1323,9 +1459,10 @@ static int hfi_process_session_init_done(u32 device_id, } static int hfi_process_session_load_res_done(u32 device_id, - struct hfi_msg_session_load_resources_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_load_resources_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%#x]\n", pkt->session_id); @@ -1352,9 +1489,10 @@ static int hfi_process_session_load_res_done(u32 device_id, } static int hfi_process_session_flush_done(u32 device_id, - struct hfi_msg_session_flush_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_flush_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n", @@ -1397,20 +1535,19 @@ static int hfi_process_session_flush_done(u32 device_id, } static int hfi_process_session_etb_done(u32 device_id, - struct hfi_msg_session_empty_buffer_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt; struct msm_vidc_cb_data_done data_done = {0}; struct hfi_picture_type *hfi_picture_type = NULL; + u32 is_sync_frame; dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id); if (!pkt || pkt->size < - sizeof(struct hfi_msg_session_empty_buffer_done_packet)) { - dprintk(VIDC_ERR, - "hal_process_session_etb_done: bad_pkt_size\n"); - return -E2BIG; - } + sizeof(struct hfi_msg_session_empty_buffer_done_packet)) + goto bad_packet_size; data_done.device_id = device_id; data_done.session_id = (void *)(uintptr_t)pkt->session_id; @@ -1425,8 +1562,13 @@ static int hfi_process_session_etb_done(u32 device_id, (ion_phys_addr_t)pkt->extra_data_buffer; data_done.input_done.status = hfi_map_err_status(pkt->error_type); - hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[0]; - if (hfi_picture_type->is_sync_frame) { + is_sync_frame = pkt->rgData[0]; + if (is_sync_frame == 1) { + if (pkt->size < + sizeof(struct hfi_msg_session_empty_buffer_done_packet) + + sizeof(struct hfi_picture_type)) + goto bad_packet_size; + hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[1]; if (hfi_picture_type->picture_type) data_done.input_done.flags = hfi_picture_type->picture_type; @@ -1445,12 +1587,17 @@ static int hfi_process_session_etb_done(u32 device_id, }; return 0; +bad_packet_size: + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; } static int hfi_process_session_ftb_done( - u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + u32 device_id, void *_pkt, struct msm_vidc_cb_info *info) { + struct vidc_hal_msg_pkt_hdr *msg_hdr = _pkt; struct msm_vidc_cb_data_done data_done = {0}; bool is_decoder = false, is_encoder = false; @@ -1575,9 +1722,10 @@ static int hfi_process_session_ftb_done( } static int hfi_process_session_start_done(u32 device_id, - struct hfi_msg_session_start_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_start_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%#x]\n", @@ -1603,9 +1751,10 @@ static int hfi_process_session_start_done(u32 device_id, } static int hfi_process_session_stop_done(u32 device_id, - struct hfi_msg_session_stop_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_stop_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%#x]\n", @@ -1632,9 +1781,10 @@ static int hfi_process_session_stop_done(u32 device_id, } static int hfi_process_session_rel_res_done(u32 device_id, - struct hfi_msg_session_release_resources_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_release_resources_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%#x]\n", @@ -1661,9 +1811,10 @@ static int hfi_process_session_rel_res_done(u32 device_id, } static int hfi_process_session_rel_buf_done(u32 device_id, - struct hfi_msg_session_release_buffers_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_release_buffers_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; if (!pkt || pkt->size < @@ -1680,8 +1831,7 @@ static int hfi_process_session_rel_buf_done(u32 device_id, cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; cmd_done.status = hfi_map_err_status(pkt->error_type); if (pkt->rg_buffer_info) { - cmd_done.data.buffer_info = - *(struct hal_buffer_info *)pkt->rg_buffer_info; + cmd_done.data.buffer_info.buffer_addr = *pkt->rg_buffer_info; cmd_done.size = sizeof(struct hal_buffer_info); } else { dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n"); @@ -1696,9 +1846,10 @@ static int hfi_process_session_rel_buf_done(u32 device_id, } static int hfi_process_session_end_done(u32 device_id, - struct hfi_msg_sys_session_end_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_end_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id); @@ -1723,9 +1874,10 @@ static int hfi_process_session_end_done(u32 device_id, } static int hfi_process_session_abort_done(u32 device_id, - struct hfi_msg_sys_session_abort_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_abort_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n", @@ -1830,9 +1982,10 @@ static void hfi_process_sys_get_prop_image_version( } static int hfi_process_sys_property_info(u32 device_id, - struct hfi_msg_sys_property_info_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_property_info_packet *pkt = _pkt; if (!pkt) { dprintk(VIDC_ERR, "%s: invalid param\n", __func__); return -EINVAL; @@ -1864,7 +2017,7 @@ static int hfi_process_sys_property_info(u32 device_id, } static int hfi_process_ignore(u32 device_id, - struct vidc_hal_msg_pkt_hdr *msg_hdr, + void *_pkt, struct msm_vidc_cb_info *info) { *info = (struct msm_vidc_cb_info) { @@ -1948,5 +2101,6 @@ int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, break; } - return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP; + return pkt_func ? + pkt_func(device_id, (void *)msg_hdr, info) : -ENOTSUPP; } diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 579f032949a165cd3a772aa1a753214904af58cf..c778ee456d7c6f62f72b0c0e1c8e8fd074a8d3fc 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1587,7 +1587,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q, } rc = set_actual_buffer_count(inst, - bufreq->buffer_count_actual, + bufreq->buffer_count_min, HAL_BUFFER_OUTPUT); if (rc) break; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 43f32ace1727b227d2998f4e06dc4affc242381a..42c452ea94ec141cac92ed9d7da24ea2ea818912 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -556,8 +556,10 @@ static int msm_comm_vote_bus(struct msm_vidc_core *core) else vote_data[i].fps = inst->prop.fps; - if (msm_comm_turbo_session(inst)) - vote_data[i].power_mode = VIDC_POWER_TURBO; + if (msm_comm_turbo_session(inst)) { + if (msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS)) + vote_data[i].power_mode = VIDC_POWER_TURBO; + } else if (is_low_power_session(inst)) vote_data[i].power_mode = VIDC_POWER_LOW; else @@ -728,16 +730,16 @@ static void handle_sys_init_done(enum hal_command_response cmd, void *data) return; } -static void put_inst_helper(struct kref *kref) +void put_inst(struct msm_vidc_inst *inst) { - struct msm_vidc_inst *inst = container_of(kref, - struct msm_vidc_inst, kref); + void put_inst_helper(struct kref *kref) + { + struct msm_vidc_inst *inst = container_of(kref, + struct msm_vidc_inst, kref); - msm_vidc_destroy(inst); -} + msm_vidc_destroy(inst); + } -void put_inst(struct msm_vidc_inst *inst) -{ if (!inst) return; @@ -2077,8 +2079,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_READONLY; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS) vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOS; - if (fill_buf_done->flags1 & HAL_BUFFERFLAG_ENDOFFRAME) - vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_ENDOFFRAME; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG) vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME) @@ -3019,7 +3019,7 @@ static int set_output_buffers(struct msm_vidc_inst *inst, { int rc = 0; struct msm_smem *handle; - struct internal_buf *binfo = NULL; + struct internal_buf *binfo; u32 smem_flags = 0, buffer_size; struct hal_buffer_requirements *output_buf, *extradata_buf; int i; @@ -3125,10 +3125,10 @@ static int set_output_buffers(struct msm_vidc_inst *inst, } return rc; fail_set_buffers: - msm_comm_smem_free(inst, handle); -err_no_mem: kfree(binfo); fail_kzalloc: + msm_comm_smem_free(inst, handle); +err_no_mem: return rc; } @@ -3743,17 +3743,17 @@ int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb) * Don't queue if: * 1) Hardware isn't ready (that's simple) */ - defer = defer || (inst->state != MSM_VIDC_START_DONE); + defer = defer ?: inst->state != MSM_VIDC_START_DONE; /* * 2) The client explicitly tells us not to because it wants this * buffer to be batched with future frames. The batch size (on both * capabilities) is completely determined by the client. */ - defer = defer || (vb && vb->v4l2_buf.flags & V4L2_MSM_BUF_FLAG_DEFER); + defer = defer ?: vb && vb->v4l2_buf.flags & V4L2_MSM_BUF_FLAG_DEFER; /* 3) If we're in batch mode, we must have full batches of both types */ - defer = defer || (batch_mode && (!output_count || !capture_count)); + defer = defer ?: batch_mode && (!output_count || !capture_count); if (defer) { dprintk(VIDC_DBG, "Deferring queue of %pK\n", vb); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c index 70b4170ac4cd22a1bb70f8a6b24907fd16b14afe..884d1cf11b5e4d198f30da9abac445f501dac378 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2019, The Linux Foundation. All rights reserved. * * 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 @@ -223,7 +223,7 @@ void msm_dcvs_init_load(struct msm_vidc_inst *inst) core = inst->core; dcvs = &inst->dcvs; res = &core->resources; - dcvs->load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS); + dcvs->load = msm_comm_get_inst_load(inst, LOAD_CALC_IGNORE_TURBO_LOAD); num_rows = res->dcvs_tbl_size; table = res->dcvs_tbl; diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 81f050448a398bb1c01bb1875dfd0dd71c6c094f..4daae65c297c79aca3c3f4f2320a84cc3ab816b1 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -38,6 +38,7 @@ #define FIRMWARE_SIZE 0X00A00000 #define REG_ADDR_OFFSET_BITMASK 0x000FFFFF #define QDSS_IOVA_START 0x80001000 +#define MIN_PAYLOAD_SIZE 3 static struct hal_device_data hal_ctxt; @@ -327,7 +328,7 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet, { struct hfi_queue_header *queue; u32 packet_size_in_words, new_write_idx; - u32 empty_space, read_idx; + u32 empty_space, read_idx, write_idx; u32 *write_ptr; if (!qinfo || !packet) { @@ -350,16 +351,18 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet, } packet_size_in_words = (*(u32 *)packet) >> 2; - if (!packet_size_in_words) { - dprintk(VIDC_ERR, "Zero packet size\n"); + if (!packet_size_in_words || packet_size_in_words > + qinfo->q_array.mem_size>>2) { + dprintk(VIDC_ERR, "Invalid packet size\n"); return -ENODATA; } read_idx = queue->qhdr_read_idx; + write_idx = queue->qhdr_write_idx; - empty_space = (queue->qhdr_write_idx >= read_idx) ? - (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) : - (read_idx - queue->qhdr_write_idx); + empty_space = (write_idx >= read_idx) ? + ((qinfo->q_array.mem_size>>2) - (write_idx - read_idx)) : + (read_idx - write_idx); if (empty_space <= packet_size_in_words) { queue->qhdr_tx_req = 1; dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n", @@ -369,13 +372,20 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet, queue->qhdr_tx_req = 0; - new_write_idx = (queue->qhdr_write_idx + packet_size_in_words); + new_write_idx = write_idx + packet_size_in_words; write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + - (queue->qhdr_write_idx << 2)); - if (new_write_idx < queue->qhdr_q_size) { + (write_idx << 2)); + if (write_ptr < (u32 *)qinfo->q_array.align_virtual_addr || + write_ptr > (u32 *)(qinfo->q_array.align_virtual_addr + + qinfo->q_array.mem_size)) { + dprintk(VIDC_ERR, "Invalid write index"); + return -ENODATA; + } + + if (new_write_idx < (qinfo->q_array.mem_size >> 2)) { memcpy(write_ptr, packet, packet_size_in_words << 2); } else { - new_write_idx -= queue->qhdr_q_size; + new_write_idx -= qinfo->q_array.mem_size >> 2; memcpy(write_ptr, packet, (packet_size_in_words - new_write_idx) << 2); memcpy((void *)qinfo->q_array.align_virtual_addr, @@ -467,7 +477,8 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet, u32 packet_size_in_words, new_read_idx; u32 *read_ptr; u32 receive_request = 0; - int rc = 0; + u32 read_idx, write_idx; + int rc = 0; if (!qinfo || !packet || !pb_tx_req_is_set) { dprintk(VIDC_ERR, "Invalid Params\n"); @@ -498,7 +509,10 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet, if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q) receive_request = 1; - if (queue->qhdr_read_idx == queue->qhdr_write_idx) { + read_idx = queue->qhdr_read_idx; + write_idx = queue->qhdr_write_idx; + + if (read_idx == write_idx) { queue->qhdr_rx_req = receive_request; *pb_tx_req_is_set = 0; dprintk(VIDC_DBG, @@ -510,21 +524,28 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet, } read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + - (queue->qhdr_read_idx << 2)); + (read_idx << 2)); + if (read_ptr < (u32 *)qinfo->q_array.align_virtual_addr || + read_ptr > (u32 *)(qinfo->q_array.align_virtual_addr + + qinfo->q_array.mem_size - sizeof(*read_ptr))) { + dprintk(VIDC_ERR, "Invalid read index\n"); + return -ENODATA; + } + packet_size_in_words = (*read_ptr) >> 2; if (!packet_size_in_words) { dprintk(VIDC_ERR, "Zero packet size\n"); return -ENODATA; } - new_read_idx = queue->qhdr_read_idx + packet_size_in_words; - if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) - && queue->qhdr_read_idx <= queue->qhdr_q_size) { - if (new_read_idx < queue->qhdr_q_size) { + new_read_idx = read_idx + packet_size_in_words; + if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) && + read_idx <= (qinfo->q_array.mem_size >> 2)) { + if (new_read_idx < (qinfo->q_array.mem_size >> 2)) { memcpy(packet, read_ptr, packet_size_in_words << 2); } else { - new_read_idx -= queue->qhdr_q_size; + new_read_idx -= (qinfo->q_array.mem_size >> 2); memcpy(packet, read_ptr, (packet_size_in_words - new_read_idx) << 2); memcpy(packet + ((packet_size_in_words - @@ -535,19 +556,19 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet, } else { dprintk(VIDC_WARN, "BAD packet received, read_idx: %#x, pkt_size: %d\n", - queue->qhdr_read_idx, packet_size_in_words << 2); + read_idx, packet_size_in_words << 2); dprintk(VIDC_WARN, "Dropping this packet\n"); - new_read_idx = queue->qhdr_write_idx; + new_read_idx = write_idx; rc = -ENODATA; } - queue->qhdr_read_idx = new_read_idx; - - if (queue->qhdr_read_idx != queue->qhdr_write_idx) + if (new_read_idx != write_idx) queue->qhdr_rx_req = 0; else queue->qhdr_rx_req = receive_request; + queue->qhdr_read_idx = new_read_idx; + *pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0; if (msm_vidc_debug & VIDC_PKT) { @@ -2267,34 +2288,6 @@ static int venus_hfi_core_release(void *dev) return rc; } -static int __get_q_size(struct venus_hfi_device *dev, unsigned int q_index) -{ - struct hfi_queue_header *queue; - struct vidc_iface_q_info *q_info; - u32 write_ptr, read_ptr; - - if (q_index >= VIDC_IFACEQ_NUMQ) { - dprintk(VIDC_ERR, "Invalid q index: %d\n", q_index); - return -ENOENT; - } - - q_info = &dev->iface_queues[q_index]; - if (!q_info) { - dprintk(VIDC_ERR, "cannot read shared Q's\n"); - return -ENOENT; - } - - queue = (struct hfi_queue_header *)q_info->q_hdr; - if (!queue) { - dprintk(VIDC_ERR, "queue not present\n"); - return -ENOENT; - } - - write_ptr = (u32)queue->qhdr_write_idx; - read_ptr = (u32)queue->qhdr_read_idx; - return read_ptr - write_ptr; -} - static void __core_clear_interrupt(struct venus_hfi_device *device) { u32 intr_status = 0; @@ -3357,23 +3350,55 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) local_packet = true; } +#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \ + if (pkt_size < pkt_hdr_size || \ + payload_size < MIN_PAYLOAD_SIZE || \ + payload_size > \ + (pkt_size - pkt_hdr_size + sizeof(u8))) { \ + dprintk(VIDC_ERR, \ + "%s: invalid msg size - %d\n", \ + __func__, pkt->msg_size); \ + continue; \ + } \ + }) + while (!__iface_dbgq_read(device, packet)) { - struct hfi_msg_sys_coverage_packet *pkt = - (struct hfi_msg_sys_coverage_packet *) packet; + struct hfi_packet_header *pkt = + (struct hfi_packet_header *) packet; + + if (pkt->size < sizeof(struct hfi_packet_header)) { + dprintk(VIDC_ERR, "Invalid pkt size - %s\n", + __func__); + continue; + } + if (pkt->packet_type == HFI_MSG_SYS_COV) { + struct hfi_msg_sys_coverage_packet *pkt = + (struct hfi_msg_sys_coverage_packet *) packet; int stm_size = 0; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + stm_size = stm_log_inv_ts(0, 0, pkt->rg_msg_data, pkt->msg_size); if (stm_size == 0) dprintk(VIDC_ERR, "In %s, stm_log returned size of 0\n", __func__); - } else { + + } else if (pkt->packet_type == HFI_MSG_SYS_DEBUG) { struct hfi_msg_sys_debug_packet *pkt = (struct hfi_msg_sys_debug_packet *) packet; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + + pkt->rg_msg_data[pkt->msg_size-1] = '\0'; dprintk(VIDC_FW, "%s", pkt->rg_msg_data); } } +#undef SKIP_INVALID_PKT if (local_packet) kfree(packet); @@ -3548,8 +3573,7 @@ static int __response_handler(struct venus_hfi_device *device) *session_id = session->session_id; } - if (packet_count >= max_packets && - __get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) { + if (packet_count >= max_packets) { dprintk(VIDC_WARN, "Too many packets in message queue to handle at once, deferring read\n"); break; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index 4cbb59d12f92db4c78a31559a3f65fe9df59ea56..978fdc6bbb6d71dcf01cc9627d14d6c4a4bf8dd8 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016,2019 The Linux Foundation. All rights reserved. * * 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 @@ -662,7 +662,7 @@ struct hfi_msg_session_empty_buffer_done_packet { u32 input_tag; u32 packet_buffer; u32 extra_data_buffer; - u32 rgData[0]; + u32 rgData[1]; }; struct hfi_msg_session_fill_buffer_done_compressed_packet { diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 42ea8f72acfe0ca145798c44aaea07ee4ce4daea..8e8f053617044db89b3f78e64358406fb78dc575 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017,2019 The Linux Foundation. All rights reserved. * * 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 @@ -66,6 +66,9 @@ /* 16 encoder and 16 decoder sessions */ #define VIDC_MAX_SESSIONS 32 +#define VIDC_MAX_DECODE_SESSIONS 16 +#define VIDC_MAX_ENCODE_SESSIONS 16 + enum vidc_status { VIDC_ERR_NONE = 0x0, diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 31af06cd88ef1de698c5a4d25a5f202f0de5c463..828eafcad6cf781dfe2aa34030cfa4df28b0ce4c 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, 2019, The Linux Foundation. All rights reserved. * * 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 @@ -701,7 +701,6 @@ struct hfi_bit_depth { }; struct hfi_picture_type { - u32 is_sync_frame; u32 picture_type; }; @@ -974,6 +973,11 @@ struct vidc_hal_session_cmd_pkt { u32 session_id; }; +struct hfi_packet_header { + u32 size; + u32 packet_type; +}; + struct hfi_cmd_sys_init_packet { u32 size; u32 packet_type; diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 233eccc5c33e6a7e1badff93478b8d66f30ffc20..3e91109b205d39475144ad403a463375a66e0976 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2117,6 +2117,7 @@ error_csiphy: static void isp_detach_iommu(struct isp_device *isp) { + arm_iommu_detach_device(isp->dev); arm_iommu_release_mapping(isp->mapping); isp->mapping = NULL; iommu_group_remove_device(isp->dev); @@ -2150,8 +2151,7 @@ static int isp_attach_iommu(struct isp_device *isp) mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); if (IS_ERR(mapping)) { dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); - ret = PTR_ERR(mapping); - goto error; + return PTR_ERR(mapping); } isp->mapping = mapping; @@ -2166,7 +2166,8 @@ static int isp_attach_iommu(struct isp_device *isp) return 0; error: - isp_detach_iommu(isp); + arm_iommu_release_mapping(isp->mapping); + isp->mapping = NULL; return ret; } diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index df33e720d66436390e6c5dd3b6273454f0ca78af..bb4a57e55aed23a2020f56d686d6c9df30025cc8 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -117,6 +117,8 @@ static int sensor_set_power(struct camif_dev *camif, int on) if (camif->sensor.power_count == !on) err = v4l2_subdev_call(sensor->sd, core, s_power, on); + if (err == -ENOIOCTLCMD) + err = 0; if (!err) sensor->power_count += on ? 1 : -1; @@ -1280,16 +1282,17 @@ static void __camif_subdev_try_format(struct camif_dev *camif, { const struct s3c_camif_variant *variant = camif->variant; const struct vp_pix_limits *pix_lim; - int i = ARRAY_SIZE(camif_mbus_formats); + unsigned int i; /* FIXME: constraints against codec or preview path ? */ pix_lim = &variant->vp_pix_limits[VP_CODEC]; - while (i-- >= 0) + for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++) if (camif_mbus_formats[i] == mf->code) break; - mf->code = camif_mbus_formats[i]; + if (i == ARRAY_SIZE(camif_mbus_formats)) + mf->code = camif_mbus_formats[0]; if (pad == CAMIF_SD_PAD_SINK) { v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH, diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2a497c80c77f2e1c2996403c356992a771c5df82..80261e556367d697df25df1cddebe0d73c8e4c39 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -96,7 +96,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); */ int si470x_get_register(struct si470x_device *radio, int regnr) { - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -121,7 +121,7 @@ int si470x_get_register(struct si470x_device *radio, int regnr) int si470x_set_register(struct si470x_device *radio, int regnr) { int i; - u16 buf[WRITE_REG_NUM]; + __be16 buf[WRITE_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -151,7 +151,7 @@ int si470x_set_register(struct si470x_device *radio, int regnr) static int si470x_get_all_registers(struct si470x_device *radio) { int i; - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index eb9e7feb9b131bb84d751f10a3a11ff3538030b7..7a16e9ea041c5e020f68facf8e421416c69c119f 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2419,6 +2419,11 @@ static int imon_probe(struct usb_interface *interface, mutex_lock(&driver_lock); first_if = usb_ifnum_to_if(usbdev, 0); + if (!first_if) { + ret = -ENODEV; + goto fail; + } + first_if_ctx = usb_get_intfdata(first_if); if (ifnum == 0) { diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index cb62275243dfcdf5dffaaf2f749856518788b05f..071f323f1f39cd732900e35e66c55516a79e49e5 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -298,11 +298,14 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (!dev->max_timeout) return -ENOSYS; + /* Check for multiply overflow */ + if (val > U32_MAX / 1000) + return -EINVAL; + tmp = val * 1000; - if (tmp < dev->min_timeout || - tmp > dev->max_timeout) - return -EINVAL; + if (tmp < dev->min_timeout || tmp > dev->max_timeout) + return -EINVAL; dev->timeout = tmp; break; diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index f838d9c7ed1234ff9d93a069b0aa04dc622a198c..0fba4a2c160287c4313a18d4c937f1f9a4cb7f1a 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1370,8 +1370,13 @@ static int mceusb_dev_probe(struct usb_interface *intf, goto rc_dev_fail; /* wire up inbound data handler */ - usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, - mceusb_dev_recv, ir, ep_in->bInterval); + if (usb_endpoint_xfer_int(ep_in)) + usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, + mceusb_dev_recv, ir, ep_in->bInterval); + else + usb_fill_bulk_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, + mceusb_dev_recv, ir); + ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index a759742cae7bef51e784dec900fd1e422df39d79..babcfede55586f450561c1477eaf8e98aecfe1c2 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -410,9 +410,11 @@ static int r820t_write(struct r820t_priv *priv, u8 reg, const u8 *val, return 0; } -static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val) +static inline int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val) { - return r820t_write(priv, reg, &val, 1); + u8 tmp = val; /* work around GCC PR81715 with asan-stack=1 */ + + return r820t_write(priv, reg, &tmp, 1); } static int r820t_read_cache_reg(struct r820t_priv *priv, int reg) @@ -425,17 +427,18 @@ static int r820t_read_cache_reg(struct r820t_priv *priv, int reg) return -EINVAL; } -static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, +static inline int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, u8 bit_mask) { + u8 tmp = val; int rc = r820t_read_cache_reg(priv, reg); if (rc < 0) return rc; - val = (rc & ~bit_mask) | (val & bit_mask); + tmp = (rc & ~bit_mask) | (tmp & bit_mask); - return r820t_write(priv, reg, &val, 1); + return r820t_write(priv, reg, &tmp, 1); } static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c index 07d08c49f4d495d0fc40d26a3bde82051eae7c30..b2e16bb675727c9547401487351d0179c80d3a74 100644 --- a/drivers/media/usb/as102/as102_fw.c +++ b/drivers/media/usb/as102/as102_fw.c @@ -101,18 +101,23 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, unsigned char *cmd, const struct firmware *firmware) { - struct as10x_fw_pkt_t fw_pkt; + struct as10x_fw_pkt_t *fw_pkt; int total_read_bytes = 0, errno = 0; unsigned char addr_has_changed = 0; + fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL); + if (!fw_pkt) + return -ENOMEM; + + for (total_read_bytes = 0; total_read_bytes < firmware->size; ) { int read_bytes = 0, data_len = 0; /* parse intel hex line */ read_bytes = parse_hex_line( (u8 *) (firmware->data + total_read_bytes), - fw_pkt.raw.address, - fw_pkt.raw.data, + fw_pkt->raw.address, + fw_pkt->raw.data, &data_len, &addr_has_changed); @@ -122,28 +127,28 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, /* detect the end of file */ total_read_bytes += read_bytes; if (total_read_bytes == firmware->size) { - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x03; + fw_pkt->u.request[0] = 0x00; + fw_pkt->u.request[1] = 0x03; /* send EOF command */ errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) - &fw_pkt, 2, 0); + fw_pkt, 2, 0); if (errno < 0) goto error; } else { if (!addr_has_changed) { /* prepare command to send */ - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x01; + fw_pkt->u.request[0] = 0x00; + fw_pkt->u.request[1] = 0x01; - data_len += sizeof(fw_pkt.u.request); - data_len += sizeof(fw_pkt.raw.address); + data_len += sizeof(fw_pkt->u.request); + data_len += sizeof(fw_pkt->raw.address); /* send cmd to device */ errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) - &fw_pkt, + fw_pkt, data_len, 0); if (errno < 0) @@ -152,6 +157,7 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, } } error: + kfree(fw_pkt); return (errno == 0) ? total_read_bytes : errno; } diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 9caea8344547a790db13b04690d5d5c14aaf9451..d793c630f1dde32010c0b48963919ca0fe5dce7f 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -812,7 +812,7 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) struct camera_data *cam = video_drvdata(file); if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->index > cam->num_frames) + buf->index >= cam->num_frames) return -EINVAL; buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; @@ -863,7 +863,7 @@ static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || buf->memory != V4L2_MEMORY_MMAP || - buf->index > cam->num_frames) + buf->index >= cam->num_frames) return -EINVAL; DBG("QBUF #%d\n", buf->index); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 9592ba876451afb293e8fc12dbe37f4184e400c7..bb7204a7dcf92cd57dde6e142e42feabe3c0e6db 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -805,6 +805,9 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_CNXT_RDE_250}, {USB_DEVICE(0x0572, 0x58A0), .driver_info = CX231XX_BOARD_CNXT_RDU_250}, + /* AverMedia DVD EZMaker 7 */ + {USB_DEVICE(0x07ca, 0xc039), + .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER}, {USB_DEVICE(0x2040, 0xb110), .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL}, {USB_DEVICE(0x2040, 0xb111), @@ -1511,7 +1514,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, nr = dev->devno; assoc_desc = udev->actconfig->intf_assoc[0]; - if (assoc_desc->bFirstInterface != ifnum) { + if (!assoc_desc || assoc_desc->bFirstInterface != ifnum) { cx231xx_err(DRIVER_NAME ": Not found " "matching IAD interface\n"); retval = -ENODEV; diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 180103e48036727e322399c53437599ced61b8c5..6ec0ac8a737e84661501e4b6dca291380c0b92d7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -365,7 +365,12 @@ int cx231xx_send_vendor_cmd(struct cx231xx *dev, */ if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) || (ven_req->bRequest == 0x5) || - (ven_req->bRequest == 0x6))) { + (ven_req->bRequest == 0x6) || + + /* Internal Master 3 Bus can send + * and receive only 4 bytes per time + */ + (ven_req->bRequest == 0x2))) { unsend_size = 0; pdata = ven_req->pBuff; diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 2273ce78f5c80323e461d9b1cf83f908e09d43a2..f17e2cb4acb63a41377158dd52c33e0f12fe8ed9 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -438,18 +438,23 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, static int lme2510_return_status(struct dvb_usb_device *d) { - int ret = 0; + int ret; u8 *data; - data = kzalloc(10, GFP_KERNEL); + data = kzalloc(6, GFP_KERNEL); if (!data) return -ENOMEM; - ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); - info("Firmware Status: %x (%x)", ret , data[2]); + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + 0x06, 0x80, 0x0302, 0x00, + data, 0x6, 200); + if (ret != 6) + ret = -EINVAL; + else + ret = data[2]; + + info("Firmware Status: %6ph", data); - ret = (ret < 0) ? -ENODEV : data[2]; kfree(data); return ret; } @@ -1113,8 +1118,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) if (adap->fe[0]) { info("FE Found M88RS2000"); - dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config, - &d->i2c_adap); st->i2c_tuner_gate_w = 5; st->i2c_tuner_gate_r = 5; st->i2c_tuner_addr = 0x60; @@ -1177,17 +1180,18 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) ret = st->tuner_config; break; case TUNER_RS2000: - ret = st->tuner_config; + if (dvb_attach(ts2020_attach, adap->fe[0], + &ts2020_config, &d->i2c_adap)) + ret = st->tuner_config; break; default: break; } - if (ret) + if (ret) { info("TUN Found %s tuner", tun_msg[ret]); - else { - info("TUN No tuner found --- resetting device"); - lme_coldreset(d); + } else { + info("TUN No tuner found"); return -ENODEV; } @@ -1231,6 +1235,7 @@ static int lme2510_get_adapter_count(struct dvb_usb_device *d) static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) { struct lme2510_state *st = d->priv; + int status; usb_reset_configuration(d->udev); @@ -1239,12 +1244,16 @@ static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; - if (lme2510_return_status(d) == 0x44) { + status = lme2510_return_status(d); + if (status == 0x44) { *name = lme_firmware_switch(d, 0); return COLD; } - return 0; + if (status != 0x47) + return -EINVAL; + + return WARM; } static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 356abb369c20b6cd07649fd1f75252f939d0a6e0..55b1a93f6e300b837597fd573e56415a6ac73617 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -923,6 +923,8 @@ static int dvico_bluebird_xc2028_callback(void *ptr, int component, case XC2028_RESET_CLK: deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg); break; + case XC2028_I2C_FLUSH: + break; default: deb_info("%s: unknown command %d, arg %d\n", __func__, command, arg); diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 6aa4e9f4e4418207b904ad68531503c03d85e6e0..b7dd332465b9bde2106ff2defad331b953ab5276 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -292,7 +292,7 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) stk7700d_dib7000p_mt2266_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -326,7 +326,7 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) stk7700d_dib7000p_mt2266_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -431,6 +431,7 @@ static int stk7700ph_xc3028_callback(void *ptr, int component, state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); break; case XC2028_RESET_CLK: + case XC2028_I2C_FLUSH: break; default: err("%s: unknown command %d, arg %d\n", __func__, @@ -479,7 +480,7 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) &stk7700ph_dib7700_xc3028_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -1013,7 +1014,7 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) &dib7070p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -1071,7 +1072,7 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) &dib7770p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3039,7 +3040,7 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); @@ -3092,7 +3093,7 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) /* initialize IC 0 */ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3122,7 +3123,7 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3197,7 +3198,7 @@ static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap) 1, 0x10, &tfe7790p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, @@ -3292,7 +3293,7 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) stk7070pd_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3367,7 +3368,7 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap) stk7070pd_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -3603,7 +3604,7 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) { /* Demodulator not found for some reason? */ - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index ef3a8f75f82ebe21b4ee5b7963aed9bbf8449c32..7b15aea2723d633df5e21862c698be7aecdd0041 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -179,8 +179,20 @@ EXPORT_SYMBOL(dibusb_i2c_algo); int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) { - u8 wbuf[1] = { offs }; - return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); + u8 *buf; + int rc; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = offs; + + rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1); + *val = buf[1]; + kfree(buf); + + return rc; } EXPORT_SYMBOL(dibusb_read_eeprom_byte); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index a21a7463b557913ff0c97eb41f203a1f1d95c930..0b4825ed6886c209b3205b6532685faad13603a6 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -183,7 +183,7 @@ USB 2.0 spec says bulk packet size is always 512 bytes */ #define EM28XX_BULK_PACKET_MULTIPLIER 384 -#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384 +#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94 #define EM28XX_INTERLACED_DEFAULT 1 diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 095f5db1a790f90ddc1307e3aa5572e289ecfcbc..4f317e2686e9e511e5b529f4611e407ae7e50c14 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -275,6 +275,11 @@ static int register_dvb(struct tm6000_core *dev) ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", THIS_MODULE, &dev->udev->dev, adapter_nr); + if (ret < 0) { + pr_err("tm6000: couldn't register the adapter!\n"); + goto err; + } + dvb->adapter.priv = dev; if (dvb->frontend) { diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 29428bef272c657346f2850f6372f55cb33208d2..483457d4904f05f8ae3648087ac476c392c2b197 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -95,6 +95,8 @@ static int usbtv_probe(struct usb_interface *intf, return 0; usbtv_audio_fail: + /* we must not free at this point */ + usb_get_dev(usbtv->udev); usbtv_video_free(usbtv); usbtv_video_fail: @@ -127,6 +129,7 @@ static void usbtv_disconnect(struct usb_interface *intf) static struct usb_device_id usbtv_id_table[] = { { USB_DEVICE(0x1b71, 0x3002) }, + { USB_DEVICE(0x1f71, 0x3301) }, {} }; MODULE_DEVICE_TABLE(usb, usbtv_id_table); diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 57d2f89350d26fb92ebeaa1d3c185240abf48a71..9532235b07de13156e9e8fb35ea8f4d572c16aef 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2004,6 +2004,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, goto done; } + /* Validate the user-provided bit-size and offset */ + if (mapping->size > 32 || + mapping->offset + mapping->size > ctrl->info.size * 8) { + ret = -EINVAL; + goto done; + } + list_for_each_entry(map, &ctrl->info.mappings, list) { if (mapping->id == map->id) { uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', " diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index df81b9c4faf12ae0e00f6267d380d76608b4c8ba..beb8072b57616714eb68c0533640fbaf054c9e4a 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -155,14 +155,27 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, } } +static size_t uvc_video_ctrl_size(struct uvc_streaming *stream) +{ + /* + * Return the size of the video probe and commit controls, which depends + * on the protocol version. + */ + if (stream->dev->uvc_version < 0x0110) + return 26; + else if (stream->dev->uvc_version < 0x0150) + return 34; + else + return 48; +} + static int uvc_get_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe, __u8 query) { + __u16 size = uvc_video_ctrl_size(stream); __u8 *data; - __u16 size; int ret; - size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) return -EIO; @@ -217,7 +230,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]); ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]); - if (size == 34) { + if (size >= 34) { ctrl->dwClockFrequency = get_unaligned_le32(&data[26]); ctrl->bmFramingInfo = data[30]; ctrl->bPreferedVersion = data[31]; @@ -246,11 +259,10 @@ out: static int uvc_set_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe) { + __u16 size = uvc_video_ctrl_size(stream); __u8 *data; - __u16 size; int ret; - size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; data = kzalloc(size, GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -267,7 +279,7 @@ static int uvc_set_video_ctrl(struct uvc_streaming *stream, put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); - if (size == 34) { + if (size >= 34) { put_unaligned_le32(ctrl->dwClockFrequency, &data[26]); data[30] = ctrl->bmFramingInfo; data[31] = ctrl->bPreferedVersion; diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 823d8b0f27ee5ba8818c6a9a0d2716fd30984800..8ba134da1fa1b19625cf1cc485babc721925f86a 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -18,8 +18,18 @@ #include #include #include +#include +#include #include +/* Use the same argument order as copy_in_user */ +#define assign_in_user(to, from) \ +({ \ + typeof(*from) __assign_tmp; \ + \ + get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -33,117 +43,90 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct v4l2_clip32 { struct v4l2_rect c; - compat_caddr_t next; + compat_caddr_t next; }; struct v4l2_window32 { struct v4l2_rect w; - __u32 field; /* enum v4l2_field */ + __u32 field; /* enum v4l2_field */ __u32 chromakey; compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8 global_alpha; }; -static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) -{ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) - return -EFAULT; - if (kp->clipcount > 2048) - return -EINVAL; - if (kp->clipcount) { - struct v4l2_clip32 __user *uclips; - struct v4l2_clip __user *kclips; - int n = kp->clipcount; - compat_caddr_t p; - - if (get_user(p, &up->clips)) - return -EFAULT; - uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); - kp->clips = kclips; - while (--n >= 0) { - if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; - return 0; -} - -static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int get_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up, + void __user *aux_buf, u32 aux_space) { - if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) + struct v4l2_clip32 __user *uclips; + struct v4l2_clip __user *kclips; + compat_caddr_t p; + u32 clipcount; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + copy_in_user(&kp->w, &up->w, sizeof(up->w)) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->chromakey, &up->chromakey) || + assign_in_user(&kp->global_alpha, &up->global_alpha) || + get_user(clipcount, &up->clipcount) || + put_user(clipcount, &kp->clipcount)) return -EFAULT; - return 0; -} + if (clipcount > 2048) + return -EINVAL; + if (!clipcount) + return put_user(NULL, &kp->clips); -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) + if (get_user(p, &up->clips)) return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) + uclips = compat_ptr(p); + if (aux_space < clipcount * sizeof(*kclips)) return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) + kclips = aux_buf; + if (put_user(kclips, &kp->clips)) return -EFAULT; - return 0; -} -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; + while (clipcount--) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + return -EFAULT; + if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next)) + return -EFAULT; + uclips++; + kclips++; + } return 0; } -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +static int put_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) + struct v4l2_clip __user *kclips; + struct v4l2_clip32 __user *uclips; + compat_caddr_t p; + u32 clipcount; + + if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->chromakey, &kp->chromakey) || + assign_in_user(&up->global_alpha, &kp->global_alpha) || + get_user(clipcount, &kp->clipcount) || + put_user(clipcount, &up->clipcount)) return -EFAULT; - return 0; -} + if (!clipcount) + return 0; -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) + if (get_user(kclips, &kp->clips)) return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) + if (get_user(p, &up->clips)) return -EFAULT; + uclips = compat_ptr(p); + while (clipcount--) { + if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } @@ -176,89 +159,152 @@ struct v4l2_create_buffers32 { __u32 reserved[8]; }; -static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) +{ + u32 type; + + if (get_user(type, &up->type)) + return -EFAULT; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { + u32 clipcount; + + if (get_user(clipcount, &up->fmt.win.clipcount)) + return -EFAULT; + if (clipcount > 2048) + return -EINVAL; + *size = clipcount * sizeof(struct v4l2_clip); + return 0; + } + default: + *size = 0; + return 0; + } +} + +static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) { - if (get_user(kp->type, &up->type)) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; + return __bufsize_v4l2_format(up, size); +} + +static int __get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + u32 type; - switch (kp->type) { + if (get_user(type, &up->type) || put_user(type, &kp->type)) + return -EFAULT; + + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_in_user(&kp->fmt.pix, &up->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); + return get_v4l2_window32(&kp->fmt.win, &up->fmt.win, + aux_buf, aux_space); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; + return __get_v4l2_format32(kp, up, aux_buf, aux_space); +} + +static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up, + u32 *size) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; - return __get_v4l2_format32(kp, up); + return __bufsize_v4l2_format(&up->format, size); } -static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int get_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up, + void __user *aux_buf, u32 aux_space) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || - copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + copy_in_user(kp, up, + offsetof(struct v4l2_create_buffers32, format)) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - return __get_v4l2_format32(&kp->format, &up->format); + return __get_v4l2_format32(&kp->format, &up->format, + aux_buf, aux_space); } -static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) { - switch (kp->type) { + u32 type; + + if (get_user(type, &kp->type)) + return -EFAULT; + + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_in_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } -static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || - put_user(kp->type, &up->type)) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); } -static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int put_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) - return -EFAULT; + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + copy_in_user(up, kp, + offsetof(struct v4l2_create_buffers32, format)) || + copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); } @@ -271,25 +317,28 @@ struct v4l2_standard32 { __u32 reserved[4]; }; -static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int get_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || - get_user(kp->index, &up->index)) + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + assign_in_user(&kp->index, &up->index)) return -EFAULT; return 0; } -static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int put_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || - put_user(kp->index, &up->index) || - copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) - return -EFAULT; + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + assign_in_user(&up->index, &kp->index) || + copy_in_user(&up->id, &kp->id, sizeof(up->id)) || + copy_in_user(up->name, kp->name, sizeof(up->name)) || + copy_in_user(&up->frameperiod, &kp->frameperiod, + sizeof(up->frameperiod)) || + assign_in_user(&up->framelines, &kp->framelines) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; return 0; } @@ -328,11 +377,11 @@ struct v4l2_buffer32 { __u32 reserved; }; -static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, - enum v4l2_memory memory) +static int get_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, + enum v4l2_memory memory) { - void __user *up_pln; - compat_long_t p; + compat_ulong_t p; if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(&up->data_offset, &up32->data_offset, @@ -343,27 +392,33 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ sizeof(__u32))) return -EFAULT; - if (memory == V4L2_MEMORY_USERPTR) { - if (get_user(p, &up32->m.userptr)) - return -EFAULT; - up_pln = compat_ptr(p); - if (put_user((unsigned long)up_pln, &up->m.userptr)) + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, + sizeof(up32->m.mem_offset))) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { - if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) + break; + case V4L2_MEMORY_USERPTR: + if (get_user(p, &up32->m.userptr) || + put_user((unsigned long)compat_ptr(p), &up->m.userptr)) return -EFAULT; - } else { - if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(__u32))) + break; + case V4L2_MEMORY_DMABUF: + if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) return -EFAULT; + break; } return 0; } -static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, - enum v4l2_memory memory) +static int put_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, + enum v4l2_memory memory) { + unsigned long p; + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(up32->reserved, up->reserved, sizeof(up32->reserved)) || @@ -371,101 +426,143 @@ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ sizeof(__u32))) return -EFAULT; - /* For MMAP, driver might've set up the offset, so copy it back. - * USERPTR stays the same (was userspace-provided), so no copying. */ - if (memory == V4L2_MEMORY_MMAP) + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, - sizeof(__u32))) + sizeof(up->m.mem_offset))) return -EFAULT; - /* For DMABUF, driver might've set up the fd, so copy it back. */ - if (memory == V4L2_MEMORY_DMABUF) - if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(int))) + break; + case V4L2_MEMORY_USERPTR: + if (get_user(p, &up->m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), + &up32->m.userptr)) return -EFAULT; - if (memory == V4L2_MEMORY_USERPTR) - if (copy_in_user(&up32->m.userptr, &up->m.userptr, - sizeof(compat_long_t))) + break; + case V4L2_MEMORY_DMABUF: + if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + } return 0; } -static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size) { + u32 type; + u32 length; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(type, &up->type) || + get_user(length, &up->length)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + if (length > VIDEO_MAX_PLANES) + return -EINVAL; + + /* + * We don't really care if userspace decides to kill itself + * by passing a very big length value + */ + *size = length * sizeof(struct v4l2_plane); + } else { + *size = 0; + } + return 0; +} + +static int get_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->length, &up->length)) - return -EFAULT; + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + assign_in_user(&kp->index, &up->index) || + get_user(type, &up->type) || + put_user(type, &kp->type) || + assign_in_user(&kp->flags, &up->flags) || + get_user(memory, &up->memory) || + put_user(memory, &kp->memory) || + get_user(length, &up->length) || + put_user(length, &kp->length)) + return -EFAULT; - if (V4L2_TYPE_IS_OUTPUT(kp->type)) - if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) + if (V4L2_TYPE_IS_OUTPUT(type)) + if (assign_in_user(&kp->bytesused, &up->bytesused) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->timestamp.tv_sec, + &up->timestamp.tv_sec) || + assign_in_user(&kp->timestamp.tv_usec, + &up->timestamp.tv_usec)) return -EFAULT; - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; + if (num_planes == 0) { - kp->m.planes = NULL; - /* num_planes == 0 is legal, e.g. when userspace doesn't - * need planes array on DQBUF*/ - return 0; + /* + * num_planes == 0 is legal, e.g. when userspace doesn't + * need planes array on DQBUF + */ + return put_user(NULL, &kp->m.planes); } + if (num_planes > VIDEO_MAX_PLANES) + return -EINVAL; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) + num_planes * sizeof(*uplane32))) return -EFAULT; - /* We don't really care if userspace decides to kill itself - * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); - kp->m.planes = (__force struct v4l2_plane *)uplane; + /* + * We don't really care if userspace decides to kill itself + * by passing a very big num_planes value + */ + if (aux_space < num_planes * sizeof(*uplane)) + return -EFAULT; - while (--num_planes >= 0) { - ret = get_v4l2_plane32(uplane, uplane32, kp->memory); + uplane = aux_buf; + if (put_user((__force struct v4l2_plane *)uplane, + &kp->m.planes)) + return -EFAULT; + + while (num_planes--) { + ret = get_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; - ++uplane; - ++uplane32; + uplane++; + uplane32++; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: - if (get_user(kp->m.offset, &up->m.offset)) + case V4L2_MEMORY_OVERLAY: + if (assign_in_user(&kp->m.offset, &up->m.offset)) return -EFAULT; break; - case V4L2_MEMORY_USERPTR: - { - compat_long_t tmp; + case V4L2_MEMORY_USERPTR: { + compat_ulong_t userptr; - if (get_user(tmp, &up->m.userptr)) - return -EFAULT; - - kp->m.userptr = (unsigned long)compat_ptr(tmp); - } - break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) + if (get_user(userptr, &up->m.userptr) || + put_user((unsigned long)compat_ptr(userptr), + &kp->m.userptr)) return -EFAULT; break; + } case V4L2_MEMORY_DMABUF: - if (get_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&kp->m.fd, &up->m.fd)) return -EFAULT; break; } @@ -474,65 +571,70 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user return 0; } -static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int put_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up) { + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret; - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory)) - return -EFAULT; + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + assign_in_user(&up->index, &kp->index) || + get_user(type, &kp->type) || + put_user(type, &up->type) || + assign_in_user(&up->flags, &kp->flags) || + get_user(memory, &kp->memory) || + put_user(memory, &up->memory)) + return -EFAULT; - if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved) || - put_user(kp->length, &up->length)) - return -EFAULT; + if (assign_in_user(&up->bytesused, &kp->bytesused) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) || + copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->reserved2, &kp->reserved2) || + assign_in_user(&up->reserved, &kp->reserved) || + get_user(length, &kp->length) || + put_user(length, &up->length)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; if (num_planes == 0) return 0; - uplane = (__force struct v4l2_plane __user *)kp->m.planes; + if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes))) + return -EFAULT; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); - while (--num_planes >= 0) { - ret = put_v4l2_plane32(uplane, uplane32, kp->memory); + while (num_planes--) { + ret = put_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; ++uplane; ++uplane32; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: - if (put_user(kp->m.offset, &up->m.offset)) + case V4L2_MEMORY_OVERLAY: + if (assign_in_user(&up->m.offset, &kp->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (put_user(kp->m.userptr, &up->m.userptr)) - return -EFAULT; - break; - case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) + if (assign_in_user(&up->m.userptr, &kp->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (put_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&up->m.fd, &kp->m.fd)) return -EFAULT; break; } @@ -544,7 +646,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user struct v4l2_framebuffer32 { __u32 capability; __u32 flags; - compat_caddr_t base; + compat_caddr_t base; struct { __u32 width; __u32 height; @@ -557,30 +659,33 @@ struct v4l2_framebuffer32 { } fmt; }; -static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp; - - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || - get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags) || - copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) - return -EFAULT; - kp->base = (__force void *)compat_ptr(tmp); + compat_caddr_t tmp; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(tmp, &up->base) || + put_user((__force void *)compat_ptr(tmp), &kp->base) || + assign_in_user(&kp->capability, &up->capability) || + assign_in_user(&kp->flags, &up->flags) || + copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt))) + return -EFAULT; return 0; } -static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->base); - - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags) || - copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) - return -EFAULT; + void *base; + + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + get_user(base, &kp->base) || + put_user(ptr_to_compat(base), &up->base) || + assign_in_user(&up->capability, &kp->capability) || + assign_in_user(&up->flags, &kp->flags) || + copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt))) + return -EFAULT; return 0; } @@ -590,33 +695,38 @@ struct v4l2_input32 { __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* Associated tuner */ - v4l2_std_id std; + compat_u64 std; __u32 status; - __u32 reserved[4]; -} __attribute__ ((packed)); + __u32 capabilities; + __u32 reserved[3]; +}; -/* The 64-bit v4l2_input struct has extra padding at the end of the struct. - Otherwise it is identical to the 32-bit version. */ -static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +/* + * The 64-bit v4l2_input struct has extra padding at the end of the struct. + * Otherwise it is identical to the 32-bit version. + */ +static inline int get_v4l2_input32(struct v4l2_input __user *kp, + struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) + if (copy_in_user(kp, up, sizeof(*up))) return -EFAULT; return 0; } -static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +static inline int put_v4l2_input32(struct v4l2_input __user *kp, + struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) + if (copy_in_user(up, kp, sizeof(*up))) return -EFAULT; return 0; } struct v4l2_ext_controls32 { - __u32 ctrl_class; - __u32 count; - __u32 error_idx; - __u32 reserved[2]; - compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ + __u32 ctrl_class; + __u32 count; + __u32 error_idx; + __u32 reserved[2]; + compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ }; struct v4l2_ext_control32 { @@ -630,57 +740,95 @@ struct v4l2_ext_control32 { }; } __attribute__ ((packed)); -/* The following function really belong in v4l2-common, but that causes - a circular dependency between modules. We need to think about this, but - for now this will do. */ - -/* Return non-zero if this control is a pointer type. Currently only - type STRING is a pointer type. */ -static inline int ctrl_is_pointer(u32 id) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + struct video_device *vdev = video_devdata(file); + struct v4l2_fh *fh = NULL; + struct v4l2_ctrl_handler *hdl = NULL; + struct v4l2_query_ext_ctrl qec = { id }; + const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; + + if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) + fh = file->private_data; + + if (fh && fh->ctrl_handler) + hdl = fh->ctrl_handler; + else if (vdev->ctrl_handler) + hdl = vdev->ctrl_handler; + + if (hdl) { + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id); + + return ctrl && ctrl->is_ptr; } + + if (!ops || !ops->vidioc_query_ext_ctrl) + return false; + + return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && + (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } -static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up, + u32 *size) +{ + u32 count; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(count, &up->count)) + return -EFAULT; + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; + *size = count * sizeof(struct v4l2_ext_control); + return 0; +} + +static int get_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls __user *kp, + struct v4l2_ext_controls32 __user *up, + void __user *aux_buf, u32 aux_space) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; - int n; + u32 count; + u32 n; compat_caddr_t p; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) - return -EFAULT; - n = kp->count; - if (n == 0) { - kp->controls = NULL; - return 0; - } + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + assign_in_user(&kp->ctrl_class, &up->ctrl_class) || + get_user(count, &up->count) || + put_user(count, &kp->count) || + assign_in_user(&kp->error_idx, &up->error_idx) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; + + if (count == 0) + return put_user(NULL, &kp->controls); + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); - kp->controls = (__force struct v4l2_ext_control *)kcontrols; - while (--n >= 0) { + if (aux_space < count * sizeof(*kcontrols)) + return -EFAULT; + kcontrols = aux_buf; + if (put_user((__force struct v4l2_ext_control *)kcontrols, + &kp->controls)) + return -EFAULT; + + for (n = 0; n < count; n++) { u32 id; if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; + if (get_user(id, &kcontrols->id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + + if (ctrl_is_pointer(file, id)) { void __user *s; if (get_user(p, &ucontrols->string)) @@ -695,43 +843,55 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return 0; } -static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int put_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls __user *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = - (__force struct v4l2_ext_control __user *)kp->controls; - int n = kp->count; + struct v4l2_ext_control __user *kcontrols; + u32 count; + u32 n; compat_caddr_t p; - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) - return -EFAULT; - if (!kp->count) - return 0; + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + assign_in_user(&up->ctrl_class, &kp->ctrl_class) || + get_user(count, &kp->count) || + put_user(count, &up->count) || + assign_in_user(&up->error_idx, &kp->error_idx) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) || + get_user(kcontrols, &kp->controls)) + return -EFAULT; + if (!count || count > (U32_MAX/sizeof(*ucontrols))) + return 0; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols))) return -EFAULT; - while (--n >= 0) { - unsigned size = sizeof(*ucontrols); + for (n = 0; n < count; n++) { + unsigned int size = sizeof(*ucontrols); u32 id; - if (get_user(id, &kcontrols->id)) + if (get_user(id, &kcontrols->id) || + put_user(id, &ucontrols->id) || + assign_in_user(&ucontrols->size, &kcontrols->size) || + copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2, + sizeof(ucontrols->reserved2))) return -EFAULT; - /* Do not modify the pointer when copying a pointer control. - The contents of the pointer was changed, not the pointer - itself. */ - if (ctrl_is_pointer(id)) + + /* + * Do not modify the pointer when copying a pointer control. + * The contents of the pointer was changed, not the pointer + * itself. + */ + if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); + if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; + ucontrols++; kcontrols++; } @@ -753,17 +913,19 @@ struct v4l2_event32 { __u32 reserved[8]; }; -static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) +static int put_v4l2_event32(struct v4l2_event __user *kp, + struct v4l2_event32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || - put_user(kp->type, &up->type) || - copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || - put_user(kp->pending, &up->pending) || - put_user(kp->sequence, &up->sequence) || - compat_put_timespec(&kp->timestamp, &up->timestamp) || - put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) - return -EFAULT; + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + assign_in_user(&up->type, &kp->type) || + copy_in_user(&up->u, &kp->u, sizeof(kp->u)) || + assign_in_user(&up->pending, &kp->pending) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) || + assign_in_user(&up->id, &kp->id) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; return 0; } @@ -775,32 +937,35 @@ struct v4l2_edid32 { compat_caddr_t edid; }; -static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int get_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp; - - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || - get_user(kp->pad, &up->pad) || - get_user(kp->start_block, &up->start_block) || - get_user(kp->blocks, &up->blocks) || - get_user(tmp, &up->edid) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) - return -EFAULT; - kp->edid = (__force u8 *)compat_ptr(tmp); + compat_uptr_t tmp; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + assign_in_user(&kp->pad, &up->pad) || + assign_in_user(&kp->start_block, &up->start_block) || + assign_in_user(&kp->blocks, &up->blocks) || + get_user(tmp, &up->edid) || + put_user(compat_ptr(tmp), &kp->edid) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; return 0; } -static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int put_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->edid); - - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || - put_user(kp->pad, &up->pad) || - put_user(kp->start_block, &up->start_block) || - put_user(kp->blocks, &up->blocks) || - put_user(tmp, &up->edid) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) - return -EFAULT; + void *edid; + + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || + assign_in_user(&up->pad, &kp->pad) || + assign_in_user(&up->start_block, &kp->start_block) || + assign_in_user(&up->blocks, &kp->blocks) || + get_user(edid, &kp->edid) || + put_user(ptr_to_compat(edid), &up->edid) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; return 0; } @@ -816,7 +981,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) -#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) +#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) @@ -832,26 +997,26 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) +static int alloc_userspace(unsigned int size, u32 aux_space, + void __user **up_native) +{ + *up_native = compat_alloc_user_space(size + aux_space); + if (!*up_native) + return -ENOMEM; + if (clear_user(*up_native, size)) + return -EFAULT; + return 0; +} + static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - union { - struct v4l2_format v2f; - struct v4l2_buffer v2b; - struct v4l2_framebuffer v2fb; - struct v4l2_input v2i; - struct v4l2_standard v2s; - struct v4l2_ext_controls v2ecs; - struct v4l2_event v2ev; - struct v4l2_create_buffers v2crt; - struct v4l2_edid v2edid; - unsigned long vx; - int vi; - } karg; void __user *up = compat_ptr(arg); + void __user *up_native = NULL; + void __user *aux_buf; + u32 aux_space; int compatible_arg = 1; long err = 0; - memset(&karg, 0, sizeof(karg)); /* First, convert the command. */ switch (cmd) { case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break; @@ -887,30 +1052,52 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_STREAMOFF: case VIDIOC_S_INPUT: case VIDIOC_S_OUTPUT: - err = get_user(karg.vi, (s32 __user *)up); + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); + if (!err && assign_in_user((unsigned int __user *)up_native, + (compat_uint_t __user *)up)) + err = -EFAULT; compatible_arg = 0; break; case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); compatible_arg = 0; break; case VIDIOC_G_EDID: case VIDIOC_S_EDID: - err = get_v4l2_edid32(&karg.v2edid, up); + err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native); + if (!err) + err = get_v4l2_edid32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = get_v4l2_format32(&karg.v2f, up); + err = bufsize_v4l2_format(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_format), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_format); + err = get_v4l2_format32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_CREATE_BUFS: - err = get_v4l2_create32(&karg.v2crt, up); + err = bufsize_v4l2_create(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_create_buffers), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_create_buffers); + err = get_v4l2_create32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; @@ -918,36 +1105,63 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = get_v4l2_buffer32(&karg.v2b, up); + err = bufsize_v4l2_buffer(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_buffer), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_buffer); + err = get_v4l2_buffer32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_S_FBUF: - err = get_v4l2_framebuffer32(&karg.v2fb, up); + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); + if (!err) + err = get_v4l2_framebuffer32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_FBUF: + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); compatible_arg = 0; break; case VIDIOC_ENUMSTD: - err = get_v4l2_standard32(&karg.v2s, up); + err = alloc_userspace(sizeof(struct v4l2_standard), 0, + &up_native); + if (!err) + err = get_v4l2_standard32(up_native, up); compatible_arg = 0; break; case VIDIOC_ENUMINPUT: - err = get_v4l2_input32(&karg.v2i, up); + err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native); + if (!err) + err = get_v4l2_input32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(&karg.v2ecs, up); + err = bufsize_v4l2_ext_controls(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_ext_controls), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_ext_controls); + err = get_v4l2_ext_controls32(file, up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_DQEVENT: + err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native); compatible_arg = 0; break; } @@ -956,22 +1170,26 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar if (compatible_arg) err = native_ioctl(file, cmd, (unsigned long)up); - else { - mm_segment_t old_fs = get_fs(); + else + err = native_ioctl(file, cmd, (unsigned long)up_native); - set_fs(KERNEL_DS); - err = native_ioctl(file, cmd, (unsigned long)&karg); - set_fs(old_fs); - } + if (err == -ENOTTY) + return err; - /* Special case: even after an error we need to put the - results back for these ioctls since the error_idx will - contain information on which control failed. */ + /* + * Special case: even after an error we need to put the + * results back for these ioctls since the error_idx will + * contain information on which control failed. + */ switch (cmd) { case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(&karg.v2ecs, up)) + if (put_v4l2_ext_controls32(file, up_native, up)) + err = -EFAULT; + break; + case VIDIOC_S_EDID: + if (put_v4l2_edid32(up_native, up)) err = -EFAULT; break; } @@ -983,44 +1201,46 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_OUTPUT: case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: - err = put_user(((s32)karg.vi), (s32 __user *)up); + if (assign_in_user((compat_uint_t __user *)up, + ((unsigned int __user *)up_native))) + err = -EFAULT; break; case VIDIOC_G_FBUF: - err = put_v4l2_framebuffer32(&karg.v2fb, up); + err = put_v4l2_framebuffer32(up_native, up); break; case VIDIOC_DQEVENT: - err = put_v4l2_event32(&karg.v2ev, up); + err = put_v4l2_event32(up_native, up); break; case VIDIOC_G_EDID: - case VIDIOC_S_EDID: - err = put_v4l2_edid32(&karg.v2edid, up); + err = put_v4l2_edid32(up_native, up); break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = put_v4l2_format32(&karg.v2f, up); + err = put_v4l2_format32(up_native, up); break; case VIDIOC_CREATE_BUFS: - err = put_v4l2_create32(&karg.v2crt, up); + err = put_v4l2_create32(up_native, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = put_v4l2_buffer32(&karg.v2b, up); + err = put_v4l2_buffer32(up_native, up); break; case VIDIOC_ENUMSTD: - err = put_v4l2_standard32(&karg.v2s, up); + err = put_v4l2_standard32(up_native, up); break; case VIDIOC_ENUMINPUT: - err = put_v4l2_input32(&karg.v2i, up); + err = put_v4l2_input32(up_native, up); break; } return err; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 5f9818c730cc0e3ff6e54d9f98c38de092f617a6..b5b8973fc34250fd02525270688ce29792108cd0 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1201,6 +1201,16 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, } EXPORT_SYMBOL(v4l2_ctrl_fill); +static u32 user_flags(const struct v4l2_ctrl *ctrl) +{ + u32 flags = ctrl->flags; + + if (ctrl->is_ptr) + flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; + + return flags; +} + static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) { memset(ev->reserved, 0, sizeof(ev->reserved)); @@ -1208,7 +1218,7 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change ev->id = ctrl->id; ev->u.ctrl.changes = changes; ev->u.ctrl.type = ctrl->type; - ev->u.ctrl.flags = ctrl->flags; + ev->u.ctrl.flags = user_flags(ctrl); if (ctrl->is_ptr) ev->u.ctrl.value64 = 0; else @@ -1614,6 +1624,15 @@ static int cluster_changed(struct v4l2_ctrl *master) if (ctrl == NULL) continue; + /* + * Set has_changed to false to avoid generating + * the event V4L2_EVENT_CTRL_CH_VALUE + */ + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { + ctrl->has_changed = false; + continue; + } + for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, ctrl->p_cur, ctrl->p_new); @@ -1663,10 +1682,8 @@ static int check_range(enum v4l2_ctrl_type type, } /* Validate a new control */ -static int validate_new(const struct v4l2_ctrl *ctrl, - struct v4l2_ext_control *c) +static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) { - union v4l2_ctrl_ptr ptr; unsigned idx; int err = 0; @@ -1679,19 +1696,14 @@ static int validate_new(const struct v4l2_ctrl *ctrl, case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BUTTON: case V4L2_CTRL_TYPE_CTRL_CLASS: - ptr.p_s32 = &c->value; - return ctrl->type_ops->validate(ctrl, 0, ptr); - case V4L2_CTRL_TYPE_INTEGER64: - ptr.p_s64 = &c->value64; - return ctrl->type_ops->validate(ctrl, 0, ptr); + return ctrl->type_ops->validate(ctrl, 0, p_new); default: break; } } - ptr.p = c->ptr; - for (idx = 0; !err && idx < c->size / ctrl->elem_size; idx++) - err = ctrl->type_ops->validate(ctrl, idx, ptr); + for (idx = 0; !err && idx < ctrl->elems; idx++) + err = ctrl->type_ops->validate(ctrl, idx, p_new); return err; } @@ -2545,10 +2557,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr else qc->id = ctrl->id; strlcpy(qc->name, ctrl->name, sizeof(qc->name)); - qc->flags = ctrl->flags; + qc->flags = user_flags(ctrl); qc->type = ctrl->type; - if (ctrl->is_ptr) - qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; qc->elem_size = ctrl->elem_size; qc->elems = ctrl->elems; qc->nr_of_dims = ctrl->nr_of_dims; @@ -3017,6 +3027,7 @@ static int validate_ctrls(struct v4l2_ext_controls *cs, cs->error_idx = cs->count; for (i = 0; i < cs->count; i++) { struct v4l2_ctrl *ctrl = helpers[i].ctrl; + union v4l2_ctrl_ptr p_new; cs->error_idx = i; @@ -3030,7 +3041,17 @@ static int validate_ctrls(struct v4l2_ext_controls *cs, best-effort to avoid that. */ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) return -EBUSY; - ret = validate_new(ctrl, &cs->controls[i]); + /* + * Skip validation for now if the payload needs to be copied + * from userspace into kernelspace. We'll validate those later. + */ + if (ctrl->is_ptr) + continue; + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + p_new.p_s64 = &cs->controls[i].value64; + else + p_new.p_s32 = &cs->controls[i].value; + ret = validate_new(ctrl, p_new); if (ret) return ret; } @@ -3125,7 +3146,11 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, /* Copy the new caller-supplied control values. user_to_new() sets 'is_new' to 1. */ do { - ret = user_to_new(cs->controls + idx, helpers[idx].ctrl); + struct v4l2_ctrl *ctrl = helpers[idx].ctrl; + + ret = user_to_new(cs->controls + idx, ctrl); + if (!ret && ctrl->is_ptr) + ret = validate_new(ctrl, ctrl->p_new); idx = helpers[idx].next; } while (!ret && idx); @@ -3175,10 +3200,10 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls); /* Helper function for VIDIOC_S_CTRL compatibility */ -static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, - struct v4l2_ext_control *c, u32 ch_flags) +static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) { struct v4l2_ctrl *master = ctrl->cluster[0]; + int ret; int i; /* Reset the 'is_new' flags of the cluster */ @@ -3186,8 +3211,9 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, if (master->cluster[i]) master->cluster[i]->is_new = 0; - if (c) - user_to_new(c, ctrl); + ret = validate_new(ctrl, ctrl->p_new); + if (ret) + return ret; /* For autoclusters with volatiles that are switched from auto to manual mode we have to update the current volatile values since @@ -3204,15 +3230,14 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c) { - int ret = validate_new(ctrl, c); + int ret; - if (!ret) { - v4l2_ctrl_lock(ctrl); - ret = set_ctrl(fh, ctrl, c, 0); - if (!ret) - cur_to_user(c, ctrl); - v4l2_ctrl_unlock(ctrl); - } + v4l2_ctrl_lock(ctrl); + user_to_new(c, ctrl); + ret = set_ctrl(fh, ctrl, 0); + if (!ret) + cur_to_user(c, ctrl); + v4l2_ctrl_unlock(ctrl); return ret; } @@ -3220,7 +3245,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) { struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); - struct v4l2_ext_control c; + struct v4l2_ext_control c = { control->id }; int ret; if (ctrl == NULL || !ctrl->is_int) @@ -3249,7 +3274,7 @@ int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) /* It's a driver bug if this happens. */ WARN_ON(!ctrl->is_int); ctrl->val = val; - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl); @@ -3260,7 +3285,7 @@ int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val) /* It's a driver bug if this happens. */ WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64); *ctrl->p_new.p_s64 = val; - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64); @@ -3271,7 +3296,7 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) /* It's a driver bug if this happens. */ WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING); strlcpy(ctrl->p_new.p_char, s, ctrl->maximum + 1); - return set_ctrl(NULL, ctrl, NULL, 0); + return set_ctrl(NULL, ctrl, 0); } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string); @@ -3294,8 +3319,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify); int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def) { + bool changed; int ret; - struct v4l2_ext_control c; lockdep_assert_held(ctrl->handler->lock); @@ -3322,11 +3347,20 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, ctrl->maximum = max; ctrl->step = step; ctrl->default_value = def; - c.value = *ctrl->p_cur.p_s32; - if (validate_new(ctrl, &c)) - c.value = def; - if (c.value != *ctrl->p_cur.p_s32) - ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE); + cur_to_new(ctrl); + if (validate_new(ctrl, ctrl->p_new)) { + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + *ctrl->p_new.p_s64 = def; + else + *ctrl->p_new.p_s32 = def; + } + + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; + else + changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; + if (changed) + ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); else send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); return ret; diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 8761aab99de95b2f6e0efc80e2a4d9780b62e9b3..4b1a347d2b3ad4a30f8f4ca7e6244ab6f29ea71e 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -119,14 +119,6 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e if (sev == NULL) return; - /* - * If the event has been added to the fh->subscribed list, but its - * add op has not completed yet elems will be 0, treat this as - * not being subscribed. - */ - if (!sev->elems) - return; - /* Increase event sequence number on fh. */ fh->sequence++; @@ -209,6 +201,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, struct v4l2_subscribed_event *sev, *found_ev; unsigned long flags; unsigned i; + int ret = 0; if (sub->type == V4L2_EVENT_ALL) return -EINVAL; @@ -226,31 +219,36 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, sev->flags = sub->flags; sev->fh = fh; sev->ops = ops; + sev->elems = elems; + + mutex_lock(&fh->subscribe_lock); spin_lock_irqsave(&fh->vdev->fh_lock, flags); found_ev = v4l2_event_subscribed(fh, sub->type, sub->id); - if (!found_ev) - list_add(&sev->list, &fh->subscribed); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); if (found_ev) { + /* Already listening */ kfree(sev); - return 0; /* Already listening */ + goto out_unlock; } if (sev->ops && sev->ops->add) { - int ret = sev->ops->add(sev, elems); + ret = sev->ops->add(sev, elems); if (ret) { - sev->ops = NULL; - v4l2_event_unsubscribe(fh, sub); - return ret; + kfree(sev); + goto out_unlock; } } - /* Mark as ready for use */ - sev->elems = elems; + spin_lock_irqsave(&fh->vdev->fh_lock, flags); + list_add(&sev->list, &fh->subscribed); + spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - return 0; +out_unlock: + mutex_unlock(&fh->subscribe_lock); + + return ret; } EXPORT_SYMBOL_GPL(v4l2_event_subscribe); @@ -289,6 +287,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, return 0; } + mutex_lock(&fh->subscribe_lock); + spin_lock_irqsave(&fh->vdev->fh_lock, flags); sev = v4l2_event_subscribed(fh, sub->type, sub->id); @@ -307,6 +307,7 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, sev->ops->del(sev); kfree(sev); + mutex_unlock(&fh->subscribe_lock); return 0; } diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index c97067a25bd29af93e302086add3421ee6f3fafb..1d076deb05a90a5f147f2ef14502653b68217bb7 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -49,6 +49,7 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) INIT_LIST_HEAD(&fh->available); INIT_LIST_HEAD(&fh->subscribed); fh->sequence = -1; + mutex_init(&fh->subscribe_lock); } EXPORT_SYMBOL_GPL(v4l2_fh_init); @@ -93,6 +94,7 @@ void v4l2_fh_exit(struct v4l2_fh *fh) if (fh->vdev == NULL) return; v4l2_event_unsubscribe_all(fh); + mutex_destroy(&fh->subscribe_lock); fh->vdev = NULL; } EXPORT_SYMBOL_GPL(v4l2_fh_exit); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index ae5f0c52807689ce1d2f4a8901c666b43e54dfd8..5a07fd4fc0814eee49e4ec4e67f466d3b8d04143 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2543,8 +2543,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, /* Handles IOCTL */ err = func(file, cmd, parg); - if (err == -ENOIOCTLCMD) + if (err == -ENOTTY || err == -ENOIOCTLCMD) { err = -ENOTTY; + goto out; + } + if (err == 0) { if (cmd == VIDIOC_DQBUF) trace_v4l2_dqbuf(video_devdata(file)->minor, parg); diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 2b49e393567de97eb7de7c577b3ffcf1fec90f64..c1f781468f2cc9c8c46a1edbb9812c20f4a40349 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2064,6 +2064,11 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n dprintk(1, "dqbuf of buffer %d, with state %d\n", vb->v4l2_buf.index, vb->state); + /* + * After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be + * cleared. + */ + b->flags &= ~V4L2_BUF_FLAG_DONE; return 0; } diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index fc73937290812df292d9654ed43ec19f40497edf..227164ace516783aa333cef5a20913b548a712f3 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -2694,6 +2694,8 @@ mptctl_hp_targetinfo(unsigned long arg) __FILE__, __LINE__, iocnum); return -ENODEV; } + if (karg.hdr.id >= MPT_MAX_FC_DEVICES) + return -EINVAL; dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", ioc->name)); diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 0707fa2c701b543ef597d4797e77b8272c658ca4..4ccbea5402d589f3fe25c911013e7f99e6f857d8 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1994,6 +1994,7 @@ static struct scsi_host_template mptsas_driver_template = { .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mptscsih_host_attrs, + .no_write_same = 1, }; static int mptsas_get_linkerrors(struct sas_phy *phy) diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 28cb048f4760786630e03037be8a2fdf7fbc213e..907247bc2501de6566f6f0eafadae2585cbb127b 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -430,6 +430,20 @@ static void palmas_power_off(void) { unsigned int addr; int ret, slave; + struct device_node *np = palmas_dev->dev->of_node; + + if (of_property_read_bool(np, "ti,palmas-override-powerhold")) { + addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, + PALMAS_PRIMARY_SECONDARY_PAD2); + slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE); + + ret = regmap_update_bits(palmas_dev->regmap[slave], addr, + PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK, 0); + if (ret) + dev_err(palmas_dev->dev, + "Unable to write PRIMARY_SECONDARY_PAD2 %d\n", + ret); + } if (!palmas_dev) return; diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 6ce6e62003590c7c92b9bf459cffd4a0fe33ac04..c9cbbca92e538e35524e2a010e22e737c4f54a46 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -714,6 +714,7 @@ sm501_create_subdev(struct sm501_devdata *sm, char *name, smdev->pdev.name = name; smdev->pdev.id = sm->pdev_id; smdev->pdev.dev.parent = sm->dev; + smdev->pdev.dev.coherent_dma_mask = 0xffffffff; if (res_count) { smdev->pdev.resource = (struct resource *)(smdev+1); diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index d877e777cce667261112503c8b0050df1eda6d96..5726bf4e6c61f352fc524dd94657ac80e9417173 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -227,14 +227,13 @@ static int ti_tscadc_probe(struct platform_device *pdev) * The TSC_ADC_SS controller design assumes the OCP clock is * at least 6x faster than the ADC clock. */ - clk = clk_get(&pdev->dev, "adc_tsc_fck"); + clk = devm_clk_get(&pdev->dev, "adc_tsc_fck"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get TSC fck\n"); err = PTR_ERR(clk); goto err_disable_clk; } clock_rate = clk_get_rate(clk); - clk_put(clk); tscadc->clk_div = clock_rate / ADC_CLK; /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 07fe542e6fc008a48995dc6191b73b758a20dcf6..9372f5e6b677871335b559ab01a92601746e92cb 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -159,13 +159,18 @@ unsigned int twl4030_audio_get_mclk(void) EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); static bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata, - struct device_node *node) + struct device_node *parent) { + struct device_node *node; + if (pdata && pdata->codec) return true; - if (of_find_node_by_name(node, "codec")) + node = of_get_child_by_name(parent, "codec"); + if (node) { + of_node_put(node); return true; + } return false; } diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 9687645162aef9b16b53ede89b2af858a31936fa..902acc48bc6c4609a664a195ac1fa1fc27157e3c 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -97,12 +97,16 @@ static struct reg_default twl6040_patch[] = { }; -static bool twl6040_has_vibra(struct device_node *node) +static bool twl6040_has_vibra(struct device_node *parent) { -#ifdef CONFIG_OF - if (of_find_node_by_name(node, "vibra")) + struct device_node *node; + + node = of_get_child_by_name(parent, "vibra"); + if (node) { + of_node_put(node); return true; -#endif + } + return false; } diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c index de1b1ba28f83db20f0998d5c12a74454bdef1e66..3c4bf8a985013362d31569767b853976587dcd8a 100644 --- a/drivers/mfd/wcd9xxx-core.c +++ b/drivers/mfd/wcd9xxx-core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * 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 diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index ca5a12726d0dc25f884cf3ed8963a89c7f3cafa8..497e5c92a9d29bffb9e09e8470a813b07ce45e61 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -274,6 +274,9 @@ static ssize_t at24_read(struct at24_data *at24, if (unlikely(!count)) return count; + if (off + count > at24->chip.byte_len) + return -EINVAL; + /* * Read data from chip, protecting against concurrent updates * from this host, but not from other I2C masters. @@ -328,6 +331,9 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, unsigned long timeout, write_time; unsigned next_page; + if (offset + count > at24->chip.byte_len) + return -EINVAL; + /* Get corresponding I2C address and adjust offset */ client = at24_translate_offset(at24, &offset); diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index e8b933111e0df78f100ba1ed0459b9d511afec55..92109cadc3fc0189381c93607ba0e056bfe1494e 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -507,35 +507,14 @@ static int remote_settings_file_close(struct inode *inode, struct file *file) static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { void __iomem *address = (void __iomem *)file->private_data; - unsigned char *page; - int retval; int len = 0; unsigned int value; - - if (*offset < 0) - return -EINVAL; - if (count == 0 || count > 1024) - return 0; - if (*offset != 0) - return 0; - - page = (unsigned char *)__get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; + char lbuf[20]; value = readl(address); - len = sprintf(page, "%d\n", value); - - if (copy_to_user(buf, page, len)) { - retval = -EFAULT; - goto exit; - } - *offset += len; - retval = len; + len = snprintf(lbuf, sizeof(lbuf), "%d\n", value); -exit: - free_page((unsigned long)page); - return retval; + return simple_read_from_buffer(buf, count, offset, lbuf, len); } static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset) diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 2a6eaf1122b4e9b742eb3777fb4b6b317c07b201..8e06e1020ad982895a5d517131dc8bd8f398a86f 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -47,11 +47,18 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_IDE #include #endif +struct lkdtm_list { + struct list_head node; +}; + /* * Make sure our attempts to over run the kernel stack doesn't trigger * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we @@ -88,6 +95,9 @@ enum ctype { CT_EXCEPTION, CT_LOOP, CT_OVERFLOW, + CT_CORRUPT_LIST_ADD, + CT_CORRUPT_LIST_DEL, + CT_CORRUPT_USER_DS, CT_CORRUPT_STACK, CT_UNALIGNED_LOAD_STORE_WRITE, CT_OVERWRITE_ALLOCATION, @@ -126,6 +136,9 @@ static char* cp_type[] = { "EXCEPTION", "LOOP", "OVERFLOW", + "CORRUPT_LIST_ADD", + "CORRUPT_LIST_DEL", + "CORRUPT_USER_DS", "CORRUPT_STACK", "UNALIGNED_LOAD_STORE_WRITE", "OVERWRITE_ALLOCATION", @@ -548,6 +561,75 @@ static void lkdtm_do_action(enum ctype which) do_overwritten(); break; } + case CT_CORRUPT_LIST_ADD: { + /* + * Initially, an empty list via LIST_HEAD: + * test_head.next = &test_head + * test_head.prev = &test_head + */ + LIST_HEAD(test_head); + struct lkdtm_list good, bad; + void *target[2] = { }; + void *redirection = ⌖ + + pr_info("attempting good list addition\n"); + + /* + * Adding to the list performs these actions: + * test_head.next->prev = &good.node + * good.node.next = test_head.next + * good.node.prev = test_head + * test_head.next = good.node + */ + list_add(&good.node, &test_head); + + pr_info("attempting corrupted list addition\n"); + /* + * In simulating this "write what where" primitive, the "what" is + * the address of &bad.node, and the "where" is the address held + * by "redirection". + */ + test_head.next = redirection; + list_add(&bad.node, &test_head); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_add() corruption not detected!\n"); + break; + } + case CT_CORRUPT_LIST_DEL: { + LIST_HEAD(test_head); + struct lkdtm_list item; + void *target[2] = { }; + void *redirection = ⌖ + + list_add(&item.node, &test_head); + + pr_info("attempting good list removal\n"); + list_del(&item.node); + + pr_info("attempting corrupted list removal\n"); + list_add(&item.node, &test_head); + + /* As with the list_add() test above, this corrupts "next". */ + item.node.next = redirection; + list_del(&item.node); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_del() corruption not detected!\n"); + break; + } + case CT_CORRUPT_USER_DS: { + pr_info("setting bad task size limit\n"); + set_fs(KERNEL_DS); + + /* Make sure we do not keep running with a KERNEL_DS! */ + force_sig(SIGKILL, current); + break; + } case CT_NONE: default: break; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index beedc91f03a631cc9fd5902d7cd14e840edcef33..94a18bcd2d1d15b4964a1032ad81a3df0134ebe2 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -556,7 +556,6 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) break; default: - dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd); rets = -ENOIOCTLCMD; } diff --git a/drivers/misc/qcom/Kconfig b/drivers/misc/qcom/Kconfig index 8a343d2146cd4e1e44877d188f3f90409d1d3d35..7baab66c282ad24816bee1a7000e20a12f637604 100644 --- a/drivers/misc/qcom/Kconfig +++ b/drivers/misc/qcom/Kconfig @@ -1,6 +1,6 @@ config MSM_QDSP6V2_CODECS bool "Audio QDSP6V2 APR support" - depends on MSM_SMD + depends on MSM_SMD || MSM_HAB help Enable Audio codecs with APR IPC protocol support between application processor and QDSP6 for B-family. APR is diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils.c b/drivers/misc/qcom/qdsp6v2/audio_utils.c index 15d82d126df7d61ad70fb0f3860572665dbf421f..af95daef6503df5a6ccedfccbb4370bde1fc2d02 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_utils.c +++ b/drivers/misc/qcom/qdsp6v2/audio_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2016, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -879,8 +879,7 @@ ssize_t audio_in_write(struct file *file, __func__, audio->ac->session); } } - xfer = (count > (audio->pcm_cfg.buffer_size)) ? - (audio->pcm_cfg.buffer_size) : count; + xfer = (count > size) ? size : count; if (copy_from_user(cpy_ptr, buf, xfer)) { rc = -EFAULT; diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c index 334e705ca8f1f4177bb0f185b520050ef6ee5b3b..30a81ba39001d1a618fc78f80af63452aab8f3d0 100644 --- a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c +++ b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2019, The Linux Foundation. All rights reserved. * * 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 @@ -507,6 +507,12 @@ static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv) uint32_t token; uint32_t *payload = data->payload; + if (data->payload_size < (2 * sizeof(uint32_t))) { + pr_err("%s: payload has invalid size[%d]\n", __func__, + data->payload_size); + return -EINVAL; + } + pr_debug("%s: ptr0[0x%x]; ptr1[0x%x]; opcode[0x%x]\n", __func__, payload[0], payload[1], data->opcode); pr_debug("%s: token[0x%x]; payload_size[%d]; src[%d]; dest[%d];\n", @@ -567,6 +573,11 @@ static int32_t q6usm_callback(struct apr_client_data *data, void *priv) } if (data->opcode == APR_BASIC_RSP_RESULT) { + if (data->payload_size < (2 * sizeof(uint32_t))) { + pr_err("%s: payload has invalid size[%d]\n", __func__, + data->payload_size); + return -EINVAL; + } /* status field check */ if (payload[1]) { pr_err("%s: wrong response[%d] on cmd [%d]\n", @@ -630,6 +641,14 @@ static int32_t q6usm_callback(struct apr_client_data *data, void *priv) opcode = Q6USM_EVENT_READ_DONE; spin_lock_irqsave(&port->dsp_lock, dsp_flags); + if (data->payload_size < + (sizeof(uint32_t)*(READDONE_IDX_STATUS + 1))) { + pr_err("%s: Invalid payload size for READDONE[%d]\n", + __func__, data->payload_size); + spin_unlock_irqrestore(&port->dsp_lock, + dsp_flags); + return -EINVAL; + } if (payload[READDONE_IDX_STATUS]) { pr_err("%s: wrong READDONE[%d]; token[%d]\n", __func__, @@ -675,6 +694,12 @@ static int32_t q6usm_callback(struct apr_client_data *data, void *priv) struct us_port_data *port = &usc->port[IN]; opcode = Q6USM_EVENT_WRITE_DONE; + if (data->payload_size < + (sizeof(uint32_t)*(WRITEDONE_IDX_STATUS + 1))) { + pr_err("%s: Invalid payload size for WRITEDONE[%d]\n", + __func__, data->payload_size); + return -EINVAL; + } if (payload[WRITEDONE_IDX_STATUS]) { pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n", __func__, diff --git a/drivers/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c index 56a9b8ae3f83cfd7a34d3f2571c14ae15601973e..ff8a2f6ea0a98055260696cb54fb304cf7f664ee 100644 --- a/drivers/misc/qpnp-misc.c +++ b/drivers/misc/qpnp-misc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define QPNP_MISC_DEV_NAME "qcom,qpnp-misc" @@ -29,8 +30,20 @@ #define PWM_SEL_MAX 0x03 #define GP_DRIVER_EN_BIT BIT(0) +enum twm { + TWM_MODE_1 = 1, + TWM_MODE_2, + TWM_MODE_3, +}; + +enum twm_attrib { + TWM_ENABLE, + TWM_EXIT, +}; + static DEFINE_MUTEX(qpnp_misc_dev_list_mutex); static LIST_HEAD(qpnp_misc_dev_list); +static RAW_NOTIFIER_HEAD(twm_notifier); struct qpnp_misc_version { u8 subtype; @@ -57,9 +70,13 @@ struct qpnp_misc_dev { struct resource *resource; struct spmi_device *spmi; struct qpnp_misc_version version; + struct class twm_class; + u8 twm_mode; u8 pwm_sel; bool enable_gp_driver; + bool support_twm_config; + bool twm_enable; }; static struct of_device_id qpnp_misc_match_table[] = { @@ -207,9 +224,99 @@ int qpnp_misc_irqs_available(struct device *consumer_dev) return __misc_irqs_available(mdev_found); } +#define MISC_SPARE_1 0x50 +#define MISC_SPARE_2 0x51 +#define ENABLE_TWM_MODE 0x80 +#define DISABLE_TWM_MODE 0x0 +#define TWM_EXIT_BIT BIT(0) +static ssize_t twm_enable_store(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_misc_dev *mdev = container_of(c, + struct qpnp_misc_dev, twm_class); + u8 val = 0; + ssize_t rc = 0; + + rc = kstrtou8(buf, 10, &val); + if (rc < 0) + return rc; + + mdev->twm_enable = val ? true : false; + + /* Notify the TWM state */ + raw_notifier_call_chain(&twm_notifier, + mdev->twm_enable ? PMIC_TWM_ENABLE : PMIC_TWM_CLEAR, NULL); + + return count; +} + +static ssize_t twm_enable_show(struct class *c, + struct class_attribute *attr, char *buf) +{ + struct qpnp_misc_dev *mdev = container_of(c, + struct qpnp_misc_dev, twm_class); + + return snprintf(buf, PAGE_SIZE, "%d\n", mdev->twm_enable); +} + +static ssize_t twm_exit_show(struct class *c, + struct class_attribute *attr, char *buf) +{ + struct qpnp_misc_dev *mdev = container_of(c, + struct qpnp_misc_dev, twm_class); + ssize_t rc = 0; + u8 val = 0; + + rc = qpnp_read_byte(mdev->spmi, + mdev->resource->start + MISC_SPARE_1, &val); + if (rc < 0) { + pr_err("Failed to read TWM enable (misc_spare_1) rc=%d\n", rc); + return rc; + } + + pr_debug("TWM_EXIT (misc_spare_1) register = 0x%02x\n", val); + + return snprintf(buf, PAGE_SIZE, "%d\n", !!(val & TWM_EXIT_BIT)); +} + +static struct class_attribute twm_attributes[] = { + [TWM_ENABLE] = __ATTR(twm_enable, S_IRUGO | S_IWUSR, + twm_enable_show, twm_enable_store), + [TWM_EXIT] = __ATTR(twm_exit, S_IRUGO | S_IWUSR, + twm_exit_show, NULL), + __ATTR_NULL, +}; + +int qpnp_misc_twm_notifier_register(struct notifier_block *nb) +{ + return raw_notifier_chain_register(&twm_notifier, nb); +} +EXPORT_SYMBOL(qpnp_misc_twm_notifier_register); + +int qpnp_misc_twm_notifier_unregister(struct notifier_block *nb) +{ + return raw_notifier_chain_unregister(&twm_notifier, nb); +} +EXPORT_SYMBOL(qpnp_misc_twm_notifier_unregister); + static int qpnp_misc_dt_init(struct qpnp_misc_dev *mdev) { u32 val; + int rc; + + if (of_property_read_bool(mdev->dev->of_node, + "qcom,support-twm-config")) { + mdev->support_twm_config = true; + mdev->twm_mode = TWM_MODE_3; + rc = of_property_read_u8(mdev->dev->of_node, "qcom,twm-mode", + &mdev->twm_mode); + if (!rc && (mdev->twm_mode < TWM_MODE_1 || + mdev->twm_mode > TWM_MODE_3)) { + pr_err("Invalid TWM mode %d\n", mdev->twm_mode); + return -EINVAL; + } + } if (!of_property_read_u32(mdev->dev->of_node, "qcom,pwm-sel", &val)) { if (val > PWM_SEL_MAX) { @@ -261,6 +368,18 @@ static int qpnp_misc_config(struct qpnp_misc_dev *mdev) break; } + if (mdev->support_twm_config) { + mdev->twm_class.name = "pmic_twm", + mdev->twm_class.owner = THIS_MODULE, + mdev->twm_class.class_attrs = twm_attributes; + + rc = class_register(&mdev->twm_class); + if (rc < 0) { + pr_err("Failed to register pmic_twm class rc=%d\n", rc); + return rc; + } + } + return 0; } @@ -283,6 +402,7 @@ static int qpnp_misc_probe(struct spmi_device *spmi) mdev->spmi = spmi; mdev->dev = &(spmi->dev); mdev->resource = resource; + dev_set_drvdata(&spmi->dev, mdev); rc = qpnp_read_byte(spmi, resource->start + REG_SUBTYPE, &mdev->version.subtype); @@ -320,8 +440,35 @@ static int qpnp_misc_probe(struct spmi_device *spmi) return 0; } +static void qpnp_misc_shutdown(struct spmi_device *spmi) +{ + struct qpnp_misc_dev *mdev = dev_get_drvdata(&spmi->dev); + int rc; + + if (mdev->support_twm_config) { + rc = qpnp_write_byte(mdev->spmi, + mdev->resource->start + MISC_SPARE_2, + mdev->twm_enable ? mdev->twm_mode : 0x0); + if (rc < 0) + pr_err("Failed to write MISC_SPARE_2 (twm_mode) val=%d rc=%d\n", + mdev->twm_enable ? mdev->twm_mode : 0x0, rc); + + rc = qpnp_write_byte(mdev->spmi, + mdev->resource->start + MISC_SPARE_1, + mdev->twm_enable ? ENABLE_TWM_MODE : 0x0); + if (rc < 0) + pr_err("Failed to write MISC_SPARE_1 (twm_state) val=%d rc=%d\n", + mdev->twm_enable ? ENABLE_TWM_MODE : 0x0, rc); + + pr_debug("PMIC configured for TWM-%s MODE=%d\n", + mdev->twm_enable ? "enabled" : "disabled", + mdev->twm_mode); + } +} + static struct spmi_driver qpnp_misc_driver = { .probe = qpnp_misc_probe, + .shutdown = qpnp_misc_shutdown, .driver = { .name = QPNP_MISC_DEV_NAME, .owner = THIS_MODULE, diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index f2955be6189984b5c35c7bcaf584b8f910e156ac..82eb2517565515c6cac8447f9da7799e5a1e810f 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1,6 +1,7 @@ -/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver +/* + * QTI Secure Execution Environment Communicator (QSEECOM) driver * - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -43,13 +44,13 @@ #include #include #include -#include "qseecom_legacy.h" #include "qseecom_kernel.h" #include #include #include #include "compat_qseecom.h" +#include #define QSEECOM_DEV "qseecom" #define QSEOS_VERSION_14 0x14 @@ -65,7 +66,7 @@ #define QSEE_CE_CLK_100MHZ 100000000 #define CE_CLK_DIV 1000000 -#define QSEECOM_MAX_SG_ENTRY 512 +#define QSEECOM_MAX_SG_ENTRY 4096 #define QSEECOM_SG_ENTRY_MSG_BUF_SZ_64BIT \ (QSEECOM_MAX_SG_ENTRY * SG_ENTRY_SZ_64BIT) @@ -100,6 +101,10 @@ #define QSEECOM_STATE_READY 2 #define QSEECOM_ICE_FDE_KEY_SIZE_MASK 2 +#define QSEECOM_SCM_EBUSY_WAIT_MS 30 +#define QSEECOM_SCM_EBUSY_MAX_RETRY 67 +#define QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT 33 + /* * default ce info unit to 0 for * services which @@ -118,9 +123,12 @@ enum qseecom_clk_definitions { }; enum qseecom_ice_key_size_type { - QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE = (0 << QSEECOM_ICE_FDE_KEY_SIZE_MASK), - QSEECOM_ICE_FDE_KEY_SIZE_32_BYTE = (1 << QSEECOM_ICE_FDE_KEY_SIZE_MASK), - QSEECOM_ICE_FDE_KEY_SIZE_UNDEF = (0xF << QSEECOM_ICE_FDE_KEY_SIZE_MASK), + QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE = + (0 << QSEECOM_ICE_FDE_KEY_SIZE_MASK), + QSEECOM_ICE_FDE_KEY_SIZE_32_BYTE = + (1 << QSEECOM_ICE_FDE_KEY_SIZE_MASK), + QSEE_ICE_FDE_KEY_SIZE_UNDEFINED = + (0xF << QSEECOM_ICE_FDE_KEY_SIZE_MASK), }; enum qseecom_client_handle_type { @@ -137,12 +145,25 @@ enum qseecom_ce_hw_instance { CLK_INVALID, }; +enum qseecom_listener_unregister_kthread_state { + LSNR_UNREG_KT_SLEEP = 0, + LSNR_UNREG_KT_WAKEUP, +}; + +enum qseecom_unload_app_kthread_state { + UNLOAD_APP_KT_SLEEP = 0, + UNLOAD_APP_KT_WAKEUP, +}; + static struct class *driver_class; static dev_t qseecom_device_no; static DEFINE_MUTEX(qsee_bw_mutex); static DEFINE_MUTEX(app_access_lock); static DEFINE_MUTEX(clk_access_lock); +static DEFINE_MUTEX(listener_access_lock); +static DEFINE_MUTEX(unload_app_pending_list_lock); + struct sglist_info { uint32_t indexAndFlags; @@ -182,13 +203,21 @@ struct qseecom_registered_listener_list { size_t sb_length; struct ion_handle *ihandle; /* Retrieve phy addr */ wait_queue_head_t rcv_req_wq; + /* rcv_req_flag: 0: ready and empty; 1: received req */ int rcv_req_flag; int send_resp_flag; bool listener_in_use; /* wq for thread blocked on this listener*/ wait_queue_head_t listener_block_app_wq; - struct sglist_info sglistinfo_ptr[MAX_ION_FD]; - uint32_t sglist_cnt; + struct sglist_info sglistinfo_ptr[MAX_ION_FD]; + uint32_t sglist_cnt; + int abort; + bool unregister_pending; +}; + +struct qseecom_unregister_pending_list { + struct list_head list; + struct qseecom_dev_handle *data; }; struct qseecom_registered_app_list { @@ -198,6 +227,7 @@ struct qseecom_registered_app_list { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; bool app_blocked; + u32 check_block; u32 blocked_on_listener_id; }; @@ -235,7 +265,6 @@ struct qseecom_clk { struct qseecom_control { struct ion_client *ion_clnt; /* Ion client */ struct list_head registered_listener_list_head; - spinlock_t registered_listener_list_lock; struct list_head registered_app_list_head; spinlock_t registered_app_list_lock; @@ -252,7 +281,6 @@ struct qseecom_control { bool whitelist_support; bool commonlib_loaded; bool commonlib64_loaded; - struct ion_handle *cmnlib_ion_handle; struct ce_hw_usage_info ce_info; int qsee_bw_count; @@ -282,6 +310,23 @@ struct qseecom_control { wait_queue_head_t app_block_wq; atomic_t qseecom_state; int is_apps_region_protected; + bool smcinvoke_support; + + struct list_head unregister_lsnr_pending_list_head; + wait_queue_head_t register_lsnr_pending_wq; + struct task_struct *unregister_lsnr_kthread_task; + wait_queue_head_t unregister_lsnr_kthread_wq; + atomic_t unregister_lsnr_kthread_state; + + struct list_head unload_app_pending_list_head; + struct task_struct *unload_app_kthread_task; + wait_queue_head_t unload_app_kthread_wq; + atomic_t unload_app_kthread_state; +}; + +struct qseecom_unload_app_pending_list { + struct list_head list; + struct qseecom_dev_handle *data; }; struct qseecom_sec_buf_fd_info { @@ -306,10 +351,14 @@ struct qseecom_client_handle { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD]; + bool from_smcinvoke; + bool unload_pending; }; struct qseecom_listener_handle { u32 id; + bool unregister_pending; + bool release_called; }; static struct qseecom_control qseecom; @@ -381,6 +430,8 @@ static int qseecom_free_ce_info(struct qseecom_dev_handle *data, void __user *argp); static int qseecom_query_ce_info(struct qseecom_dev_handle *data, void __user *argp); +static int __qseecom_unload_app(struct qseecom_dev_handle *data, + uint32_t app_id); static int get_qseecom_keymaster_status(char *str) { @@ -389,6 +440,25 @@ static int get_qseecom_keymaster_status(char *str) } __setup("androidboot.keymaster=", get_qseecom_keymaster_status); +static int __qseecom_scm_call2_locked(uint32_t smc_id, struct scm_desc *desc) +{ + int ret = 0; + int retry_count = 0; + + do { + ret = scm_call2_noretry(smc_id, desc); + if (ret == -EBUSY) { + mutex_unlock(&app_access_lock); + msleep(QSEECOM_SCM_EBUSY_WAIT_MS); + mutex_lock(&app_access_lock); + } + if (retry_count == QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT) + pr_warn("secure world has been busy for 1 second!\n"); + } while (ret == -EBUSY && + (retry_count++ < QSEECOM_SCM_EBUSY_MAX_RETRY)); + return ret; +} + static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, const void *req_buf, void *resp_buf) { @@ -416,7 +486,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, svc_id, tz_cmd_id); return -EINVAL; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case SCM_SVC_ES: { @@ -427,10 +497,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_save_partition_hash_req *) req_buf; char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("error allocating data\n"); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, p_hash_req->digest, SHA256_DIGEST_LENGTH); @@ -440,7 +509,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = p_hash_req->partition_id; desc.args[1] = virt_to_phys(tzbuf); desc.args[2] = SHA256_DIGEST_LENGTH; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -458,6 +527,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, case QSEOS_APP_START_COMMAND: { struct qseecom_load_app_ireq *req; struct qseecom_load_app_64bit_ireq *req_64bit; + smc_id = TZ_OS_APP_START_ID; desc.arginfo = TZ_OS_APP_START_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -474,11 +544,12 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_APP_SHUTDOWN_COMMAND: { struct qseecom_unload_app_ireq *req; + req = (struct qseecom_unload_app_ireq *)req_buf; smc_id = TZ_OS_APP_SHUTDOWN_ID; desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID; @@ -490,11 +561,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, struct qseecom_check_app_ireq *req; u32 tzbuflen = PAGE_ALIGN(sizeof(req->app_name)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } req = (struct qseecom_check_app_ireq *)req_buf; pr_debug("Lookup app_name = %s\n", req->app_name); strlcpy(tzbuf, req->app_name, sizeof(req->app_name)); @@ -504,13 +573,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = strlen(req->app_name); __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } case QSEOS_APP_REGION_NOTIFICATION: { struct qsee_apps_region_info_ireq *req; struct qsee_apps_region_info_64bit_ireq *req_64bit; + smc_id = TZ_OS_APP_REGION_NOTIFICATION_ID; desc.arginfo = TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID; @@ -527,12 +597,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[1] = req_64bit->size; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LOAD_SERV_IMAGE_COMMAND: { struct qseecom_load_lib_image_ireq *req; struct qseecom_load_lib_image_64bit_ireq *req_64bit; + smc_id = TZ_OS_LOAD_SERVICES_IMAGE_ID; desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -550,19 +621,20 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_UNLOAD_SERV_IMAGE_COMMAND: { smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID; desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_REGISTER_LISTENER: { struct qseecom_register_listener_ireq *req; struct qseecom_register_listener_64bit_ireq *req_64bit; + desc.arginfo = TZ_OS_REGISTER_LISTENER_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -579,30 +651,31 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[1] = req_64bit->sb_ptr; desc.args[2] = req_64bit->sb_len; } + qseecom.smcinvoke_support = true; smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID; - __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); - if (ret) { + ret = __qseecom_scm_call2_locked(smc_id, &desc); + if (ret == -EIO) { + /* smcinvoke is not supported */ + qseecom.smcinvoke_support = false; smc_id = TZ_OS_REGISTER_LISTENER_ID; - __qseecom_reentrancy_check_if_no_app_blocked( - smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); } break; } case QSEOS_DEREGISTER_LISTENER: { struct qseecom_unregister_listener_ireq *req; + req = (struct qseecom_unregister_listener_ireq *) req_buf; smc_id = TZ_OS_DEREGISTER_LISTENER_ID; desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID; desc.args[0] = req->listener_id; - __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LISTENER_DATA_RSP_COMMAND: { struct qseecom_client_listener_data_irsp *req; + req = (struct qseecom_client_listener_data_irsp *) req_buf; smc_id = TZ_OS_LISTENER_RESPONSE_HANDLER_ID; @@ -610,7 +683,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID; desc.args[0] = req->listener_id; desc.args[1] = req->status; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: { @@ -638,12 +711,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64->sglistinfo_ptr; desc.args[3] = req_64->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: { struct qseecom_load_app_ireq *req; struct qseecom_load_app_64bit_ireq *req_64bit; + smc_id = TZ_OS_LOAD_EXTERNAL_IMAGE_ID; desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -659,20 +733,21 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND: { smc_id = TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID; desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CLIENT_SEND_DATA_COMMAND: { struct qseecom_client_send_data_ireq *req; struct qseecom_client_send_data_64bit_ireq *req_64bit; + smc_id = TZ_APP_QSAPP_SEND_DATA_ID; desc.arginfo = TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -693,7 +768,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->rsp_ptr; desc.args[4] = req_64bit->rsp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: { @@ -725,32 +800,33 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_PROVISION_KEY_COMMAND: { struct qseecom_client_send_service_ireq *req; + req = (struct qseecom_client_send_service_ireq *) req_buf; smc_id = TZ_OS_RPMB_PROVISION_KEY_ID; desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID; desc.args[0] = req->key_type; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_ERASE_COMMAND: { smc_id = TZ_OS_RPMB_ERASE_ID; desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND: { smc_id = TZ_OS_RPMB_CHECK_PROV_STATUS_ID; desc.arginfo = TZ_OS_RPMB_CHECK_PROV_STATUS_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_GENERATE_KEY: { @@ -758,6 +834,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_generate_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); + if (!tzbuf) return -ENOMEM; memset(tzbuf, 0, tzbuflen); @@ -770,7 +847,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -779,11 +856,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_delete_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof(struct qseecom_key_delete_ireq) - @@ -794,7 +869,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -803,11 +878,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_select_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof(struct qseecom_key_select_ireq) - @@ -818,7 +891,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -827,11 +900,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_userinfo_update_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof (struct qseecom_key_userinfo_update_ireq) - @@ -842,13 +913,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } case QSEOS_TEE_OPEN_SESSION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_OPEN_SESSION_ID; desc.arginfo = TZ_APP_GPAPP_OPEN_SESSION_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -867,7 +939,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_OPEN_SESSION_WHITELIST: { @@ -897,12 +969,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_ID; desc.arginfo = TZ_APP_GPAPP_INVOKE_COMMAND_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -921,7 +994,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: { @@ -951,12 +1024,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_CLOSE_SESSION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_CLOSE_SESSION_ID; desc.arginfo = TZ_APP_GPAPP_CLOSE_SESSION_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -975,12 +1049,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_REQUEST_CANCELLATION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_REQUEST_CANCELLATION_ID; desc.arginfo = TZ_APP_GPAPP_REQUEST_CANCELLATION_ID_PARAM_ID; @@ -1000,22 +1075,26 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CONTINUE_BLOCKED_REQ_COMMAND: { struct qseecom_continue_blocked_request_ireq *req = (struct qseecom_continue_blocked_request_ireq *) req_buf; - smc_id = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID; + if (qseecom.smcinvoke_support) + smc_id = + TZ_OS_CONTINUE_BLOCKED_REQUEST_SMCINVOKE_ID; + else + smc_id = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID; desc.arginfo = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID; - desc.args[0] = req->app_id; - ret = scm_call2(smc_id, &desc); + desc.args[0] = req->app_or_session_id; + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } default: { - pr_err("qseos_cmd_id 0x%d is not supported by armv8 scm_call2.\n", + pr_err("qseos_cmd_id %d is not supported by armv8 scm_call2.\n", qseos_cmd_id); ret = -EINVAL; break; @@ -1051,42 +1130,18 @@ static int qseecom_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf, return qseecom_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf); } -static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data, - struct qseecom_register_listener_req *svc) -{ - struct qseecom_registered_listener_list *ptr; - int unique = 1; - unsigned long flags; - - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) { - if (ptr->svc.listener_id == svc->listener_id) { - pr_err("Service id: %u is already registered\n", - ptr->svc.listener_id); - unique = 0; - break; - } - } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); - return unique; -} - static struct qseecom_registered_listener_list *__qseecom_find_svc( int32_t listener_id) { struct qseecom_registered_listener_list *entry = NULL; - unsigned long flags; - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(entry, &qseecom.registered_listener_list_head, list) - { + list_for_each_entry(entry, + &qseecom.registered_listener_list_head, list) { if (entry->svc.listener_id == listener_id) break; } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); - if ((entry != NULL) && (entry->svc.listener_id != listener_id)) { - pr_err("Service id: %u is not found\n", listener_id); + pr_debug("Service id: %u is not found\n", listener_id); return NULL; } @@ -1146,8 +1201,14 @@ static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc, resp.result = QSEOS_RESULT_INCOMPLETE; + mutex_unlock(&listener_access_lock); + mutex_lock(&app_access_lock); + __qseecom_reentrancy_check_if_no_app_blocked( + TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); + mutex_lock(&listener_access_lock); if (ret) { pr_err("qseecom_scm_call failed with err: %d\n", ret); return -EINVAL; @@ -1165,9 +1226,9 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, void __user *argp) { int ret = 0; - unsigned long flags; struct qseecom_register_listener_req rcvd_lstnr; struct qseecom_registered_listener_list *new_entry; + struct qseecom_registered_listener_list *ptr_svc; ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr)); if (ret) { @@ -1178,18 +1239,33 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, rcvd_lstnr.sb_size)) return -EFAULT; - data->listener.id = 0; - if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) { - pr_err("Service is not unique and is already registered\n"); - data->released = true; - return -EBUSY; + ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id); + if (ptr_svc) { + if (ptr_svc->unregister_pending == false) { + pr_err("Service %d is not unique\n", + rcvd_lstnr.listener_id); + data->released = true; + return -EBUSY; + } + /*wait until listener is unregistered*/ + pr_debug("register %d has to wait\n", + rcvd_lstnr.listener_id); + mutex_unlock(&listener_access_lock); + ret = wait_event_interruptible( + qseecom.register_lsnr_pending_wq, + list_empty( + &qseecom.unregister_lsnr_pending_list_head)); + if (ret) { + pr_err("interrupted register_pending_wq %d\n", + rcvd_lstnr.listener_id); + mutex_lock(&listener_access_lock); + return -ERESTARTSYS; + } + mutex_lock(&listener_access_lock); } - new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); - if (!new_entry) { - pr_err("kmalloc failed\n"); + if (!new_entry) return -ENOMEM; - } memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr)); new_entry->rcv_req_flag = 0; @@ -1197,30 +1273,28 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, new_entry->sb_length = rcvd_lstnr.sb_size; new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base; if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) { - pr_err("qseecom_set_sb_memoryfailed\n"); + pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n", + rcvd_lstnr.listener_id, rcvd_lstnr.sb_size); kzfree(new_entry); return -ENOMEM; } - data->listener.id = rcvd_lstnr.listener_id; init_waitqueue_head(&new_entry->rcv_req_wq); init_waitqueue_head(&new_entry->listener_block_app_wq); new_entry->send_resp_flag = 0; new_entry->listener_in_use = false; - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head); - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); + data->listener.id = rcvd_lstnr.listener_id; + pr_debug("Service %d is registered\n", rcvd_lstnr.listener_id); return ret; } -static int qseecom_unregister_listener(struct qseecom_dev_handle *data) +static int __qseecom_unregister_listener(struct qseecom_dev_handle *data, + struct qseecom_registered_listener_list *ptr_svc) { int ret = 0; - unsigned long flags; - uint32_t unmap_mem = 0; struct qseecom_register_listener_ireq req; - struct qseecom_registered_listener_list *ptr_svc = NULL; struct qseecom_command_scm_resp resp; struct ion_handle *ihandle = NULL; /* Retrieve phy addr */ @@ -1228,68 +1302,157 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) req.listener_id = data->listener.id; resp.result = QSEOS_RESULT_INCOMPLETE; + mutex_unlock(&listener_access_lock); + mutex_lock(&app_access_lock); + __qseecom_reentrancy_check_if_no_app_blocked( + TZ_OS_DEREGISTER_LISTENER_ID); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req), &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); + mutex_lock(&listener_access_lock); if (ret) { pr_err("scm_call() failed with err: %d (lstnr id=%d)\n", ret, data->listener.id); - return ret; + if (ret == -EBUSY) + return ret; + goto exit; } if (resp.result != QSEOS_RESULT_SUCCESS) { pr_err("Failed resp.result=%d,(lstnr id=%d)\n", resp.result, data->listener.id); - return -EPERM; - } - - data->abort = 1; - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, - list) { - if (ptr_svc->svc.listener_id == data->listener.id) { - wake_up_all(&ptr_svc->rcv_req_wq); - break; - } + ret = -EPERM; + goto exit; } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); while (atomic_read(&data->ioctl_count) > 1) { - if (wait_event_freezable(data->abort_wq, + if (wait_event_interruptible(data->abort_wq, atomic_read(&data->ioctl_count) <= 1)) { pr_err("Interrupted from abort\n"); ret = -ERESTARTSYS; - return ret; } } - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(ptr_svc, - &qseecom.registered_listener_list_head, - list) - { - if (ptr_svc->svc.listener_id == data->listener.id) { - if (ptr_svc->sb_virt) { - unmap_mem = 1; - ihandle = ptr_svc->ihandle; - } - list_del(&ptr_svc->list); - kzfree(ptr_svc); - break; - } - } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); - - /* Unmap the memory */ - if (unmap_mem) { +exit: + if (ptr_svc->sb_virt) { + ihandle = ptr_svc->ihandle; if (!IS_ERR_OR_NULL(ihandle)) { ion_unmap_kernel(qseecom.ion_clnt, ihandle); ion_free(qseecom.ion_clnt, ihandle); - } + } } + list_del(&ptr_svc->list); + kzfree(ptr_svc); + data->released = true; + pr_debug("Service %d is unregistered\n", data->listener.id); return ret; } +static int qseecom_unregister_listener(struct qseecom_dev_handle *data) +{ + struct qseecom_registered_listener_list *ptr_svc = NULL; + struct qseecom_unregister_pending_list *entry = NULL; + + if (data->released) { + pr_err("Don't unregister lsnr %d\n", data->listener.id); + return -EINVAL; + } + + ptr_svc = __qseecom_find_svc(data->listener.id); + if (!ptr_svc) { + pr_err("Unregiser invalid listener ID %d\n", data->listener.id); + return -ENODATA; + } + /* stop CA thread waiting for listener response */ + ptr_svc->abort = 1; + wake_up_interruptible_all(&qseecom.send_resp_wq); + + /* stop listener thread waiting for listener request */ + data->abort = 1; + wake_up_all(&ptr_svc->rcv_req_wq); + + /* return directly if pending*/ + if (ptr_svc->unregister_pending) + return 0; + + /*add unregistration into pending list*/ + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->data = data; + list_add_tail(&entry->list, + &qseecom.unregister_lsnr_pending_list_head); + ptr_svc->unregister_pending = true; + pr_debug("unregister %d pending\n", data->listener.id); + return 0; +} + +static void __qseecom_processing_pending_lsnr_unregister(void) +{ + struct qseecom_unregister_pending_list *entry = NULL; + struct qseecom_registered_listener_list *ptr_svc = NULL; + struct list_head *pos; + int ret = 0; + + mutex_lock(&listener_access_lock); + while (!list_empty(&qseecom.unregister_lsnr_pending_list_head)) { + pos = qseecom.unregister_lsnr_pending_list_head.next; + entry = list_entry(pos, + struct qseecom_unregister_pending_list, list); + if (entry && entry->data) { + pr_debug("process pending unregister %d\n", + entry->data->listener.id); + /* don't process if qseecom_release is not called*/ + if (!entry->data->listener.release_called) + break; + ptr_svc = __qseecom_find_svc( + entry->data->listener.id); + if (ptr_svc) { + ret = __qseecom_unregister_listener( + entry->data, ptr_svc); + if (ret == -EBUSY) { + pr_debug("unregister %d pending again\n", + entry->data->listener.id); + mutex_unlock(&listener_access_lock); + return; + } + } else + pr_err("invalid listener %d\n", + entry->data->listener.id); + kzfree(entry->data); + } + list_del(pos); + kzfree(entry); + } + mutex_unlock(&listener_access_lock); + wake_up_interruptible(&qseecom.register_lsnr_pending_wq); +} + +static void __wakeup_unregister_listener_kthread(void) +{ + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_WAKEUP); + wake_up_interruptible(&qseecom.unregister_lsnr_kthread_wq); +} + +static int __qseecom_unregister_listener_kthread_func(void *data) +{ + while (!kthread_should_stop()) { + wait_event_interruptible( + qseecom.unregister_lsnr_kthread_wq, + atomic_read(&qseecom.unregister_lsnr_kthread_state) + == LSNR_UNREG_KT_WAKEUP); + pr_debug("kthread to unregister listener is called %d\n", + atomic_read(&qseecom.unregister_lsnr_kthread_state)); + __qseecom_processing_pending_lsnr_unregister(); + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_SLEEP); + } + pr_warn("kthread to unregister listener stopped\n"); + return 0; +} + static int __qseecom_set_msm_bus_request(uint32_t mode) { int ret = 0; @@ -1338,39 +1501,35 @@ static void qseecom_bw_inactive_req_work(struct work_struct *work) qseecom.timer_running = false; mutex_unlock(&qsee_bw_mutex); mutex_unlock(&app_access_lock); - return; } static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data) { schedule_work(&qseecom.bw_inactive_req_ws); - return; } static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce) { struct qseecom_clk *qclk; int ret = 0; + mutex_lock(&clk_access_lock); if (ce == CLK_QSEE) qclk = &qseecom.qsee; else qclk = &qseecom.ce_drv; - if (qclk->clk_access_cnt > 2) { + if (qclk->clk_access_cnt > 0) { + qclk->clk_access_cnt--; + } else { pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt); ret = -EINVAL; - goto err_dec_ref_cnt; } - if (qclk->clk_access_cnt == 2) - qclk->clk_access_cnt--; -err_dec_ref_cnt: mutex_unlock(&clk_access_lock); return ret; } - static int qseecom_scale_bus_bandwidth_timer(uint32_t mode) { int32_t ret = 0; @@ -1440,6 +1599,7 @@ static int __qseecom_register_bus_bandwidth_needs( static int qseecom_perf_enable(struct qseecom_dev_handle *data) { int ret = 0; + ret = qsee_vote_for_clock(data, CLK_DFAB); if (ret) { pr_err("Failed to vote for DFAB clock with err %d\n", ret); @@ -1476,9 +1636,9 @@ static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data, } /* - * Register bus bandwidth needs if bus scaling feature is enabled; - * otherwise, qseecom enable/disable clocks for the client directly. - */ + * Register bus bandwidth needs if bus scaling feature is enabled; + * otherwise, qseecom enable/disable clocks for the client directly. + */ if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); ret = __qseecom_register_bus_bandwidth_needs(data, req_mode); @@ -1521,12 +1681,12 @@ static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data) else __qseecom_add_bw_scale_down_timer( QSEECOM_LOAD_APP_CRYPTO_TIMEOUT); - return; } static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data) { int ret = 0; + if (qseecom.support_bus_scaling) { ret = qseecom_scale_bus_bandwidth_timer(MEDIUM); if (ret) @@ -1578,7 +1738,7 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, } if (len < req.sb_len) { - pr_err("Requested length (0x%x) is > allocated (0x%zu)\n", + pr_err("Requested length (0x%x) is > allocated (%zu)\n", req.sb_len, len); return -EINVAL; } @@ -1595,11 +1755,13 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, return 0; } -static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data) +static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data, + struct qseecom_registered_listener_list *ptr_svc) { int ret; + ret = (qseecom.send_resp_flag != 0); - return ret || data->abort; + return ret || data->abort || ptr_svc->abort; } static int __qseecom_reentrancy_listener_has_sent_rsp( @@ -1609,56 +1771,7 @@ static int __qseecom_reentrancy_listener_has_sent_rsp( int ret; ret = (ptr_svc->send_resp_flag != 0); - return ret || data->abort; -} - -static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data, - struct qseecom_command_scm_resp *resp, - struct qseecom_client_listener_data_irsp *send_data_rsp, - struct qseecom_registered_listener_list *ptr_svc, - uint32_t lstnr) { - int ret = 0; - - send_data_rsp->status = QSEOS_RESULT_FAILURE; - qseecom.send_resp_flag = 0; - send_data_rsp->qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND; - send_data_rsp->listener_id = lstnr; - if (ptr_svc) - pr_warn("listener_id:%x, lstnr: %x\n", - ptr_svc->svc.listener_id, lstnr); - if (ptr_svc && ptr_svc->ihandle) { - ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, - ptr_svc->sb_virt, ptr_svc->sb_length, - ION_IOC_CLEAN_INV_CACHES); - if (ret) { - pr_err("cache operation failed %d\n", ret); - return ret; - } - } - - if (lstnr == RPMB_SERVICE) { - ret = __qseecom_enable_clk(CLK_QSEE); - if (ret) - return ret; - } - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp, - sizeof(send_data_rsp), resp, sizeof(*resp)); - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; - } - if ((resp->result != QSEOS_RESULT_SUCCESS) && - (resp->result != QSEOS_RESULT_INCOMPLETE)) { - pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", - resp->result, data->client.app_id, lstnr); - ret = -EINVAL; - } - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; + return ret || data->abort || ptr_svc->abort; } static void __qseecom_clean_listener_sglistinfo( @@ -1677,9 +1790,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, int ret = 0; int rc = 0; uint32_t lstnr; - unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -1688,13 +1801,13 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, size_t cmd_len; struct sglist_info *table = NULL; + qseecom.app_block_ref_cnt++; while (resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id */ - spin_lock_irqsave(&qseecom.registered_listener_list_lock, - flags); + mutex_lock(&listener_access_lock); list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { @@ -1704,29 +1817,38 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, break; } } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, - flags); if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } + + if (ptr_svc->abort == 1) { + pr_debug("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); /* initialize the new signal mask with all signals*/ @@ -1734,6 +1856,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, /* block all signals */ sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); + mutex_unlock(&listener_access_lock); do { /* * When reentrancy is not supported, check global @@ -1741,22 +1864,23 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, * send_resp_flag. */ if (!qseecom.qsee_reentrancy_support && - !wait_event_freezable(qseecom.send_resp_wq, - __qseecom_listener_has_sent_rsp(data))) { - break; + !wait_event_interruptible(qseecom.send_resp_wq, + __qseecom_listener_has_sent_rsp( + data, ptr_svc))) { + break; } if (qseecom.qsee_reentrancy_support && - !wait_event_freezable(qseecom.send_resp_wq, + !wait_event_interruptible(qseecom.send_resp_wq, __qseecom_reentrancy_listener_has_sent_rsp( data, ptr_svc))) { - break; + break; } } while (1); - + mutex_lock(&listener_access_lock); /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -1764,83 +1888,98 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, } else { status = QSEOS_RESULT_SUCCESS; } - +err_resp: qseecom.send_resp_flag = 0; - ptr_svc->send_resp_flag = 0; - table = ptr_svc->sglistinfo_ptr; + if (ptr_svc) { + ptr_svc->send_resp_flag = 0; + table = ptr_svc->sglistinfo_ptr; + } if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) { + if (ptr_svc && ptr_svc->ihandle) { ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, ION_IOC_CLEAN_INV_CACHES); if (ret) { pr_err("cache operation failed %d\n", ret); - return ret; + goto exit; } } if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) - return ret; + goto exit; } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); + if (ptr_svc) { + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); + } if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) __qseecom_disable_clk(CLK_QSEE); - return ret; + goto exit; } + pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n", + status, resp->result, data->client.app_id, lstnr); if ((resp->result != QSEOS_RESULT_SUCCESS) && (resp->result != QSEOS_RESULT_INCOMPLETE)) { pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", resp->result, data->client.app_id, lstnr); ret = -EINVAL; + goto exit; } +exit: + mutex_unlock(&listener_access_lock); if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) __qseecom_disable_clk(CLK_QSEE); } + qseecom.app_block_ref_cnt--; + wake_up_interruptible_all(&qseecom.app_block_wq); if (rc) return rc; return ret; } -int __qseecom_process_reentrancy_blocked_on_listener( +static int __qseecom_process_reentrancy_blocked_on_listener( struct qseecom_command_scm_resp *resp, struct qseecom_registered_app_list *ptr_app, struct qseecom_dev_handle *data) @@ -1849,9 +1988,12 @@ int __qseecom_process_reentrancy_blocked_on_listener( int ret = 0; struct qseecom_continue_blocked_request_ireq ireq; struct qseecom_command_scm_resp continue_resp; - sigset_t new_sigset, old_sigset; + unsigned int session_id; + sigset_t new_sigset; + sigset_t old_sigset; unsigned long flags; bool found_app = false; + struct qseecom_registered_app_list dummy_app_entry = { {NULL} }; if (!resp || !data) { pr_err("invalid resp or data pointer\n"); @@ -1861,76 +2003,111 @@ int __qseecom_process_reentrancy_blocked_on_listener( /* find app_id & img_name from list */ if (!ptr_app) { - spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); - list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, - list) { - if ((ptr_app->app_id == data->client.app_id) && - (!strcmp(ptr_app->app_name, + if (data->client.from_smcinvoke) { + pr_debug("This request is from smcinvoke\n"); + ptr_app = &dummy_app_entry; + ptr_app->app_id = data->client.app_id; + } else { + spin_lock_irqsave(&qseecom.registered_app_list_lock, + flags); + list_for_each_entry(ptr_app, + &qseecom.registered_app_list_head, list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp(ptr_app->app_name, data->client.app_name))) { - found_app = true; - break; + found_app = true; + break; + } + } + spin_unlock_irqrestore( + &qseecom.registered_app_list_lock, flags); + if (!found_app) { + pr_err("app_id %d (%s) is not found\n", + data->client.app_id, + (char *)data->client.app_name); + ret = -ENOENT; + goto exit; } } - spin_unlock_irqrestore(&qseecom.registered_app_list_lock, - flags); - if (!found_app) { - pr_err("app_id %d (%s) is not found\n", - data->client.app_id, - (char *)data->client.app_name); - ret = -ENOENT; - goto exit; - } } - list_ptr = __qseecom_find_svc(resp->data); - if (!list_ptr) { - pr_err("Invalid listener ID\n"); - ret = -ENODATA; - goto exit; - } - pr_debug("lsntr %d in_use = %d\n", - resp->data, list_ptr->listener_in_use); - ptr_app->blocked_on_listener_id = resp->data; - /* sleep until listener is available */ do { - qseecom.app_block_ref_cnt++; - ptr_app->app_blocked = true; + session_id = resp->resp_type; + mutex_lock(&listener_access_lock); + list_ptr = __qseecom_find_svc(resp->data); + if (!list_ptr) { + pr_err("Invalid listener ID %d\n", resp->data); + ret = -ENODATA; + mutex_unlock(&listener_access_lock); + goto exit; + } + ptr_app->blocked_on_listener_id = resp->data; + + pr_warn("Lsntr %d in_use %d, block session(%d) app(%d)\n", + resp->data, list_ptr->listener_in_use, + session_id, data->client.app_id); + + /* sleep until listener is available */ sigfillset(&new_sigset); sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); - mutex_unlock(&app_access_lock); + do { - if (!wait_event_freezable( + qseecom.app_block_ref_cnt++; + ptr_app->app_blocked = true; + mutex_unlock(&listener_access_lock); + mutex_unlock(&app_access_lock); + wait_event_interruptible( list_ptr->listener_block_app_wq, - !list_ptr->listener_in_use)) { - break; - } - } while (1); - mutex_lock(&app_access_lock); + !list_ptr->listener_in_use); + mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); + ptr_app->app_blocked = false; + qseecom.app_block_ref_cnt--; + } while (list_ptr->listener_in_use); + sigprocmask(SIG_SETMASK, &old_sigset, NULL); - ptr_app->app_blocked = false; - qseecom.app_block_ref_cnt--; - } while (list_ptr->listener_in_use == true); - ptr_app->blocked_on_listener_id = 0; - /* notify the blocked app that listener is available */ - pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n", - resp->data, data->client.app_id, - data->client.app_name); - ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; - ireq.app_id = data->client.app_id; - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, - &ireq, sizeof(ireq), - &continue_resp, sizeof(continue_resp)); - if (ret) { - pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n", - data->client.app_id, - data->client.app_name, ret); - goto exit; + + ptr_app->blocked_on_listener_id = 0; + pr_warn("Lsntr %d is available, unblock session(%d) app(%d)\n", + resp->data, session_id, data->client.app_id); + + /* notify TZ that listener is available */ + ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; + + if (qseecom.smcinvoke_support) + ireq.app_or_session_id = session_id; + else + ireq.app_or_session_id = data->client.app_id; + + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + &ireq, sizeof(ireq), + &continue_resp, sizeof(continue_resp)); + if (ret && qseecom.smcinvoke_support) { + /* retry with legacy cmd */ + qseecom.smcinvoke_support = false; + ireq.app_or_session_id = data->client.app_id; + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + &ireq, sizeof(ireq), + &continue_resp, sizeof(continue_resp)); + qseecom.smcinvoke_support = true; + if (ret) { + pr_err("unblock app %d or session %d fail\n", + data->client.app_id, session_id); + mutex_unlock(&listener_access_lock); + goto exit; + } + } + mutex_unlock(&listener_access_lock); + resp->result = continue_resp.result; + resp->resp_type = continue_resp.resp_type; + resp->data = continue_resp.data; + pr_debug("unblock resp = %d\n", resp->result); + } while (resp->result == QSEOS_RESULT_BLOCKED_ON_LISTENER); + + if (resp->result != QSEOS_RESULT_INCOMPLETE) { + pr_err("Unexpected unblock resp %d\n", resp->result); + ret = -EINVAL; } - /* - * After TZ app is unblocked, then continue to next case - * for incomplete request processing - */ - resp->result = QSEOS_RESULT_INCOMPLETE; exit: return ret; } @@ -1941,10 +2118,10 @@ static int __qseecom_reentrancy_process_incomplete_cmd( { int ret = 0; int rc = 0; - uint32_t lstnr = 0; - unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + uint32_t lstnr; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -1953,13 +2130,12 @@ static int __qseecom_reentrancy_process_incomplete_cmd( size_t cmd_len; struct sglist_info *table = NULL; - while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { + while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id */ - spin_lock_irqsave(&qseecom.registered_listener_list_lock, - flags); + mutex_lock(&listener_access_lock); list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { @@ -1969,23 +2145,38 @@ static int __qseecom_reentrancy_process_incomplete_cmd( break; } } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, - flags); if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } + + if (ptr_svc->abort == 1) { + pr_debug("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); /* initialize the new signal mask with all signals*/ @@ -1995,22 +2186,24 @@ static int __qseecom_reentrancy_process_incomplete_cmd( sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); /* unlock mutex btw waking listener and sleep-wait */ + mutex_unlock(&listener_access_lock); mutex_unlock(&app_access_lock); do { - if (!wait_event_freezable(qseecom.send_resp_wq, + if (!wait_event_interruptible(qseecom.send_resp_wq, __qseecom_reentrancy_listener_has_sent_rsp( data, ptr_svc))) { - break; + break; } } while (1); /* lock mutex again after resp sent */ mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); ptr_svc->send_resp_flag = 0; qseecom.send_resp_flag = 0; /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -2018,55 +2211,64 @@ static int __qseecom_reentrancy_process_incomplete_cmd( } else { status = QSEOS_RESULT_SUCCESS; } - table = ptr_svc->sglistinfo_ptr; +err_resp: + if (ptr_svc) + table = ptr_svc->sglistinfo_ptr; if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) { + if (ptr_svc && ptr_svc->ihandle) { ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, ION_IOC_CLEAN_INV_CACHES); if (ret) { pr_err("cache operation failed %d\n", ret); - return ret; + goto exit; } } if (lstnr == RPMB_SERVICE) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) - return ret; + goto exit; } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); - wake_up_interruptible(&ptr_svc->listener_block_app_wq); + if (ptr_svc) { + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); + wake_up_interruptible(&ptr_svc->listener_block_app_wq); + } if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", @@ -2084,8 +2286,10 @@ static int __qseecom_reentrancy_process_incomplete_cmd( ret = -EINVAL; goto exit; } + mutex_unlock(&listener_access_lock); ret = __qseecom_process_reentrancy_blocked_on_listener( resp, NULL, data); + mutex_lock(&listener_access_lock); if (ret) { pr_err("failed to process App(%d) %s blocked on listener %d\n", data->client.app_id, @@ -2102,8 +2306,10 @@ static int __qseecom_reentrancy_process_incomplete_cmd( goto exit; } exit: + mutex_unlock(&listener_access_lock); if (lstnr == RPMB_SERVICE) __qseecom_disable_clk(CLK_QSEE); + } if (rc) return rc; @@ -2119,23 +2325,15 @@ exit: */ static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id) { - sigset_t new_sigset, old_sigset; - if (qseecom.qsee_reentrancy_support > QSEE_REENTRANCY_PHASE_0 && qseecom.qsee_reentrancy_support < QSEE_REENTRANCY_PHASE_3 && IS_OWNER_TRUSTED_OS(TZ_SYSCALL_OWNER_ID(smc_id))) { /* thread sleep until this app unblocked */ while (qseecom.app_block_ref_cnt > 0) { - sigfillset(&new_sigset); - sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); mutex_unlock(&app_access_lock); - do { - if (!wait_event_freezable(qseecom.app_block_wq, - (qseecom.app_block_ref_cnt == 0))) - break; - } while (1); + wait_event_interruptible(qseecom.app_block_wq, + (!qseecom.app_block_ref_cnt)); mutex_lock(&app_access_lock); - sigprocmask(SIG_SETMASK, &old_sigset, NULL); } } } @@ -2148,22 +2346,17 @@ static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id) static void __qseecom_reentrancy_check_if_this_app_blocked( struct qseecom_registered_app_list *ptr_app) { - sigset_t new_sigset, old_sigset; if (qseecom.qsee_reentrancy_support) { + ptr_app->check_block++; while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) { /* thread sleep until this app unblocked */ - sigfillset(&new_sigset); - sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); mutex_unlock(&app_access_lock); - do { - if (!wait_event_freezable(qseecom.app_block_wq, - (!ptr_app->app_blocked && - qseecom.app_block_ref_cnt <= 1))) - break; - } while (1); + wait_event_interruptible(qseecom.app_block_wq, + (!ptr_app->app_blocked && + qseecom.app_block_ref_cnt <= 1)); mutex_lock(&app_access_lock); - sigprocmask(SIG_SETMASK, &old_sigset, NULL); } + ptr_app->check_block--; } } @@ -2390,8 +2583,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { - pr_err("process_incomplete_cmd failed err: %d\n", - ret); + /* TZ has created app_id, need to unload it */ + pr_err("incomp_cmd err %d, %d, unload %d %s\n", + ret, resp.result, resp.data, + load_img_req.img_name); + __qseecom_unload_app(data, resp.data); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); ret = -EFAULT; @@ -2412,7 +2608,6 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { - pr_err("kmalloc failed\n"); ret = -ENOMEM; goto loadapp_err; } @@ -2420,11 +2615,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) entry->ref_cnt = 1; entry->app_arch = load_img_req.app_arch; /* - * keymaster app may be first loaded as "keymaste" by qseecomd, - * and then used as "keymaster" on some targets. To avoid app - * name checking error, register "keymaster" into app_list and - * thread private data. - */ + * keymaster app may be first loaded as "keymaste" by qseecomd, + * and then used as "keymaster" on some targets. To avoid app + * name checking error, register "keymaster" into app_list and + * thread private data. + */ if (!strcmp(load_img_req.img_name, "keymaste")) strlcpy(entry->app_name, "keymaster", MAX_APP_NAME_SIZE); @@ -2433,6 +2628,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) @@ -2443,7 +2639,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags); - pr_warn("App with id %d (%s) now loaded\n", app_id, + pr_warn("App with id %u (%s) now loaded\n", app_id, (char *)(load_img_req.img_name)); } data->client.app_id = app_id; @@ -2481,11 +2677,12 @@ enable_clk_err: static int __qseecom_cleanup_app(struct qseecom_dev_handle *data) { int ret = 1; /* Set unload app */ + wake_up_all(&qseecom.send_resp_wq); if (qseecom.qsee_reentrancy_support) mutex_unlock(&app_access_lock); while (atomic_read(&data->ioctl_count) > 1) { - if (wait_event_freezable(data->abort_wq, + if (wait_event_interruptible(data->abort_wq, atomic_read(&data->ioctl_count) <= 1)) { pr_err("Interrupted from abort\n"); ret = -ERESTARTSYS; @@ -2500,10 +2697,56 @@ static int __qseecom_cleanup_app(struct qseecom_dev_handle *data) static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data) { int ret = 0; + if (!IS_ERR_OR_NULL(data->client.ihandle)) { ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle); ion_free(qseecom.ion_clnt, data->client.ihandle); - data->client.ihandle = NULL; + memset((void *)&data->client, + 0, sizeof(struct qseecom_client_handle)); + } + return ret; +} + +static int __qseecom_unload_app(struct qseecom_dev_handle *data, + uint32_t app_id) +{ + struct qseecom_unload_app_ireq req; + struct qseecom_command_scm_resp resp; + int ret = 0; + + /* Populate the structure for sending scm call to load image */ + req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND; + req.app_id = app_id; + + /* SCM_CALL to unload the app */ + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, + sizeof(struct qseecom_unload_app_ireq), + &resp, sizeof(resp)); + if (ret) { + pr_err("scm_call to unload app (id = %d) failed\n", app_id); + return -EFAULT; + } + switch (resp.result) { + case QSEOS_RESULT_SUCCESS: + pr_warn("App (%d) is unloaded\n", app_id); + break; + case QSEOS_RESULT_INCOMPLETE: + ret = __qseecom_process_incomplete_cmd(data, &resp); + if (ret) + pr_err("unload app %d fail proc incom cmd: %d,%d,%d\n", + app_id, ret, resp.result, resp.data); + else + pr_warn("App (%d) is unloaded\n", app_id); + break; + case QSEOS_RESULT_FAILURE: + pr_err("app (%d) unload_failed!!\n", app_id); + ret = -EFAULT; + break; + default: + pr_err("unload app %d get unknown resp.result %d\n", + app_id, resp.result); + ret = -EFAULT; + break; } return ret; } @@ -2514,11 +2757,11 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, unsigned long flags; unsigned long flags1; int ret = 0; - struct qseecom_command_scm_resp resp; struct qseecom_registered_app_list *ptr_app = NULL; bool unload = false; bool found_app = false; bool found_dead_app = false; + bool doublecheck = false; if (!data) { pr_err("Invalid/uninitialized device handle\n"); @@ -2541,13 +2784,15 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, if (!strcmp((void *)ptr_app->app_name, (void *)data->client.app_name)) { found_app = true; + if (ptr_app->app_blocked || + ptr_app->check_block) + app_crash = false; if (app_crash || ptr_app->ref_cnt == 1) unload = true; break; - } else { - found_dead_app = true; - break; } + found_dead_app = true; + break; } } spin_unlock_irqrestore(&qseecom.registered_app_list_lock, @@ -2566,42 +2811,30 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, (char *)data->client.app_name); if (unload) { - struct qseecom_unload_app_ireq req; - /* Populate the structure for sending scm call to load image */ - req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND; - req.app_id = data->client.app_id; + ret = __qseecom_unload_app(data, data->client.app_id); - /* SCM_CALL to unload the app */ - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, - sizeof(struct qseecom_unload_app_ireq), - &resp, sizeof(resp)); - if (ret) { - pr_err("scm_call to unload app (id = %d) failed\n", - req.app_id); - ret = -EFAULT; - goto unload_exit; - } else { - pr_warn("App id %d now unloaded\n", req.app_id); - } - if (resp.result == QSEOS_RESULT_FAILURE) { - pr_err("app (%d) unload_failed!!\n", - data->client.app_id); - ret = -EFAULT; - goto unload_exit; - } - if (resp.result == QSEOS_RESULT_SUCCESS) - pr_debug("App (%d) is unloaded!!\n", - data->client.app_id); - if (resp.result == QSEOS_RESULT_INCOMPLETE) { - ret = __qseecom_process_incomplete_cmd(data, &resp); - if (ret) { - pr_err("process_incomplete_cmd fail err: %d\n", - ret); - goto unload_exit; + /* double check if this app_entry still exists */ + spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); + list_for_each_entry(ptr_app, + &qseecom.registered_app_list_head, list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp((void *)ptr_app->app_name, + (void *)data->client.app_name))) { + doublecheck = true; + break; } } + spin_unlock_irqrestore(&qseecom.registered_app_list_lock, + flags1); + if (!doublecheck) { + pr_warn("app %d(%s) entry is already removed\n", + data->client.app_id, + (char *)data->client.app_name); + found_app = false; + } } +unload_exit: if (found_app) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); if (app_crash) { @@ -2624,12 +2857,105 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags1); } -unload_exit: qseecom_unmap_ion_allocated_memory(data); data->released = true; return ret; } + +static int qseecom_prepare_unload_app(struct qseecom_dev_handle *data) +{ + struct qseecom_unload_app_pending_list *entry = NULL; + + pr_debug("prepare to unload app(%d)(%s), pending %d\n", + data->client.app_id, data->client.app_name, + data->client.unload_pending); + if (data->client.unload_pending) + return 0; + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->data = data; + list_add_tail(&entry->list, + &qseecom.unload_app_pending_list_head); + data->client.unload_pending = true; + pr_debug("unload ta %d pending\n", data->client.app_id); + return 0; +} + +static void __wakeup_unload_app_kthread(void) +{ + atomic_set(&qseecom.unload_app_kthread_state, + UNLOAD_APP_KT_WAKEUP); + wake_up_interruptible(&qseecom.unload_app_kthread_wq); +} + +static bool __qseecom_find_pending_unload_app(uint32_t app_id, char *app_name) +{ + struct qseecom_unload_app_pending_list *entry = NULL; + bool found = false; + + mutex_lock(&unload_app_pending_list_lock); + list_for_each_entry(entry, &qseecom.unload_app_pending_list_head, + list) { + if ((entry->data->client.app_id == app_id) && + (!strcmp(entry->data->client.app_name, app_name))) { + found = true; + break; + } + } + mutex_unlock(&unload_app_pending_list_lock); + return found; +} + +static void __qseecom_processing_pending_unload_app(void) +{ + struct qseecom_unload_app_pending_list *entry = NULL; + struct list_head *pos; + int ret = 0; + + mutex_lock(&unload_app_pending_list_lock); + while (!list_empty(&qseecom.unload_app_pending_list_head)) { + pos = qseecom.unload_app_pending_list_head.next; + entry = list_entry(pos, + struct qseecom_unload_app_pending_list, list); + if (entry && entry->data) { + pr_debug("process pending unload app %d (%s)\n", + entry->data->client.app_id, + entry->data->client.app_name); + mutex_unlock(&unload_app_pending_list_lock); + mutex_lock(&app_access_lock); + ret = qseecom_unload_app(entry->data, true); + if (ret) + pr_err("unload app %d pending failed %d\n", + entry->data->client.app_id, ret); + mutex_unlock(&app_access_lock); + mutex_lock(&unload_app_pending_list_lock); + kzfree(entry->data); + } + list_del(pos); + kzfree(entry); + } + mutex_unlock(&unload_app_pending_list_lock); +} + +static int __qseecom_unload_app_kthread_func(void *data) +{ + while (!kthread_should_stop()) { + wait_event_interruptible( + qseecom.unload_app_kthread_wq, + atomic_read(&qseecom.unload_app_kthread_state) + == UNLOAD_APP_KT_WAKEUP); + pr_debug("kthread to unload app is called, state %d\n", + atomic_read(&qseecom.unload_app_kthread_state)); + __qseecom_processing_pending_unload_app(); + atomic_set(&qseecom.unload_app_kthread_state, + UNLOAD_APP_KT_SLEEP); + } + pr_warn("kthread to unload app stopped\n"); + return 0; +} + static phys_addr_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data, unsigned long virt) { @@ -3033,7 +3359,7 @@ int __qseecom_process_reentrancy(struct qseecom_command_scm_resp *resp, ret = __qseecom_reentrancy_process_incomplete_cmd(data, resp); ptr_app->app_blocked = false; qseecom.app_block_ref_cnt--; - wake_up_interruptible(&qseecom.app_block_wq); + wake_up_interruptible_all(&qseecom.app_block_wq); if (ret) pr_err("process_incomplete_cmd failed err: %d\n", ret); @@ -3051,6 +3377,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, struct qseecom_send_cmd_req *req) { int ret = 0; + int ret2 = 0; u32 reqd_len_sb_in = 0; struct qseecom_client_send_data_ireq send_data_req = {0}; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0}; @@ -3081,6 +3408,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, return -ENOENT; } + if (__qseecom_find_pending_unload_app(data->client.app_id, + data->client.app_name)) { + pr_err("app %d (%s) unload is pending\n", + data->client.app_id, data->client.app_name); + return -ENOENT; + } + if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.app_id = data->client.app_id; send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( @@ -3149,32 +3483,38 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); - return ret; + goto exit; } if (qseecom.qsee_reentrancy_support) { ret = __qseecom_process_reentrancy(&resp, ptr_app, data); + if (ret) + goto exit; } else { if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { pr_err("process_incomplete_cmd failed err: %d\n", ret); - return ret; + goto exit; } } else { if (resp.result != QSEOS_RESULT_SUCCESS) { pr_err("Response result %d not supported\n", resp.result); ret = -EINVAL; + goto exit; } } } - ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, +exit: + ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_INV_CACHES); - if (ret) - pr_err("cache operation failed %d\n", ret); + if (ret2) { + pr_err("cache operation failed %d\n", ret2); + return ret2; + } return ret; } @@ -3206,23 +3546,50 @@ int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req, if ((data->type != QSEECOM_LISTENER_SERVICE) && (req->ifd_data[i].fd > 0)) { - if ((req->cmd_req_len < sizeof(uint32_t)) || - (req->ifd_data[i].cmd_buf_offset > - req->cmd_req_len - sizeof(uint32_t))) { - pr_err("Invalid offset (req len) 0x%x\n", - req->ifd_data[i].cmd_buf_offset); - return -EINVAL; - } + if ((req->cmd_req_len < sizeof(uint32_t)) || + (req->ifd_data[i].cmd_buf_offset > + req->cmd_req_len - sizeof(uint32_t))) { + pr_err("Invalid offset (req len) 0x%x\n", + req->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } } else if ((data->type == QSEECOM_LISTENER_SERVICE) && (lstnr_resp->ifd_data[i].fd > 0)) { - if ((lstnr_resp->resp_len < sizeof(uint32_t)) || - (lstnr_resp->ifd_data[i].cmd_buf_offset > - lstnr_resp->resp_len - sizeof(uint32_t))) { - pr_err("Invalid offset (lstnr resp len) 0x%x\n", - lstnr_resp->ifd_data[i].cmd_buf_offset); - return -EINVAL; - } + if ((lstnr_resp->resp_len < sizeof(uint32_t)) || + (lstnr_resp->ifd_data[i].cmd_buf_offset > + lstnr_resp->resp_len - sizeof(uint32_t))) { + pr_err("Invalid offset (lstnr resp len) 0x%x\n", + lstnr_resp->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } + } + return 0; +} + +static int __boundary_checks_offset_64(struct qseecom_send_modfd_cmd_req *req, + struct qseecom_send_modfd_listener_resp *lstnr_resp, + struct qseecom_dev_handle *data, int i) +{ + + if ((data->type != QSEECOM_LISTENER_SERVICE) && + (req->ifd_data[i].fd > 0)) { + if ((req->cmd_req_len < sizeof(uint64_t)) || + (req->ifd_data[i].cmd_buf_offset > + req->cmd_req_len - sizeof(uint64_t))) { + pr_err("Invalid offset (req len) 0x%x\n", + req->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } + } else if ((data->type == QSEECOM_LISTENER_SERVICE) && + (lstnr_resp->ifd_data[i].fd > 0)) { + if ((lstnr_resp->resp_len < sizeof(uint64_t)) || + (lstnr_resp->ifd_data[i].cmd_buf_offset > + lstnr_resp->resp_len - sizeof(uint64_t))) { + pr_err("Invalid offset (lstnr resp len) 0x%x\n", + lstnr_resp->ifd_data[i].cmd_buf_offset); + return -EINVAL; } + } return 0; } @@ -3303,6 +3670,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, sg = sg_ptr->sgl; if (sg_ptr->nents == 1) { uint32_t *update; + if (__boundary_checks_offset(req, lstnr_resp, data, i)) goto err; if ((data->type == QSEECOM_CLIENT_APP && @@ -3366,8 +3734,8 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, update = (struct qseecom_sg_entry *)field; for (j = 0; j < sg_ptr->nents; j++) { /* - * Check if sg list PA is under 4GB - */ + * Check if sg list PA is under 4GB + */ if ((qseecom.qsee_version >= QSEE_VERSION_40) && (!cleanup) && @@ -3583,7 +3951,9 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, sg = sg_ptr->sgl; if (sg_ptr->nents == 1) { uint64_t *update_64bit; - if (__boundary_checks_offset(req, lstnr_resp, data, i)) + + if (__boundary_checks_offset_64(req, lstnr_resp, + data, i)) goto err; /* 64bit app uses 64bit address */ update_64bit = (uint64_t *) field; @@ -3766,7 +4136,8 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data, struct qseecom_registered_listener_list *svc) { int ret; - ret = (svc->rcv_req_flag != 0); + + ret = (svc->rcv_req_flag == 1); return ret || data->abort; } @@ -3775,14 +4146,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) int ret = 0; struct qseecom_registered_listener_list *this_lstnr; + mutex_lock(&listener_access_lock); this_lstnr = __qseecom_find_svc(data->listener.id); if (!this_lstnr) { pr_err("Invalid listener ID\n"); + mutex_unlock(&listener_access_lock); return -ENODATA; } + mutex_unlock(&listener_access_lock); while (1) { - if (wait_event_freezable(this_lstnr->rcv_req_wq, + if (wait_event_interruptible(this_lstnr->rcv_req_wq, __qseecom_listener_has_rcvd_req(data, this_lstnr))) { pr_debug("Interrupted: exiting Listener Service = %d\n", @@ -3793,10 +4167,12 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) if (data->abort) { pr_err("Aborting Listener Service = %d\n", - (uint32_t)data->listener.id); + (uint32_t)data->listener.id); return -ENODEV; } + mutex_lock(&listener_access_lock); this_lstnr->rcv_req_flag = 0; + mutex_unlock(&listener_access_lock); break; } return ret; @@ -4012,9 +4388,19 @@ static int __qseecom_allocate_img_data(struct ion_handle **pihandle, ion_phys_addr_t pa; struct ion_handle *ihandle = NULL; u8 *img_data = NULL; + int retry = 0; + int ion_flag = ION_FLAG_CACHED; - ihandle = ion_alloc(qseecom.ion_clnt, fw_size, - SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0); + do { + if (retry++) { + mutex_unlock(&app_access_lock); + msleep(QSEECOM_TA_ION_ALLOCATE_DELAY); + mutex_lock(&app_access_lock); + } + ihandle = ion_alloc(qseecom.ion_clnt, fw_size, + SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), ion_flag); + } while (IS_ERR_OR_NULL(ihandle) && + (retry <= QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP)); if (IS_ERR_OR_NULL(ihandle)) { pr_err("ION alloc failed\n"); @@ -4160,8 +4546,12 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); if (ret) { - pr_err("scm_call to load failed : ret %d\n", ret); - ret = -EIO; + pr_err("scm_call to load failed : ret %d, result %x\n", + ret, resp.result); + if (resp.result == QSEOS_RESULT_FAIL_APP_ALREADY_LOADED) + ret = -EEXIST; + else + ret = -EIO; goto exit_disable_clk_vote; } @@ -4171,10 +4561,14 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, break; case QSEOS_RESULT_INCOMPLETE: ret = __qseecom_process_incomplete_cmd(data, &resp); - if (ret) - pr_err("process_incomplete_cmd FAILED\n"); - else + if (ret) { + pr_err("incomp_cmd err %d, %d, unload %d %s\n", + ret, resp.result, resp.data, appname); + __qseecom_unload_app(data, resp.data); + ret = -EFAULT; + } else { *app_id = resp.data; + } break; case QSEOS_RESULT_FAILURE: pr_err("scm call failed with response QSEOS_RESULT FAILURE\n"); @@ -4213,6 +4607,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data, void *cmd_buf = NULL; size_t cmd_len; uint32_t app_arch = 0; + struct ion_handle *cmnlib_ion_handle = NULL; if (!cmnlib_name) { pr_err("cmnlib_name is NULL\n"); @@ -4227,7 +4622,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data, if (__qseecom_get_fw_size(cmnlib_name, &fw_size, &app_arch)) return -EIO; - ret = __qseecom_allocate_img_data(&qseecom.cmnlib_ion_handle, + ret = __qseecom_allocate_img_data(&cmnlib_ion_handle, &img_data, fw_size, &pa); if (ret) return -EIO; @@ -4268,7 +4663,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data, goto exit_unregister_bus_bw_need; } - ret = msm_ion_do_cache_op(qseecom.ion_clnt, qseecom.cmnlib_ion_handle, + ret = msm_ion_do_cache_op(qseecom.ion_clnt, cmnlib_ion_handle, img_data, fw_size, ION_IOC_CLEAN_INV_CACHES); if (ret) { @@ -4316,7 +4711,7 @@ exit_unregister_bus_bw_need: } exit_free_img_data: - __qseecom_free_img_data(&qseecom.cmnlib_ion_handle); + __qseecom_free_img_data(&cmnlib_ion_handle); return ret; } @@ -4369,6 +4764,9 @@ int qseecom_start_app(struct qseecom_handle **handle, uint32_t fw_size, app_arch; uint32_t app_id = 0; + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); + if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", atomic_read(&qseecom.qseecom_state)); @@ -4386,19 +4784,13 @@ int qseecom_start_app(struct qseecom_handle **handle, } *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL); - if (!(*handle)) { - pr_err("failed to allocate memory for kernel client handle\n"); + if (!(*handle)) return -ENOMEM; - } data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { - pr_err("kmalloc failed\n"); - if (ret == 0) { - kfree(*handle); - *handle = NULL; - } - return -ENOMEM; + ret = -ENOMEM; + goto exit_handle_free; } data->abort = 0; data->type = QSEECOM_CLIENT_APP; @@ -4413,18 +4805,17 @@ int qseecom_start_app(struct qseecom_handle **handle, ION_HEAP(ION_QSECOM_HEAP_ID), 0); if (IS_ERR_OR_NULL(data->client.ihandle)) { pr_err("Ion client could not retrieve the handle\n"); - kfree(data); - kfree(*handle); - *handle = NULL; - return -EINVAL; + ret = -ENOMEM; + goto exit_data_free; } mutex_lock(&app_access_lock); +recheck: app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND; strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE); ret = __qseecom_check_app_exists(app_ireq, &app_id); if (ret) - goto err; + goto exit_ion_free; strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE); if (app_id) { @@ -4449,28 +4840,31 @@ int qseecom_start_app(struct qseecom_handle **handle, pr_debug("%s: Loading app for the first time'\n", qseecom.pdev->init_name); ret = __qseecom_load_fw(data, app_name, &app_id); - if (ret < 0) - goto err; + if (ret == -EEXIST) { + pr_err("recheck if TA %s is loaded\n", app_name); + goto recheck; + } else if (ret < 0) + goto exit_ion_free; } data->client.app_id = app_id; if (!found_app) { entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { pr_err("kmalloc for app entry failed\n"); - ret = -ENOMEM; - goto err; + ret = -ENOMEM; + goto exit_ion_free; } entry->app_id = app_id; entry->ref_cnt = 1; strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE); if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) { ret = -EIO; - kfree(entry); - goto err; + goto exit_entry_free; } entry->app_arch = app_arch; entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, &qseecom.registered_app_list_head); spin_unlock_irqrestore(&qseecom.registered_app_list_lock, @@ -4482,7 +4876,7 @@ int qseecom_start_app(struct qseecom_handle **handle, if (ret) { pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n", ret); - goto err; + goto exit_entry_free; } /* Populate the structure for sending scm call to load image */ @@ -4491,7 +4885,7 @@ int qseecom_start_app(struct qseecom_handle **handle, if (IS_ERR_OR_NULL(data->client.sb_virt)) { pr_err("ION memory mapping for client shared buf failed\n"); ret = -ENOMEM; - goto err; + goto exit_entry_free; } data->client.user_virt_sb_base = (uintptr_t)data->client.sb_virt; data->client.sb_phys = (phys_addr_t)pa; @@ -4501,9 +4895,8 @@ int qseecom_start_app(struct qseecom_handle **handle, kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL); if (!kclient_entry) { - pr_err("kmalloc failed\n"); ret = -ENOMEM; - goto err; + goto exit_ion_unmap_kernel; } kclient_entry->handle = *handle; @@ -4513,13 +4906,28 @@ int qseecom_start_app(struct qseecom_handle **handle, spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); mutex_unlock(&app_access_lock); + __wakeup_unload_app_kthread(); return 0; -err: - kfree(data); - kfree(*handle); - *handle = NULL; +exit_ion_unmap_kernel: + if (!IS_ERR_OR_NULL(data->client.ihandle)) + ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle); +exit_entry_free: + kfree(entry); +exit_ion_free: mutex_unlock(&app_access_lock); + if (!IS_ERR_OR_NULL(data->client.ihandle)) { + ion_free(qseecom.ion_clnt, data->client.ihandle); + data->client.ihandle = NULL; + } +exit_data_free: + kfree(data); +exit_handle_free: + if (*handle) { + kfree(*handle); + *handle = NULL; + } + __wakeup_unload_app_kthread(); return ret; } EXPORT_SYMBOL(qseecom_start_app); @@ -4533,6 +4941,9 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) unsigned long flags = 0; bool found_handle = false; + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); + if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", atomic_read(&qseecom.qseecom_state)); @@ -4568,7 +4979,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) kzfree(kclient); *handle = NULL; } - + __wakeup_unload_app_kthread(); return ret; } EXPORT_SYMBOL(qseecom_shutdown_app); @@ -4581,6 +4992,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, struct qseecom_dev_handle *data; bool perf_enabled = false; + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); + if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", atomic_read(&qseecom.qseecom_state)); @@ -4611,11 +5025,11 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, } } /* - * On targets where crypto clock is handled by HLOS, - * if clk_access_cnt is zero and perf_enabled is false, - * then the crypto clock was not enabled before sending cmd - * to tz, qseecom will enable the clock to avoid service failure. - */ + * On targets where crypto clock is handled by HLOS, + * if clk_access_cnt is zero and perf_enabled is false, + * then the crypto clock was not enabled before sending cmd + * to tz, qseecom will enable the clock to avoid service failure. + */ if (!qseecom.no_clock_support && !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { pr_debug("ce clock is not enabled!\n"); @@ -4656,6 +5070,7 @@ EXPORT_SYMBOL(qseecom_send_command); int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high) { int ret = 0; + if ((handle == NULL) || (handle->dev == NULL)) { pr_err("No valid kernel client\n"); return -EINVAL; @@ -4686,6 +5101,45 @@ int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high) } EXPORT_SYMBOL(qseecom_set_bandwidth); +int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc) +{ + struct qseecom_registered_app_list dummy_app_entry = { {0} }; + struct qseecom_dev_handle dummy_private_data = {0}; + struct qseecom_command_scm_resp resp; + int ret = 0; + + if (!desc) { + pr_err("desc is NULL\n"); + return -EINVAL; + } + + resp.result = desc->ret[0]; /*req_cmd*/ + resp.resp_type = desc->ret[1]; /*incomplete:unused;blocked:session_id*/ + resp.data = desc->ret[2]; /*listener_id*/ + + dummy_private_data.client.app_id = desc->ret[1]; + dummy_private_data.client.from_smcinvoke = true; + dummy_app_entry.app_id = desc->ret[1]; + + mutex_lock(&app_access_lock); + if (qseecom.qsee_reentrancy_support) + ret = __qseecom_process_reentrancy(&resp, &dummy_app_entry, + &dummy_private_data); + else + ret = __qseecom_process_incomplete_cmd(&dummy_private_data, + &resp); + mutex_unlock(&app_access_lock); + if (ret) + pr_err("Failed on cmd %d for lsnr %d session %d, ret = %d\n", + (int)desc->ret[0], (int)desc->ret[2], + (int)desc->ret[1], ret); + desc->ret[0] = resp.result; + desc->ret[1] = resp.resp_type; + desc->ret[2] = resp.data; + return ret; +} +EXPORT_SYMBOL(qseecom_process_listener_from_smcinvoke); + static int qseecom_send_resp(void) { qseecom.send_resp_flag = 1; @@ -5334,6 +5788,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, @@ -5615,9 +6070,9 @@ static int __qseecom_update_current_key_user_info( int ret; if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || - usage >= QSEOS_KM_USAGE_MAX) { - pr_err("Error:: unsupported usage %d\n", usage); - return -EFAULT; + usage >= QSEOS_KM_USAGE_MAX) { + pr_err("Error:: unsupported usage %d\n", usage); + return -EFAULT; } ret = __qseecom_enable_clk(CLK_QSEE); if (ret) @@ -5834,18 +6289,22 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32, QSEECOM_HASH_SIZE); - - /* It will return false if it is GPCE based crypto instance or - ICE is setup properly */ - if (qseecom_enable_ice_setup(create_key_req.usage)) + /* + * It will return false if it is GPCE based crypto instance or + * ICE is setup properly + */ + ret = qseecom_enable_ice_setup(create_key_req.usage); + if (ret) goto free_buf; do { ret = __qseecom_set_clear_ce_key(data, create_key_req.usage, &set_key_ireq); - /* wait a little before calling scm again to let other - processes run */ + /* + * wait a little before calling scm again to let other + * processes run + */ if (ret == QSEOS_RESULT_FAIL_PENDING_OPERATION) msleep(50); @@ -5960,9 +6419,12 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID; memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); - /* It will return false if it is GPCE based crypto instance or - ICE is setup properly */ - if (qseecom_enable_ice_setup(wipe_key_req.usage)) + /* + * It will return false if it is GPCE based crypto instance or + * ICE is setup properly + */ + ret = qseecom_enable_ice_setup(wipe_key_req.usage); + if (ret) goto free_buf; ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage, @@ -6026,8 +6488,10 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, ret = __qseecom_update_current_key_user_info(data, update_key_req.usage, &ireq); - /* wait a little before calling scm again to let other - processes run */ + /* + * wait a little before calling scm again to let other + * processes run + */ if (ret == QSEOS_RESULT_FAIL_PENDING_OPERATION) msleep(50); @@ -6041,7 +6505,7 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, } static int qseecom_is_es_activated(void __user *argp) { - struct qseecom_is_es_activated_req req; + struct qseecom_is_es_activated_req req = {0}; struct qseecom_command_scm_resp resp; int ret; @@ -6132,9 +6596,9 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) req.in_buf_size == 0 || req.in_buf_size > MAX_DIP || req.out_buf_size == 0 || req.out_buf_size > MAX_DIP || req.direction > 1) { - pr_err("invalid parameters\n"); - ret = -EINVAL; - break; + pr_err("invalid parameters\n"); + ret = -EINVAL; + break; } /* Copy the input buffer from userspace to kernel space */ @@ -6177,7 +6641,7 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) if (ret) break; - ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc); + ret = __qseecom_scm_call2_locked(TZ_MDTP_CIPHER_DIP_ID, &desc); __qseecom_disable_clk(CLK_QSEE); @@ -6292,10 +6756,10 @@ static int __qseecom_qteec_handle_pre_alc_fd(struct qseecom_dev_handle *data, return -ENOMEM; } /* - * Allocate a buffer, populate it with number of entry plus - * each sg entry's phy addr and lenth; then return the - * phy_addr of the buffer. - */ + * Allocate a buffer, populate it with number of entry plus + * each sg entry's phy addr and length; then return the + * phy_addr of the buffer. + */ size = sizeof(uint32_t) + sizeof(struct qseecom_sg_entry) * sg_ptr->nents; size = (size + PAGE_SIZE) & PAGE_MASK; @@ -6343,9 +6807,11 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req, pr_err("Ion client can't retrieve the handle\n"); return -ENOMEM; } - if ((req->req_len < sizeof(uint32_t)) || + if ((req->req_len < + sizeof(struct qseecom_param_memref)) || (req->ifd_data[i].cmd_buf_offset > - req->req_len - sizeof(uint32_t))) { + req->req_len - + sizeof(struct qseecom_param_memref))) { pr_err("Invalid offset/req len 0x%x/0x%x\n", req->req_len, req->ifd_data[i].cmd_buf_offset); @@ -6463,6 +6929,7 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, bool found_app = false; unsigned long flags; int ret = 0; + int ret2 = 0; uint32_t reqd_len_sb_in = 0; void *cmd_buf = NULL; size_t cmd_len; @@ -6493,6 +6960,12 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); return -ENOENT; } + if (__qseecom_find_pending_unload_app(data->client.app_id, + data->client.app_name)) { + pr_err("app %d (%s) unload is pending\n", + data->client.app_id, data->client.app_name); + return -ENOENT; + } req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req->req_ptr); @@ -6572,43 +7045,47 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); - return ret; + goto exit; } if (qseecom.qsee_reentrancy_support) { ret = __qseecom_process_reentrancy(&resp, ptr_app, data); + if (ret) + goto exit; } else { if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { pr_err("process_incomplete_cmd failed err: %d\n", ret); - return ret; + goto exit; } } else { if (resp.result != QSEOS_RESULT_SUCCESS) { pr_err("Response result %d not supported\n", resp.result); ret = -EINVAL; + goto exit; } } } - ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, +exit: + ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, data->client.sb_length, ION_IOC_INV_CACHES); - if (ret) { + if (ret2) { pr_err("cache operation failed %d\n", ret); - return ret; + return ret2; } if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { - ret = __qseecom_update_qteec_req_buf( + ret2 = __qseecom_update_qteec_req_buf( (struct qseecom_qteec_modfd_req *)req, data, true); - if (ret) - return ret; + if (ret2) + return ret2; } - return 0; + return ret; } static int qseecom_qteec_open_session(struct qseecom_dev_handle *data, @@ -6692,6 +7169,12 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); return -ENOENT; } + if (__qseecom_find_pending_unload_app(data->client.app_id, + data->client.app_name)) { + pr_err("app %d (%s) unload is pending\n", + data->client.app_id, data->client.app_name); + return -ENOENT; + } /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { @@ -6822,61 +7305,8 @@ static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data) } } - -static int __qseecom_bus_scaling_enable(struct qseecom_dev_handle *data, - bool *perf_enabled) -{ - int ret = 0; - - if (qseecom.support_bus_scaling) { - if (!data->mode) { - mutex_lock(&qsee_bw_mutex); - __qseecom_register_bus_bandwidth_needs( - data, HIGH); - mutex_unlock(&qsee_bw_mutex); - } - ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); - if (ret) { - pr_err("Failed to set bw\n"); - ret = -EINVAL; - goto exit; - } - } - /* - * On targets where crypto clock is handled by HLOS, - * if clk_access_cnt is zero and perf_enabled is false, - * then the crypto clock was not enabled before sending cmd - * to tz, qseecom will enable the clock to avoid service failure. - */ - if (!qseecom.no_clock_support && - !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { - pr_debug("ce clock is not enabled\n"); - ret = qseecom_perf_enable(data); - if (ret) { - pr_err("Failed to vote for clock with err %d\n", - ret); - ret = -EINVAL; - goto exit; - } - *perf_enabled = true; - } -exit: - return ret; -} - -static void __qseecom_bus_scaling_disable(struct qseecom_dev_handle *data, - bool perf_enabled) -{ - if (qseecom.support_bus_scaling) - __qseecom_add_bw_scale_down_timer( - QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); - if (perf_enabled) { - qsee_disable_clock_vote(data, CLK_DFAB); - qsee_disable_clock_vote(data, CLK_SFPB); - } -} - -long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) +long qseecom_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { int ret = 0; struct qseecom_dev_handle *data = file->private_data; @@ -6892,6 +7322,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_err("Aborting qseecom driver\n"); return -ENODEV; } + if (cmd != QSEECOM_IOCTL_RECEIVE_REQ && + cmd != QSEECOM_IOCTL_SEND_RESP_REQ && + cmd != QSEECOM_IOCTL_SEND_MODFD_RESP && + cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64) + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); switch (cmd) { case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: { @@ -6902,17 +7338,18 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) break; } pr_debug("ioctl register_listener_req()\n"); - mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); data->type = QSEECOM_LISTENER_SERVICE; ret = qseecom_register_listener(data, argp); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); - mutex_unlock(&app_access_lock); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_register_listener: %d\n", ret); break; } + case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: { if ((data->listener.id == 0) || (data->type != QSEECOM_LISTENER_SERVICE)) { @@ -6922,12 +7359,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) break; } pr_debug("ioctl unregister_listener_req()\n"); - mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_unregister_listener(data); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); - mutex_unlock(&app_access_lock); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_unregister_listener: %d\n", ret); break; @@ -6942,14 +7379,50 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; + if (qseecom.support_bus_scaling) { + /* register bus bw in case the client doesn't do it */ + if (!data->mode) { + mutex_lock(&qsee_bw_mutex); + __qseecom_register_bus_bandwidth_needs( + data, HIGH); + mutex_unlock(&qsee_bw_mutex); + } + ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); + if (ret) { + pr_err("Failed to set bw.\n"); + ret = -EINVAL; + mutex_unlock(&app_access_lock); + break; + } + } + /* + * On targets where crypto clock is handled by HLOS, + * if clk_access_cnt is zero and perf_enabled is false, + * then the crypto clock was not enabled before sending cmd to + * tz, qseecom will enable the clock to avoid service failure. + */ + if (!qseecom.no_clock_support && + !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { + pr_debug("ce clock is not enabled!\n"); + ret = qseecom_perf_enable(data); + if (ret) { + pr_err("Failed to vote for clock with err %d\n", + ret); + mutex_unlock(&app_access_lock); + ret = -EINVAL; + break; + } + perf_enabled = true; } atomic_inc(&data->ioctl_count); ret = qseecom_send_cmd(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); + if (qseecom.support_bus_scaling) + __qseecom_add_bw_scale_down_timer( + QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); + if (perf_enabled) { + qsee_disable_clock_vote(data, CLK_DFAB); + qsee_disable_clock_vote(data, CLK_SFPB); + } atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -6968,17 +7441,52 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; + if (qseecom.support_bus_scaling) { + if (!data->mode) { + mutex_lock(&qsee_bw_mutex); + __qseecom_register_bus_bandwidth_needs( + data, HIGH); + mutex_unlock(&qsee_bw_mutex); + } + ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); + if (ret) { + pr_err("Failed to set bw.\n"); + mutex_unlock(&app_access_lock); + ret = -EINVAL; + break; + } + } + /* + * On targets where crypto clock is handled by HLOS, + * if clk_access_cnt is zero and perf_enabled is false, + * then the crypto clock was not enabled before sending cmd to + * tz, qseecom will enable the clock to avoid service failure. + */ + if (!qseecom.no_clock_support && + !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { + pr_debug("ce clock is not enabled!\n"); + ret = qseecom_perf_enable(data); + if (ret) { + pr_err("Failed to vote for clock with err %d\n", + ret); + mutex_unlock(&app_access_lock); + ret = -EINVAL; + break; + } + perf_enabled = true; } atomic_inc(&data->ioctl_count); if (cmd == QSEECOM_IOCTL_SEND_MODFD_CMD_REQ) ret = qseecom_send_modfd_cmd(data, argp); else ret = qseecom_send_modfd_cmd_64(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); + if (qseecom.support_bus_scaling) + __qseecom_add_bw_scale_down_timer( + QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); + if (perf_enabled) { + qsee_disable_clock_vote(data, CLK_DFAB); + qsee_disable_clock_vote(data, CLK_SFPB); + } atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7011,6 +7519,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = -EINVAL; break; } + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); if (!qseecom.qsee_reentrancy_support) ret = qseecom_send_resp(); @@ -7018,6 +7527,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = qseecom_reentrancy_send_resp(data); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_send_resp: %d\n", ret); break; @@ -7059,6 +7569,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed load_app request: %d\n", ret); + __wakeup_unload_app_kthread(); break; } case QSEECOM_IOCTL_UNLOAD_APP_REQ: { @@ -7077,6 +7588,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed unload_app request: %d\n", ret); + __wakeup_unload_app_kthread(); break; } case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: { @@ -7197,6 +7709,13 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) break; } case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: { + if ((data->type != QSEECOM_GENERIC) && + (data->type != QSEECOM_CLIENT_APP)) { + pr_err("app loaded query req: invalid handle (%d)\n", + data->type); + ret = -EINVAL; + break; + } data->type = QSEECOM_CLIENT_APP; mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); @@ -7353,6 +7872,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = -EINVAL; break; } + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP) ret = qseecom_send_modfd_resp(data, argp); @@ -7360,6 +7880,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = qseecom_send_modfd_resp_64(data, argp); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_send_mod_resp: %d\n", ret); __qseecom_clean_data_sglistinfo(data); @@ -7380,14 +7901,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; - } atomic_inc(&data->ioctl_count); ret = qseecom_qteec_open_session(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7435,14 +7950,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; - } atomic_inc(&data->ioctl_count); ret = qseecom_qteec_invoke_modfd_cmd(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7512,10 +8021,8 @@ static int qseecom_open(struct inode *inode, struct file *file) struct qseecom_dev_handle *data; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - pr_err("kmalloc failed\n"); + if (!data) return -ENOMEM; - } file->private_data = data; data->abort = 0; data->type = QSEECOM_GENERIC; @@ -7527,24 +8034,57 @@ static int qseecom_open(struct inode *inode, struct file *file) return ret; } +static void __qseecom_release_disable_clk(struct qseecom_dev_handle *data) +{ + if (qseecom.no_clock_support) + return; + if (qseecom.support_bus_scaling) { + mutex_lock(&qsee_bw_mutex); + if (data->mode != INACTIVE) { + qseecom_unregister_bus_bandwidth_needs(data); + if (qseecom.cumulative_mode == INACTIVE) + __qseecom_set_msm_bus_request(INACTIVE); + } + mutex_unlock(&qsee_bw_mutex); + } else { + if (data->fast_load_enabled) + qsee_disable_clock_vote(data, CLK_SFPB); + if (data->perf_enabled) + qsee_disable_clock_vote(data, CLK_DFAB); + } +} + static int qseecom_release(struct inode *inode, struct file *file) { struct qseecom_dev_handle *data = file->private_data; int ret = 0; + bool free_private_data = true; - if (data->released == false) { + __qseecom_release_disable_clk(data); + if (!data->released) { pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n", data->type, data->mode, data); switch (data->type) { case QSEECOM_LISTENER_SERVICE: - mutex_lock(&app_access_lock); + pr_debug("release lsnr svc %d\n", data->listener.id); + mutex_lock(&listener_access_lock); ret = qseecom_unregister_listener(data); - mutex_unlock(&app_access_lock); + if (!ret) + free_private_data = false; + data->listener.release_called = true; + mutex_unlock(&listener_access_lock); + __wakeup_unregister_listener_kthread(); break; case QSEECOM_CLIENT_APP: - mutex_lock(&app_access_lock); - ret = qseecom_unload_app(data, true); - mutex_unlock(&app_access_lock); + pr_debug("release app %d (%s)\n", + data->client.app_id, data->client.app_name); + if (data->client.app_id) { + free_private_data = false; + mutex_lock(&unload_app_pending_list_lock); + ret = qseecom_prepare_unload_app(data); + mutex_unlock(&unload_app_pending_list_lock); + __wakeup_unload_app_kthread(); + } break; case QSEECOM_SECURE_SERVICE: case QSEECOM_GENERIC: @@ -7561,34 +8101,19 @@ static int qseecom_release(struct inode *inode, struct file *file) } } - if (qseecom.support_bus_scaling) { - mutex_lock(&qsee_bw_mutex); - if (data->mode != INACTIVE) { - qseecom_unregister_bus_bandwidth_needs(data); - if (qseecom.cumulative_mode == INACTIVE) { - ret = __qseecom_set_msm_bus_request(INACTIVE); - if (ret) - pr_err("Fail to scale down bus\n"); - } - } - mutex_unlock(&qsee_bw_mutex); - } else { - if (data->fast_load_enabled == true) - qsee_disable_clock_vote(data, CLK_SFPB); - if (data->perf_enabled == true) - qsee_disable_clock_vote(data, CLK_DFAB); - } - kfree(data); - + if (free_private_data) + kfree(data); return ret; } +#ifndef CONFIG_COMPAT +#define compat_qseecom_ioctl NULL +#endif + static const struct file_operations qseecom_fops = { .owner = THIS_MODULE, .unlocked_ioctl = qseecom_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = compat_qseecom_ioctl, -#endif .open = qseecom_open, .release = qseecom_release }; @@ -7640,14 +8165,14 @@ static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce) /* Get CE3 src core clk. */ qclk->ce_core_src_clk = clk_get(pdev, core_clk_src); if (!IS_ERR(qclk->ce_core_src_clk)) { - rc = clk_set_rate(qclk->ce_core_src_clk, - qseecom.ce_opp_freq_hz); - if (rc) { - clk_put(qclk->ce_core_src_clk); - qclk->ce_core_src_clk = NULL; - pr_err("Unable to set the core src clk @%uMhz.\n", - qseecom.ce_opp_freq_hz/CE_CLK_DIV); - return -EIO; + rc = clk_set_rate(qclk->ce_core_src_clk, + qseecom.ce_opp_freq_hz); + if (rc) { + clk_put(qclk->ce_core_src_clk); + qclk->ce_core_src_clk = NULL; + pr_err("Unable to set the core src clk @%uMhz.\n", + qseecom.ce_opp_freq_hz/CE_CLK_DIV); + return -EIO; } } else { pr_warn("Unable to get CE core src clk, set to NULL\n"); @@ -8402,17 +8927,23 @@ static int qseecom_probe(struct platform_device *pdev) } INIT_LIST_HEAD(&qseecom.registered_listener_list_head); - spin_lock_init(&qseecom.registered_listener_list_lock); INIT_LIST_HEAD(&qseecom.registered_app_list_head); spin_lock_init(&qseecom.registered_app_list_lock); + INIT_LIST_HEAD(&qseecom.unregister_lsnr_pending_list_head); INIT_LIST_HEAD(&qseecom.registered_kclient_list_head); spin_lock_init(&qseecom.registered_kclient_list_lock); init_waitqueue_head(&qseecom.send_resp_wq); + init_waitqueue_head(&qseecom.register_lsnr_pending_wq); + init_waitqueue_head(&qseecom.unregister_lsnr_kthread_wq); + INIT_LIST_HEAD(&qseecom.unload_app_pending_list_head); + init_waitqueue_head(&qseecom.unload_app_kthread_wq); qseecom.send_resp_flag = 0; qseecom.qsee_version = QSEEE_VERSION_00; + mutex_lock(&app_access_lock); rc = qseecom_scm_call(6, 3, &feature, sizeof(feature), &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); pr_info("qseecom.qsee_version = 0x%x\n", resp.result); if (rc) { pr_err("Failed to get QSEE version info %d\n", rc); @@ -8451,9 +8982,9 @@ static int qseecom_probe(struct platform_device *pdev) "qcom,commonlib64-loaded-by-uefi"); pr_debug("qseecom.commonlib64-loaded-by-uefi = 0x%x", qseecom.commonlib64_loaded); - qseecom.fde_key_size = of_property_read_bool( - (&pdev->dev)->of_node, - "qcom,fde-key-size"); + qseecom.fde_key_size = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,fde-key-size"); qseecom.no_clock_support = of_property_read_bool((&pdev->dev)->of_node, "qcom,no-clock-support"); @@ -8567,9 +9098,11 @@ static int qseecom_probe(struct platform_device *pdev) rc = -EIO; goto exit_deinit_clock; } + mutex_lock(&app_access_lock); rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); __qseecom_disable_clk(CLK_QSEE); if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) { pr_err("send secapp reg fail %d resp.res %d\n", @@ -8608,9 +9141,36 @@ static int qseecom_probe(struct platform_device *pdev) if (!qseecom.qsee_perf_client) pr_err("Unable to register bus client\n"); + /*create a kthread to process pending listener unregister task */ + qseecom.unregister_lsnr_kthread_task = kthread_run( + __qseecom_unregister_listener_kthread_func, + NULL, "qseecom-unreg-lsnr"); + if (IS_ERR(qseecom.unregister_lsnr_kthread_task)) { + pr_err("failed to create kthread to unregister listener\n"); + rc = -EINVAL; + goto exit_deinit_clock; + } + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_SLEEP); + + /*create a kthread to process pending ta unloading task */ + qseecom.unload_app_kthread_task = kthread_run( + __qseecom_unload_app_kthread_func, + NULL, "qseecom-unload-ta"); + if (IS_ERR(qseecom.unload_app_kthread_task)) { + pr_err("failed to create kthread to unload ta\n"); + rc = -EINVAL; + goto exit_kill_unreg_lsnr_kthread; + } + atomic_set(&qseecom.unload_app_kthread_state, + UNLOAD_APP_KT_SLEEP); + atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; +exit_kill_unreg_lsnr_kthread: + kthread_stop(qseecom.unregister_lsnr_kthread_task); + exit_deinit_clock: __qseecom_deinit_clk(CLK_QSEE); if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && @@ -8648,6 +9208,7 @@ exit_unreg_chrdev_region: static int qseecom_remove(struct platform_device *pdev) { struct qseecom_registered_kclient_list *kclient = NULL; + struct qseecom_registered_kclient_list *kclient_tmp = NULL; unsigned long flags = 0; int ret = 0; int i; @@ -8657,17 +9218,15 @@ static int qseecom_remove(struct platform_device *pdev) atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_NOT_READY); spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags); - list_for_each_entry(kclient, &qseecom.registered_kclient_list_head, - list) { - if (!kclient) - goto exit_irqrestore; + list_for_each_entry_safe(kclient, kclient_tmp, + &qseecom.registered_kclient_list_head, list) { /* Break the loop if client handle is NULL */ - if (!kclient->handle) - goto exit_free_kclient; - - if (list_empty(&kclient->list)) - goto exit_free_kc_handle; + if (!kclient->handle) { + list_del(&kclient->list); + kzfree(kclient); + break; + } list_del(&kclient->list); mutex_lock(&app_access_lock); @@ -8680,11 +9239,6 @@ static int qseecom_remove(struct platform_device *pdev) } } -exit_free_kc_handle: - kzfree(kclient->handle); -exit_free_kclient: - kzfree(kclient); -exit_irqrestore: spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); if (qseecom.qseos_version > QSEEE_VERSION_00) @@ -8730,6 +9284,10 @@ exit_irqrestore: ion_client_destroy(qseecom.ion_clnt); + kthread_stop(qseecom.unload_app_kthread_task); + + kthread_stop(qseecom.unregister_lsnr_kthread_task); + cdev_del(&qseecom.cdev); device_destroy(driver_class, qseecom_device_no); @@ -8745,8 +9303,8 @@ static int qseecom_suspend(struct platform_device *pdev, pm_message_t state) { int ret = 0; struct qseecom_clk *qclk; - qclk = &qseecom.qsee; + qclk = &qseecom.qsee; atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_SUSPEND); if (qseecom.no_clock_support) return 0; @@ -8787,8 +9345,8 @@ static int qseecom_resume(struct platform_device *pdev) int mode = 0; int ret = 0; struct qseecom_clk *qclk; - qclk = &qseecom.qsee; + qclk = &qseecom.qsee; if (qseecom.no_clock_support) goto exit; @@ -8861,7 +9419,8 @@ exit: atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return ret; } -static struct of_device_id qseecom_match[] = { + +static const struct of_device_id qseecom_match[] = { { .compatible = "qcom,qseecom", }, @@ -8891,7 +9450,7 @@ static void qseecom_exit(void) } MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator"); +MODULE_DESCRIPTION("QTI Secure Execution Environment Communicator"); module_init(qseecom_init); module_exit(qseecom_exit); diff --git a/drivers/misc/qseecom_kernel.h b/drivers/misc/qseecom_kernel.h index 894e124e9998178fbace8614d15a8fa483682323..82dbe27a83c47e5773e81830ae90cd5d2e4486e2 100644 --- a/drivers/misc/qseecom_kernel.h +++ b/drivers/misc/qseecom_kernel.h @@ -14,6 +14,7 @@ #define __QSEECOM_KERNEL_H_ #include +#include #define QSEECOM_ALIGN_SIZE 0x40 #define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1) @@ -38,5 +39,6 @@ int qseecom_shutdown_app(struct qseecom_handle **handle); int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len); int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high); +int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc); #endif /* __QSEECOM_KERNEL_H_ */ diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index b00335652e52ac45087a65510f0c82a799920879..59b9e46c0a7b236e3e83006d05265c4d27dee0a8 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -177,7 +177,7 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1) } else lux = 0; else - return -EAGAIN; + return 0; /* LUX range check */ return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 080c937cef0bafd50ecdcb2154f1c5ea0bad25fd..551dab358d0efcaaecce5d19306a3d0998445179 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -766,7 +766,7 @@ cmd_rel_host: mmc_hostname(card->host), __func__); } cmd_rel_host_halt: - mmc_release_host(card->host); + mmc_put_card(card); cmd_done: mmc_blk_put(md); @@ -3722,6 +3722,7 @@ cmdq_switch: pr_err("%s: %s: mmc_blk_cmdq_switch failed: %d\n", mmc_hostname(host), __func__, err); ret = err; + goto out; } cmdq_unhalt: err = mmc_cmdq_halt(host, false); @@ -3772,7 +3773,7 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) } else { pr_err("%s: %s: partition switch failed err = %d\n", md->disk->disk_name, __func__, err); - ret = 0; + ret = err; goto out; } } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bac22ef4e0835d457eeb61750d42f3c8e18efae6..7cceec44d2d8a19722d1e1728374edf734929b1c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -4170,6 +4170,14 @@ int mmc_pm_notify(struct notifier_block *notify_block, if (!err) break; + if (!mmc_card_is_removable(host)) { + dev_warn(mmc_dev(host), + "pre_suspend failed for non-removable host: " + "%d\n", err); + /* Avoid removing non-removable hosts */ + break; + } + /* Calling bus_ops->remove() with a claimed host can deadlock */ host->bus_ops->remove(host); mmc_claim_host(host); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 251a9d90cdbdf8af60cd2a02857808513fac85ad..2b8dc80edc0ae9b50beb8fbc40bb9d6ce52d5238 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -694,9 +694,6 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host), card->ext_csd.barrier_support, card->ext_csd.cache_flush_policy); - card->ext_csd.enhanced_rpmb_supported = - (card->ext_csd.rel_param & - EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR); } else { card->ext_csd.cmdq_support = 0; card->ext_csd.cmdq_depth = 0; @@ -712,6 +709,13 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.device_life_time_est_typ_b = ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; } + + /* eMMC v5.1 or later */ + if (card->ext_csd.rev >= 8) + card->ext_csd.enhanced_rpmb_supported = + (card->ext_csd.rel_param & + EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR); + out: return err; } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index fa995b94b86a0a90448ad5a93923115746caf34d..bb6f370ea5f9dccd895a42ced0ae28140261172d 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1167,6 +1167,11 @@ static void mmc_sd_detect(struct mmc_host *host) pm_runtime_put_autosuspend(&host->card->dev); return; } +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + if (mmc_bus_needs_resume(host)) + mmc_resume_bus(host); +#endif + mmc_power_up(host, host->ocr_avail); #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME if (mmc_bus_needs_resume(host)) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index b4803b819748be7e2bc353e599f30e5f1157686c..e3916ac6a9f97a81917c2b6b7722b07dc485a5a5 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -278,7 +278,7 @@ static void sdio_release_func(struct device *dev) sdio_free_func_cis(func); kfree(func->info); - + kfree(func->tmpbuf); kfree(func); } @@ -293,6 +293,16 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) if (!func) return ERR_PTR(-ENOMEM); + /* + * allocate buffer separately to make sure it's properly aligned for + * DMA usage (incl. 64 bit DMA) + */ + func->tmpbuf = kmalloc(4, GFP_KERNEL); + if (!func->tmpbuf) { + kfree(func); + return ERR_PTR(-ENOMEM); + } + func->card = card; device_initialize(&func->dev); diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 9772c7d032cc8068287345fbd6c5d7a87e362ede..8987fb4e57ea7d143cb8ddebee7af4f19d4d5c92 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -795,7 +795,7 @@ static int cmdq_get_first_valid_tag(struct cmdq_host *cq_host) } tag = ffs(dbr_set) - 1; - pr_info("%s: error tag selected: tag = %d\n", + pr_err("%s: error tag selected: tag = %d\n", mmc_hostname(cq_host->mmc), tag); return tag; } @@ -804,8 +804,8 @@ static bool cmdq_is_valid_tag(struct mmc_host *mmc, unsigned int tag) { struct mmc_cmdq_context_info *ctx_info = &mmc->cmdq_ctx; - return ((tag == DCMD_SLOT) || - !!(ctx_info->data_active_reqs & (1 << tag))); + return + (!!(ctx_info->data_active_reqs & (1 << tag)) || tag == DCMD_SLOT); } static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 76e8bce6f46e7015bb6ae9e3dfe082d2cf58db35..ad572a0f212464b5346205c5441279e77db51ee7 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -368,9 +368,9 @@ static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, host->irq_mask &= ~irq; else host->irq_mask |= irq; - spin_unlock_irqrestore(&host->lock, flags); writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); + spin_unlock_irqrestore(&host->lock, flags); } static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9c2b9cbcbce0100e0b821f32a42f5c78af7ee598..e4a159aa0e1ac6509313c8a51f2d816e944e7ab4 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1757,8 +1757,8 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host) */ if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) { struct pinctrl *p = devm_pinctrl_get(host->dev); - if (!p) { - ret = -ENODEV; + if (IS_ERR(p)) { + ret = PTR_ERR(p); goto err_free_irq; } if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) { diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 94cddf381ba3d72d1e9359afffb694f06dce6118..5186ac611564732ea768d1848b69384ec8a61be8 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index b83f03343f20071eb7114032a9617154e3492d86..c9d7283dee6c19c2b456792097f040cbd885e673 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -4607,6 +4607,7 @@ static int sdhci_msm_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct mmc_host *mmc = host->mmc; int ret = 0; int sdio_cfg = 0; ktime_t start = ktime_get(); @@ -4622,6 +4623,8 @@ static int sdhci_msm_suspend(struct device *dev) } ret = sdhci_msm_runtime_suspend(dev); out: + /* cancel any clock gating work scheduled by mmc_host_clk_release() */ + cancel_delayed_work_sync(&mmc->clk_gate_work); sdhci_msm_disable_controller_clock(host); if (host->mmc->card && mmc_card_sdio(host->mmc->card)) { sdio_cfg = sdhci_msm_cfg_sdio_wakeup(host, true); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 438f7613b2259ee704de0a3045c9691fc188fae5..03a1ad8e93395bcbd65c02c2a9305b0549a622ae 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3228,7 +3228,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) return IRQ_NONE; } - if (!host->clock && host->mmc->card && + if (!(!host->mmc->clk_gated && host->clock) && host->mmc->card && mmc_card_sdio(host->mmc->card)) { if (!mmc_card_and_host_support_async_int(host->mmc)) { spin_unlock(&host->lock); diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 3096f3ded3adf051454d5a99176267b070ceae2d..8e2a7d077b16478bc047f88e920253d08640c4ec 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -45,6 +45,7 @@ #define I82802AB 0x00ad #define I82802AC 0x00ac #define PF38F4476 0x881c +#define M28F00AP30 0x8963 /* STMicroelectronics chips */ #define M50LPW080 0x002F #define M50FLW080A 0x0080 @@ -375,6 +376,17 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, extp->MinorVersion = '1'; } +static int cfi_is_micron_28F00AP30(struct cfi_private *cfi, struct flchip *chip) +{ + /* + * Micron(was Numonyx) 1Gbit bottom boot are buggy w.r.t + * Erase Supend for their small Erase Blocks(0x8000) + */ + if (cfi->mfr == CFI_MFR_INTEL && cfi->id == M28F00AP30) + return 1; + return 0; +} + static inline struct cfi_pri_intelext * read_pri_intelext(struct map_info *map, __u16 adr) { @@ -825,21 +837,30 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) goto sleep; + /* Do not allow suspend iff read/write to EB address */ + if ((adr & chip->in_progress_block_mask) == + chip->in_progress_block_addr) + goto sleep; + + /* do not suspend small EBs, buggy Micron Chips */ + if (cfi_is_micron_28F00AP30(cfi, chip) && + (chip->in_progress_block_mask == ~(0x8000-1))) + goto sleep; /* Erase suspend */ - map_write(map, CMD(0xB0), adr); + map_write(map, CMD(0xB0), chip->in_progress_block_addr); /* If the flash has finished erasing, then 'erase suspend' * appears to make some (28F320) flash devices switch to * 'read' mode. Make sure that we switch to 'read status' * mode so we get the right data. --rmk */ - map_write(map, CMD(0x70), adr); + map_write(map, CMD(0x70), chip->in_progress_block_addr); chip->oldstate = FL_ERASING; chip->state = FL_ERASE_SUSPENDING; chip->erase_suspended = 1; for (;;) { - status = map_read(map, adr); + status = map_read(map, chip->in_progress_block_addr); if (map_word_andequal(map, status, status_OK, status_OK)) break; @@ -1035,8 +1056,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad sending the 0x70 (Read Status) command to an erasing chip and expecting it to be ignored, that's what we do. */ - map_write(map, CMD(0xd0), adr); - map_write(map, CMD(0x70), adr); + map_write(map, CMD(0xd0), chip->in_progress_block_addr); + map_write(map, CMD(0x70), chip->in_progress_block_addr); chip->oldstate = FL_READY; chip->state = FL_ERASING; break; @@ -1927,6 +1948,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; chip->erase_suspended = 0; + chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(len - 1); ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, len, diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index c50d8cf0f60dd01b0b6c25822788b53dd2884bfd..529115b219b6cc1df85caab479b1c146ebcdd29d 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -42,7 +42,7 @@ #define AMD_BOOTLOC_BUG #define FORCE_WORD_WRITE 0 -#define MAX_WORD_RETRIES 3 +#define MAX_RETRIES 3 #define SST49LF004B 0x0060 #define SST49LF040B 0x0050 @@ -814,9 +814,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) goto sleep; - /* We could check to see if we're trying to access the sector - * that is currently being erased. However, no user will try - * anything like that so we just wait for the timeout. */ + /* Do not allow suspend iff read/write to EB address */ + if ((adr & chip->in_progress_block_mask) == + chip->in_progress_block_addr) + goto sleep; /* Erase suspend */ /* It's harmless to issue the Erase-Suspend and Erase-Resume @@ -1644,7 +1645,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; @@ -1877,7 +1878,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, if (time_after(jiffies, timeo) && !chip_ready(map, adr)) break; - if (chip_ready(map, adr)) { + if (chip_good(map, adr, datum)) { xip_enable(map, chip, adr); goto op_done; } @@ -2103,7 +2104,7 @@ retry: map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; @@ -2238,6 +2239,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) unsigned long int adr; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr = cfi->addr_unlock1; @@ -2255,6 +2257,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2265,6 +2268,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(map->size - 1); INVALIDATE_CACHE_UDELAY(map, chip, adr, map->size, @@ -2290,12 +2294,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->erase_suspended = 0; } - if (chip_ready(map, adr)) + if (chip_good(map, adr, map_word_ff(map))) break; if (time_after(jiffies, timeo)) { printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); + ret = -EIO; break; } @@ -2303,12 +2308,15 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - ret = -EIO; + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; + goto retry; + } } chip->state = FL_READY; @@ -2327,6 +2335,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr += chip->start; @@ -2344,6 +2353,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2354,6 +2364,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(len - 1); INVALIDATE_CACHE_UDELAY(map, chip, adr, len, @@ -2379,7 +2390,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->erase_suspended = 0; } - if (chip_ready(map, adr)) { + if (chip_good(map, adr, map_word_ff(map))) { xip_enable(map, chip, adr); break; } @@ -2388,6 +2399,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); + ret = -EIO; break; } @@ -2395,12 +2407,15 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - ret = -EIO; + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; + goto retry; + } } chip->state = FL_READY; @@ -2530,7 +2545,7 @@ static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct ppb_lock { struct flchip *chip; - loff_t offset; + unsigned long adr; int locked; }; @@ -2548,8 +2563,9 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, unsigned long timeo; int ret; + adr += chip->start; mutex_lock(&chip->mutex); - ret = get_chip(map, chip, adr + chip->start, FL_LOCKING); + ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { mutex_unlock(&chip->mutex); return ret; @@ -2567,8 +2583,8 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { chip->state = FL_LOCKING; - map_write(map, CMD(0xA0), chip->start + adr); - map_write(map, CMD(0x00), chip->start + adr); + map_write(map, CMD(0xA0), adr); + map_write(map, CMD(0x00), adr); } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { /* * Unlocking of one specific sector is not supported, so we @@ -2606,7 +2622,7 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, map_write(map, CMD(0x00), chip->start); chip->state = FL_READY; - put_chip(map, chip, adr + chip->start); + put_chip(map, chip, adr); mutex_unlock(&chip->mutex); return ret; @@ -2663,9 +2679,9 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, * sectors shall be unlocked, so lets keep their locking * status at "unlocked" (locked=0) for the final re-locking. */ - if ((adr < ofs) || (adr >= (ofs + len))) { + if ((offset < ofs) || (offset >= (ofs + len))) { sect[sectors].chip = &cfi->chips[chipnum]; - sect[sectors].offset = offset; + sect[sectors].adr = adr; sect[sectors].locked = do_ppb_xxlock( map, &cfi->chips[chipnum], adr, 0, DO_XXLOCK_ONEBLOCK_GETLOCK); @@ -2679,6 +2695,8 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, i++; if (adr >> cfi->chipshift) { + if (offset >= (ofs + len)) + break; adr = 0; chipnum++; @@ -2709,7 +2727,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, */ for (i = 0; i < sectors; i++) { if (sect[i].locked) - do_ppb_xxlock(map, sect[i].chip, sect[i].offset, 0, + do_ppb_xxlock(map, sect[i].chip, sect[i].adr, 0, DO_XXLOCK_ONEBLOCK_LOCK); } diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 7c0b27d132b1bca8aa546cedac726cf5e92c6613..b479bd81120b3432e015b76496c3f3ea1d32580c 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1889,6 +1889,8 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base, do { uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi); mask = (1 << (cfi->device_type * 8)) - 1; + if (ofs >= map->size) + return 0; result = map_read(map, base + ofs); bank++; } while ((result.x[0] & mask) == CFI_MFR_CONTINUATION); diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index b087c5e17c573986b83dbe4605ac40ec0b3a3be9..e6877d878bbcb0b9539ac3df0d2483546f09ed88 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -14,10 +14,208 @@ */ #include "msm_qpic_nand.h" +#include #define QPIC_BAM_DEFAULT_IPC_LOGLVL 2 +#define SW_REQ_TIMEOUT_SEC 10 static bool enable_euclean; +static bool enable_perfstats; + +static ssize_t msm_nand_attr_perf_stats_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t msm_nand_attr_perf_stats_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static struct device_attribute dev_msm_nand_perf_stats = + __ATTR(perf_stats, S_IRUGO | S_IWUSR, + msm_nand_attr_perf_stats_show, msm_nand_attr_perf_stats_store); + +#define print_sysfs(fmt, ...) \ +{ \ + count += scnprintf(buf + count, PAGE_SIZE - count, \ + fmt, ##__VA_ARGS__); \ +} + +static ssize_t msm_nand_attr_perf_stats_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t count = 0; + struct msm_nand_info *info = dev_get_drvdata(dev); + + if (!enable_perfstats) { + print_sysfs("Performance stats is disabled\n"); + return count; + } + + spin_lock(&info->perf.lock); + print_sysfs("total_read_size = %llu\n", info->perf.total_read_size); + print_sysfs("total_write_size = %llu\n", info->perf.total_write_size); + print_sysfs("total_erase_blks = %llu\n\n", info->perf.total_erase_blks); + + print_sysfs("total_read_time_us = %lld\n", + ktime_to_us(info->perf.total_read_time)); + print_sysfs("total_write_time_us = %lld\n", + ktime_to_us(info->perf.total_write_time)); + print_sysfs("total_erase_time_us = %lld\n\n", + ktime_to_us(info->perf.total_erase_time)); + + print_sysfs("min_read_time_us = %lld\n", + ktime_to_us(info->perf.min_read_time)); + print_sysfs("min_write_time_us = %lld\n", + ktime_to_us(info->perf.min_write_time)); + print_sysfs("min_erase_time_us = %lld\n\n", + ktime_to_us(info->perf.min_erase_time)); + + print_sysfs("max_read_time_us = %lld\n", + ktime_to_us(info->perf.max_read_time)); + print_sysfs("max_write_time_us = %lld\n", + ktime_to_us(info->perf.max_write_time)); + print_sysfs("max_erase_time_us = %lld\n\n", + ktime_to_us(info->perf.max_erase_time)); + + spin_unlock(&info->perf.lock); + return count; +} + +static ssize_t msm_nand_attr_perf_stats_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct msm_nand_info *info = dev_get_drvdata(dev); + + if (!enable_perfstats) { + pr_err("couldn't write as perf stats is disabled\n"); + return -EPERM; + } + + if (count > 1 || (count == 1 && *buf != '\n')) { + pr_err("write not permitted\n"); + return -EPERM; + } + + spin_lock(&info->perf.lock); + info->perf.min_read_time = ktime_set(KTIME_MAX, 0); + info->perf.min_write_time = ktime_set(KTIME_MAX, 0); + info->perf.min_erase_time = ktime_set(KTIME_MAX, 0); + + info->perf.max_read_time = ktime_set(0, 0); + info->perf.max_write_time = ktime_set(0, 0); + info->perf.max_erase_time = ktime_set(0, 0); + + info->perf.total_read_time = ktime_set(0, 0); + info->perf.total_write_time = ktime_set(0, 0); + info->perf.total_erase_time = ktime_set(0, 0); + + info->perf.total_read_size = 0; + info->perf.total_write_size = 0; + info->perf.total_erase_blks = 0; + spin_unlock(&info->perf.lock); + + return count; +} + +static void msm_nand_init_perf_stats(struct msm_nand_info *info) +{ + spin_lock_init(&info->perf.lock); + info->perf.min_read_time = ktime_set(KTIME_MAX, 0); + info->perf.min_write_time = ktime_set(KTIME_MAX, 0); + info->perf.min_erase_time = ktime_set(KTIME_MAX, 0); +} + +static void msm_nand_init_sysfs(struct device *dev) +{ + sysfs_attr_init(&dev_msm_nand_perf_stats); + if (device_create_file(dev, &dev_msm_nand_perf_stats)) + pr_err("Sysfs entry create failed"); +} + +static void msm_nand_cleanup_sysfs(struct device *dev) +{ + device_remove_file(dev, &dev_msm_nand_perf_stats); +} + +static void msm_nand_update_read_perf_stats(struct msm_nand_info *info, + ktime_t start, u32 size) +{ + ktime_t time_delta; + + time_delta = ktime_sub(ktime_get(), start); + + spin_lock(&info->perf.lock); + info->perf.total_read_size += size; + info->perf.total_read_time = ktime_add(info->perf.total_read_time, + time_delta); + if (ktime_after(time_delta, info->perf.max_read_time)) + info->perf.max_read_time = time_delta; + + if (ktime_before(time_delta, info->perf.min_read_time)) + info->perf.min_read_time = time_delta; + + spin_unlock(&info->perf.lock); +} + +static void msm_nand_update_write_perf_stats(struct msm_nand_info *info, + ktime_t start, u32 size) +{ + ktime_t time_delta; + + time_delta = ktime_sub(ktime_get(), start); + + spin_lock(&info->perf.lock); + info->perf.total_write_size += size; + info->perf.total_write_time = ktime_add(info->perf.total_write_time, + time_delta); + if (ktime_after(time_delta, info->perf.max_write_time)) + info->perf.max_write_time = time_delta; + + if (ktime_before(time_delta, info->perf.min_write_time)) + info->perf.min_write_time = time_delta; + + spin_unlock(&info->perf.lock); +} + +static void msm_nand_update_erase_perf_stats(struct msm_nand_info *info, + ktime_t start, u32 count) +{ + ktime_t time_delta; + + time_delta = ktime_sub(ktime_get(), start); + + spin_lock(&info->perf.lock); + info->perf.total_erase_blks += count; + info->perf.total_erase_time = ktime_add(info->perf.total_erase_time, + time_delta); + if (ktime_after(time_delta, info->perf.max_erase_time)) + info->perf.max_erase_time = time_delta; + + if (ktime_before(time_delta, info->perf.min_erase_time)) + info->perf.min_erase_time = time_delta; + + spin_unlock(&info->perf.lock); +} + +static struct timer_list timer; + +static void msm_nand_tout_work_fn(struct work_struct *work) +{ + struct msm_nand_info *info = container_of(work, struct msm_nand_info, + tout_work); + + sps_get_bam_debug_info(info->sps.bam_handle, 93, + (SPS_BAM_PIPE(0) | SPS_BAM_PIPE(1) | SPS_BAM_PIPE(2)), + 0, 2); +} +static void msm_nand_transfer_timeout(unsigned long data) +{ + struct msm_nand_info *info = (struct msm_nand_info *)data; + + pr_err("NAND request timeout\n"); + schedule_work(&info->tout_work); +} /* * Get the DMA memory for requested amount of size. It returns the pointer @@ -1590,7 +1788,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct msm_nand_chip *chip = &info->nand_chip; struct flash_identification *flash_dev = &info->flash_dev; uint32_t cwperpage = (mtd->writesize >> 9); - int err, pageerr = 0, rawerr = 0, submitted_num_desc = 0; + int err, pageerr = 0, rawerr = 0, submitted_num_desc = 0, count = 0; uint32_t n = 0, pages_read = 0; uint32_t ecc_errors = 0, total_ecc_errors = 0, ecc_capability; struct msm_nand_rw_params rw_params; @@ -1599,6 +1797,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct sps_iovec iovec_temp; bool erased_page; uint64_t fix_data_in_pages = 0; + ktime_t start; /* * The following 6 commands will be sent only once for the first @@ -1624,6 +1823,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } *dma_buffer; struct msm_nand_rw_cmd_desc *cmd_list = NULL; + if (unlikely(enable_perfstats)) + start = ktime_get(); + memset(&rw_params, 0, sizeof(struct msm_nand_rw_params)); err = msm_nand_validate_mtd_params(mtd, true, from, ops, &rw_params); if (err) @@ -1707,6 +1909,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, iovec++; } mutex_lock(&info->lock); + mod_timer(&timer, jiffies + SW_REQ_TIMEOUT_SEC * HZ); err = msm_nand_get_device(chip->dev); if (err) goto unlock_mutex; @@ -1758,6 +1961,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } err = msm_nand_put_device(chip->dev); + del_timer_sync(&timer); mutex_unlock(&info->lock); if (err) goto free_dma; @@ -1832,7 +2036,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, * and this will only handle about 64 pages being read * at a time i.e. one erase block worth of pages. */ - fix_data_in_pages |= BIT(rw_params.page_count); + fix_data_in_pages |= BIT_ULL(pages_read); } /* check for correctable errors */ if (!rawerr) { @@ -1884,6 +2088,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, put_dev: msm_nand_put_device(chip->dev); unlock_mutex: + del_timer_sync(&timer); mutex_unlock(&info->lock); free_dma: msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer)); @@ -1900,7 +2105,7 @@ free_dma: */ while (fix_data_in_pages) { int temp_page = 0, oobsize = rw_params.cwperpage << 2; - int count = 0, offset = 0; + int offset = 0; temp_page = fix_data_in_pages & BIT_MASK(0); fix_data_in_pages = fix_data_in_pages >> 1; @@ -1931,6 +2136,8 @@ validate_mtd_params_failed: err, ops->retlen, ops->oobretlen); pr_debug("========================================================\n"); + if (unlikely(enable_perfstats) && likely(!err)) + msm_nand_update_read_perf_stats(info, start, ops->retlen); return err; } @@ -2151,6 +2358,8 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, struct msm_nand_rw_reg_data data; struct sps_iovec *iovec; struct sps_iovec iovec_temp; + ktime_t start; + /* * The following 7 commands will be sent only once : * For first codeword (CW) - addr0, addr1, dev0_cfg0, dev0_cfg1, @@ -2175,6 +2384,9 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, } *dma_buffer; struct msm_nand_rw_cmd_desc *cmd_list = NULL; + if (unlikely(enable_perfstats)) + start = ktime_get(); + memset(&rw_params, 0, sizeof(struct msm_nand_rw_params)); err = msm_nand_validate_mtd_params(mtd, false, to, ops, &rw_params); if (err) @@ -2244,6 +2456,7 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, iovec++; } mutex_lock(&info->lock); + mod_timer(&timer, jiffies + SW_REQ_TIMEOUT_SEC * HZ); err = msm_nand_get_device(chip->dev); if (err) goto unlock_mutex; @@ -2294,6 +2507,7 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, } err = msm_nand_put_device(chip->dev); + del_timer_sync(&timer); mutex_unlock(&info->lock); if (err) goto free_dma; @@ -2327,6 +2541,7 @@ static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to, put_dev: msm_nand_put_device(chip->dev); unlock_mutex: + del_timer_sync(&timer); mutex_unlock(&info->lock); free_dma: msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer)); @@ -2350,6 +2565,8 @@ validate_mtd_params_failed: err, ops->retlen, ops->oobretlen); pr_debug("================================================\n"); + if (unlikely(enable_perfstats) && likely(!err)) + msm_nand_update_write_perf_stats(info, start, ops->retlen); return err; } @@ -2447,6 +2664,8 @@ static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) struct sps_iovec *iovec; struct sps_iovec iovec_temp; uint32_t total_cnt = 9; + ktime_t start; + /* * The following 9 commands are required to erase a page - * flash, addr0, addr1, cfg0, cfg1, exec, flash_status(read), @@ -2459,6 +2678,9 @@ static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) uint32_t flash_status; } *dma_buffer; + if (unlikely(enable_perfstats)) + start = ktime_get(); + if (mtd->writesize == PAGE_SIZE_2K) page = instr->addr >> 11; @@ -2526,6 +2748,7 @@ static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) iovec++; } mutex_lock(&info->lock); + mod_timer(&timer, jiffies + SW_REQ_TIMEOUT_SEC * HZ); err = msm_nand_get_device(chip->dev); if (err) goto unlock_mutex; @@ -2570,9 +2793,12 @@ static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr) put_dev: msm_nand_put_device(chip->dev); unlock_mutex: + del_timer_sync(&timer); mutex_unlock(&info->lock); msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer)); out: + if (unlikely(enable_perfstats) && likely(!err)) + msm_nand_update_erase_perf_stats(info, start, 1); return err; } @@ -2695,8 +2921,10 @@ static int msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs) iovec++; } mutex_lock(&info->lock); + mod_timer(&timer, jiffies + SW_REQ_TIMEOUT_SEC * HZ); ret = msm_nand_get_device(chip->dev); if (ret) { + del_timer_sync(&timer); mutex_unlock(&info->lock); goto free_dma; } @@ -2734,6 +2962,7 @@ static int msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs) } ret = msm_nand_put_device(chip->dev); + del_timer_sync(&timer); mutex_unlock(&info->lock); if (ret) goto free_dma; @@ -2756,6 +2985,7 @@ static int msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs) goto free_dma; put_dev: msm_nand_put_device(chip->dev); + del_timer_sync(&timer); mutex_unlock(&info->lock); free_dma: msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer) + 4); @@ -3511,6 +3741,8 @@ static int msm_nand_probe(struct platform_device *pdev) err = -ENXIO; goto free_bam; } + INIT_WORK(&info->tout_work, msm_nand_tout_work_fn); + setup_timer(&timer, msm_nand_transfer_timeout, (unsigned long)info); for (i = 0; i < nr_parts; i++) { mtd_part[i].offset *= info->mtd.erasesize; mtd_part[i].size *= info->mtd.erasesize; @@ -3526,6 +3758,8 @@ static int msm_nand_probe(struct platform_device *pdev) info->nand_phys, info->bam_phys, info->bam_irq); pr_info("Allocated DMA buffer at virt_addr 0x%p, phys_addr 0x%x\n", info->nand_chip.dma_virt_addr, info->nand_chip.dma_phys_addr); + msm_nand_init_sysfs(dev); + msm_nand_init_perf_stats(info); goto out; free_bam: msm_nand_bam_free(info); @@ -3547,6 +3781,7 @@ static int msm_nand_remove(struct platform_device *pdev) { struct msm_nand_info *info = dev_get_drvdata(&pdev->dev); + msm_nand_cleanup_sysfs(&pdev->dev); if (pm_runtime_suspended(&(pdev)->dev)) pm_runtime_resume(&(pdev)->dev); @@ -3591,6 +3826,9 @@ static struct platform_driver msm_nand_driver = { module_param(enable_euclean, bool, 0644); MODULE_PARM_DESC(enable_euclean, "Set this parameter to enable reporting EUCLEAN to upper layer when the correctable bitflips are equal to the max correctable limit."); +module_param(enable_perfstats, bool, 0644); +MODULE_PARM_DESC(enable_perfstats, "Set this parameter to enable collection and reporting of performance data."); + module_platform_driver(msm_nand_driver); MODULE_ALIAS(DRIVER_NAME); diff --git a/drivers/mtd/devices/msm_qpic_nand.h b/drivers/mtd/devices/msm_qpic_nand.h index 48c625443ff6e975fa0d5da0b98721aae1a6a860..383453598475f12273bff81323aad8d032777700 100644 --- a/drivers/mtd/devices/msm_qpic_nand.h +++ b/drivers/mtd/devices/msm_qpic_nand.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 +36,8 @@ #include #include #include +#include +#include #include #define PAGE_SIZE_2K 2048 @@ -296,6 +298,23 @@ struct msm_nand_clk_data { atomic_t curr_vote; }; +struct msm_nand_perf_stats { + u64 total_read_size; + u64 total_write_size; + u64 total_erase_blks; + ktime_t total_read_time; + ktime_t total_write_time; + ktime_t total_erase_time; + ktime_t min_read_time; + ktime_t min_write_time; + ktime_t min_erase_time; + ktime_t max_read_time; + ktime_t max_write_time; + ktime_t max_erase_time; + spinlock_t lock; +}; + + /* Structure that defines NANDc private data. */ struct msm_nand_info { struct mtd_info mtd; @@ -320,7 +339,9 @@ struct msm_nand_info { struct mutex lock; struct flash_identification flash_dev; struct msm_nand_clk_data clk_data; + struct msm_nand_perf_stats perf; u64 dma_mask; + struct work_struct tout_work; }; /* Structure that defines an ONFI parameter page (512B) */ diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index bb580bc164459a3dee5b27ef34125af8f31ba2d5..c07f21b20463252e63a0ac0f313f75a7c4c05eaa 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -59,9 +59,9 @@ static int __init init_soleng_maps(void) return -ENXIO; } } - printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n", - soleng_flash_map.phys & 0x1fffffff, - soleng_eprom_map.phys & 0x1fffffff); + printk(KERN_NOTICE "Solution Engine: Flash at 0x%pap, EPROM at 0x%pap\n", + &soleng_flash_map.phys, + &soleng_eprom_map.phys); flash_mtd->owner = THIS_MODULE; eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 11c8b468c6d889e4aca657f96a9a731f8183b46d..000be88d3fb3ed0b81dedb3fecfb9b97c939ae47 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -191,8 +191,12 @@ static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count, pr_debug("MTD_read\n"); - if (*ppos + count > mtd->size) - count = mtd->size - *ppos; + if (*ppos + count > mtd->size) { + if (*ppos < mtd->size) + count = mtd->size - *ppos; + else + count = 0; + } if (!count) return 0; @@ -277,7 +281,7 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c pr_debug("MTD_write\n"); - if (*ppos == mtd->size) + if (*ppos >= mtd->size) return -ENOSPC; if (*ppos + count > mtd->size) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 959cb9b7031077a460cc1e7c39bbd06d47c65152..0b27e338dae972fa6925e0158f1a5a33eefaf95e 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1025,9 +1025,6 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, return ret; } - /* handle the block mark swapping */ - block_mark_swapping(this, payload_virt, auxiliary_virt); - /* Loop over status bytes, accumulating ECC status. */ status = auxiliary_virt + nfc_geo->auxiliary_status_offset; @@ -1043,6 +1040,9 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, max_bitflips = max_t(unsigned int, max_bitflips, *status); } + /* handle the block mark swapping */ + block_mark_swapping(this, buf, auxiliary_virt); + if (oob_required) { /* * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index dba262bf766ff197c3afe9db1c68e11ca12f7a2b..7cf0473c79e854bb9f3ed0c3d1d1f5e2a0bc3fd1 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -49,7 +49,7 @@ #define NFC_V1_V2_CONFIG (host->regs + 0x0a) #define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c) #define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e) -#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10) +#define NFC_V21_RSLTSPARE_AREA (host->regs + 0x10) #define NFC_V1_V2_WRPROT (host->regs + 0x12) #define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14) #define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16) @@ -958,6 +958,9 @@ static void preset_v2(struct mtd_info *mtd) writew(config1, NFC_V1_V2_CONFIG1); /* preset operation */ + /* spare area size in 16-bit half-words */ + writew(mtd->oobsize / 2, NFC_V21_RSLTSPARE_AREA); + /* Unlock the internal RAM Buffer */ writew(0x2, NFC_V1_V2_CONFIG); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 2e2da0a4be1a3bdd01ddb14f261e5ca65374615b..c8f20467ff1d1aacfcdda6ae87ca857fae958234 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -600,7 +600,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, readcmd, ctrl); ctrl &= ~NAND_CTRL_CHANGE; } - chip->cmd_ctrl(mtd, command, ctrl); + if (command != NAND_CMD_NONE) + chip->cmd_ctrl(mtd, command, ctrl); /* Address cycle, when necessary */ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; @@ -629,6 +630,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, */ switch (command) { + case NAND_CMD_NONE: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: @@ -691,7 +693,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, } /* Command latch cycle */ - chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + if (command != NAND_CMD_NONE) + chip->cmd_ctrl(mtd, command, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); if (column != -1 || page_addr != -1) { int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; @@ -724,6 +728,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, */ switch (command) { + case NAND_CMD_NONE: case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: @@ -1872,6 +1877,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { + unsigned int max_bitflips = 0; int page, realpage, chipnr; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; @@ -1932,6 +1938,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } + max_bitflips = max_t(unsigned int, max_bitflips, ret); + readlen -= len; if (!readlen) break; @@ -1957,7 +1965,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; - return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; + return max_bitflips; } /** @@ -2501,15 +2509,18 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + int chipnr = (int)(to >> chip->chip_shift); struct mtd_oob_ops ops; int ret; - /* Wait for the device to get ready */ - panic_nand_wait(mtd, chip, 400); - /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); + chip->select_chip(mtd, chipnr); + + /* Wait for the device to get ready */ + panic_nand_wait(mtd, chip, 400); + ops.len = len; ops.datbuf = (uint8_t *)buf; ops.oobbuf = NULL; diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index d5269a26c839384eefa052534013828f6feaab89..56d39f2b22ce13b15cb37bb83b5fb6c5f2c68d13 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -138,15 +138,15 @@ #define LUT_MODE 4 #define LUT_MODE2 5 #define LUT_MODE4 6 -#define LUT_READ 7 -#define LUT_WRITE 8 +#define LUT_FSL_READ 7 +#define LUT_FSL_WRITE 8 #define LUT_JMP_ON_CS 9 #define LUT_ADDR_DDR 10 #define LUT_MODE_DDR 11 #define LUT_MODE2_DDR 12 #define LUT_MODE4_DDR 13 -#define LUT_READ_DDR 14 -#define LUT_WRITE_DDR 15 +#define LUT_FSL_READ_DDR 14 +#define LUT_FSL_WRITE_DDR 15 #define LUT_DATA_LEARN 16 /* @@ -306,7 +306,7 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); - writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo), + writel(LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo), base + QUADSPI_LUT(lut_base + 1)); /* Write enable */ @@ -327,11 +327,11 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); - writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1)); + writel(LUT0(FSL_WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1)); /* Read Status */ lut_base = SEQID_RDSR * 4; - writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(READ, PAD1, 0x1), + writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(FSL_READ, PAD1, 0x1), base + QUADSPI_LUT(lut_base)); /* Erase a sector */ @@ -356,17 +356,17 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* READ ID */ lut_base = SEQID_RDID * 4; - writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(READ, PAD1, 0x8), + writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(FSL_READ, PAD1, 0x8), base + QUADSPI_LUT(lut_base)); /* Write Register */ lut_base = SEQID_WRSR * 4; - writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(WRITE, PAD1, 0x2), + writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(FSL_WRITE, PAD1, 0x2), base + QUADSPI_LUT(lut_base)); /* Read Configuration Register */ lut_base = SEQID_RDCR * 4; - writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(READ, PAD1, 0x1), + writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(FSL_READ, PAD1, 0x1), base + QUADSPI_LUT(lut_base)); /* Write disable */ diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 1a92d30689e76e5cd1ce1a22bff6bbac6a1bbbbb..d408c05121b73016d93c81334b9c7ff0c2aff149 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -242,7 +242,7 @@ static int ubiblock_open(struct block_device *bdev, fmode_t mode) * in any case. */ if (mode & FMODE_WRITE) { - ret = -EPERM; + ret = -EROFS; goto out_unlock; } diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 92c8dc234e2bbfbb7855b43bb03f2af24d7e2f4d..fcafdd7222aaf3712ed93db5c4297197440951b3 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -951,6 +951,17 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, return -EINVAL; } + /* + * Both UBI and UBIFS have been designed for SLC NAND and NOR flashes. + * MLC NAND is different and needs special care, otherwise UBI or UBIFS + * will die soon and you will lose all your data. + */ + if (mtd->type == MTD_MLCNANDFLASH) { + pr_err("ubi: refuse attaching mtd%d - MLC NAND is not supported\n", + mtd->index); + return -EINVAL; + } + if (ubi_num == UBI_DEV_NUM_AUTO) { /* Search for an empty slot in the @ubi_devices array */ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 65b35e0a127242cf96232cf71a7c66f1697ba515..bb477bdaf1914d13daabe8bb8369e670bea4b4a6 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -350,6 +350,82 @@ out_unlock: return err; } +#ifdef CONFIG_MTD_UBI_FASTMAP +/** + * check_mapping - check and fixup a mapping + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @pnum: physical eraseblock number + * + * Checks whether a given mapping is valid. Fastmap cannot track LEB unmap + * operations, if such an operation is interrupted the mapping still looks + * good, but upon first read an ECC is reported to the upper layer. + * Normaly during the full-scan at attach time this is fixed, for Fastmap + * we have to deal with it while reading. + * If the PEB behind a LEB shows this symthom we change the mapping to + * %UBI_LEB_UNMAPPED and schedule the PEB for erasure. + * + * Returns 0 on success, negative error code in case of failure. + */ +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + int err; + struct ubi_vid_hdr *vid_hdr; + + if (!ubi->fast_attach) + return 0; + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) + return -ENOMEM; + + err = ubi_io_read_vid_hdr(ubi, *pnum, vid_hdr, 0); + if (err > 0 && err != UBI_IO_BITFLIPS) { + int torture = 0; + + switch (err) { + case UBI_IO_FF: + case UBI_IO_FF_BITFLIPS: + case UBI_IO_BAD_HDR: + case UBI_IO_BAD_HDR_EBADMSG: + break; + default: + ubi_assert(0); + } + + if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_FF_BITFLIPS) + torture = 1; + + down_read(&ubi->fm_sem); + vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; + up_read(&ubi->fm_sem); + ubi_wl_put_peb(ubi, vol->vol_id, lnum, *pnum, torture); + + *pnum = UBI_LEB_UNMAPPED; + } else if (err < 0) { + ubi_err("unable to read VID header back from PEB %i: %i", + *pnum, err); + + goto out_free; + } + + err = 0; + +out_free: + ubi_free_vid_hdr(ubi, vid_hdr); + + return err; +} +#else +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + return 0; +} +#endif + /** * ubi_eba_read_leb - read data. * @ubi: UBI device description object @@ -381,7 +457,13 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl[lnum]; - if (pnum < 0) { + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) + goto out_unlock; + } + + if (pnum == UBI_LEB_UNMAPPED) { /* * The logical eraseblock is not mapped, fill the whole buffer * with 0xFF bytes. The exception is static volumes for which @@ -688,6 +770,14 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl[lnum]; + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) { + leb_write_unlock(ubi, vol_id, lnum); + return err; + } + } + if (pnum >= 0) { dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); @@ -993,7 +1083,6 @@ retry: goto write_error; } - down_read(&ubi->fm_eba_sem); old_pnum = vol->eba_tbl[lnum]; vol->eba_tbl[lnum] = pnum; up_read(&ubi->fm_eba_sem); diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 3ea4c022cbb9cd136a0746beabf240cc1f94ef0f..ccdb3dd74421243ef6a31b6ebe956d2ce78647c6 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -265,6 +265,12 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vol->last_eb_bytes = vol->usable_leb_size; } + /* Make volume "available" before it becomes accessible via sysfs */ + spin_lock(&ubi->volumes_lock); + ubi->volumes[vol_id] = vol; + ubi->vol_count += 1; + spin_unlock(&ubi->volumes_lock); + /* Register character device for the volume */ cdev_init(&vol->cdev, &ubi_vol_cdev_operations); vol->cdev.owner = THIS_MODULE; @@ -304,11 +310,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) if (err) goto out_sysfs; - spin_lock(&ubi->volumes_lock); - ubi->volumes[vol_id] = vol; - ubi->vol_count += 1; - spin_unlock(&ubi->volumes_lock); - ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED); self_check_volumes(ubi); return err; @@ -328,6 +329,10 @@ out_sysfs: out_cdev: cdev_del(&vol->cdev); out_mapping: + spin_lock(&ubi->volumes_lock); + ubi->volumes[vol_id] = NULL; + ubi->vol_count -= 1; + spin_unlock(&ubi->volumes_lock); if (do_free) kfree(vol->eba_tbl); out_acc: diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index e90c6a7333d76b4f11e3fccfdcad094be141108e..4e98e5aff7c5949d1f8bf783cb6fe655785883ca 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -191,7 +191,7 @@ static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) */ static int ipddp_create(struct ipddp_route *new_rt) { - struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL); + struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL); if (rt == NULL) return -ENOMEM; @@ -284,8 +284,12 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCFINDIPDDPRT: spin_lock_bh(&ipddp_route_lock); rp = __ipddp_find_route(&rcp); - if (rp) - memcpy(&rcp2, rp, sizeof(rcp2)); + if (rp) { + memset(&rcp2, 0, sizeof(rcp2)); + rcp2.ip = rp->ip; + rcp2.at = rp->at; + rcp2.flags = rp->flags; + } spin_unlock_bh(&ipddp_route_lock); if (rp) { diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 4a69284570151e7e55c2c374ab073ba9b5ac7df7..bb54622f6f17a0c578a49dca8f0cc6f8a4588435 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -453,7 +453,7 @@ static void rlb_update_client(struct rlb_client_info *client_info) { int i; - if (!client_info->slave) + if (!client_info->slave || !is_valid_ether_addr(client_info->mac_dst)) return; for (i = 0; i < RLB_ARP_BURST_SIZE; i++) { diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 566054c0eb9aaede5f6a5fc7d202f730ca137fb7..126ce5e24fc185522196be95f2453ef537b21e4c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1384,39 +1384,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_close; } - /* If the mode uses primary, then the following is handled by - * bond_change_active_slave(). - */ - if (!bond_uses_primary(bond)) { - /* set promiscuity level to new slave */ - if (bond_dev->flags & IFF_PROMISC) { - res = dev_set_promiscuity(slave_dev, 1); - if (res) - goto err_close; - } - - /* set allmulti level to new slave */ - if (bond_dev->flags & IFF_ALLMULTI) { - res = dev_set_allmulti(slave_dev, 1); - if (res) - goto err_close; - } - - netif_addr_lock_bh(bond_dev); - - dev_mc_sync_multiple(slave_dev, bond_dev); - dev_uc_sync_multiple(slave_dev, bond_dev); - - netif_addr_unlock_bh(bond_dev); - } - - if (BOND_MODE(bond) == BOND_MODE_8023AD) { - /* add lacpdu mc addr to mc list */ - u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; - - dev_mc_add(slave_dev, lacpdu_multicast); - } - res = vlan_vids_add_by_dev(slave_dev, bond_dev); if (res) { netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", @@ -1538,8 +1505,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } /* switch(bond_mode) */ #ifdef CONFIG_NET_POLL_CONTROLLER - slave_dev->npinfo = bond->dev->npinfo; - if (slave_dev->npinfo) { + if (bond->dev->npinfo) { if (slave_enable_netpoll(new_slave)) { netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n"); res = -EBUSY; @@ -1567,6 +1533,40 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_upper_unlink; } + /* If the mode uses primary, then the following is handled by + * bond_change_active_slave(). + */ + if (!bond_uses_primary(bond)) { + /* set promiscuity level to new slave */ + if (bond_dev->flags & IFF_PROMISC) { + res = dev_set_promiscuity(slave_dev, 1); + if (res) + goto err_sysfs_del; + } + + /* set allmulti level to new slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + res = dev_set_allmulti(slave_dev, 1); + if (res) { + if (bond_dev->flags & IFF_PROMISC) + dev_set_promiscuity(slave_dev, -1); + goto err_sysfs_del; + } + } + + netif_addr_lock_bh(bond_dev); + dev_mc_sync_multiple(slave_dev, bond_dev); + dev_uc_sync_multiple(slave_dev, bond_dev); + netif_addr_unlock_bh(bond_dev); + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + /* add lacpdu mc addr to mc list */ + u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; + + dev_mc_add(slave_dev, lacpdu_multicast); + } + } + bond->slave_cnt++; bond_compute_features(bond); bond_set_carrier(bond); @@ -1589,6 +1589,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) return 0; /* Undo stages on error */ +err_sysfs_del: + bond_sysfs_slave_del(new_slave); + err_upper_unlink: bond_upper_dev_unlink(bond_dev, slave_dev); @@ -1596,9 +1599,6 @@ err_unregister: netdev_rx_handler_unregister(slave_dev); err_detach: - if (!bond_uses_primary(bond)) - bond_hw_addr_flush(bond_dev, slave_dev); - vlan_vids_del_by_dev(slave_dev, bond_dev); if (rcu_access_pointer(bond->primary_slave) == new_slave) RCU_INIT_POINTER(bond->primary_slave, NULL); @@ -2425,11 +2425,13 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) bond_for_each_slave_rcu(bond, slave, iter) { unsigned long trans_start = dev_trans_start(slave->dev); + slave->new_link = BOND_LINK_NOCHANGE; + if (slave->link != BOND_LINK_UP) { if (bond_time_in_interval(bond, trans_start, 1) && bond_time_in_interval(bond, slave->last_rx, 1)) { - slave->link = BOND_LINK_UP; + slave->new_link = BOND_LINK_UP; slave_state_changed = 1; /* primary_slave has no meaning in round-robin @@ -2456,7 +2458,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) if (!bond_time_in_interval(bond, trans_start, 2) || !bond_time_in_interval(bond, slave->last_rx, 2)) { - slave->link = BOND_LINK_DOWN; + slave->new_link = BOND_LINK_DOWN; slave_state_changed = 1; if (slave->link_failure_count < UINT_MAX) @@ -2487,6 +2489,11 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) if (!rtnl_trylock()) goto re_arm; + bond_for_each_slave(bond, slave, iter) { + if (slave->new_link != BOND_LINK_NOCHANGE) + slave->link = slave->new_link; + } + if (slave_state_changed) { bond_slave_state_change(bond); if (BOND_MODE(bond) == BOND_MODE_XOR) diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c index 7be393c96b1a0481c1f181443a7b521b647378f5..8d2724327f698bcb8fb0aaabd24167f72014659e 100644 --- a/drivers/net/can/c_can/c_can_pci.c +++ b/drivers/net/can/c_can/c_can_pci.c @@ -177,7 +177,6 @@ static int c_can_pci_probe(struct pci_dev *pdev, break; case BOSCH_D_CAN: priv->regs = reg_map_d_can; - priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; break; default: ret = -EINVAL; diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index fb279d6ae484ffe3c66f45ab6a8cbb339ef0808f..ef056a33604e8e16e7d43c6f440834a2a70ff6c9 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -257,7 +257,6 @@ static int c_can_plat_probe(struct platform_device *pdev) break; case BOSCH_D_CAN: priv->regs = reg_map_d_can; - priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; priv->read_reg32 = d_can_plat_read_reg32; diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index d8379278d648a2160f63d386eb5056dc47d70b7a..b8f4614fb02f312a5682925c9540e4f9eae63ca8 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -390,37 +390,23 @@ static int cc770_get_berr_counter(const struct net_device *dev, return 0; } -static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void cc770_tx(struct net_device *dev, int mo) { struct cc770_priv *priv = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct can_frame *cf = (struct can_frame *)skb->data; - unsigned int mo = obj2msgobj(CC770_OBJ_TX); + struct can_frame *cf = (struct can_frame *)priv->tx_skb->data; u8 dlc, rtr; u32 id; int i; - if (can_dropped_invalid_skb(dev, skb)) - return NETDEV_TX_OK; - - if ((cc770_read_reg(priv, - msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { - netdev_err(dev, "TX register is still occupied!\n"); - return NETDEV_TX_BUSY; - } - - netif_stop_queue(dev); - dlc = cf->can_dlc; id = cf->can_id; - if (cf->can_id & CAN_RTR_FLAG) - rtr = 0; - else - rtr = MSGCFG_DIR; + rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR; + + cc770_write_reg(priv, msgobj[mo].ctrl0, + MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); cc770_write_reg(priv, msgobj[mo].ctrl1, RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); - cc770_write_reg(priv, msgobj[mo].ctrl0, - MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES); + if (id & CAN_EFF_FLAG) { id &= CAN_EFF_MASK; cc770_write_reg(priv, msgobj[mo].config, @@ -439,22 +425,30 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) for (i = 0; i < dlc; i++) cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]); - /* Store echo skb before starting the transfer */ - can_put_echo_skb(skb, dev, 0); - cc770_write_reg(priv, msgobj[mo].ctrl1, - RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC); + RMTPND_UNC | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC); + cc770_write_reg(priv, msgobj[mo].ctrl0, + MSGVAL_SET | TXIE_SET | RXIE_SET | INTPND_UNC); +} - stats->tx_bytes += dlc; +static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct cc770_priv *priv = netdev_priv(dev); + unsigned int mo = obj2msgobj(CC770_OBJ_TX); + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; - /* - * HM: We had some cases of repeated IRQs so make sure the - * INT is acknowledged I know it's already further up, but - * doing again fixed the issue - */ - cc770_write_reg(priv, msgobj[mo].ctrl0, - MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); + netif_stop_queue(dev); + + if ((cc770_read_reg(priv, + msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { + netdev_err(dev, "TX register is still occupied!\n"); + return NETDEV_TX_BUSY; + } + + priv->tx_skb = skb; + cc770_tx(dev, mo); return NETDEV_TX_OK; } @@ -679,19 +673,46 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) struct cc770_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; unsigned int mo = obj2msgobj(o); + struct can_frame *cf; + u8 ctrl1; + + ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1); - /* Nothing more to send, switch off interrupts */ cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); - /* - * We had some cases of repeated IRQ so make sure the - * INT is acknowledged + cc770_write_reg(priv, msgobj[mo].ctrl1, + RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES); + + if (unlikely(!priv->tx_skb)) { + netdev_err(dev, "missing tx skb in tx interrupt\n"); + return; + } + + if (unlikely(ctrl1 & MSGLST_SET)) { + stats->rx_over_errors++; + stats->rx_errors++; + } + + /* When the CC770 is sending an RTR message and it receives a regular + * message that matches the id of the RTR message, it will overwrite the + * outgoing message in the TX register. When this happens we must + * process the received message and try to transmit the outgoing skb + * again. */ - cc770_write_reg(priv, msgobj[mo].ctrl0, - MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); + if (unlikely(ctrl1 & NEWDAT_SET)) { + cc770_rx(dev, mo, ctrl1); + cc770_tx(dev, mo); + return; + } + cf = (struct can_frame *)priv->tx_skb->data; + stats->tx_bytes += cf->can_dlc; stats->tx_packets++; + + can_put_echo_skb(priv->tx_skb, dev, 0); can_get_echo_skb(dev, 0); + priv->tx_skb = NULL; + netif_wake_queue(dev); } @@ -803,6 +824,7 @@ struct net_device *alloc_cc770dev(int sizeof_priv) priv->can.do_set_bittiming = cc770_set_bittiming; priv->can.do_set_mode = cc770_set_mode; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; + priv->tx_skb = NULL; memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags)); diff --git a/drivers/net/can/cc770/cc770.h b/drivers/net/can/cc770/cc770.h index a1739db98d911f006f82a44682f0be1b8694a01c..95752e1d128397260968ee100b0b3035923547c9 100644 --- a/drivers/net/can/cc770/cc770.h +++ b/drivers/net/can/cc770/cc770.h @@ -193,6 +193,8 @@ struct cc770_priv { u8 cpu_interface; /* CPU interface register */ u8 clkout; /* Clock out register */ u8 bus_config; /* Bus conffiguration register */ + + struct sk_buff *tx_skb; }; struct net_device *alloc_cc770dev(int sizeof_priv); diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 031b6877acf9440aaf054031fbad1b981eb1643f..85db2a5e7878f42c0b9806f9843b830ab839036a 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -471,7 +471,7 @@ void can_bus_off(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - netdev_dbg(dev, "bus-off\n"); + netdev_info(dev, "bus-off\n"); netif_carrier_off(dev); priv->can_stats.bus_off++; diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 44725296f72a25b07d21bb92f9af1f0534980bc5..655a387eb9ad58fa2a4d01d2310ad1be731aa382 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -86,6 +86,11 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, return 0; } cdm = of_iomap(np_cdm, 0); + if (!cdm) { + of_node_put(np_cdm); + dev_err(&ofdev->dev, "can't map clock node!\n"); + return 0; + } if (in_8(&cdm->ipb_clk_sel) & 0x1) freq *= 2; diff --git a/drivers/net/can/spi/k61.c b/drivers/net/can/spi/k61.c index 4668d40a16125bb4d6032626eec29d536aa8c6e8..6bb9204dfc2f483f89dbea3a1ca533afb60129c2 100644 --- a/drivers/net/can/spi/k61.c +++ b/drivers/net/can/spi/k61.c @@ -60,6 +60,7 @@ struct k61_can { int cmd_result; int bits_per_word; int reset_delay_msec; + s64 time_diff; }; struct k61_netdev_privdata { @@ -97,6 +98,9 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_CAN_DATA_BUFF_REMOVE 0x88 #define CMD_CAN_RELEASE_BUFFER 0x89 #define CMD_CAN_DATA_BUFF_REMOVE_ALL 0x8A +#define CMD_UPDATE_TIME_INFO 0x9D +#define CMD_SUSPEND_EVENT 0x9E +#define CMD_RESUME_EVENT 0x9F #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -112,7 +116,7 @@ struct can_fw_resp { } __packed; struct can_write_req { - u32 ts; + u64 ts; u32 mid; u8 dlc; u8 data[]; @@ -123,7 +127,7 @@ struct can_write_resp { } __packed; struct can_receive_frame { - u32 ts; + u64 ts; u32 mid; u8 dlc; u8 data[]; @@ -136,6 +140,10 @@ struct can_add_filter_req { u8 type; } __packed; +struct can_time_info { + u64 time; +} __packed; + static struct can_bittiming_const k61_bittiming_const = { .name = "k61", .tseg1_min = 4, @@ -199,8 +207,7 @@ static void k61_receive_frame(struct k61_can *priv_data, struct can_frame *cf; struct sk_buff *skb; struct skb_shared_hwtstamps *skt; - struct timeval tv; - static int msec; + ktime_t nsec; struct net_device *netdev; int i; @@ -217,7 +224,7 @@ static void k61_receive_frame(struct k61_can *priv_data, return; } - LOGDI("rcv frame %d %x %d %x %x %x %x %x %x %x %x\n", + LOGDI("rcv frame %llu %x %d %x %x %x %x %x %x %x %x\n", frame->ts, frame->mid, frame->dlc, frame->data[0], frame->data[1], frame->data[2], frame->data[3], frame->data[4], frame->data[5], frame->data[6], frame->data[7]); @@ -227,13 +234,11 @@ static void k61_receive_frame(struct k61_can *priv_data, for (i = 0; i < cf->can_dlc; i++) cf->data[i] = frame->data[i]; - msec = le32_to_cpu(frame->ts); - tv.tv_sec = msec / 1000; - tv.tv_usec = (msec - tv.tv_sec * 1000) * 1000; + nsec = ms_to_ktime(le64_to_cpu(frame->ts) + priv_data->time_diff); skt = skb_hwtstamps(skb); - skt->hwtstamp = timeval_to_ktime(tv); + skt->hwtstamp = nsec; LOGDI(" hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp)); - skb->tstamp = timeval_to_ktime(tv); + skb->tstamp = nsec; netif_rx(skb); netdev->stats.rx_packets++; netdev->stats.rx_bytes += cf->can_dlc; @@ -243,6 +248,9 @@ static void k61_process_response(struct k61_can *priv_data, struct spi_miso *resp) { int ret = 0; + u64 mstime; + ktime_t ktime_now; + LOGDI("<%x %2d [%d]\n", resp->cmd, resp->len, resp->seq); if (resp->cmd == CMD_CAN_RECEIVE_FRAME) { struct can_receive_frame *frame = @@ -253,6 +261,12 @@ static void k61_process_response(struct k61_can *priv_data, dev_info(&priv_data->spidev->dev, "fw %d.%d.%d", fw_resp->maj, fw_resp->min, fw_resp->ver); + } else if (resp->cmd == CMD_UPDATE_TIME_INFO) { + struct can_time_info *time_data = + (struct can_time_info *)resp->data; + ktime_now = ktime_get_boottime(); + mstime = ktime_to_ms(ktime_now); + priv_data->time_diff = mstime - (le64_to_cpu(time_data->time)); } if (resp->cmd == priv_data->wait_cmd) { @@ -377,6 +391,30 @@ static int k61_query_firmware_version(struct k61_can *priv_data) return ret; } +static int k61_notify_power_events(struct k61_can *priv_data, u8 event_type) +{ + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = event_type; + req->len = 0; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + ret = k61_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + + return ret; +} + static int k61_can_write(struct k61_can *priv_data, struct can_frame *cf) { char *tx_buf, *rx_buf; @@ -813,6 +851,7 @@ static int k61_probe(struct spi_device *spi) int err, retry = 0, query_err = -1; struct k61_can *priv_data; struct device *dev; + u32 irq_type; dev = &spi->dev; dev_dbg(dev, "k61_probe"); @@ -869,8 +908,11 @@ static int k61_probe(struct spi_device *spi) goto unregister_candev; } + irq_type = irq_get_trigger_type(spi->irq); + if (irq_type == IRQ_TYPE_NONE) + irq_type = IRQ_TYPE_EDGE_FALLING; err = request_threaded_irq(spi->irq, NULL, k61_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + irq_type | IRQF_ONESHOT, "k61", priv_data); if (err) { dev_err(dev, "Failed to request irq: %d", err); @@ -924,7 +966,10 @@ static const struct of_device_id k61_match_table[] = { static int k61_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); + struct k61_can *priv_data = spi_get_drvdata(spi); + u8 power_event = CMD_SUSPEND_EVENT; + k61_notify_power_events(priv_data, power_event); enable_irq_wake(spi->irq); return 0; } @@ -933,9 +978,10 @@ static int k61_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct k61_can *priv_data = spi_get_drvdata(spi); + u8 power_event = CMD_RESUME_EVENT; disable_irq_wake(spi->irq); - k61_rx_message(priv_data); + k61_notify_power_events(priv_data, power_event); return 0; } diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index 253e341dbb585cf8c52531cdca255d839ee4d736..9ffa7e9b3041b5bd21e960253e0f6aa947dc1c9c 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -70,6 +70,7 @@ struct qti_can { bool can_fw_cmd_timeout_req; u32 rem_all_buffering_timeout_ms; u32 can_fw_cmd_timeout_ms; + s64 time_diff; }; struct qti_can_netdev_privdata { @@ -118,6 +119,8 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_BEGIN_BOOT_ROM_UPGRADE 0x99 #define CMD_BOOT_ROM_UPGRADE_DATA 0x9A #define CMD_END_BOOT_ROM_UPGRADE 0x9B +#define CMD_END_FW_UPDATE_FILE 0x9C +#define CMD_UPDATE_TIME_INFO 0x9D #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -132,6 +135,7 @@ struct spi_miso { /* TLV for MISO line */ #define IOCTL_BEGIN_BOOT_ROM_UPGRADE (SIOCDEVPRIVATE + 11) #define IOCTL_BOOT_ROM_UPGRADE_DATA (SIOCDEVPRIVATE + 12) #define IOCTL_END_BOOT_ROM_UPGRADE (SIOCDEVPRIVATE + 13) +#define IOCTL_END_FW_UPDATE_FILE (SIOCDEVPRIVATE + 14) #define IFR_DATA_OFFSET 0x100 struct can_fw_resp { @@ -163,7 +167,7 @@ struct can_add_filter_resp { struct can_receive_frame { u8 can_if; - u32 ts; + u64 ts; u32 mid; u8 dlc; u8 data[8]; @@ -178,6 +182,10 @@ struct can_config_bit_timing { u32 brp; } __packed; +struct can_time_info { + u64 time; +} __packed; + static struct can_bittiming_const rh850_bittiming_const = { .name = "qti_can", .tseg1_min = 1, @@ -291,7 +299,7 @@ static void qti_can_receive_frame(struct qti_can *priv_data, return; } - LOGDI("rcv frame %d %d %x %d %x %x %x %x %x %x %x %x\n", + LOGDI("rcv frame %d %llu %x %d %x %x %x %x %x %x %x %x\n", frame->can_if, frame->ts, frame->mid, frame->dlc, frame->data[0], frame->data[1], frame->data[2], frame->data[3], frame->data[4], frame->data[5], frame->data[6], frame->data[7]); @@ -301,7 +309,8 @@ static void qti_can_receive_frame(struct qti_can *priv_data, for (i = 0; i < cf->can_dlc; i++) cf->data[i] = frame->data[i]; - nsec = ms_to_ktime(le32_to_cpu(frame->ts)); + nsec = ms_to_ktime(le64_to_cpu(frame->ts) + priv_data->time_diff); + skt = skb_hwtstamps(skb); skt->hwtstamp = nsec; LOGDI(" hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp)); @@ -354,6 +363,8 @@ static int qti_can_process_response(struct qti_can *priv_data, struct spi_miso *resp, int length) { int ret = 0; + u64 mstime; + ktime_t ktime_now; LOGDI("<%x %2d [%d]\n", resp->cmd, resp->len, resp->seq); if (resp->cmd == CMD_CAN_RECEIVE_FRAME) { @@ -402,6 +413,12 @@ static int qti_can_process_response(struct qti_can *priv_data, ret |= (fw_resp->br_min & 0xFF) << 16; ret |= (fw_resp->maj & 0xF) << 8; ret |= (fw_resp->min & 0xFF); + } else if (resp->cmd == CMD_UPDATE_TIME_INFO) { + struct can_time_info *time_data = + (struct can_time_info *)resp->data; + ktime_now = ktime_get_boottime(); + mstime = ktime_to_ms(ktime_now); + priv_data->time_diff = mstime - (le64_to_cpu(time_data->time)); } if (resp->cmd == priv_data->wait_cmd) { @@ -983,6 +1000,8 @@ static int qti_can_convert_ioctl_cmd_to_spi_cmd(int ioctl_cmd) return CMD_BOOT_ROM_UPGRADE_DATA; case IOCTL_END_BOOT_ROM_UPGRADE: return CMD_END_BOOT_ROM_UPGRADE; + case IOCTL_END_FW_UPDATE_FILE: + return CMD_END_FW_UPDATE_FILE; } return -EINVAL; } @@ -1119,6 +1138,7 @@ static int qti_can_netdev_do_ioctl(struct net_device *netdev, case IOCTL_BEGIN_BOOT_ROM_UPGRADE: case IOCTL_BOOT_ROM_UPGRADE_DATA: case IOCTL_END_BOOT_ROM_UPGRADE: + case IOCTL_END_FW_UPDATE_FILE: ret = qti_can_do_blocking_ioctl(netdev, ifr, cmd); break; } @@ -1243,6 +1263,7 @@ static int qti_can_probe(struct spi_device *spi) int err, retry = 0, query_err = -1, i; struct qti_can *priv_data = NULL; struct device *dev; + u32 irq_type; dev = &spi->dev; dev_info(dev, "qti_can_probe"); @@ -1319,7 +1340,7 @@ static int qti_can_probe(struct spi_device *spi) } priv_data->support_can_fd = of_property_read_bool(spi->dev.of_node, - "support-can-fd"); + "qcom,support-can-fd"); if (of_device_is_compatible(spi->dev.of_node, "qcom,nxp,mpc5746c")) qti_can_bittiming_const = flexcan_bittiming_const; @@ -1349,8 +1370,11 @@ static int qti_can_probe(struct spi_device *spi) } } + irq_type = irq_get_trigger_type(spi->irq); + if (irq_type == IRQ_TYPE_NONE) + irq_type = IRQ_TYPE_EDGE_FALLING; err = request_threaded_irq(spi->irq, NULL, qti_can_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + irq_type | IRQF_ONESHOT, "qti-can", priv_data); if (err) { LOGDE("Failed to request irq: %d", err); diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 5c9f06cc35cce6efd6b35b05410a82d208ce0f68..2af6e3c8b718653671df478efcd3ea3720a66909 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -290,6 +290,8 @@ static void ems_usb_read_interrupt_callback(struct urb *urb) case -ECONNRESET: /* unlink */ case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; @@ -1081,6 +1083,7 @@ static void ems_usb_disconnect(struct usb_interface *intf) usb_free_urb(dev->intr_urb); kfree(dev->intr_in_buffer); + kfree(dev->tx_msg_buffer); } } diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index c063a54ab8dd8a598f36e5a7e712722bb5931df1..195bb59c61ab14a6ab47e51c5dda433071538a4c 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -334,7 +334,7 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv, } cf->can_id = id & ESD_IDMASK; - cf->can_dlc = get_can_dlc(msg->msg.rx.dlc); + cf->can_dlc = get_can_dlc(msg->msg.rx.dlc & ~ESD_RTR); if (id & ESD_EXTID) cf->can_id |= CAN_EFF_FLAG; @@ -395,6 +395,8 @@ static void esd_usb2_read_bulk_callback(struct urb *urb) break; case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 991aff587f6380e4bb7b4408f948493db3ec21a1..4c13320f7a1e726182c7c4ad91b9a313c16c5a63 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -356,6 +356,8 @@ static void gs_usb_recieve_bulk_callback(struct urb *urb) gs_free_tx_context(txc); + atomic_dec(&dev->active_tx_urbs); + netif_wake_queue(netdev); } @@ -428,7 +430,7 @@ static int gs_usb_set_bittiming(struct net_device *netdev) dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)", rc); - return rc; + return (rc > 0) ? 0 : rc; } static void gs_usb_xmit_callback(struct urb *urb) @@ -444,14 +446,6 @@ static void gs_usb_xmit_callback(struct urb *urb) urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); - - atomic_dec(&dev->active_tx_urbs); - - if (!netif_device_present(netdev)) - return; - - if (netif_queue_stopped(netdev)) - netif_wake_queue(netdev); } static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, struct net_device *netdev) diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 5d777956ae1fd1a882a6a38c58524f82586389fe..a50b32bebd75f5db7b0ff026bbcd18ad7dd6c93d 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -415,8 +415,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, } if (pos + tmp->len > actual_len) { - dev_err(dev->udev->dev.parent, - "Format error\n"); + dev_err_ratelimited(dev->udev->dev.parent, + "Format error\n"); break; } @@ -850,7 +850,7 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, skb = alloc_can_skb(priv->netdev, &cf); if (!skb) { - stats->tx_dropped++; + stats->rx_dropped++; return; } @@ -980,6 +980,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) case 0: break; case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; default: @@ -988,7 +990,7 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) goto resubmit_urb; } - while (pos <= urb->actual_length - MSG_HEADER_LEN) { + while (pos <= (int)(urb->actual_length - MSG_HEADER_LEN)) { msg = urb->transfer_buffer + pos; /* The Kvaser firmware can only read and write messages that @@ -1006,7 +1008,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) } if (pos + msg->len > urb->actual_length) { - dev_err(dev->udev->dev.parent, "Format error\n"); + dev_err_ratelimited(dev->udev->dev.parent, + "Format error\n"); break; } @@ -1251,7 +1254,8 @@ static int kvaser_usb_close(struct net_device *netdev) if (err) netdev_warn(netdev, "Cannot flush queue, error %d\n", err); - if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel)) + err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel); + if (err) netdev_warn(netdev, "Cannot reset card, error %d\n", err); err = kvaser_usb_stop_chip(priv); diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index ef674ecb82f8e64ef3b57de77626ff31c67e1ba5..271b42134c501ec47612e50d41c769296c856cd3 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -527,6 +527,8 @@ static void usb_8dev_read_bulk_callback(struct urb *urb) break; case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 8a998e3884ce0d502d9ebb19e7abde941ab85d3e..8ca23539c23a07c48f034492574ade2e941e63dd 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -25,8 +25,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -100,7 +102,7 @@ enum xcan_reg { #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK) + XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK) /* CAN register bit shift - XCAN___SHIFT */ #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ @@ -117,6 +119,7 @@ enum xcan_reg { /** * struct xcan_priv - This definition define CAN driver instance * @can: CAN private data structure. + * @tx_lock: Lock for synchronizing TX interrupt handling * @tx_head: Tx CAN packets ready to send on the queue * @tx_tail: Tx CAN packets successfully sended on the queue * @tx_max: Maximum number packets the driver can send @@ -131,6 +134,7 @@ enum xcan_reg { */ struct xcan_priv { struct can_priv can; + spinlock_t tx_lock; unsigned int tx_head; unsigned int tx_tail; unsigned int tx_max; @@ -158,6 +162,11 @@ static const struct can_bittiming_const xcan_bittiming_const = { .brp_inc = 1, }; +#define XCAN_CAP_WATERMARK 0x0001 +struct xcan_devtype_data { + unsigned int caps; +}; + /** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure @@ -237,6 +246,10 @@ static int set_reset_mode(struct net_device *ndev) usleep_range(500, 10000); } + /* reset clears FIFOs */ + priv->tx_head = 0; + priv->tx_tail = 0; + return 0; } @@ -391,6 +404,7 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct net_device_stats *stats = &ndev->stats; struct can_frame *cf = (struct can_frame *)skb->data; u32 id, dlc, data[2] = {0, 0}; + unsigned long flags; if (can_dropped_invalid_skb(ndev, skb)) return NETDEV_TX_OK; @@ -438,6 +452,9 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); + + spin_lock_irqsave(&priv->tx_lock, flags); + priv->tx_head++; /* Write the Frame to Xilinx CAN TX FIFO */ @@ -453,10 +470,16 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) stats->tx_bytes += cf->can_dlc; } + /* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ + if (priv->tx_max > 1) + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK); + /* Check if the TX buffer is full */ if ((priv->tx_head - priv->tx_tail) == priv->tx_max) netif_stop_queue(ndev); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_OK; } @@ -598,7 +621,6 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) if (isr & XCAN_IXR_RXOFLW_MASK) { stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); if (skb) { cf->can_id |= CAN_ERR_CRTL; cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; @@ -710,15 +732,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) isr = priv->read_reg(priv, XCAN_ISR_OFFSET); while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) { - if (isr & XCAN_IXR_RXOK_MASK) { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXOK_MASK); - work_done += xcan_rx(ndev); - } else { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXNEMP_MASK); - break; - } + work_done += xcan_rx(ndev); priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } @@ -729,7 +743,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) if (work_done < quota) { napi_complete(napi); ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK); + ier |= XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); } return work_done; @@ -801,9 +815,9 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) } /* Check for the type of receive interrupt and Processing it */ - if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) { + if (isr & XCAN_IXR_RXNEMP_MASK) { ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK); + ier &= ~XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); napi_schedule(&priv->napi); } @@ -1032,6 +1046,18 @@ static int __maybe_unused xcan_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume); +static const struct xcan_devtype_data xcan_zynq_data = { + .caps = XCAN_CAP_WATERMARK, +}; + +/* Match table for OF platform binding */ +static const struct of_device_id xcan_of_match[] = { + { .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data }, + { .compatible = "xlnx,axi-can-1.00.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xcan_of_match); + /** * xcan_probe - Platform registration call * @pdev: Handle to the platform device structure @@ -1046,8 +1072,10 @@ static int xcan_probe(struct platform_device *pdev) struct resource *res; /* IO mem resources */ struct net_device *ndev; struct xcan_priv *priv; + const struct of_device_id *of_id; + int caps = 0; void __iomem *addr; - int ret, rx_max, tx_max; + int ret, rx_max, tx_max, tx_fifo_depth; /* Get the virtual base address for the device */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1057,7 +1085,8 @@ static int xcan_probe(struct platform_device *pdev) goto err; } - ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max); + ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", + &tx_fifo_depth); if (ret < 0) goto err; @@ -1065,6 +1094,30 @@ static int xcan_probe(struct platform_device *pdev) if (ret < 0) goto err; + of_id = of_match_device(xcan_of_match, &pdev->dev); + if (of_id) { + const struct xcan_devtype_data *devtype_data = of_id->data; + + if (devtype_data) + caps = devtype_data->caps; + } + + /* There is no way to directly figure out how many frames have been + * sent when the TXOK interrupt is processed. If watermark programming + * is supported, we can have 2 frames in the FIFO and use TXFEMP + * to determine if 1 or 2 frames have been sent. + * Theoretically we should be able to use TXFWMEMP to determine up + * to 3 frames, but it seems that after putting a second frame in the + * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less + * than 2 frames in FIFO) is set anyway with no TXOK (a frame was + * sent), which is not a sensible state - possibly TXFWMEMP is not + * completely synchronized with the rest of the bits? + */ + if (caps & XCAN_CAP_WATERMARK) + tx_max = min(tx_fifo_depth, 2); + else + tx_max = 1; + /* Create a CAN device instance */ ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); if (!ndev) @@ -1079,6 +1132,7 @@ static int xcan_probe(struct platform_device *pdev) CAN_CTRLMODE_BERR_REPORTING; priv->reg_base = addr; priv->tx_max = tx_max; + spin_lock_init(&priv->tx_lock); /* Get IRQ for the device */ ndev->irq = platform_get_irq(pdev, 0); @@ -1146,9 +1200,9 @@ static int xcan_probe(struct platform_device *pdev) devm_can_led_init(ndev); clk_disable_unprepare(priv->bus_clk); clk_disable_unprepare(priv->can_clk); - netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", + netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n", priv->reg_base, ndev->irq, priv->can.clock.freq, - priv->tx_max); + tx_fifo_depth, priv->tx_max); return 0; @@ -1184,14 +1238,6 @@ static int xcan_remove(struct platform_device *pdev) return 0; } -/* Match table for OF platform binding */ -static struct of_device_id xcan_of_match[] = { - { .compatible = "xlnx,zynq-can-1.0", }, - { .compatible = "xlnx,axi-can-1.00.a", }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(of, xcan_of_match); - static struct platform_driver xcan_driver = { .probe = xcan_probe, .remove = xcan_remove, diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c index 48775b88bac72a9de44342b4c43b04e33dead760..247879a68f293fa133b9b073e7a2d82c19ea9e15 100644 --- a/drivers/net/ethernet/3com/typhoon.c +++ b/drivers/net/ethernet/3com/typhoon.c @@ -2366,9 +2366,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * 4) Get the hardware address. * 5) Put the card to sleep. */ - if (typhoon_reset(ioaddr, WaitSleep) < 0) { + err = typhoon_reset(ioaddr, WaitSleep); + if (err < 0) { err_msg = "could not reset 3XP"; - err = -EIO; goto error_out_dma; } @@ -2382,24 +2382,25 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) typhoon_init_interface(tp); typhoon_init_rings(tp); - if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) { + err = typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST); + if (err < 0) { err_msg = "cannot boot 3XP sleep image"; - err = -EIO; goto error_out_reset; } INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS); - if(typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp) < 0) { + err = typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp); + if (err < 0) { err_msg = "cannot read MAC address"; - err = -EIO; goto error_out_reset; } *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1)); *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2)); - if(!is_valid_ether_addr(dev->dev_addr)) { + if (!is_valid_ether_addr(dev->dev_addr)) { err_msg = "Could not obtain valid ethernet address, aborting"; + err = -EIO; goto error_out_reset; } @@ -2407,7 +2408,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * later when we print out the version reported. */ INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS); - if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) { + err = typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp); + if (err < 0) { err_msg = "Could not get Sleep Image version"; goto error_out_reset; } @@ -2424,9 +2426,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if(xp_resp[0].numDesc != 0) tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET; - if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) { + err = typhoon_sleep(tp, PCI_D3hot, 0); + if (err < 0) { err_msg = "cannot put adapter to sleep"; - err = -EIO; goto error_out_reset; } @@ -2449,7 +2451,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->features = dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXCSUM; - if(register_netdev(dev) < 0) { + err = register_netdev(dev); + if (err < 0) { err_msg = "unable to register netdev"; goto error_out_reset; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 789957d43a1379939e2aa9b8d15f267473a271a6..ef301f45cbdc776379385658ebaca54e9f87ddfb 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -124,7 +124,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 7ba83ffb08ac73b6437f1fd4a87c3a560b9d4f84..570e5284ff5f0ecc92ad0ac445ff124b4773d77f 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -535,6 +535,7 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb); cb |= CFG_CLE_BYPASS_EN0; CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); + CFG_CLE_IP_HDR_LEN_SET(&cb, 0); xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb); xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index ec45f3256f0e3da2928c8be98ba9abcc0d58fb27..66c3d0cd506fb7ec5da22527db0cebe49b7d5283 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -143,6 +143,7 @@ enum xgene_enet_rm { #define CFG_TXCLK_MUXSEL0_SET(dst, val) xgene_set_bits(dst, val, 29, 3) #define CFG_CLE_IP_PROTOCOL0_SET(dst, val) xgene_set_bits(dst, val, 16, 2) +#define CFG_CLE_IP_HDR_LEN_SET(dst, val) xgene_set_bits(dst, val, 8, 5) #define CFG_CLE_DSTQID0_SET(dst, val) xgene_set_bits(dst, val, 0, 12) #define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4) #define CFG_MACMODE_SET(dst, val) xgene_set_bits(dst, val, 18, 2) diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index abe1eabc017177ede3d1bdc7df6bec5a8ded86da..9cc5daed13eddab50620179dbd1ce2f236fe9650 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -250,39 +250,48 @@ static int arc_emac_rx(struct net_device *ndev, int budget) continue; } - pktlen = info & LEN_MASK; - stats->rx_packets++; - stats->rx_bytes += pktlen; - skb = rx_buff->skb; - skb_put(skb, pktlen); - skb->dev = ndev; - skb->protocol = eth_type_trans(skb, ndev); - - dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr), - dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE); - - /* Prepare the BD for next cycle */ - rx_buff->skb = netdev_alloc_skb_ip_align(ndev, - EMAC_BUFFER_SIZE); - if (unlikely(!rx_buff->skb)) { + /* Prepare the BD for next cycle. netif_receive_skb() + * only if new skb was allocated and mapped to avoid holes + * in the RX fifo. + */ + skb = netdev_alloc_skb_ip_align(ndev, EMAC_BUFFER_SIZE); + if (unlikely(!skb)) { + if (net_ratelimit()) + netdev_err(ndev, "cannot allocate skb\n"); + /* Return ownership to EMAC */ + rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); stats->rx_errors++; - /* Because receive_skb is below, increment rx_dropped */ stats->rx_dropped++; continue; } - /* receive_skb only if new skb was allocated to avoid holes */ - netif_receive_skb(skb); - - addr = dma_map_single(&ndev->dev, (void *)rx_buff->skb->data, + addr = dma_map_single(&ndev->dev, (void *)skb->data, EMAC_BUFFER_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(&ndev->dev, addr)) { if (net_ratelimit()) - netdev_err(ndev, "cannot dma map\n"); - dev_kfree_skb(rx_buff->skb); + netdev_err(ndev, "cannot map dma buffer\n"); + dev_kfree_skb(skb); + /* Return ownership to EMAC */ + rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); stats->rx_errors++; + stats->rx_dropped++; continue; } + + /* unmap previosly mapped skb */ + dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr), + dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE); + + pktlen = info & LEN_MASK; + stats->rx_packets++; + stats->rx_bytes += pktlen; + skb_put(rx_buff->skb, pktlen); + rx_buff->skb->dev = ndev; + rx_buff->skb->protocol = eth_type_trans(rx_buff->skb, ndev); + + netif_receive_skb(rx_buff->skb); + + rx_buff->skb = skb; dma_unmap_addr_set(rx_buff, addr, addr); dma_unmap_len_set(rx_buff, len, EMAC_BUFFER_SIZE); diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c index c31c7407b75353c1d2d4f855957b13098a65ab96..425dae560322378ad8c9e9e9e26d95e58600de07 100644 --- a/drivers/net/ethernet/arc/emac_rockchip.c +++ b/drivers/net/ethernet/arc/emac_rockchip.c @@ -150,8 +150,10 @@ static int emac_rockchip_probe(struct platform_device *pdev) /* Optional regulator for PHY */ priv->regulator = devm_regulator_get_optional(dev, "phy"); if (IS_ERR(priv->regulator)) { - if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) { + err = -EPROBE_DEFER; + goto out_clk_disable; + } dev_err(dev, "no regulator found\n"); priv->regulator = NULL; } diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 067f2cb9b215a8908e72e0855c5b6683bae86e24..ae05c8734d495737b0e8882498c841a1d06cb67e 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1674,6 +1674,7 @@ static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter) skb = build_skb(page_address(page) + adapter->rx_page_offset, adapter->rx_frag_size); if (likely(skb)) { + skb_reserve(skb, NET_SKB_PAD); adapter->rx_page_offset += adapter->rx_frag_size; if (adapter->rx_page_offset >= PAGE_SIZE) adapter->rx_page = NULL; diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 3e8d1a88ed3d7b597298100798e5286449ffafe8..101ff33c90917a9a9c92d1a88868b97286c6605d 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1063,7 +1063,8 @@ static int bcm_enet_open(struct net_device *dev) val = enet_readl(priv, ENET_CTL_REG); val |= ENET_CTL_ENABLE_MASK; enet_writel(priv, val, ENET_CTL_REG); - enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); + if (priv->dma_has_sram) + enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); enet_dmac_writel(priv, priv->dma_chan_en_mask, ENETDMAC_CHANCFG, priv->rx_chan); @@ -1788,7 +1789,9 @@ static int bcm_enet_probe(struct platform_device *pdev) ret = PTR_ERR(priv->mac_clk); goto out; } - clk_prepare_enable(priv->mac_clk); + ret = clk_prepare_enable(priv->mac_clk); + if (ret) + goto out_put_clk_mac; /* initialize default and fetch platform data */ priv->rx_ring_size = BCMENET_DEF_RX_DESC; @@ -1820,9 +1823,11 @@ static int bcm_enet_probe(struct platform_device *pdev) if (IS_ERR(priv->phy_clk)) { ret = PTR_ERR(priv->phy_clk); priv->phy_clk = NULL; - goto out_put_clk_mac; + goto out_disable_clk_mac; } - clk_prepare_enable(priv->phy_clk); + ret = clk_prepare_enable(priv->phy_clk); + if (ret) + goto out_put_clk_phy; } /* do minimal hardware init to be able to probe mii bus */ @@ -1922,13 +1927,16 @@ out_free_mdio: out_uninit_hw: /* turn off mdc clock */ enet_writel(priv, 0, ENET_MIISC_REG); - if (priv->phy_clk) { + if (priv->phy_clk) clk_disable_unprepare(priv->phy_clk); + +out_put_clk_phy: + if (priv->phy_clk) clk_put(priv->phy_clk); - } -out_put_clk_mac: +out_disable_clk_mac: clk_disable_unprepare(priv->mac_clk); +out_put_clk_mac: clk_put(priv->mac_clk); out: free_netdev(dev); @@ -2769,7 +2777,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev) ret = PTR_ERR(priv->mac_clk); goto out_unmap; } - clk_enable(priv->mac_clk); + ret = clk_prepare_enable(priv->mac_clk); + if (ret) + goto out_put_clk; priv->rx_chan = 0; priv->tx_chan = 1; @@ -2790,7 +2800,7 @@ static int bcm_enetsw_probe(struct platform_device *pdev) ret = register_netdev(dev); if (ret) - goto out_put_clk; + goto out_disable_clk; netif_carrier_off(dev); platform_set_drvdata(pdev, dev); @@ -2799,6 +2809,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev) return 0; +out_disable_clk: + clk_disable_unprepare(priv->mac_clk); + out_put_clk: clk_put(priv->mac_clk); @@ -2830,6 +2843,9 @@ static int bcm_enetsw_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); + clk_disable_unprepare(priv->mac_clk); + clk_put(priv->mac_clk); + free_netdev(dev); return 0; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 2559206d8704604150ba8ae59d8d2a3c903c4052..3a794871423bb9bff0f72bf7ffcb0aa59fe376d9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -22,7 +22,7 @@ #include #include -#include +#include /* compilation time flags */ @@ -1613,6 +1613,7 @@ struct bnx2x { struct link_vars link_vars; u32 link_cnt; struct bnx2x_link_report_data last_reported_link; + bool force_link_down; struct mdio_if_info mdio; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index c4ad4b3902390af85b69738bbfdf26daaa0d1a46..82e6c7f12ec268443550052dba1c7d598e8b1bda 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1257,6 +1257,11 @@ void __bnx2x_link_report(struct bnx2x *bp) { struct bnx2x_link_report_data cur_data; + if (bp->force_link_down) { + bp->link_vars.link_up = 0; + return; + } + /* reread mf_cfg */ if (IS_PF(bp) && !CHIP_IS_E1(bp)) bnx2x_read_mf_cfg(bp); @@ -2024,6 +2029,7 @@ static void bnx2x_set_rx_buf_size(struct bnx2x *bp) ETH_OVREHEAD + mtu + BNX2X_FW_RX_ALIGN_END; + fp->rx_buf_size = SKB_DATA_ALIGN(fp->rx_buf_size); /* Note : rx_buf_size doesn't take into account NET_SKB_PAD */ if (fp->rx_buf_size + NET_SKB_PAD <= PAGE_SIZE) fp->rx_frag_size = fp->rx_buf_size + NET_SKB_PAD; @@ -2798,6 +2804,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bp->pending_max = 0; } + bp->force_link_down = false; if (bp->port.pmf) { rc = bnx2x_initial_phy_init(bp, load_mode); if (rc) @@ -2994,7 +3001,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) del_timer_sync(&bp->timer); - if (IS_PF(bp)) { + if (IS_PF(bp) && !BP_NOMCP(bp)) { /* Set ALWAYS_ALIVE bit in shmem */ bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE; bnx2x_drv_pulse(bp); @@ -3076,7 +3083,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) bp->cnic_loaded = false; /* Clear driver version indication in shmem */ - if (IS_PF(bp)) + if (IS_PF(bp) && !BP_NOMCP(bp)) bnx2x_update_mng_version(bp); /* Check if there are pending parity attentions. If there are - set @@ -3875,15 +3882,26 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* when transmitting in a vf, start bd must hold the ethertype * for fw to enforce it */ + u16 vlan_tci = 0; #ifndef BNX2X_STOP_ON_ERROR - if (IS_VF(bp)) + if (IS_VF(bp)) { #endif - tx_start_bd->vlan_or_ethertype = - cpu_to_le16(ntohs(eth->h_proto)); + /* Still need to consider inband vlan for enforced */ + if (__vlan_get_tag(skb, &vlan_tci)) { + tx_start_bd->vlan_or_ethertype = + cpu_to_le16(ntohs(eth->h_proto)); + } else { + tx_start_bd->bd_flags.as_bitfield |= + (X_ETH_INBAND_VLAN << + ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT); + tx_start_bd->vlan_or_ethertype = + cpu_to_le16(vlan_tci); + } #ifndef BNX2X_STOP_ON_ERROR - else + } else { /* used by FW for packet accounting */ tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod); + } #endif } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 1edc931b145848b238d2450b5c2468d029644feb..2a518c998ecc0b49ad64a024f816950a84634d4d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -3296,14 +3296,18 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info) DP(BNX2X_MSG_ETHTOOL, "rss re-configured, UDP 4-tupple %s\n", udp_rss_requested ? "enabled" : "disabled"); - return bnx2x_rss(bp, &bp->rss_conf_obj, false, true); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_rss(bp, &bp->rss_conf_obj, false, + true); } else if ((info->flow_type == UDP_V6_FLOW) && (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; DP(BNX2X_MSG_ETHTOOL, "rss re-configured, UDP 4-tupple %s\n", udp_rss_requested ? "enabled" : "disabled"); - return bnx2x_rss(bp, &bp->rss_conf_obj, false, true); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_rss(bp, &bp->rss_conf_obj, false, + true); } return 0; @@ -3401,7 +3405,10 @@ static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id; } - return bnx2x_config_rss_eth(bp, false); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_config_rss_eth(bp, false); + + return 0; } /** diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 549549eaf580f79518295bd4a13234cef8520968..8beea2750808255c7782701813fd5d1d662310f1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -588,7 +588,7 @@ static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params, * slots for the highest priority. */ REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS : - NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); /* Mapping between the CREDIT_WEIGHT registers and actual client * numbers */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 1217eafb61a44b5e4593915a3567f011f21e7182..4d389a032cfd8084017c676b34d05b68c4ecedca 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9472,6 +9472,15 @@ static int bnx2x_init_shmem(struct bnx2x *bp) do { bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + + /* If we read all 0xFFs, means we are in PCI error state and + * should bail out to avoid crashes on adapter's FW reads. + */ + if (bp->common.shmem_base == 0xFFFFFFFF) { + bp->flags |= NO_MCP_FLAG; + return -ENODEV; + } + if (bp->common.shmem_base) { val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); if (val & SHR_MEM_VALIDITY_MB) @@ -10027,6 +10036,12 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work) bp->sp_rtnl_state = 0; smp_mb(); + /* Immediately indicate link as down */ + bp->link_vars.link_up = 0; + bp->force_link_down = true; + netif_carrier_off(bp->dev); + BNX2X_ERR("Indicating link is down due to Tx-timeout\n"); + bnx2x_nic_unload(bp, UNLOAD_NORMAL, true); bnx2x_nic_load(bp, LOAD_NORMAL); @@ -13743,7 +13758,10 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev) BNX2X_ERR("IO slot reset --> driver unload\n"); /* MCP should have been reset; Need to wait for validity */ - bnx2x_init_shmem(bp); + if (bnx2x_init_shmem(bp)) { + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) { u32 v; @@ -14607,7 +14625,7 @@ static void bnx2x_init_cyclecounter(struct bnx2x *bp) { memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter)); bp->cyclecounter.read = bnx2x_cyclecounter_read; - bp->cyclecounter.mask = CLOCKSOURCE_MASK(64); + bp->cyclecounter.mask = CYCLECOUNTER_MASK(64); bp->cyclecounter.shift = 1; bp->cyclecounter.mult = 1; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index b1d9c44aa56c919732721207d88163cda8080a53..07eba80f6fb1279fe31a3467b316a2483b3f8197 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -826,7 +826,7 @@ int bnx2x_vfpf_set_mcast(struct net_device *dev) struct bnx2x *bp = netdev_priv(dev); struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; - int rc, i = 0; + int rc = 0, i = 0; struct netdev_hw_addr *ha; if (bp->state != BNX2X_STATE_OPEN) { @@ -841,6 +841,15 @@ int bnx2x_vfpf_set_mcast(struct net_device *dev) /* Get Rx mode requested */ DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags); + /* We support PFVF_MAX_MULTICAST_PER_VF mcast addresses tops */ + if (netdev_mc_count(dev) > PFVF_MAX_MULTICAST_PER_VF) { + DP(NETIF_MSG_IFUP, + "VF supports not more than %d multicast MAC addresses\n", + PFVF_MAX_MULTICAST_PER_VF); + rc = -EINVAL; + goto out; + } + netdev_for_each_mc_addr(ha, dev) { DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n", bnx2x_mc_addr(ha)); @@ -848,16 +857,6 @@ int bnx2x_vfpf_set_mcast(struct net_device *dev) i++; } - /* We support four PFVF_MAX_MULTICAST_PER_VF mcast - * addresses tops - */ - if (i >= PFVF_MAX_MULTICAST_PER_VF) { - DP(NETIF_MSG_IFUP, - "VF supports not more than %d multicast MAC addresses\n", - PFVF_MAX_MULTICAST_PER_VF); - return -EINVAL; - } - req->n_multicast = i; req->flags |= VFPF_SET_Q_FILTERS_MULTICAST_CHANGED; req->vf_qid = 0; @@ -882,7 +881,7 @@ int bnx2x_vfpf_set_mcast(struct net_device *dev) out: bnx2x_vfpf_finalize(bp, &req->first_tlv); - return 0; + return rc; } int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 936448e4894ce33f9fbc3fe643bf743c80c7247b..87f0f6e0a15cd89ab7811be5d0db291883a3bc79 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1,7 +1,7 @@ /* * Broadcom GENET (Gigabit Ethernet) controller driver * - * Copyright (c) 2014 Broadcom Corporation + * Copyright (c) 2014-2017 Broadcom * * 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 @@ -610,8 +610,9 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { STAT_GENET_RUNT("rx_runt_bytes", mib.rx_runt_bytes), /* Misc UniMAC counters */ STAT_GENET_MISC("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, - UMAC_RBUF_OVFL_CNT), - STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT), + UMAC_RBUF_OVFL_CNT_V1), + STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, + UMAC_RBUF_ERR_CNT_V1), STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT), }; @@ -651,6 +652,45 @@ static void bcmgenet_get_strings(struct net_device *dev, u32 stringset, } } +static u32 bcmgenet_update_stat_misc(struct bcmgenet_priv *priv, u16 offset) +{ + u16 new_offset; + u32 val; + + switch (offset) { + case UMAC_RBUF_OVFL_CNT_V1: + if (GENET_IS_V2(priv)) + new_offset = RBUF_OVFL_CNT_V2; + else + new_offset = RBUF_OVFL_CNT_V3PLUS; + + val = bcmgenet_rbuf_readl(priv, new_offset); + /* clear if overflowed */ + if (val == ~0) + bcmgenet_rbuf_writel(priv, 0, new_offset); + break; + case UMAC_RBUF_ERR_CNT_V1: + if (GENET_IS_V2(priv)) + new_offset = RBUF_ERR_CNT_V2; + else + new_offset = RBUF_ERR_CNT_V3PLUS; + + val = bcmgenet_rbuf_readl(priv, new_offset); + /* clear if overflowed */ + if (val == ~0) + bcmgenet_rbuf_writel(priv, 0, new_offset); + break; + default: + val = bcmgenet_umac_readl(priv, offset); + /* clear if overflowed */ + if (val == ~0) + bcmgenet_umac_writel(priv, 0, offset); + break; + } + + return val; +} + static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) { int i, j = 0; @@ -665,19 +705,28 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) switch (s->type) { case BCMGENET_STAT_NETDEV: continue; - case BCMGENET_STAT_MIB_RX: - case BCMGENET_STAT_MIB_TX: case BCMGENET_STAT_RUNT: - if (s->type != BCMGENET_STAT_MIB_RX) - offset = BCMGENET_STAT_OFFSET; + offset += BCMGENET_STAT_OFFSET; + /* fall through */ + case BCMGENET_STAT_MIB_TX: + offset += BCMGENET_STAT_OFFSET; + /* fall through */ + case BCMGENET_STAT_MIB_RX: val = bcmgenet_umac_readl(priv, UMAC_MIB_START + j + offset); + offset = 0; /* Reset Offset */ break; case BCMGENET_STAT_MISC: - val = bcmgenet_umac_readl(priv, s->reg_offset); - /* clear if overflowed */ - if (val == ~0) - bcmgenet_umac_writel(priv, 0, s->reg_offset); + if (GENET_IS_V1(priv)) { + val = bcmgenet_umac_readl(priv, s->reg_offset); + /* clear if overflowed */ + if (val == ~0) + bcmgenet_umac_writel(priv, 0, + s->reg_offset); + } else { + val = bcmgenet_update_stat_misc(priv, + s->reg_offset); + } break; } @@ -2549,6 +2598,7 @@ static int bcmgenet_probe(struct platform_device *pdev) const void *macaddr; struct resource *r; int err = -EIO; + const char *phy_mode_str; /* Up to GENET_MAX_MQ_CNT + 1 TX queues and a single RX queue */ dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1, 1); @@ -2636,6 +2686,13 @@ static int bcmgenet_probe(struct platform_device *pdev) if (IS_ERR(priv->clk_wol)) dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n"); + /* If this is an internal GPHY, power it on now, before UniMAC is + * brought out of reset as absolutely no UniMAC activity is allowed + */ + if (dn && !of_property_read_string(dn, "phy-mode", &phy_mode_str) && + !strcasecmp(phy_mode_str, "internal")) + bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + err = reset_umac(priv); if (err) goto err_clk_disable; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index eeda0281c684ed52d9c4eeb2d44242435c373619..942271f9ab192b5913a10b0b4abec4e38eee1345 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Broadcom Corporation + * Copyright (c) 2014-2017 Broadcom * * 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 @@ -196,7 +196,9 @@ struct bcmgenet_mib_counters { #define MDIO_REG_SHIFT 16 #define MDIO_REG_MASK 0x1F -#define UMAC_RBUF_OVFL_CNT 0x61C +#define UMAC_RBUF_OVFL_CNT_V1 0x61C +#define RBUF_OVFL_CNT_V2 0x80 +#define RBUF_OVFL_CNT_V3PLUS 0x94 #define UMAC_MPD_CTRL 0x620 #define MPD_EN (1 << 0) @@ -206,7 +208,9 @@ struct bcmgenet_mib_counters { #define UMAC_MPD_PW_MS 0x624 #define UMAC_MPD_PW_LS 0x628 -#define UMAC_RBUF_ERR_CNT 0x634 +#define UMAC_RBUF_ERR_CNT_V1 0x634 +#define RBUF_ERR_CNT_V2 0x84 +#define RBUF_ERR_CNT_V3PLUS 0x98 #define UMAC_MDF_ERR_CNT 0x638 #define UMAC_MDF_CTRL 0x650 #define UMAC_MDF_ADDR 0x654 diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index a79e73781c0bbb8c94c9f55085284037ecea7347..4dbe218f2de296e861be5d69f99c187bb7fef39c 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8705,14 +8705,15 @@ static void tg3_free_consistent(struct tg3 *tp) tg3_mem_rx_release(tp); tg3_mem_tx_release(tp); - /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */ - tg3_full_lock(tp, 0); + /* tp->hw_stats can be referenced safely: + * 1. under rtnl_lock + * 2. or under tp->lock if TG3_FLAG_INIT_COMPLETE is set. + */ if (tp->hw_stats) { dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats), tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } - tg3_full_unlock(tp); } /* @@ -10028,6 +10029,16 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) tw32(GRC_MODE, tp->grc_mode | val); + /* On one of the AMD platform, MRRS is restricted to 4000 because of + * south bridge limitation. As a workaround, Driver is setting MRRS + * to 2048 instead of default 4096. + */ + if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && + tp->pdev->subsystem_device == TG3PCI_SUBDEVICE_ID_DELL_5762) { + val = tr32(TG3PCI_DEV_STATUS_CTRL) & ~MAX_READ_REQ_MASK; + tw32(TG3PCI_DEV_STATUS_CTRL, val | MAX_READ_REQ_SIZE_2048); + } + /* Setup the timer prescalar register. Clock is always 66Mhz. */ val = tr32(GRC_MISC_CFG); val &= ~0xff; @@ -14127,7 +14138,7 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, struct tg3 *tp = netdev_priv(dev); spin_lock_bh(&tp->lock); - if (!tp->hw_stats) { + if (!tp->hw_stats || !tg3_flag(tp, INIT_COMPLETE)) { *stats = tp->net_stats_prev; spin_unlock_bh(&tp->lock); return stats; @@ -14202,7 +14213,10 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) /* Reset PHY, otherwise the read DMA engine will be in a mode that * breaks all requests to 256 bytes. */ - if (tg3_asic_rev(tp) == ASIC_REV_57766) + if (tg3_asic_rev(tp) == ASIC_REV_57766 || + tg3_asic_rev(tp) == ASIC_REV_5717 || + tg3_asic_rev(tp) == ASIC_REV_5719 || + tg3_asic_rev(tp) == ASIC_REV_5720) reset_phy = true; err = tg3_restart_hw(tp, reset_phy); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 31c9f829595384cb843e299c6b51054101d8f6c6..19532961e1737baf5261273358ae0996b1a093df 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -95,6 +95,7 @@ #define TG3PCI_SUBDEVICE_ID_DELL_JAGUAR 0x0106 #define TG3PCI_SUBDEVICE_ID_DELL_MERLOT 0x0109 #define TG3PCI_SUBDEVICE_ID_DELL_SLIM_MERLOT 0x010a +#define TG3PCI_SUBDEVICE_ID_DELL_5762 0x07f0 #define TG3PCI_SUBVENDOR_ID_COMPAQ PCI_VENDOR_ID_COMPAQ #define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE 0x007c #define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE_2 0x009a @@ -280,6 +281,9 @@ #define TG3PCI_STD_RING_PROD_IDX 0x00000098 /* 64-bit */ #define TG3PCI_RCV_RET_RING_CON_IDX 0x000000a0 /* 64-bit */ /* 0xa8 --> 0xb8 unused */ +#define TG3PCI_DEV_STATUS_CTRL 0x000000b4 +#define MAX_READ_REQ_SIZE_2048 0x00004000 +#define MAX_READ_REQ_MASK 0x00007000 #define TG3PCI_DUAL_MAC_CTRL 0x000000b8 #define DUAL_MAC_CTRL_CH_MASK 0x00000003 #define DUAL_MAC_CTRL_ID 0x00000004 diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c index 354ae9792badb329e89b0ab37f59ff78c73efd11..27651d26fb8a30a1352b57a0e149cd7243e791c2 100644 --- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c +++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c @@ -2856,7 +2856,7 @@ bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver) static void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer) { - memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN); + strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN); } static void diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 4d9fc0509af68c91cfd7c7e45f5aa3ec96b7bf88..b3e134e53bf11849e08f3afc097603a0d0acfa8e 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -464,7 +464,7 @@ static int macb_halt_tx(struct macb *bp) if (!(status & MACB_BIT(TGO))) return 0; - usleep_range(10, 250); + udelay(250); } while (time_before(halt_time, timeout)); return -ETIMEDOUT; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index a9db2337d9e29ca57953c1e376e76bb112f20007..faee5ed88e5c15fff7cb38c89d10e21b52c3dce2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -529,7 +529,7 @@ static void dcb_tx_queue_prio_enable(struct net_device *dev, int enable) "Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n", enable ? "set" : "unset", pi->port_id, i, -err); else - txq->dcb_prio = value; + txq->dcb_prio = enable ? value : 0; } } #endif /* CONFIG_CHELSIO_T4_DCB */ diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 0be6850be8a2383e11240093bd421dfbd2595595..d911a3e94528e4783c41e42e283274a37fd24b78 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -78,7 +78,6 @@ void enic_rfs_flw_tbl_init(struct enic *enic) enic->rfs_h.max = enic->config.num_arfs; enic->rfs_h.free = enic->rfs_h.max; enic->rfs_h.toclean = 0; - enic_rfs_timer_start(enic); } void enic_rfs_flw_tbl_free(struct enic *enic) @@ -87,7 +86,6 @@ void enic_rfs_flw_tbl_free(struct enic *enic) enic_rfs_timer_stop(enic); spin_lock_bh(&enic->rfs_h.lock); - enic->rfs_h.free = 0; for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { struct hlist_head *hhead; struct hlist_node *tmp; @@ -98,6 +96,7 @@ void enic_rfs_flw_tbl_free(struct enic *enic) enic_delfltr(enic, n->fltr_id); hlist_del(&n->node); kfree(n); + enic->rfs_h.free++; } } spin_unlock_bh(&enic->rfs_h.lock); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 167cd8ede3972c24a611798412b0a71450ec1fbf..04eb59e6b826911d1d6b673f1feeaf4d98797be1 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1643,7 +1643,7 @@ static int enic_open(struct net_device *netdev) vnic_intr_unmask(&enic->intr[i]); enic_notify_timer_start(enic); - enic_rfs_flw_tbl_init(enic); + enic_rfs_timer_start(enic); return 0; @@ -1717,10 +1717,32 @@ static int enic_stop(struct net_device *netdev) return 0; } +static int _enic_change_mtu(struct net_device *netdev, int new_mtu) +{ + bool running = netif_running(netdev); + int err = 0; + + ASSERT_RTNL(); + if (running) { + err = enic_stop(netdev); + if (err) + return err; + } + + netdev->mtu = new_mtu; + + if (running) { + err = enic_open(netdev); + if (err) + return err; + } + + return 0; +} + static int enic_change_mtu(struct net_device *netdev, int new_mtu) { struct enic *enic = netdev_priv(netdev); - int running = netif_running(netdev); if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU) return -EINVAL; @@ -1728,20 +1750,12 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu) if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) return -EOPNOTSUPP; - if (running) - enic_stop(netdev); - - netdev->mtu = new_mtu; - if (netdev->mtu > enic->port_mtu) netdev_warn(netdev, - "interface MTU (%d) set higher than port MTU (%d)\n", - netdev->mtu, enic->port_mtu); + "interface MTU (%d) set higher than port MTU (%d)\n", + netdev->mtu, enic->port_mtu); - if (running) - enic_open(netdev); - - return 0; + return _enic_change_mtu(netdev, new_mtu); } static void enic_change_mtu_work(struct work_struct *work) @@ -1749,47 +1763,9 @@ static void enic_change_mtu_work(struct work_struct *work) struct enic *enic = container_of(work, struct enic, change_mtu_work); struct net_device *netdev = enic->netdev; int new_mtu = vnic_dev_mtu(enic->vdev); - int err; - unsigned int i; - - new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu)); rtnl_lock(); - - /* Stop RQ */ - del_timer_sync(&enic->notify_timer); - - for (i = 0; i < enic->rq_count; i++) - napi_disable(&enic->napi[i]); - - vnic_intr_mask(&enic->intr[0]); - enic_synchronize_irqs(enic); - err = vnic_rq_disable(&enic->rq[0]); - if (err) { - rtnl_unlock(); - netdev_err(netdev, "Unable to disable RQ.\n"); - return; - } - vnic_rq_clean(&enic->rq[0], enic_free_rq_buf); - vnic_cq_clean(&enic->cq[0]); - vnic_intr_clean(&enic->intr[0]); - - /* Fill RQ with new_mtu-sized buffers */ - netdev->mtu = new_mtu; - vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); - /* Need at least one buffer on ring to get going */ - if (vnic_rq_desc_used(&enic->rq[0]) == 0) { - rtnl_unlock(); - netdev_err(netdev, "Unable to alloc receive buffers.\n"); - return; - } - - /* Start RQ */ - vnic_rq_enable(&enic->rq[0]); - napi_enable(&enic->napi[0]); - vnic_intr_unmask(&enic->intr[0]); - enic_notify_timer_start(enic); - + (void)_enic_change_mtu(netdev, new_mtu); rtnl_unlock(); netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu); @@ -2362,11 +2338,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); /* Query PCI controller on system for DMA addressing - * limitation for the device. Try 64-bit first, and + * limitation for the device. Try 47-bit first, and * fail to 32-bit. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { @@ -2380,10 +2356,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_release_regions; } } else { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { dev_err(dev, "Unable to obtain %u-bit DMA " - "for consistent allocations, aborting\n", 64); + "for consistent allocations, aborting\n", 47); goto err_out_release_regions; } using_dac = 1; @@ -2508,6 +2484,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) enic->notify_timer.function = enic_notify_timer; enic->notify_timer.data = (unsigned long)enic; + enic_rfs_flw_tbl_init(enic); enic_set_rx_coal_setting(enic); INIT_WORK(&enic->reset, enic_reset); INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work); @@ -2519,7 +2496,6 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ enic->port_mtu = enic->config.mtu; - (void)enic_change_mtu(netdev, enic->port_mtu); err = enic_set_mac_addr(netdev, enic->mac_addr); if (err) { @@ -2568,6 +2544,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features |= NETIF_F_HIGHDMA; netdev->priv_flags |= IFF_UNICAST_FLT; + netdev->mtu = enic->port_mtu; err = register_netdev(netdev); if (err) { diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index c77fa4a6984458648a97960deeef2d0a54b6637c..0900fd5098eb5fdde5cb916eca6279238e33cf14 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index b1b9ebafb354d28676f85b5b9522655e0daeaff1..a3b2e23921bfa4219cd10b74370e83028c7e7d8f 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -257,8 +257,8 @@ enum rx_desc_status_bits { RXFSD = 0x00000800, /* first descriptor */ RXLSD = 0x00000400, /* last descriptor */ ErrorSummary = 0x80, /* error summary */ - RUNT = 0x40, /* runt packet received */ - LONG = 0x20, /* long packet received */ + RUNTPKT = 0x40, /* runt packet received */ + LONGPKT = 0x20, /* long packet received */ FAE = 0x10, /* frame align error */ CRC = 0x08, /* crc error */ RXER = 0x04, /* receive error */ @@ -1633,7 +1633,7 @@ static int netdev_rx(struct net_device *dev) dev->name, rx_status); dev->stats.rx_errors++; /* end of a packet. */ - if (rx_status & (LONG | RUNT)) + if (rx_status & (LONGPKT | RUNTPKT)) dev->stats.rx_length_errors++; if (rx_status & RXER) dev->stats.rx_frame_errors++; diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 9af296a1ca999f3e659f2ec41d140f14da87149b..5e13f31e750608a05db8cccdb21195e3f703a79c 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -16,6 +16,7 @@ #include #include #include +#include #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ @@ -546,6 +547,7 @@ struct fec_enet_private { }; void fec_ptp_init(struct platform_device *pdev); +void fec_ptp_stop(struct platform_device *pdev); void fec_ptp_start_cyclecounter(struct net_device *ndev); int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 51f65299094b28d6e861e86d7d1940a81bfda252..02262b8e57ee264c2d0be2ae3c14c70277f31526 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -58,6 +58,7 @@ #include #include #include +#include #include @@ -2793,6 +2794,7 @@ static void set_multicast_list(struct net_device *ndev) struct netdev_hw_addr *ha; unsigned int i, bit, data, crc, tmp; unsigned char hash; + unsigned int hash_high = 0, hash_low = 0; if (ndev->flags & IFF_PROMISC) { tmp = readl(fep->hwp + FEC_R_CNTRL); @@ -2815,11 +2817,7 @@ static void set_multicast_list(struct net_device *ndev) return; } - /* Clear filter and add the addresses in hash register - */ - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - + /* Add the addresses in hash register */ netdev_for_each_mc_addr(ha, ndev) { /* calculate crc32 value of mac address */ crc = 0xffffffff; @@ -2837,16 +2835,14 @@ static void set_multicast_list(struct net_device *ndev) */ hash = (crc >> (32 - HASH_BITS)) & 0x3f; - if (hash > 31) { - tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - tmp |= 1 << (hash - 32); - writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - } else { - tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); - tmp |= 1 << hash; - writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - } + if (hash > 31) + hash_high |= 1 << (hash - 32); + else + hash_low |= 1 << hash; } + + writel(hash_high, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(hash_low, fep->hwp + FEC_GRP_HASH_TABLE_LOW); } /* Set a MAC change in hardware. */ @@ -3317,6 +3313,7 @@ failed_register: failed_mii_init: failed_irq: failed_init: + fec_ptp_stop(pdev); if (fep->reg_phy) regulator_disable(fep->reg_phy); failed_regulator: @@ -3336,15 +3333,15 @@ fec_drv_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); - cancel_delayed_work_sync(&fep->time_keep); cancel_work_sync(&fep->tx_timeout_work); + fec_ptp_stop(pdev); unregister_netdev(ndev); fec_enet_mii_remove(fep); if (fep->reg_phy) regulator_disable(fep->reg_phy); - if (fep->ptp_clock) - ptp_clock_unregister(fep->ptp_clock); fec_enet_clk_enable(ndev, false); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); of_node_put(fep->phy_node); free_netdev(ndev); diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 992c8c3db5536d431284d1569f18ea579594ecaa..9b2dcf4261a5d643329ece6cdad71739725b455f 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -620,6 +620,16 @@ void fec_ptp_init(struct platform_device *pdev) schedule_delayed_work(&fep->time_keep, HZ); } +void fec_ptp_stop(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct fec_enet_private *fep = netdev_priv(ndev); + + cancel_delayed_work_sync(&fep->time_keep); + if (fep->ptp_clock) + ptp_clock_unregister(fep->ptp_clock); +} + /** * fec_ptp_check_pps_event * @fep: the fec_enet_private structure handle diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 964c6bf377104df3eafd6043299d04051b51db5c..4b9f5074ec32c00c23d36fdeafff3f1ab9a1cf63 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -370,7 +370,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) { const struct of_device_id *id = of_match_device(fsl_pq_mdio_match, &pdev->dev); - const struct fsl_pq_mdio_data *data = id->data; + const struct fsl_pq_mdio_data *data; struct device_node *np = pdev->dev.of_node; struct resource res; struct device_node *tbi; @@ -378,6 +378,13 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) struct mii_bus *new_bus; int err; + if (!id) { + dev_err(&pdev->dev, "Failed to match device\n"); + return -ENODEV; + } + + data = id->data; + dev_dbg(&pdev->dev, "found %s compatible node\n", id->compatible); new_bus = mdiobus_alloc_size(sizeof(*priv)); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 4fdf0aa16978baf237ae8f778ed941792e922d90..f239b0c845cdfc5cec31223d18b571e71ee16345 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1356,9 +1356,11 @@ static int gfar_probe(struct platform_device *ofdev) gfar_init_addr_hash_table(priv); - /* Insert receive time stamps into padding alignment bytes */ + /* Insert receive time stamps into padding alignment bytes, and + * plus 2 bytes padding to ensure the cpu alignment. + */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) - priv->padding = 8; + priv->padding = 8 + DEFAULT_PADDING; if (dev->features & NETIF_F_IP_CSUM || priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index bb568006f37df605e808d1d6c7195a09b6e8d48f..50399182355147faf0b4b50aeda2c890045a4f96 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -314,11 +314,10 @@ static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta) now = tmr_cnt_read(etsects); now += delta; tmr_cnt_write(etsects, now); + set_fipers(etsects); spin_unlock_irqrestore(&etsects->lock, flags); - set_fipers(etsects); - return 0; } diff --git a/drivers/net/ethernet/hp/hp100.c b/drivers/net/ethernet/hp/hp100.c index 76a6e0c77d69e1a01544a388b465e7e82ddbfd87..03447100324965122e398d5eee9c879671f11c36 100644 --- a/drivers/net/ethernet/hp/hp100.c +++ b/drivers/net/ethernet/hp/hp100.c @@ -2637,7 +2637,7 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) /* Wait for link to drop */ time = jiffies + (HZ / 10); do { - if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) + if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; if (!in_interrupt()) schedule_timeout_interruptible(1); diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 87bd953cc2eeaef7f6af65902841645e98f7eda5..41ce1aafcc1cae2500ad9c59470492779a172457 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -349,6 +349,7 @@ static int emac_reset(struct emac_instance *dev) { struct emac_regs __iomem *p = dev->emacp; int n = 20; + bool __maybe_unused try_internal_clock = false; DBG(dev, "reset" NL); @@ -361,6 +362,7 @@ static int emac_reset(struct emac_instance *dev) } #ifdef CONFIG_PPC_DCR_NATIVE +do_retry: /* * PPC460EX/GT Embedded Processor Advanced User's Manual * section 28.10.1 Mode Register 0 (EMACx_MR0) states: @@ -368,10 +370,19 @@ static int emac_reset(struct emac_instance *dev) * of the EMAC. If none is present, select the internal clock * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1). * After a soft reset, select the external clock. + * + * The AR8035-A PHY Meraki MR24 does not provide a TX Clk if the + * ethernet cable is not attached. This causes the reset to timeout + * and the PHY detection code in emac_init_phy() is unable to + * communicate and detect the AR8035-A PHY. As a result, the emac + * driver bails out early and the user has no ethernet. + * In order to stay compatible with existing configurations, the + * driver will temporarily switch to the internal clock, after + * the first reset fails. */ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) { - if (dev->phy_address == 0xffffffff && - dev->phy_map == 0xffffffff) { + if (try_internal_clock || (dev->phy_address == 0xffffffff && + dev->phy_map == 0xffffffff)) { /* No PHY: select internal loop clock before reset */ dcri_clrset(SDR0, SDR0_ETH_CFG, 0, SDR0_ETH_CFG_ECS << dev->cell_index); @@ -389,8 +400,15 @@ static int emac_reset(struct emac_instance *dev) #ifdef CONFIG_PPC_DCR_NATIVE if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) { - if (dev->phy_address == 0xffffffff && - dev->phy_map == 0xffffffff) { + if (!n && !try_internal_clock) { + /* first attempt has timed out. */ + n = 20; + try_internal_clock = true; + goto do_retry; + } + + if (try_internal_clock || (dev->phy_address == 0xffffffff && + dev->phy_map == 0xffffffff)) { /* No PHY: restore external clock source after reset */ dcri_clrset(SDR0, SDR0_ETH_CFG, SDR0_ETH_CFG_ECS << dev->cell_index, 0); diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h index 69707108d23cdeb57bda5c6dd5e3e1aa29faa2b6..4cd6dac110f05eb2362f43ade67b3daff64c4ae3 100644 --- a/drivers/net/ethernet/intel/e1000/e1000.h +++ b/drivers/net/ethernet/intel/e1000/e1000.h @@ -328,7 +328,8 @@ struct e1000_adapter { enum e1000_state_t { __E1000_TESTING, __E1000_RESETTING, - __E1000_DOWN + __E1000_DOWN, + __E1000_DISABLED }; #undef pr_fmt diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index b691eb4f63766b281786623f1b533cdcb4fb3a0d..615d2145f41133e93ffb9693dd9e1a9207cc8521 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -646,14 +646,14 @@ static int e1000_set_ringparam(struct net_device *netdev, adapter->tx_ring = tx_old; e1000_free_all_rx_resources(adapter); e1000_free_all_tx_resources(adapter); - kfree(tx_old); - kfree(rx_old); adapter->rx_ring = rxdr; adapter->tx_ring = txdr; err = e1000_up(adapter); if (err) goto err_setup; } + kfree(tx_old); + kfree(rx_old); clear_bit(__E1000_RESETTING, &adapter->flags); return 0; @@ -666,7 +666,8 @@ err_setup_rx: err_alloc_rx: kfree(txdr); err_alloc_tx: - e1000_up(adapter); + if (netif_running(adapter->netdev)) + e1000_up(adapter); err_setup: clear_bit(__E1000_RESETTING, &adapter->flags); return err; diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 3a06cae4ff683363f7d00d7497c3ee4506f0c194..883d971c6cca838517be3f78a382724a0affcc30 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -940,7 +940,7 @@ static int e1000_init_hw_struct(struct e1000_adapter *adapter, static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; - struct e1000_adapter *adapter; + struct e1000_adapter *adapter = NULL; struct e1000_hw *hw; static int cards_found = 0; @@ -950,6 +950,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u16 tmp = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; int bars, need_ioport; + bool disable_dev = false; /* do not allocate ioport bars when not needed */ need_ioport = e1000_is_need_ioport(pdev); @@ -1250,11 +1251,13 @@ err_mdio_ioremap: iounmap(hw->ce4100_gbe_mdio_base_virt); iounmap(hw->hw_addr); err_ioremap: + disable_dev = !test_and_set_bit(__E1000_DISABLED, &adapter->flags); free_netdev(netdev); err_alloc_etherdev: pci_release_selected_regions(pdev, bars); err_pci_reg: - pci_disable_device(pdev); + if (!adapter || disable_dev) + pci_disable_device(pdev); return err; } @@ -1272,6 +1275,7 @@ static void e1000_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + bool disable_dev; e1000_down_and_stop(adapter); e1000_release_manageability(adapter); @@ -1290,9 +1294,11 @@ static void e1000_remove(struct pci_dev *pdev) iounmap(hw->flash_address); pci_release_selected_regions(pdev, adapter->bars); + disable_dev = !test_and_set_bit(__E1000_DISABLED, &adapter->flags); free_netdev(netdev); - pci_disable_device(pdev); + if (disable_dev) + pci_disable_device(pdev); } /** @@ -5137,7 +5143,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) if (netif_running(netdev)) e1000_free_irq(adapter); - pci_disable_device(pdev); + if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags)) + pci_disable_device(pdev); return 0; } @@ -5181,6 +5188,10 @@ static int e1000_resume(struct pci_dev *pdev) pr_err("Cannot enable PCI device from suspend\n"); return err; } + + /* flush memory to make sure state is correct */ + smp_mb__before_atomic(); + clear_bit(__E1000_DISABLED, &adapter->flags); pci_set_master(pdev); pci_enable_wake(pdev, PCI_D3hot, 0); @@ -5255,7 +5266,9 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, if (netif_running(netdev)) e1000_down(adapter); - pci_disable_device(pdev); + + if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags)) + pci_disable_device(pdev); /* Request a slot slot reset. */ return PCI_ERS_RESULT_NEED_RESET; @@ -5283,6 +5296,10 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) pr_err("Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } + + /* flush memory to make sure state is correct */ + smp_mb__before_atomic(); + clear_bit(__E1000_DISABLED, &adapter->flags); pci_set_master(pdev); pci_enable_wake(pdev, PCI_D3hot, 0); diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 7785240a0da1a1b409cfbc3d4b18ff63b5f2966a..9416e5a7e0c82262b078ebda3b1374b8ce58934d 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index feb618468d15c0fd4d2d88e88cd41b50212d97e0..24b4df8fd5e99f13347c2a0e61b1d0f81dc79d73 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1299,6 +1299,9 @@ out: * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. + * + * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link + * up). **/ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) { @@ -1313,7 +1316,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * Change or Rx Sequence Error interrupt. */ if (!mac->get_link_status) - return 0; + return 1; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -1438,7 +1441,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return -E1000_ERR_CONFIG; + return 1; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to @@ -1452,10 +1455,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * different link partner. */ ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) + if (ret_val) { e_dbg("Error configuring flow control\n"); + return ret_val; + } - return ret_val; + return 1; } static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index 30b74d590bee461663291d803bbfd06e042ba255..3aa3e9e813270a6a53299491493f71f5af704dd9 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -410,6 +410,9 @@ void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw) * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. + * + * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link + * up). **/ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) { @@ -423,7 +426,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * Change or Rx Sequence Error interrupt. */ if (!mac->get_link_status) - return 0; + return 1; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -447,7 +450,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return -E1000_ERR_CONFIG; + return 1; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to @@ -461,10 +464,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * different link partner. */ ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) + if (ret_val) { e_dbg("Error configuring flow control\n"); + return ret_val; + } - return ret_val; + return 1; } /** diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 247335d2c7ec26cb9c50bb93c6a675b4ff35879a..0bf0d12f9282d443c899f2b324c5730bb5b82c03 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1181,6 +1181,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) struct e1000_hw *hw = &adapter->hw; if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) { + struct sk_buff *skb = adapter->tx_hwtstamp_skb; struct skb_shared_hwtstamps shhwtstamps; u64 txstmp; @@ -1189,9 +1190,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp); - skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->tx_hwtstamp_skb); + /* Clear the global tx_hwtstamp_skb pointer and force writes + * prior to notifying the stack of a Tx timestamp. + */ adapter->tx_hwtstamp_skb = NULL; + wmb(); /* force write prior to skb_tstamp_tx */ + + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } else if (time_after(jiffies, adapter->tx_hwtstamp_start + adapter->tx_timeout_factor * HZ)) { dev_kfree_skb_any(adapter->tx_hwtstamp_skb); @@ -2324,8 +2330,8 @@ static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, { struct pci_dev *pdev = adapter->pdev; - ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, - GFP_KERNEL); + ring->desc = dma_zalloc_coherent(&pdev->dev, ring->size, &ring->dma, + GFP_KERNEL); if (!ring->desc) return -ENOMEM; @@ -3507,6 +3513,12 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) switch (hw->mac.type) { case e1000_pch2lan: + /* Stable 96MHz frequency */ + incperiod = INCPERIOD_96MHz; + incvalue = INCVALUE_96MHz; + shift = INCVALUE_SHIFT_96MHz; + adapter->cc.shift = shift + INCPERIOD_SHIFT_96MHz; + break; case e1000_pch_lpt: /* On I217, the clock frequency is 25MHz or 96MHz as * indicated by the System Clock Frequency Indication @@ -4192,7 +4204,7 @@ static int e1000_sw_init(struct e1000_adapter *adapter) /* Setup hardware time stamping cyclecounter */ if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) { adapter->cc.read = e1000e_cyclecounter_read; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.mult = 1; /* cc.shift set in e1000e_get_base_tininca() */ @@ -4844,7 +4856,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter) case e1000_media_type_copper: if (hw->mac.get_link_status) { ret_val = hw->mac.ops.check_for_link(hw); - link_active = !hw->mac.get_link_status; + link_active = ret_val > 0; } else { link_active = true; } @@ -4862,7 +4874,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter) break; } - if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) && + if ((ret_val == -E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) && (er32(CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) { /* See e1000_kmrn_lock_loss_workaround_ich8lan() */ e_info("Gigabit has been disabled, downgrading speed\n"); @@ -6351,12 +6363,17 @@ static int e1000e_pm_thaw(struct device *dev) static int e1000e_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + int rc; e1000e_flush_lpic(pdev); e1000e_pm_freeze(dev); - return __e1000_shutdown(pdev, false); + rc = __e1000_shutdown(pdev, false); + if (rc) + e1000e_pm_thaw(dev); + + return rc; } static int e1000e_pm_resume(struct device *dev) diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c index b2005e13fb01583a10f58aa37339feb2336191bd..0963aa2d5e45ba8f827d3ac44bbd6e38a56ddeac 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.c +++ b/drivers/net/ethernet/intel/e1000e/phy.c @@ -1744,6 +1744,7 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, s32 ret_val = 0; u16 i, phy_status; + *success = false; for (i = 0; i < iterations; i++) { /* Some PHYs require the MII_BMSR register to be read * twice due to the link bit being sticky. No harm doing @@ -1763,16 +1764,16 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, ret_val = e1e_rphy(hw, MII_BMSR, &phy_status); if (ret_val) break; - if (phy_status & BMSR_LSTATUS) + if (phy_status & BMSR_LSTATUS) { + *success = true; break; + } if (usec_interval >= 1000) msleep(usec_interval / 1000); else udelay(usec_interval); } - *success = (i < iterations); - return ret_val; } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c index 2d04464e6aa32f0bed0f491c621376a4f52afd80..125fdf40daa6ee89f5b29f01b93cfccf95738acc 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c @@ -840,7 +840,7 @@ static void fm10k_self_test(struct net_device *dev, memset(data, 0, sizeof(*data) * FM10K_TEST_LEN); - if (FM10K_REMOVED(hw)) { + if (FM10K_REMOVED(hw->hw_addr)) { netif_err(interface, drv, dev, "Interface removed - test blocked\n"); eth_test->flags |= ETH_TEST_FL_FAILED; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c index 0601908642389077b1df46546af52e4a734c8db0..682d99350342e8e325499853d875b1b9ade9704f 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c @@ -145,6 +145,9 @@ process_mbx: struct fm10k_mbx_info *mbx = &vf_info->mbx; u16 glort = vf_info->glort; + /* process the SM mailbox first to drain outgoing messages */ + hw->mbx.ops.process(hw, &hw->mbx); + /* verify port mapping is valid, if not reset port */ if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort)) hw->iov.ops.reset_lport(hw, vf_info); diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index e645af412e76bda4622f09bd946f98003e181c45..1f9b9c8da5a44437db8fd85f99b01191c90c5ddb 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -1218,7 +1218,7 @@ static bool fm10k_clean_tx_irq(struct fm10k_q_vector *q_vector, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->flags & FM10K_TXD_FLAG_DONE)) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c3a7f4a4b7757a35afa4a23b944a64e0ac4d673b..f7ed3dbd98008b87c51f68382430de90bbce04be 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3214,7 +3214,7 @@ static bool i40e_clean_fdir_tx_irq(struct i40e_ring *tx_ring, int budget) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if the descriptor isn't done, no work yet to do */ if (!(eop_desc->cmd_type_offset_bsz & @@ -3814,8 +3814,12 @@ static void i40e_napi_enable_all(struct i40e_vsi *vsi) if (!vsi->netdev) return; - for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) - napi_enable(&vsi->q_vectors[q_idx]->napi); + for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) { + struct i40e_q_vector *q_vector = vsi->q_vectors[q_idx]; + + if (q_vector->rx.ring || q_vector->tx.ring) + napi_enable(&q_vector->napi); + } } /** @@ -3829,8 +3833,12 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi) if (!vsi->netdev) return; - for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) - napi_disable(&vsi->q_vectors[q_idx]->napi); + for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) { + struct i40e_q_vector *q_vector = vsi->q_vectors[q_idx]; + + if (q_vector->rx.ring || q_vector->tx.ring) + napi_disable(&q_vector->napi); + } } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 3195d82e49425369951185ccc1e664a8485ea716..2d8d49e8bd997fec95a887459e127ab2c04e4d75 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -688,7 +688,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* we have caught up to head, no work left to do */ if (tx_head == tx_desc) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 04c7c1557a0c770ab0f256d3012cd3b9be70240e..139c8103d83a77aa4fd0aa1b945a17d9adce6c5b 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -222,7 +222,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* we have caught up to head, no work left to do */ if (tx_head == tx_desc) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 051ea94bdcd3e8046181b361d8985c51d15ea19c..38d68623ea334c1ffdd32804833429545b7a74cb 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -215,6 +215,17 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; + /* Make sure the PHY is in a good state. Several people have reported + * firmware leaving the PHY's page select register set to something + * other than the default of zero, which causes the PHY ID read to + * access something other than the intended register. + */ + ret_val = hw->phy.ops.reset(hw); + if (ret_val) { + hw_dbg("Error resetting the PHY.\n"); + goto out; + } + /* Set phy->phy_addr and phy->id. */ ret_val = igb_get_phy_id_82575(hw); if (ret_val) diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c index 65d931669f813bbcca0a21cc13a68c53663b03ee..89402fce7d79a53e8511f6d63f6c164086c85840 100644 --- a/drivers/net/ethernet/intel/igb/e1000_i210.c +++ b/drivers/net/ethernet/intel/igb/e1000_i210.c @@ -699,9 +699,9 @@ static s32 igb_update_flash_i210(struct e1000_hw *hw) ret_val = igb_pool_flash_update_done_i210(hw); if (ret_val) - hw_dbg("Flash update complete\n"); - else hw_dbg("Flash update time out\n"); + else + hw_dbg("Flash update complete\n"); out: return ret_val; diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 95f47b9f50d4f3bf86c07a34f06af3ec0c745589..5c8be806b83a7fbd447255afe8f7860d0441b9c5 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -29,7 +29,7 @@ #include "e1000_mac.h" #include "e1000_82575.h" -#include +#include #include #include #include diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index e0f36647d3dd6d2e4e2ba3ff9645db3d62cd55df..1ffad88e8a297157cf0a19b30d73a5db2192b84b 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3001,6 +3001,8 @@ static int igb_sw_init(struct igb_adapter *adapter) /* Setup and initialize a copy of the hw vlan table array */ adapter->shadow_vfta = kcalloc(E1000_VLAN_FILTER_TBL_SIZE, sizeof(u32), GFP_ATOMIC); + if (!adapter->shadow_vfta) + return -ENOMEM; /* This call may decrease the number of queues */ if (igb_init_interrupt_scheme(adapter, true)) { @@ -3170,7 +3172,9 @@ static int __igb_close(struct net_device *netdev, bool suspending) static int igb_close(struct net_device *netdev) { - return __igb_close(netdev, false); + if (netif_device_present(netdev) || netdev->dismantle) + return __igb_close(netdev, false); + return 0; } /** @@ -6381,7 +6385,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD))) @@ -7328,12 +7332,14 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake, int retval = 0; #endif + rtnl_lock(); netif_device_detach(netdev); if (netif_running(netdev)) __igb_close(netdev, true); igb_clear_interrupt_scheme(adapter); + rtnl_unlock(); #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -7452,16 +7458,15 @@ static int igb_resume(struct device *dev) wr32(E1000_WUS, ~0); - if (netdev->flags & IFF_UP) { - rtnl_lock(); + rtnl_lock(); + if (!err && netif_running(netdev)) err = __igb_open(netdev, true); - rtnl_unlock(); - if (err) - return err; - } - netif_device_attach(netdev); - return 0; + if (!err) + netif_device_attach(netdev); + rtnl_unlock(); + + return err; } #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 794c139f0cc04f86bf8319ea7e42840677db2c6c..5573ca17d3a4cd15cd5940276702882c67fff752 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -770,7 +770,7 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.settime = igb_ptp_settime_82576; adapter->ptp_caps.enable = igb_ptp_feature_enable; adapter->cc.read = igb_ptp_read_82576; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.mult = 1; adapter->cc.shift = IGB_82576_TSYNC_SHIFT; /* Dial the nominal frequency. */ @@ -790,7 +790,7 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.settime = igb_ptp_settime_82576; adapter->ptp_caps.enable = igb_ptp_feature_enable; adapter->cc.read = igb_ptp_read_82580; - adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580); + adapter->cc.mask = CYCLECOUNTER_MASK(IGB_NBITS_82580); adapter->cc.mult = 1; adapter->cc.shift = 0; /* Enable the timer functions by clearing bit 31. */ diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 63c807c9b21c0f7d68f330bab3be65f2d806f173..7cf3fbb8bc35f04b3ad3e930267081c1b037ffec 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -808,7 +808,7 @@ static bool igbvf_clean_tx_irq(struct igbvf_ring *tx_ring) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD))) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 5032a602d5c98265d63037d6aac1e1bfc3188c76..f26eeb705a7737dfb7b41ae2ec0908b798160e19 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index b5f484bf3fdadd599517a4b549e08a776c596ec8..4be0a22757d2cc93eb003fe262c6386e67b67fe9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -1781,7 +1781,12 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, if (enable_addr != 0) rar_high |= IXGBE_RAH_AV; + /* Record lower 32 bits of MAC address and then make + * sure that write is flushed to hardware before writing + * the upper 16 bits and setting the valid bit. + */ IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); + IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); return 0; @@ -1813,8 +1818,13 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); - IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); + /* Clear the address valid bit and upper 16 bits of the address + * before clearing the lower bits. This way we aren't updating + * a live filter. + */ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + IXGBE_WRITE_FLUSH(hw); + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); /* clear VMDq pool/queue selection for this RAR */ hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index cc51554c9e99a49e74c24ab7bf8f97848a06d7a3..b250aa806d073b9c14391cbd5690426031c1594b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1080,7 +1080,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD))) @@ -5560,7 +5560,8 @@ static int ixgbe_close(struct net_device *netdev) ixgbe_ptp_stop(adapter); - ixgbe_close_suspend(adapter); + if (netif_device_present(netdev)) + ixgbe_close_suspend(adapter); ixgbe_fdir_filter_exit(adapter); @@ -5605,14 +5606,12 @@ static int ixgbe_resume(struct pci_dev *pdev) if (!err && netif_running(netdev)) err = ixgbe_open(netdev); - rtnl_unlock(); - - if (err) - return err; - netif_device_attach(netdev); + if (!err) + netif_device_attach(netdev); + rtnl_unlock(); - return 0; + return err; } #endif /* CONFIG_PM */ @@ -5627,14 +5626,14 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) int retval = 0; #endif + rtnl_lock(); netif_device_detach(netdev); - rtnl_lock(); if (netif_running(netdev)) ixgbe_close_suspend(adapter); - rtnl_unlock(); ixgbe_clear_interrupt_scheme(adapter); + rtnl_unlock(); #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -8575,7 +8574,7 @@ skip_bad_vf_detection: } if (netif_running(netdev)) - ixgbe_down(adapter); + ixgbe_close_suspend(adapter); if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state)) pci_disable_device(pdev); @@ -8645,10 +8644,12 @@ static void ixgbe_io_resume(struct pci_dev *pdev) } #endif + rtnl_lock(); if (netif_running(netdev)) - ixgbe_up(adapter); + ixgbe_open(netdev); netif_device_attach(netdev); + rtnl_unlock(); } static const struct pci_error_handlers ixgbe_err_handler = { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 5fd4b5271f9a19b5df9b06ebb8a1b81fbdbe8eb1..abe176916cf7b05f0d7b54a0a90c26c6d9a18c5b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -802,7 +802,7 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) memset(&adapter->cc, 0, sizeof(adapter->cc)); adapter->cc.read = ixgbe_ptp_read; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.shift = shift; adapter->cc.mult = 1; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 030a219c85e363802644f1302dbf56c0ac709c8b..85bf4453b90502b6c6adbddf7fd3be38c127cb94 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -249,7 +249,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD))) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index fc2fb25343f417964070c058baea2e8162dab595..c122b3b99cd8e4012b90058c505f59959955e557 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -241,7 +241,8 @@ static int orion_mdio_probe(struct platform_device *pdev) dev->regs + MVMDIO_ERR_INT_MASK); } else if (dev->err_interrupt == -EPROBE_DEFER) { - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto out_mdio; } mutex_init(&dev->lock); diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index e6a7b50a478159394dd8893a0e350e9e184ccfc8..6212177781d56e3d805b719c20e4160b94d1a512 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -748,6 +748,7 @@ static void mvneta_port_up(struct mvneta_port *pp) } mvreg_write(pp, MVNETA_TXQ_CMD, q_map); + q_map = 0; /* Enable all initialized RXQs. */ q_map = 0; for (queue = 0; queue < rxq_number; queue++) { @@ -851,6 +852,10 @@ static void mvneta_port_disable(struct mvneta_port *pp) val &= ~MVNETA_GMAC0_PORT_ENABLE; mvreg_write(pp, MVNETA_GMAC_CTRL_0, val); + pp->link = 0; + pp->duplex = -1; + pp->speed = 0; + udelay(200); } @@ -2472,7 +2477,6 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu) } mvneta_start_dev(pp); - mvneta_port_up(pp); netdev_update_features(dev); diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index bd3366267039bc233e526acf3926d4f8b6fb5638..edc41554aae774148c6157c5d6ddcc8e2da74552 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -5069,7 +5069,7 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&hw->restart_work, sky2_restart); pci_set_drvdata(pdev, hw); - pdev->d3_delay = 150; + pdev->d3_delay = 200; return 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 57dda95b67d8d4325e19f03b6d01f982cfc54cb7..682daf86e74feee7968a88ce3577537f4a96bc1d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -32,6 +32,7 @@ */ #include +#include #include "mlx4_en.h" diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index ae83da9cd18a3f870ab51bc3ff9cb207b6f0432e..a3f355d1e0933a147ff45afdbb1af3f6e41322fb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -453,6 +453,22 @@ static int mlx4_en_set_coalesce(struct net_device *dev, if (!coal->tx_max_coalesced_frames_irq) return -EINVAL; + if (coal->tx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME || + coal->rx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME || + coal->rx_coalesce_usecs_low > MLX4_EN_MAX_COAL_TIME || + coal->rx_coalesce_usecs_high > MLX4_EN_MAX_COAL_TIME) { + netdev_info(dev, "%s: maximum coalesce time supported is %d usecs\n", + __func__, MLX4_EN_MAX_COAL_TIME); + return -ERANGE; + } + + if (coal->tx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS || + coal->rx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS) { + netdev_info(dev, "%s: maximum coalesced frames supported is %d\n", + __func__, MLX4_EN_MAX_COAL_PKTS); + return -ERANGE; + } + priv->rx_frames = (coal->rx_max_coalesced_frames == MLX4_EN_AUTO_CONF) ? MLX4_EN_RX_COAL_TARGET : diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 90de6e1ad06e9eb0bf002d9c1f87a5d80019fffe..7fea86c0678337e465c1a5a53c5cdc3a1664a7a4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -648,8 +648,6 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) return -ENOSYS; } - mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz; - dev->caps.hca_core_clock = hca_param.hca_core_clock; memset(&dev_cap, 0, sizeof(dev_cap)); diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 872843179f44af3c7442614477bd2af131118347..c704e7bcda9d0a8af191f44ad1e1b115a3f5d6bc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -35,6 +35,7 @@ #include #include +#include #include #include "mlx4.h" @@ -985,16 +986,21 @@ int mlx4_flow_attach(struct mlx4_dev *dev, if (IS_ERR(mailbox)) return PTR_ERR(mailbox); + if (!mlx4_qp_lookup(dev, rule->qpn)) { + mlx4_err_rule(dev, "QP doesn't exist\n", rule); + ret = -EINVAL; + goto out; + } + trans_rule_ctrl_to_hw(rule, mailbox->buf); size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); list_for_each_entry(cur, &rule->list, list) { ret = parse_trans_rule(dev, cur, mailbox->buf + size); - if (ret < 0) { - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; - } + if (ret < 0) + goto out; + size += ret; } @@ -1006,6 +1012,7 @@ int mlx4_flow_attach(struct mlx4_dev *dev, else if (ret) mlx4_err_rule(dev, "Fail to register network rule\n", rule); +out: mlx4_free_cmd_mailbox(dev, mailbox); return ret; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 4f908065accfffff4b9d47d4e80e5874a8c5518b..76a5b93baa7f47e2b978bb46333697fb38531195 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -138,6 +138,9 @@ enum { #define MLX4_EN_TX_COAL_PKTS 16 #define MLX4_EN_TX_COAL_TIME 0x10 +#define MLX4_EN_MAX_COAL_PKTS U16_MAX +#define MLX4_EN_MAX_COAL_TIME U16_MAX + #define MLX4_EN_RX_RATE_LOW 400000 #define MLX4_EN_RX_COAL_TIME_LOW 0 #define MLX4_EN_RX_RATE_HIGH 450000 @@ -535,8 +538,8 @@ struct mlx4_en_priv { u16 rx_usecs_low; u32 pkt_rate_high; u16 rx_usecs_high; - u16 sample_interval; - u16 adaptive_rx_coal; + u32 sample_interval; + u32 adaptive_rx_coal; u32 msg_enable; u32 loopback_ok; u32 validate_loopback; diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 2301365c79c710b01d07d4a8be7353f2a371e03a..4b588a39bc63145fe30a088bfd1ec96c3cd7c051 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -257,6 +257,9 @@ void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) u64 in_param = 0; int err; + if (!cnt) + return; + if (mlx4_is_mfunc(dev)) { set_param_l(&in_param, base_qpn); set_param_h(&in_param, cnt); @@ -355,6 +358,19 @@ static void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) __mlx4_qp_free_icm(dev, qpn); } +struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + struct mlx4_qp *qp; + + spin_lock_irq(&qp_table->lock); + + qp = __mlx4_qp_lookup(dev, qpn); + + spin_unlock_irq(&qp_table->lock); + return qp; +} + int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index fbb0c02276f9e7640d5025b1a392b3a3d98bf8c8..816b614025b4313300029eb656ab963e34d2e3aa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2709,7 +2709,7 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, u32 srqn = qp_get_srqn(qpc) & 0xffffff; int use_srq = (qp_get_srqn(qpc) >> 24) & 1; struct res_srq *srq; - int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; + int local_qpn = vhcr->in_modifier & 0xffffff; err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index dea4ade73f99970f8b247f207685d92c60e884d9..f8d2ee843e5eed7c3ea0f47cf1279d37f831c5b0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -480,6 +480,7 @@ static void cmd_work_handler(struct work_struct *work) struct mlx5_core_dev *dev = container_of(cmd, struct mlx5_core_dev, cmd); struct mlx5_cmd_layout *lay; struct semaphore *sem; + int cmd_mode; sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem; down(sem); @@ -513,13 +514,14 @@ static void cmd_work_handler(struct work_struct *work) set_signature(ent, !cmd->checksum_disabled); dump_command(dev, ent, 1); ent->ts1 = ktime_get_ns(); + cmd_mode = cmd->mode; /* ring doorbell after the descriptor is valid */ wmb(); iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell); mlx5_core_dbg(dev, "write 0x%x to command doorbell\n", 1 << ent->idx); mmiowb(); - if (cmd->mode == CMD_MODE_POLLING) { + if (cmd_mode == CMD_MODE_POLLING) { poll_timeout(ent); /* make sure we read the descriptor after ownership is SW */ rmb(); @@ -933,7 +935,7 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf, { struct mlx5_core_dev *dev = filp->private_data; struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; - char outlen_str[8]; + char outlen_str[8] = {0}; int outlen; void *ptr; int err; @@ -948,8 +950,6 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf, if (copy_from_user(outlen_str, buf, count)) return -EFAULT; - outlen_str[7] = 0; - err = sscanf(outlen_str, "%d", &outlen); if (err < 0) return err; @@ -1371,7 +1371,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) cmd->checksum_disabled = 1; cmd->max_reg_cmds = (1 << cmd->log_sz) - 1; - cmd->bitmask = (1 << cmd->max_reg_cmds) - 1; + cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1; cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16; if (cmd->cmdif_rev > CMD_IF_REV) { diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c index cd22429ced6d99271e533bbed961b2228e9904d1..c355fa6ddaeb8679683e1ceb917a2d4c4f20b856 100644 --- a/drivers/net/ethernet/msm/ecm_ipa.c +++ b/drivers/net/ethernet/msm/ecm_ipa.c @@ -9,6 +9,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include #include #include #include @@ -30,17 +31,49 @@ #define TX_TIMEOUT (5 * HZ) +#define IPA_ECM_IPC_LOG_PAGES 50 + +#define IPA_ECM_IPC_LOGGING(buf, fmt, args...) \ + do { \ + if (buf) \ + ipc_log_string((buf), fmt, __func__, __LINE__, \ + ## args); \ + } while (0) + +static void *ipa_ecm_logbuf; + #define ECM_IPA_DEBUG(fmt, args...) \ - pr_debug("ctx:%s: "\ - fmt, current->comm, ## args) + do { \ + pr_debug(DRIVER_NAME " %s:%d "\ + fmt, __func__, __LINE__, ## args);\ + if (ipa_ecm_logbuf) { \ + IPA_ECM_IPC_LOGGING(ipa_ecm_logbuf, \ + DRIVER_NAME " %s:%d " fmt, ## args); \ + } \ + } while (0) + +#define ECM_IPA_DEBUG_XMIT(fmt, args...) \ + pr_debug(DRIVER_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define ECM_IPA_INFO(fmt, args...) \ - pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\ - fmt, __func__, __LINE__, current->comm, ## args) + do { \ + pr_info(DRIVER_NAME "@%s@%d@ctx:%s: "\ + fmt, __func__, __LINE__, current->comm, ## args);\ + if (ipa_ecm_logbuf) { \ + IPA_ECM_IPC_LOGGING(ipa_ecm_logbuf, \ + DRIVER_NAME " %s:%d " fmt, ## args); \ + } \ + } while (0) #define ECM_IPA_ERROR(fmt, args...) \ - pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\ - fmt, __func__, __LINE__, current->comm, ## args) + do { \ + pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\ + fmt, __func__, __LINE__, current->comm, ## args);\ + if (ipa_ecm_logbuf) { \ + IPA_ECM_IPC_LOGGING(ipa_ecm_logbuf, \ + DRIVER_NAME " %s:%d " fmt, ## args); \ + } \ + } while (0) #define NULL_CHECK(ptr) \ do { \ @@ -547,7 +580,8 @@ static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb, net->trans_start = jiffies; - ECM_IPA_DEBUG("Tx, len=%d, skb->protocol=%d, outstanding=%d\n", + ECM_IPA_DEBUG_XMIT + ("Tx, len=%d, skb->protocol=%d, outstanding=%d\n", skb->len, skb->protocol, atomic_read(&ecm_ipa_ctx->outstanding_pkts)); @@ -1152,7 +1186,9 @@ static void ecm_ipa_tx_complete_notify(void *priv, ecm_ipa_ctx->net->stats.tx_packets++; ecm_ipa_ctx->net->stats.tx_bytes += skb->len; - atomic_dec(&ecm_ipa_ctx->outstanding_pkts); + if (atomic_read(&ecm_ipa_ctx->outstanding_pkts) > 0) + atomic_dec(&ecm_ipa_ctx->outstanding_pkts); + if (netif_queue_stopped(ecm_ipa_ctx->net) && netif_carrier_ok(ecm_ipa_ctx->net) && atomic_read(&ecm_ipa_ctx->outstanding_pkts) < @@ -1413,6 +1449,10 @@ static const char *ecm_ipa_state_string(enum ecm_ipa_state state) static int ecm_ipa_init_module(void) { ECM_IPA_LOG_ENTRY(); + ipa_ecm_logbuf = + ipc_log_context_create(IPA_ECM_IPC_LOG_PAGES, "ipa_ecm", 0); + if (ipa_ecm_logbuf == NULL) + ECM_IPA_DEBUG("failed to create IPC log, continue...\n"); ECM_IPA_LOG_EXIT(); return 0; } @@ -1424,6 +1464,9 @@ static int ecm_ipa_init_module(void) static void ecm_ipa_cleanup_module(void) { ECM_IPA_LOG_ENTRY(); + if (ipa_ecm_logbuf) + ipc_log_context_destroy(ipa_ecm_logbuf); + ipa_ecm_logbuf = NULL; ECM_IPA_LOG_EXIT(); return; } diff --git a/drivers/net/ethernet/msm/rndis_ipa.c b/drivers/net/ethernet/msm/rndis_ipa.c index be346a92ff59e1cfea6930ebb17b1b6612bb2a1c..20040d4e960652c6f8d9d68d56b476d0bfc1dfe3 100644 --- a/drivers/net/ethernet/msm/rndis_ipa.c +++ b/drivers/net/ethernet/msm/rndis_ipa.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -58,12 +59,38 @@ #define DEFAULT_AGGR_TIME_LIMIT 1 #define DEFAULT_AGGR_PKT_LIMIT 0 +#define IPA_RNDIS_IPC_LOG_PAGES 50 + +#define IPA_RNDIS_IPC_LOGGING(buf, fmt, args...) \ + do { \ + if (buf) \ + ipc_log_string((buf), fmt, __func__, __LINE__, \ + ## args); \ + } while (0) + +static void *ipa_rndis_logbuf; + +#define RNDIS_IPA_DEBUG(fmt, args...) \ + do { \ + pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\ + if (ipa_rndis_logbuf) { \ + IPA_RNDIS_IPC_LOGGING(ipa_rndis_logbuf, \ + DRV_NAME " %s:%d " fmt, ## args); \ + } \ + } while (0) + +#define RNDIS_IPA_DEBUG_XMIT(fmt, args...) \ + pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define RNDIS_IPA_ERROR(fmt, args...) \ + do { \ pr_err(DRV_NAME "@%s@%d@ctx:%s: "\ - fmt, __func__, __LINE__, current->comm, ## args) -#define RNDIS_IPA_DEBUG(fmt, args...) \ - pr_debug("ctx: %s, "fmt, current->comm, ## args) + fmt, __func__, __LINE__, current->comm, ## args);\ + if (ipa_rndis_logbuf) { \ + IPA_RNDIS_IPC_LOGGING(ipa_rndis_logbuf, \ + DRV_NAME " %s:%d " fmt, ## args); \ + } \ + } while (0) #define NULL_CHECK_RETVAL(ptr) \ do { \ @@ -837,7 +864,8 @@ static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb, net->trans_start = jiffies; - RNDIS_IPA_DEBUG("Tx, len=%d, skb->protocol=%d, outstanding=%d\n", + RNDIS_IPA_DEBUG_XMIT + ("Tx, len=%d, skb->protocol=%d, outstanding=%d\n", skb->len, skb->protocol, atomic_read(&rndis_ipa_ctx->outstanding_pkts)); @@ -946,7 +974,9 @@ static void rndis_ipa_tx_complete_notify(void *private, rndis_ipa_ctx->net->stats.tx_packets++; rndis_ipa_ctx->net->stats.tx_bytes += skb->len; - atomic_dec(&rndis_ipa_ctx->outstanding_pkts); + if (atomic_read(&rndis_ipa_ctx->outstanding_pkts) > 0) + atomic_dec(&rndis_ipa_ctx->outstanding_pkts); + if (netif_queue_stopped(rndis_ipa_ctx->net) && netif_carrier_ok(rndis_ipa_ctx->net) && atomic_read(&rndis_ipa_ctx->outstanding_pkts) < @@ -2392,12 +2422,19 @@ static ssize_t rndis_ipa_debugfs_atomic_read(struct file *file, static int rndis_ipa_init_module(void) { + ipa_rndis_logbuf = + ipc_log_context_create(IPA_RNDIS_IPC_LOG_PAGES, "ipa_rndis", 0); + if (ipa_rndis_logbuf == NULL) + RNDIS_IPA_DEBUG("failed to create IPC log, continue...\n"); pr_info("RNDIS_IPA module is loaded."); return 0; } static void rndis_ipa_cleanup_module(void) { + if (ipa_rndis_logbuf) + ipc_log_context_destroy(ipa_rndis_logbuf); + ipa_rndis_logbuf = NULL; pr_info("RNDIS_IPA module is unloaded."); return; } diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 1bd419dbda6dc34d39f1a4fe38ec30a9ca85cf16..0798b4adb0394e48f98e29188f4060ff998c2682 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -71,7 +71,7 @@ static int sonic_open(struct net_device *dev) for (i = 0; i < SONIC_NUM_RRS; i++) { dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE), SONIC_RBSIZE, DMA_FROM_DEVICE); - if (!laddr) { + if (dma_mapping_error(lp->device, laddr)) { while(i > 0) { /* free any that were mapped successfully */ i--; dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c index b8d5270359cd8a7109226c0be1731cbafa6d1423..e306765155290a31e390f5ddcf88b4f0aa8f973c 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c @@ -247,7 +247,7 @@ nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu) cmd.req.arg3 = 0; if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE) - netxen_issue_cmd(adapter, &cmd); + rcode = netxen_issue_cmd(adapter, &cmd); if (rcode != NX_RCODE_SUCCESS) return -EIO; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index dd618d7ed257cf6ade4617f1e17e3b387919c391..1c40c524f0c8c0cae05fc51f4357c5581542ad5d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -3825,7 +3825,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter) struct list_head *head = &mbx->cmd_q; struct qlcnic_cmd_args *cmd = NULL; - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); while (!list_empty(head)) { cmd = list_entry(head->next, struct qlcnic_cmd_args, list); @@ -3836,7 +3836,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter) qlcnic_83xx_notify_cmd_completion(adapter, cmd); } - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); } static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter) @@ -3872,12 +3872,12 @@ static void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter, { struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); list_del(&cmd->list); mbx->num_cmds--; - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); qlcnic_83xx_notify_cmd_completion(adapter, cmd); } @@ -3942,7 +3942,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter, init_completion(&cmd->completion); cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN; - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); list_add_tail(&cmd->list, &mbx->cmd_q); mbx->num_cmds++; @@ -3950,7 +3950,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter, *timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT; queue_work(mbx->work_q, &mbx->work); - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); return 0; } @@ -4046,15 +4046,15 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work) mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT; spin_unlock_irqrestore(&mbx->aen_lock, flags); - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); if (list_empty(head)) { - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); return; } cmd = list_entry(head->next, struct qlcnic_cmd_args, list); - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); mbx_ops->encode_cmd(adapter, cmd); mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 69b46c051cc0c299feb3db576dca2056463f3ba5..3295580b3aa017bec981cce3ed5fbf0361cd0b5b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -341,7 +341,7 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) } return -EIO; } - usleep_range(1000, 1500); + udelay(1200); } if (id_reg) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 1659c804f1d5f4fc530f7d9b2ac11c7f9f023c6b..44e3cef336bdb3c0cac6b2e14b5be00475d2eb46 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -126,6 +126,8 @@ static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id) return 0; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); + if (!pos) + return 0; pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 59a721fba018249679bf15d0984b90e4835c155e..8c787fab7993506f79f5224f188cd62a59c2320f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -1136,6 +1136,8 @@ static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp, return QL_STATUS_INVALID_PARAM; ret = kstrtoul(buf, 16, &data); + if (ret) + return ret; switch (data) { case QLC_83XX_FLASH_SECTOR_ERASE_CMD: diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c index 829be21f97b21dd694c6cad732b06a899be106c8..e3223f2fe2ffc9d4b186a42e0cac87fc37021afd 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c @@ -724,7 +724,7 @@ static void ql_build_coredump_seg_header( seg_hdr->cookie = MPI_COREDUMP_COOKIE; seg_hdr->segNum = seg_number; seg_hdr->segSize = seg_size; - memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1); + strncpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1); } /* @@ -765,7 +765,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) sizeof(struct mpi_coredump_global_header); mpi_coredump->mpi_global_header.imageSize = sizeof(struct ql_mpi_coredump); - memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", + strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", sizeof(mpi_coredump->mpi_global_header.idString)); /* Get generic NIC reg dump */ @@ -1255,7 +1255,7 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, sizeof(struct mpi_coredump_global_header); mpi_coredump->mpi_global_header.imageSize = sizeof(struct ql_reg_dump); - memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", + strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", sizeof(mpi_coredump->mpi_global_header.idString)); diff --git a/drivers/net/ethernet/qualcomm/emac/emac_hw.h b/drivers/net/ethernet/qualcomm/emac/emac_hw.h index b1bd4d686a1ba1f0a27d47f3c2e911906aa07507..bcef41d2bfc46c48e8b2f65d2ff7133c9e8dcfa0 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac_hw.h +++ b/drivers/net/ethernet/qualcomm/emac/emac_hw.h @@ -108,9 +108,7 @@ bool emac_hw_read_tx_tstamp(struct emac_hw *hw, struct emac_hwtxtstamp *ts); #define DMAR_DLY_CNT_DEF 15 #define DMAW_DLY_CNT_DEF 4 -#define MDIO_CLK_25_8 3 -#define MDIO_CLK_25_10 4 -#define MDIO_CLK_25_28 7 +#define MDIO_CLK_25_4 0 #define RXQ0_RSS_HSTYP_IPV6_TCP_EN 0x20 #define RXQ0_RSS_HSTYP_IPV6_EN 0x10 diff --git a/drivers/net/ethernet/qualcomm/emac/emac_main.c b/drivers/net/ethernet/qualcomm/emac/emac_main.c index 3f9844dd1aba8017c1d5388298f2fd7dae798706..e748214fed8c704c62830b02ffc7a44212328150 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac_main.c +++ b/drivers/net/ethernet/qualcomm/emac/emac_main.c @@ -1991,8 +1991,10 @@ void emac_mac_down(struct emac_adapter *adpt, u32 ctrl) if (adpt->irq[i].irq) free_irq(adpt->irq[i].irq, &adpt->irq[i]); - if ((ATH8030_PHY_ID == adpt->phydev->phy_id) && - (adpt->phy.is_ext_phy_connect)) { + if (((ATH8030_PHY_ID == adpt->phydev->phy_id) || + (ATH8031_PHY_ID == adpt->phydev->phy_id) || + (ATH8035_PHY_ID == adpt->phydev->phy_id)) && + (adpt->phy.is_ext_phy_connect)) { phy_disconnect(adpt->phydev); adpt->phy.is_ext_phy_connect = 0; } @@ -3091,8 +3093,6 @@ static int emac_probe(struct platform_device *pdev) if (ret) goto err_clk_init; - hw_ver = emac_reg_r32(hw, EMAC, EMAC_CORE_HW_VERSION); - netdev->watchdog_timeo = EMAC_WATCHDOG_TIME; netdev->irq = adpt->irq[0].irq; @@ -3112,9 +3112,6 @@ static int emac_probe(struct platform_device *pdev) emac_set_ethtool_ops(netdev); - /* init adapter */ - emac_init_adapter(adpt); - /* init internal phy */ ret = emac_phy_config_internal(pdev, adpt); if (ret) @@ -3125,6 +3122,11 @@ static int emac_probe(struct platform_device *pdev) if (ret) goto err_clk_init; + hw_ver = emac_reg_r32(hw, EMAC, EMAC_CORE_HW_VERSION); + + /* init adapter */ + emac_init_adapter(adpt); + /* Configure MDIO lines */ ret = adpt->gpio_on(adpt, true, true); if (ret) @@ -3212,10 +3214,14 @@ err_undo_napi: err_init_mdio_gpio: adpt->gpio_off(adpt, true, true); err_clk_init: - if (ATH8030_PHY_ID == adpt->phydev->phy_id) + if ((ATH8030_PHY_ID == adpt->phydev->phy_id) || + (ATH8031_PHY_ID == adpt->phydev->phy_id) || + (ATH8035_PHY_ID == adpt->phydev->phy_id)) emac_disable_clks(adpt); err_ldo_init: - if (ATH8030_PHY_ID == adpt->phydev->phy_id) + if ((ATH8030_PHY_ID == adpt->phydev->phy_id) || + (ATH8031_PHY_ID == adpt->phydev->phy_id) || + (ATH8035_PHY_ID == adpt->phydev->phy_id)) emac_disable_regulator(adpt, EMAC_VREG1, EMAC_VREG5); err_get_resource: free_netdev(netdev); diff --git a/drivers/net/ethernet/qualcomm/emac/emac_phy.c b/drivers/net/ethernet/qualcomm/emac/emac_phy.c index 402c949daf502a2289146cd0e468bc9bb45412ed..e831b744613b80f3699fdd86fc8ac5a1178cf3ef 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac_phy.c +++ b/drivers/net/ethernet/qualcomm/emac/emac_phy.c @@ -100,7 +100,7 @@ static int emac_mdio_read(struct mii_bus *bus, int addr, int regnum) reg = reg & ~(MDIO_REG_ADDR_BMSK | MDIO_CLK_SEL_BMSK | MDIO_MODE | MDIO_PR); reg = SUP_PREAMBLE | - ((MDIO_CLK_25_10 << MDIO_CLK_SEL_SHFT) & MDIO_CLK_SEL_BMSK) | + ((MDIO_CLK_25_4 << MDIO_CLK_SEL_SHFT) & MDIO_CLK_SEL_BMSK) | ((regnum << MDIO_REG_ADDR_SHFT) & MDIO_REG_ADDR_BMSK) | MDIO_START | MDIO_RD_NWR; @@ -156,7 +156,7 @@ static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) reg = reg & ~(MDIO_REG_ADDR_BMSK | MDIO_CLK_SEL_BMSK | MDIO_DATA_BMSK | MDIO_MODE | MDIO_PR); reg = SUP_PREAMBLE | - ((MDIO_CLK_25_10 << MDIO_CLK_SEL_SHFT) & MDIO_CLK_SEL_BMSK) | + ((MDIO_CLK_25_4 << MDIO_CLK_SEL_SHFT) & MDIO_CLK_SEL_BMSK) | ((regnum << MDIO_REG_ADDR_SHFT) & MDIO_REG_ADDR_BMSK) | ((val << MDIO_DATA_SHFT) & MDIO_DATA_BMSK) | MDIO_START; diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index f55be6ddf3a7c5757e10777365674f3ca00004ff..2ec7fa82b4cff235fb77e7f35851ba318dbb0eac 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -297,8 +297,9 @@ qcaspi_receive(struct qcaspi *qca) /* Allocate rx SKB if we don't have one available. */ if (!qca->rx_skb) { - qca->rx_skb = netdev_alloc_skb(net_dev, - net_dev->mtu + VLAN_ETH_HLEN); + qca->rx_skb = netdev_alloc_skb_ip_align(net_dev, + net_dev->mtu + + VLAN_ETH_HLEN); if (!qca->rx_skb) { netdev_dbg(net_dev, "out of RX resources\n"); qca->stats.out_of_mem++; @@ -378,7 +379,7 @@ qcaspi_receive(struct qcaspi *qca) qca->rx_skb, qca->rx_skb->dev); qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx_ni(qca->rx_skb); - qca->rx_skb = netdev_alloc_skb(net_dev, + qca->rx_skb = netdev_alloc_skb_ip_align(net_dev, net_dev->mtu + VLAN_ETH_HLEN); if (!qca->rx_skb) { netdev_dbg(net_dev, "out of RX resources\n"); @@ -635,7 +636,7 @@ qcaspi_netdev_open(struct net_device *dev) return ret; } - netif_start_queue(qca->net_dev); + /* SPI thread takes care of TX queue */ return 0; } @@ -739,6 +740,9 @@ qcaspi_netdev_tx_timeout(struct net_device *dev) qca->net_dev->stats.tx_errors++; /* Trigger tx queue flush and QCA7000 reset */ qca->sync = QCASPI_SYNC_UNKNOWN; + + if (qca->spi_thread) + wake_up_process(qca->spi_thread); } static int @@ -760,7 +764,8 @@ qcaspi_netdev_init(struct net_device *dev) if (!qca->rx_buffer) return -ENOBUFS; - qca->rx_skb = netdev_alloc_skb(dev, qca->net_dev->mtu + VLAN_ETH_HLEN); + qca->rx_skb = netdev_alloc_skb_ip_align(dev, qca->net_dev->mtu + + VLAN_ETH_HLEN); if (!qca->rx_skb) { kfree(qca->rx_buffer); netdev_info(qca->net_dev, "Failed to allocate RX sk_buff.\n"); diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 007b38cce69a0b3bde4472ab5eef75989cf0dd6c..7858f2bd894d8ebc1313947da5ba0507389ce7e5 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -2215,7 +2215,7 @@ static void rtl8139_poll_controller(struct net_device *dev) struct rtl8139_private *tp = netdev_priv(dev); const int irq = tp->pci_dev->irq; - disable_irq(irq); + disable_irq_nosync(irq); rtl8139_interrupt(irq, dev); enable_irq(irq); } diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index e95cb1faf43e713d8c486fbdcf7aa9a15c0027a8..c9aa42ca2b6488dc4f45d8f11765b5775a0093bd 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -749,7 +749,7 @@ struct rtl8169_counters { }; enum rtl_flag { - RTL_FLAG_TASK_ENABLED, + RTL_FLAG_TASK_ENABLED = 0, RTL_FLAG_TASK_SLOW_PENDING, RTL_FLAG_TASK_RESET_PENDING, RTL_FLAG_TASK_PHY_PENDING, @@ -1375,7 +1375,7 @@ DECLARE_RTL_COND(rtl_ocp_tx_cond) { void __iomem *ioaddr = tp->mmio_addr; - return RTL_R8(IBISR0) & 0x02; + return RTL_R8(IBISR0) & 0x20; } static void rtl8168dp_driver_start(struct rtl8169_private *tp) @@ -1421,7 +1421,7 @@ static void rtl8168ep_driver_stop(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; RTL_W8(IBCR2, RTL_R8(IBCR2) & ~0x01); - rtl_msleep_loop_wait_low(tp, &rtl_ocp_tx_cond, 50, 2000); + rtl_msleep_loop_wait_high(tp, &rtl_ocp_tx_cond, 50, 2000); RTL_W8(IBISR0, RTL_R8(IBISR0) | 0x20); RTL_W8(IBCR0, RTL_R8(IBCR0) & ~0x01); ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP); @@ -4764,6 +4764,9 @@ static void rtl_pll_power_down(struct rtl8169_private *tp) static void rtl_pll_power_up(struct rtl8169_private *tp) { rtl_generic_op(tp, tp->pll_power_ops.up); + + /* give MAC/PHY some time to resume */ + msleep(20); } static void rtl_init_pll_power_ops(struct rtl8169_private *tp) @@ -7520,7 +7523,8 @@ static int rtl8169_close(struct net_device *dev) rtl8169_update_counters(dev); rtl_lock_work(tp); - clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + /* Clear all task flags */ + bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); rtl8169_down(dev); rtl_unlock_work(tp); @@ -7676,7 +7680,9 @@ static void rtl8169_net_suspend(struct net_device *dev) rtl_lock_work(tp); napi_disable(&tp->napi); - clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + /* Clear all task flags */ + bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); + rtl_unlock_work(tp); rtl_pll_power_down(tp); @@ -8278,12 +8284,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->rtl_fw = RTL_FIRMWARE_UNKNOWN; + pci_set_drvdata(pdev, dev); + rc = register_netdev(dev); if (rc < 0) goto err_out_msi_4; - pci_set_drvdata(pdev, dev); - netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n", rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq); diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 24e5d21356630baf5832ed33c160774b0bf94f19..8f3f692942d8f754fd754b373a876289f5fbebf6 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2890,18 +2890,37 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* ioremap the TSU registers */ if (mdp->cd->tsu) { struct resource *rtsu; + rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1); - mdp->tsu_addr = devm_ioremap_resource(&pdev->dev, rtsu); - if (IS_ERR(mdp->tsu_addr)) { - ret = PTR_ERR(mdp->tsu_addr); + if (!rtsu) { + dev_err(&pdev->dev, "no TSU resource\n"); + ret = -ENODEV; + goto out_release; + } + /* We can only request the TSU region for the first port + * of the two sharing this TSU for the probe to succeed... + */ + if (devno % 2 == 0 && + !devm_request_mem_region(&pdev->dev, rtsu->start, + resource_size(rtsu), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "can't request TSU resource.\n"); + ret = -EBUSY; + goto out_release; + } + mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start, + resource_size(rtsu)); + if (!mdp->tsu_addr) { + dev_err(&pdev->dev, "TSU region ioremap() failed.\n"); + ret = -ENOMEM; goto out_release; } mdp->port = devno % 2; ndev->features = NETIF_F_HW_VLAN_CTAG_FILTER; } - /* initialize first or needed device */ - if (!devno || pd->needs_init) { + /* Need to init only the first port of the two sharing a TSU */ + if (devno % 2 == 0) { if (mdp->cd->chip_reset) mdp->cd->chip_reset(ndev); @@ -2914,7 +2933,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* MDIO bus init */ ret = sh_mdio_init(mdp, pd); if (ret) { - dev_err(&ndev->dev, "failed to initialise MDIO\n"); + dev_err(&pdev->dev, "failed to initialise MDIO\n"); goto out_release; } diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 22301bf9c21daeb925d75aa7ce5c7a588d977e11..be909fe4fc7af9063c92c5971c9e17251ba98442 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -326,7 +326,7 @@ enum FELIC_MODE_BIT { ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000, ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, - ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020, + ECMR_MPDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020, ECMR_RTM = 0x00000010, ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002, ECMR_PRM = 0x00000001, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c769da8d6f3a02e5d9e9f56129806f0574980730..fc7b5ac6d6fe341b290201fe28e68792bb1a8727 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -53,7 +53,7 @@ #include "stmmac.h" #include -#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) +#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES) /* Module parameters */ #define TX_TIMEO 5000 @@ -277,8 +277,14 @@ bool stmmac_eee_init(struct stmmac_priv *priv) { char *phy_bus_name = priv->plat->phy_bus_name; unsigned long flags; + int interface = priv->plat->interface; bool ret = false; + if ((interface != PHY_INTERFACE_MODE_MII) && + (interface != PHY_INTERFACE_MODE_GMII) && + !phy_interface_mode_is_rgmii(interface)) + goto out; + /* Using PCS we cannot dial with the phy registers at this stage * so we do not support extra feature like EEE. */ diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 904fd1ab5f6e3762703d2931cf8fb6963c53c32c..68738aa8e218bb6bc140749d7067c088ebfc8638 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -3443,7 +3443,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np, len = (val & RCR_ENTRY_L2_LEN) >> RCR_ENTRY_L2_LEN_SHIFT; - len -= ETH_FCS_LEN; + append_size = len + ETH_HLEN + ETH_FCS_LEN; addr = (val & RCR_ENTRY_PKT_BUF_ADDR) << RCR_ENTRY_PKT_BUF_ADDR_SHIFT; @@ -3453,7 +3453,6 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np, RCR_ENTRY_PKTBUFSZ_SHIFT]; off = addr & ~PAGE_MASK; - append_size = rcr_size; if (num_rcr == 1) { int ptype; @@ -3466,7 +3465,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np, else skb_checksum_none_assert(skb); } else if (!(val & RCR_ENTRY_MULTI)) - append_size = len - skb->len; + append_size = append_size - skb->len; niu_rx_skb_append(skb, page, off, append_size, rcr_size); if ((page->index + rp->rbr_block_size) - rcr_size == addr) { diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index fef5dec2cffe9c3bb7f09bbe728ab2dc54b0cba9..64291b6d2cc123b7d826589c4117927fc2fefe19 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -60,8 +60,7 @@ #include #include "sungem.h" -/* Stripping FCS is causing problems, disabled for now */ -#undef STRIP_FCS +#define STRIP_FCS #define DEFAULT_MSG (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ @@ -435,7 +434,7 @@ static int gem_rxmac_reset(struct gem *gp) writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); writel(val, gp->regs + RXDMA_CFG); if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) writel(((5 & RXDMA_BLANK_IPKTS) | @@ -760,7 +759,6 @@ static int gem_rx(struct gem *gp, int work_to_do) struct net_device *dev = gp->dev; int entry, drops, work_done = 0; u32 done; - __sum16 csum; if (netif_msg_rx_status(gp)) printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", @@ -855,9 +853,13 @@ static int gem_rx(struct gem *gp, int work_to_do) skb = copy_skb; } - csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); - skb->csum = csum_unfold(csum); - skb->ip_summed = CHECKSUM_COMPLETE; + if (likely(dev->features & NETIF_F_RXCSUM)) { + __sum16 csum; + + csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); + skb->csum = csum_unfold(csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } skb->protocol = eth_type_trans(skb, gp->dev); napi_gro_receive(&gp->napi, skb); @@ -1755,7 +1757,7 @@ static void gem_init_dma(struct gem *gp) writel(0, gp->regs + TXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); writel(val, gp->regs + RXDMA_CFG); writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); @@ -2973,8 +2975,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); /* We can do scatter/gather and HW checksum */ - dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; - dev->features |= dev->hw_features | NETIF_F_RXCSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + dev->features = dev->hw_features; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 48645504106e61c9fa33536d8be7fb346416709f..7503451a94f2401a83fbb7842849d60bf52faa9c 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -293,6 +293,10 @@ struct cpsw_ss_regs { /* Bit definitions for the CPSW1_TS_SEQ_LTYPE register */ #define CPSW_V1_SEQ_ID_OFS_SHIFT 16 +#define CPSW_MAX_BLKS_TX 15 +#define CPSW_MAX_BLKS_TX_SHIFT 4 +#define CPSW_MAX_BLKS_RX 5 + struct cpsw_host_regs { u32 max_blks; u32 blk_cnt; @@ -1120,11 +1124,23 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) switch (priv->version) { case CPSW_VERSION_1: slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS); break; case CPSW_VERSION_2: case CPSW_VERSION_3: case CPSW_VERSION_4: slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS); break; } diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h index 1a581ef7eee8fcbd2ed121d64a747e06e84c6113..69a46b92c7d6cdb540299c17847334784fc9fb4d 100644 --- a/drivers/net/ethernet/ti/cpts.h +++ b/drivers/net/ethernet/ti/cpts.h @@ -27,6 +27,7 @@ #include #include #include +#include struct cpsw_cpts { u32 idver; /* Identification and version */ diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index ea712512c7d1f5e155129bf073cac1d7381d38bb..03fcce11ea4e835ec9e12444752f0e16653824da 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1514,6 +1514,10 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) static int match_first_device(struct device *dev, void *data) { + if (dev->parent && dev->parent->of_node) + return of_device_is_compatible(dev->parent->of_node, + "ti,davinci_mdio"); + return !strncmp(dev_name(dev), "davinci_mdio", 12); } diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 7b90a5eba0995326ce6d808749c65aa6f77cf8e7..9d6c252c1911acf3eaed1a8808250309f2d8bf3d 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig @@ -36,6 +36,7 @@ config XILINX_AXI_EMAC config XILINX_LL_TEMAC tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" depends on (PPC || MICROBLAZE) + depends on !64BIT || BROKEN select PHYLIB ---help--- This driver supports the Xilinx 10/100/1000 LocalLink TEMAC diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c index 3b67d60d43787bb1442c2e7ec1771fd047f461fc..bc42a1d7a43f5f053f29f5f021bab59b8e5fb628 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c @@ -219,6 +219,7 @@ issue: ret = of_mdiobus_register(bus, np1); if (ret) { mdiobus_free(bus); + lp->mii_bus = NULL; return ret; } return 0; diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index c2894e43840e604e75eac9f40bcfb1470e4c47aa..35db4fc691e71d2f4dba6f734fa8a3f7dd997ee2 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -90,10 +90,6 @@ static const char banner[] __initconst = KERN_INFO \ "AX.25: bpqether driver version 004\n"; -static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - -static char bpq_eth_addr[6]; - static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); static int bpq_device_event(struct notifier_block *, unsigned long, void *); @@ -512,8 +508,8 @@ static int bpq_new_device(struct net_device *edev) bpq->ethdev = edev; bpq->axdev = ndev; - memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); - memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); + eth_broadcast_addr(bpq->dest_addr); + eth_broadcast_addr(bpq->acpt_addr); err = register_netdevice(ndev); if (err) diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index c67a27245072746c3275a3b27a4fd899ebb6f3a4..69421ac067881e0004be0909be9a487962c4cadf 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -571,6 +571,8 @@ static int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case HDLCDRVCTL_CALIBRATE: if(!capable(CAP_SYS_RAWIO)) return -EPERM; + if (s->par.bitrate <= 0) + return -EINVAL; if (bi.data.calibrate > INT_MAX / s->par.bitrate) return -EINVAL; s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16; diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index 95c0b45a68fb2654705c00470e53ffb24198d170..313e006f74feb987f1120897a48fabada86b9a69 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -1381,8 +1381,8 @@ static int rr_close(struct net_device *dev) rrpriv->info_dma); rrpriv->info = NULL; - free_irq(pdev->irq, dev); spin_unlock_irqrestore(&rrpriv->lock, flags); + free_irq(pdev->irq, dev); return 0; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index a2e556168286649f3c8d809ea8de145fdb7fbad5..aceedd7aeb2adfec9446f9469336314b2d30a6f8 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -426,8 +426,9 @@ static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr memset(rd, 0, sizeof(*rd)); rd->hw = hwmap + i; rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA); - if (rd->buf == NULL || - !(busaddr = pci_map_single(pdev, rd->buf, len, dir))) { + if (rd->buf) + busaddr = pci_map_single(pdev, rd->buf, len, dir); + if (rd->buf == NULL || pci_dma_mapping_error(pdev, busaddr)) { if (rd->buf) { IRDA_ERROR("%s: failed to create PCI-MAP for %p", __func__, rd->buf); @@ -438,8 +439,7 @@ static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr rd = r->rd + j; busaddr = rd_get_addr(rd); rd_set_addr_status(rd, 0, 0); - if (busaddr) - pci_unmap_single(pdev, busaddr, len, dir); + pci_unmap_single(pdev, busaddr, len, dir); kfree(rd->buf); rd->buf = NULL; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index bfb0b6ec8c56e26d67fa94814fe460af34c95fed..c0818ec3d427f6bed9dd82268bb232c5b3910d60 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -440,7 +440,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) struct macvlan_dev, list); else vlan = macvlan_hash_lookup(port, eth->h_dest); - if (vlan == NULL) + if (!vlan || vlan->mode == MACVLAN_MODE_SOURCE) return RX_HANDLER_PASS; dev = vlan->dev; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 91120f0ed98ce9a7615b1d58252a9a4094fbbfc8..d058c35b4985e1f4d331773f208014a4ba118991 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -1047,6 +1047,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, case TUNSETSNDBUF: if (get_user(u, up)) return -EFAULT; + if (u <= 0) + return -EINVAL; q->sk.sk_sndbuf = u; return 0; diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index fdc1b418fa6a82a434fa305c8785546bc6584ad9..5012708271ca9ae9bcbdb1c1997d45ae03ce8edc 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -105,7 +105,7 @@ static int at803x_set_wol(struct phy_device *phydev, mac = (const u8 *) ndev->dev_addr; if (!is_valid_ether_addr(mac)) - return -EFAULT; + return -EINVAL; for (i = 0; i < 3; i++) { phy_write(phydev, AT803X_MMD_ACCESS_CONTROL, diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index c5789cdf777894e70646064d8c43a377f6c23a59..cd93ba7ed931e95b2f865290c8f05ba6879a739e 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1173,6 +1173,23 @@ static void dp83640_remove(struct phy_device *phydev) kfree(dp83640); } +static int dp83640_soft_reset(struct phy_device *phydev) +{ + int ret; + + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + + /* From DP83640 datasheet: "Software driver code must wait 3 us + * following a software reset before allowing further serial MII + * operations with the DP83640." + */ + udelay(10); /* Taking udelay inaccuracy into account */ + + return 0; +} + static int dp83640_config_init(struct phy_device *phydev) { struct dp83640_private *dp83640 = phydev->priv; @@ -1470,6 +1487,7 @@ static struct phy_driver dp83640_driver = { .flags = PHY_HAS_INTERRUPT, .probe = dp83640_probe, .remove = dp83640_remove, + .soft_reset = dp83640_soft_reset, .config_init = dp83640_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index b6cad1731cbef2530684a3239c21edf297d0cbda..e8fa76a15c3e8518ad7e181a622f75a97fda1146 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -828,6 +828,15 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; + /* If WOL event happened once, the LED[2] interrupt pin + * will not be cleared unless we reading the interrupt status + * register. If interrupts are in use, the normal interrupt + * handling will clear the WOL event. Clear the WOL event + * before enabling it if !phy_interrupt_is_valid() + */ + if (!phy_interrupt_is_valid(phydev)) + phy_read(phydev, MII_M1011_IEVENT); + /* Enable the WOL interrupt */ temp = phy_read(phydev, MII_88E1318S_PHY_CSIER); temp |= MII_88E1318S_PHY_CSIER_WOL_EIE; diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c index 15bc7f9ea224b44daab666cab2ff62c4e61019b5..afd76e07088b1dd41de832142470cae79ca3b327 100644 --- a/drivers/net/phy/mdio-sun4i.c +++ b/drivers/net/phy/mdio-sun4i.c @@ -128,8 +128,10 @@ static int sun4i_mdio_probe(struct platform_device *pdev) data->regulator = devm_regulator_get(&pdev->dev, "phy"); if (IS_ERR(data->regulator)) { - if (PTR_ERR(data->regulator) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(data->regulator) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_out_free_mdiobus; + } dev_info(&pdev->dev, "no regulator found\n"); } else { diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index caf4d3469d4ad82f5a2ec266ab17a779483020cb..59a6973fe760ed6a6f6b18fe54a1f91a2032dd23 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -123,6 +123,12 @@ static inline int phy_aneg_done(struct phy_device *phydev) if (phydev->drv->aneg_done) return phydev->drv->aneg_done(phydev); + /* Avoid genphy_aneg_done() if the Clause 45 PHY does not + * implement Clause 22 registers + */ + if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) + return -EINVAL; + return genphy_aneg_done(phydev); } @@ -509,9 +515,6 @@ void phy_stop_machine(struct phy_device *phydev) if (phydev->state > PHY_UP && phydev->state != PHY_HALTED) phydev->state = PHY_UP; mutex_unlock(&phydev->lock); - - /* Now we can run the state machine synchronously */ - phy_state_machine(&phydev->state_queue.work); } /** diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index eab57fc5b967c94bdaeeb7cb958ef884aca8086e..49dfb8abc43de0af7623a0503ef1aee5c3d0bbe8 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -332,6 +332,7 @@ static int ks8995_probe(struct spi_device *spi) if (err) return err; + sysfs_attr_init(&ks->regs_attr.attr); err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr); if (err) { dev_err(&spi->dev, "unable to create sysfs file, err=%d\n", diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 3dd1c19756eca78c67c978fb9ed43cd6c08fbfb8..1f32220a868a227af6fd7bd57aa36cc100b89745 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -916,6 +916,7 @@ static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn = net_generic(net, ppp_net_id); + mutex_destroy(&pn->all_ppp_mutex); idr_destroy(&pn->units_idr); } @@ -2907,6 +2908,15 @@ ppp_connect_channel(struct channel *pch, int unit) goto outl; ppp_lock(ppp); + spin_lock_bh(&pch->downl); + if (!pch->chan) { + /* Don't connect unregistered channels */ + spin_unlock_bh(&pch->downl); + ppp_unlock(ppp); + ret = -ENOTCONN; + goto outl; + } + spin_unlock_bh(&pch->downl); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 5aa563136373d467fd710cf6a09de4846bc388b2..960e3ab723a1d4b293c7e6d3a3fb0285586d4e7a 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -613,6 +613,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); error = -EINVAL; + + if (sockaddr_len != sizeof(struct sockaddr_pppox)) + goto end; + if (sp->sa_protocol != PX_PROTO_OE) goto end; @@ -830,6 +834,7 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct pppoe_hdr *ph; struct net_device *dev; char *start; + int hlen; lock_sock(sk); if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { @@ -848,16 +853,16 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, if (total_len > (dev->mtu + dev->hard_header_len)) goto end; - - skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, - 0, GFP_KERNEL); + hlen = LL_RESERVED_SPACE(dev); + skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len + + dev->needed_tailroom, 0, GFP_KERNEL); if (!skb) { error = -ENOMEM; goto end; } /* Reserve space for headers. */ - skb_reserve(skb, dev->hard_header_len); + skb_reserve(skb, hlen); skb_reset_network_header(skb); skb->dev = dev; @@ -918,7 +923,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) /* Copy the data if there is no space for the header or if it's * read-only. */ - if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) + if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph))) goto abort; __skb_push(skb, sizeof(*ph)); diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 0710214df2bfa28585ecf84c3abc5e68cc346c37..ade047f46430e792170f2675407109393d7be155 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -488,7 +488,6 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.mtu = dst_mtu(&rt->dst); if (!po->chan.mtu) po->chan.mtu = PPP_MRU; - ip_rt_put(rt); po->chan.mtu -= PPTP_HEADER_OVERHEAD; po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 27ed25252aac502838527ec48ba48eda754ed69c..cfd81eb1b532ad229fd637cfb13fbde749980a1c 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -509,6 +509,10 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) if(x < 0 || x > comp->rslot_limit) goto bad; + /* Check if the cstate is initialized */ + if (!comp->rstate[x].initialized) + goto bad; + comp->flags &=~ SLF_TOSS; comp->recv_current = x; } else { @@ -673,6 +677,7 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) if (cs->cs_tcp.doff > 5) memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + cs->initialized = true; /* Put headers back on packet * Neither header checksum is recalculated */ diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 16c580379e38de837a0d3a5100d0b02f282f27b8..e149393bba7810de6353b4fb19d56d31aeb4b6be 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -253,6 +253,17 @@ static void __team_option_inst_mark_removed_port(struct team *team, } } +static bool __team_option_inst_tmp_find(const struct list_head *opts, + const struct team_option_inst *needle) +{ + struct team_option_inst *opt_inst; + + list_for_each_entry(opt_inst, opts, tmp_list) + if (opt_inst == needle) + return true; + return false; +} + static int __team_options_register(struct team *team, const struct team_option *option, size_t option_count) @@ -978,7 +989,8 @@ static void team_port_disable(struct team *team, static void __team_compute_features(struct team *team) { struct team_port *port; - u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL; + netdev_features_t vlan_features = TEAM_VLAN_FEATURES & + NETIF_F_ALL_FOR_ALL; unsigned short max_hard_header_len = ETH_HLEN; unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; @@ -1040,14 +1052,11 @@ static void team_port_leave(struct team *team, struct team_port *port) } #ifdef CONFIG_NET_POLL_CONTROLLER -static int team_port_enable_netpoll(struct team *team, struct team_port *port) +static int __team_port_enable_netpoll(struct team_port *port) { struct netpoll *np; int err; - if (!team->dev->npinfo) - return 0; - np = kzalloc(sizeof(*np), GFP_KERNEL); if (!np) return -ENOMEM; @@ -1061,6 +1070,14 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port) return err; } +static int team_port_enable_netpoll(struct team_port *port) +{ + if (!port->team->dev->npinfo) + return 0; + + return __team_port_enable_netpoll(port); +} + static void team_port_disable_netpoll(struct team_port *port) { struct netpoll *np = port->np; @@ -1075,7 +1092,7 @@ static void team_port_disable_netpoll(struct team_port *port) kfree(np); } #else -static int team_port_enable_netpoll(struct team *team, struct team_port *port) +static int team_port_enable_netpoll(struct team_port *port) { return 0; } @@ -1182,7 +1199,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_vids_add; } - err = team_port_enable_netpoll(team, port); + err = team_port_enable_netpoll(port); if (err) { netdev_err(dev, "Failed to enable netpoll on device %s\n", portname); @@ -1887,7 +1904,7 @@ static int team_netpoll_setup(struct net_device *dev, mutex_lock(&team->lock); list_for_each_entry(port, &team->port_list, list) { - err = team_port_enable_netpoll(team, port); + err = __team_port_enable_netpoll(port); if (err) { __team_netpoll_cleanup(team); break; @@ -2331,8 +2348,10 @@ start_again: hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags | NLM_F_MULTI, TEAM_CMD_OPTIONS_GET); - if (!hdr) + if (!hdr) { + nlmsg_free(skb); return -EMSGSIZE; + } if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) goto nla_put_failure; @@ -2366,7 +2385,7 @@ send_done: if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } @@ -2530,6 +2549,14 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) if (err) goto team_put; opt_inst->changed = true; + + /* dumb/evil user-space can send us duplicate opt, + * keep only the last one + */ + if (__team_option_inst_tmp_find(&opt_inst_list, + opt_inst)) + continue; + list_add(&opt_inst->tmp_list, &opt_inst_list); } if (!opt_found) { @@ -2599,8 +2626,10 @@ start_again: hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags | NLM_F_MULTI, TEAM_CMD_PORT_LIST_GET); - if (!hdr) + if (!hdr) { + nlmsg_free(skb); return -EMSGSIZE; + } if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) goto nla_put_failure; @@ -2644,7 +2673,7 @@ send_done: if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5219412843b396af26e079d730b37f5dcca86bba..ef6a7f6c9869fe99dbe5541a44cc7e35b4234e46 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1660,6 +1660,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (!dev) return -ENOMEM; + err = dev_get_valid_name(net, dev, name); + if (err < 0) + goto err_free_dev; dev_net_set(dev, net); dev->rtnl_link_ops = &tun_link_ops; @@ -2064,6 +2067,10 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, ret = -EFAULT; break; } + if (sndbuf <= 0) { + ret = -EINVAL; + break; + } tun->sndbuf = sndbuf; tun_set_sndbuf(tun); diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index db4b09edc6c959be4359bbce4344c16769f7a28d..224360c495cbae0ed9bd163e502cbc96e8a9d57a 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -350,7 +350,7 @@ config USB_NET_NET1080 optionally with LEDs that indicate traffic config USB_NET_PLUSB - tristate "Prolific PL-2301/2302/25A1 based cables" + tristate "Prolific PL-2301/2302/25A1/27A1 based cables" # if the handshake/init/reset problems, from original 'plusb', # are ever resolved ... then remove "experimental" depends on USB_USBNET diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index a1b47ea877fbfdb3cee022918e8e6b939f794280..1a107248b7c839d5c31a70426963cee43a592c79 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -171,6 +171,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC header\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_header_desc)) + break; info->header = (void *) buf; if (info->header->bLength != sizeof(*info->header)) { dev_dbg(&intf->dev, "CDC header len %u\n", @@ -184,6 +186,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) */ if (rndis) { struct usb_cdc_acm_descriptor *acm; + if (len < sizeof(struct usb_cdc_acm_descriptor)) + break; acm = (void *) buf; if (acm->bmCapabilities) { @@ -200,6 +204,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC union\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_union_desc)) + break; info->u = (void *) buf; if (info->u->bLength != sizeof(*info->u)) { dev_dbg(&intf->dev, "CDC union len %u\n", @@ -258,6 +264,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC ether\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_ether_desc)) + break; info->ether = (void *) buf; if (info->ether->bLength != sizeof(*info->ether)) { dev_dbg(&intf->dev, "CDC ether len %u\n", @@ -275,7 +283,6 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra MDLM descriptor\n"); goto bad_desc; } - desc = (void *)buf; if (desc->bLength != sizeof(*desc)) diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index d11415bb9bb1da8a349daf5af72e19e82fd107d3..279708e1f89073af04a04d53198c1c71f0276053 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -550,7 +550,7 @@ err: static const struct driver_info cdc_mbim_info = { .description = "CDC MBIM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, + .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP, .bind = cdc_mbim_bind, .unbind = cdc_mbim_unbind, .manage_power = cdc_mbim_manage_power, diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 1bfe0fcaccf5ba31bf125f898ec6c624f506206e..7c02231c1a1bfa6cda9b3bbea50613620f1a8b00 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -102,7 +102,7 @@ static int pl_reset(struct usbnet *dev) } static const struct driver_info prolific_info = { - .description = "Prolific PL-2301/PL-2302/PL-25A1", + .description = "Prolific PL-2301/PL-2302/PL-25A1/PL-27A1", .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, @@ -139,6 +139,17 @@ static const struct usb_device_id products [] = { * Host-to-Host Cable */ .driver_info = (unsigned long) &prolific_info, + +}, + +/* super speed cables */ +{ + USB_DEVICE(0x067b, 0x27a1), /* PL-27A1, no eeprom + * also: goobay Active USB 3.0 + * Data Link, + * Unitek Y-3501 + */ + .driver_info = (unsigned long) &prolific_info, }, { }, // END @@ -158,5 +169,5 @@ static struct usb_driver plusb_driver = { module_usb_driver(plusb_driver); MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"); +MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1/27A1 USB Host to Host Link Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index f1ab3023fe0404bf09489e951e2831a86916d0c3..2fd4807aa8cf73bfbd8471690b91e7766561f3bf 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -314,7 +314,7 @@ next_desc: } /* errors aren't fatal - we can live with the dynamic address */ - if (cdc_ether) { + if (cdc_ether && cdc_ether->wMaxSegmentSize) { dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize); usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); } @@ -460,6 +460,10 @@ static const struct usb_device_id products[] = { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x69), .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* Motorola Mapphone devices with MDM6600 */ + USB_VENDOR_AND_INTERFACE_INFO(0x22b8, USB_CLASS_VENDOR_SPEC, 0xfb, 0xff), + .driver_info = (unsigned long)&qmi_wwan_info, + }, /* 2. Combined interface devices matching on class+protocol */ { /* Huawei E367 and possibly others in "Windows mode" */ @@ -669,11 +673,16 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x9080, 8)}, {QMI_FIXED_INTF(0x05c6, 0x9083, 3)}, {QMI_FIXED_INTF(0x05c6, 0x9084, 4)}, + {QMI_FIXED_INTF(0x05c6, 0x90b2, 3)}, /* ublox R410M */ {QMI_FIXED_INTF(0x05c6, 0x920d, 0)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, + {QMI_FIXED_INTF(0x0846, 0x68d3, 8)}, /* Netgear Aircard 779S */ {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 3)}, /* Wistron NeWeb D18Q1 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 4)}, /* Wistron NeWeb D18Q1 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 5)}, /* Wistron NeWeb D18Q1 */ {QMI_FIXED_INTF(0x16d8, 0x6003, 0)}, /* CMOTech 6003 */ {QMI_FIXED_INTF(0x16d8, 0x6007, 0)}, /* CMOTech CHE-628S */ {QMI_FIXED_INTF(0x16d8, 0x6008, 0)}, /* CMOTech CMU-301 */ @@ -750,6 +759,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ {QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */ {QMI_FIXED_INTF(0x2001, 0x7e35, 4)}, /* D-Link DWM-222 */ + {QMI_FIXED_INTF(0x2020, 0x2033, 4)}, /* BroadMobi BM806U */ {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ @@ -768,8 +778,13 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x9061, 8)}, /* Sierra Wireless Modem */ {QMI_FIXED_INTF(0x1199, 0x9070, 8)}, /* Sierra Wireless MC74xx/EM74xx */ {QMI_FIXED_INTF(0x1199, 0x9070, 10)}, /* Sierra Wireless MC74xx/EM74xx */ - {QMI_FIXED_INTF(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx/EM74xx */ - {QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx/EM74xx */ + {QMI_FIXED_INTF(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx */ + {QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx */ + {QMI_FIXED_INTF(0x1199, 0x9079, 8)}, /* Sierra Wireless EM74xx */ + {QMI_FIXED_INTF(0x1199, 0x9079, 10)}, /* Sierra Wireless EM74xx */ + {QMI_FIXED_INTF(0x1199, 0x907b, 8)}, /* Sierra Wireless EM74xx */ + {QMI_FIXED_INTF(0x1199, 0x907b, 10)}, /* Sierra Wireless EM74xx */ + {QMI_FIXED_INTF(0x1199, 0x9091, 8)}, /* Sierra Wireless EM7565 */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ @@ -856,6 +871,7 @@ static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) { struct usb_device_id *id = (struct usb_device_id *)prod; + struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; /* Workaround to enable dynamic IDs. This disables usbnet * blacklisting functionality. Which, if required, can be @@ -867,6 +883,18 @@ static int qmi_wwan_probe(struct usb_interface *intf, id->driver_info = (unsigned long)&qmi_wwan_info; } + /* There are devices where the same interface number can be + * configured as different functions. We should only bind to + * vendor specific functions when matching on interface number + */ + if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER && + desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) { + dev_dbg(&intf->dev, + "Rejecting interface number match for class %02x\n", + desc->bInterfaceClass); + return -ENODEV; + } + return usbnet_probe(intf, id); } diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 850e90684e389a0f8eb67514f566a09659a9f426..68cc5f58e45cf6534d3c041f05121d6fdb48c439 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1252,6 +1252,7 @@ static int alloc_all_mem(struct r8152 *tp) spin_lock_init(&tp->tx_lock); INIT_LIST_HEAD(&tp->rx_done); INIT_LIST_HEAD(&tp->tx_free); + INIT_LIST_HEAD(&tp->rx_done); skb_queue_head_init(&tp->tx_queue); for (i = 0; i < RTL8152_MAX_RX; i++) { @@ -1589,7 +1590,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) tx_data += len; agg->skb_len += len; - agg->skb_num++; + agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1; dev_kfree_skb_any(skb); diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 30b44326364e6646f3c7668a44cca6c57cc6aaa4..ab9cfa8e6ac6b50c459baac3023d31db0822c725 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -661,7 +661,7 @@ static void rtl8150_set_multicast(struct net_device *netdev) (netdev->flags & IFF_ALLMULTI)) { rx_creg &= 0xfffe; rx_creg |= 0x0002; - dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name); + dev_dbg(&netdev->dev, "%s: allmulti set\n", netdev->name); } else { /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ rx_creg &= 0x00fc; diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 25f9faefdf303e464b78bf8cc494bb91341e9bad..c3b6815f07c35feb28d44efaa724063980038fac 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -81,6 +81,9 @@ static bool turbo_mode = true; module_param(turbo_mode, bool, 0644); MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); +static int smsc75xx_link_ok_nopm(struct usbnet *dev); +static int smsc75xx_phy_gig_workaround(struct usbnet *dev); + static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index, u32 *data, int in_pm) { @@ -840,6 +843,9 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) return -EIO; } + /* phy workaround for gig link */ + smsc75xx_phy_gig_workaround(dev); + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); @@ -945,10 +951,11 @@ static int smsc75xx_set_features(struct net_device *netdev, /* it's racing here! */ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - if (ret < 0) + if (ret < 0) { netdev_warn(dev->net, "Error writing RFE_CTL\n"); - - return ret; + return ret; + } + return 0; } static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) @@ -977,6 +984,62 @@ static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) return -EIO; } +static int smsc75xx_phy_gig_workaround(struct usbnet *dev) +{ + struct mii_if_info *mii = &dev->mii; + int ret = 0, timeout = 0; + u32 buf, link_up = 0; + + /* Set the phy in Gig loopback */ + smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040); + + /* Wait for the link up */ + do { + link_up = smsc75xx_link_ok_nopm(dev); + usleep_range(10000, 20000); + timeout++; + } while ((!link_up) && (timeout < 1000)); + + if (timeout >= 1000) { + netdev_warn(dev->net, "Timeout waiting for PHY link up\n"); + return -EIO; + } + + /* phy reset */ + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret); + return ret; + } + + buf |= PMT_CTL_PHY_RST; + + ret = smsc75xx_write_reg(dev, PMT_CTL, buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret); + return ret; + } + + timeout = 0; + do { + usleep_range(10000, 20000); + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", + ret); + return ret; + } + timeout++; + } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); + + if (timeout >= 100) { + netdev_warn(dev->net, "timeout waiting for PHY Reset\n"); + return -EIO; + } + + return 0; +} + static int smsc75xx_reset(struct usbnet *dev) { struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 32ce1cd64d51c035c3a32a8f8892b00fde76d409..b6b32282854900acfbf156818ffef298cef7f297 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -382,6 +382,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (ifmp && (dev->ifindex != 0)) peer->ifindex = ifmp->ifi_index; + peer->gso_max_size = dev->gso_max_size; + peer->gso_max_segs = dev->gso_max_segs; + err = register_netdevice(peer); put_net(net); net = NULL; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index ce2a29971230cba661085228eef519eb71be2aab..3b507ccbfac85f884ed72bc131680d5719cab3dc 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -551,7 +551,12 @@ static int add_recvbuf_small(struct receive_queue *rq, gfp_t gfp) hdr = skb_vnet_hdr(skb); sg_init_table(rq->sg, MAX_SKB_FRAGS + 2); sg_set_buf(rq->sg, &hdr->hdr, sizeof hdr->hdr); - skb_to_sgvec(skb, rq->sg + 1, 0, skb->len); + + err = skb_to_sgvec(skb, rq->sg + 1, 0, skb->len); + if (unlikely(err < 0)) { + dev_kfree_skb(skb); + return err; + } err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp); if (err < 0) @@ -854,7 +859,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) struct skb_vnet_hdr *hdr; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; struct virtnet_info *vi = sq->vq->vdev->priv; - unsigned num_sg; + int num_sg; unsigned hdr_len; bool can_push; @@ -906,11 +911,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) if (can_push) { __skb_push(skb, hdr_len); num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; /* Pull header back to avoid skew in tx bytes calculations. */ __skb_pull(skb, hdr_len); } else { sg_set_buf(sq->sg, hdr, hdr_len); - num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1; + num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; + num_sg++; } return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC); } @@ -1866,8 +1876,8 @@ static int virtnet_probe(struct virtio_device *vdev) /* Assume link up if device can't report link status, otherwise get link status from config. */ + netif_carrier_off(dev); if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { - netif_carrier_off(dev); schedule_work(&vi->config_work); } else { vi->status = VIRTIO_NET_S_LINK_UP; diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 6dfcbf523936ef69527f5d23168dbf51ee638094..56a2bc86c439b974b47782e33496f5d590cfa14a 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1420,7 +1420,6 @@ static void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq, rq->rx_ring[i].basePA); rq->rx_ring[i].base = NULL; } - rq->buf_info[i] = NULL; } if (rq->comp_ring.base) { @@ -1435,6 +1434,7 @@ static void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq, (rq->rx_ring[0].size + rq->rx_ring[1].size); dma_free_coherent(&adapter->pdev->dev, sz, rq->buf_info[0], rq->buf_info_pa); + rq->buf_info[0] = rq->buf_info[1] = NULL; } } @@ -2648,6 +2648,11 @@ vmxnet3_force_close(struct vmxnet3_adapter *adapter) /* we need to enable NAPI, otherwise dev_close will deadlock */ for (i = 0; i < adapter->num_rx_queues; i++) napi_enable(&adapter->rx_queue[i].napi); + /* + * Need to clear the quiesce bit to ensure that vmxnet3_close + * can quiesce the device properly + */ + clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state); dev_close(adapter->netdev); } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index d22686e7b22195f4c4271598e97761a09afdec52..cfdedb123ea65c636b1f51bd5049400041427e85 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -985,7 +985,7 @@ static bool vxlan_snoop(struct net_device *dev, return false; /* Don't migrate static entries, drop packets */ - if (f->state & NUD_NOARP) + if (f->state & (NUD_PERMANENT | NUD_NOARP)) return true; if (net_ratelimit()) diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 0d7645581f912d04b79e4374fa46c2ed451b7617..4842344a96f1d3a38f6e7a50af0255915f21fe28 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -574,7 +574,10 @@ static void ppp_timer(unsigned long arg) ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, 0, NULL); proto->restart_counter--; - } else + } else if (netif_carrier_ok(proto->dev)) + ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, + 0, NULL); + else ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0, 0, NULL); break; diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index bea0f313a7a80cbd7528795ff04e67162f77f347..2b2d01a3e511ea9cbdc804e66041c3552991b265 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1384,7 +1384,7 @@ static irqreturn_t lmc_interrupt (int irq, void *dev_instance) /*fold00*/ case 0x001: printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name); break; - case 0x010: + case 0x002: printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name); break; default: diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index db363856e0b52aff1a4f2f6d9ac4416ccd7d031b..2b064998915fccd41a9195289252b7f8e265d8f9 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -347,6 +347,7 @@ static int pc300_pci_init_one(struct pci_dev *pdev, card->rambase == NULL) { pr_err("ioremap() failed\n"); pc300_pci_remove_one(pdev); + return -ENOMEM; } /* PLX PCI 9050 workaround for local configuration register read bug */ diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index e7f5910a65191f4f013ae53db73d2a77510ae9e8..f8eb66ef2944ea9630237455cae4faf483b4f609 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -467,6 +467,9 @@ int i2400mu_probe(struct usb_interface *iface, struct i2400mu *i2400mu; struct usb_device *usb_dev = interface_to_usbdev(iface); + if (iface->cur_altsetting->desc.bNumEndpoints < 4) + return -ENODEV; + if (usb_dev->speed != USB_SPEED_HIGH) dev_err(dev, "device not connected as high speed\n"); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 3756feba32231cffcddd112575163d1a7cf6cc67..d3ebac0d7f7a4c96fc226e86d3d172a840f29d5b 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1079,6 +1079,15 @@ static ssize_t ath10k_write_simulate_radar(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; + struct ath10k_vif *arvif; + + /* Just check for for the first vif alone, as all the vifs will be + * sharing the same channel and if the channel is disabled, all the + * vifs will share the same 'is_started' state. + */ + arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); + if (!arvif->is_started) + return -EINVAL; ieee80211_radar_detected(ar->hw); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a9d84c18562bf5b5100a34a5557a1899f0424597..eb086e6f215d802b868fbc9069298a02c1d63fa7 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1729,6 +1729,13 @@ static int ath10k_update_channel_list(struct ath10k *ar) passive = channel->flags & IEEE80211_CHAN_NO_IR; ch->passive = passive; + /* the firmware is ignoring the "radar" flag of the + * channel and is scanning actively using Probe Requests + * on "Radar detection"/DFS channels which are not + * marked as "available" + */ + ch->passive |= ch->chan_radar; + ch->freq = channel->center_freq; ch->min_power = 0; ch->max_power = channel->max_power * 2; @@ -4320,10 +4327,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k_vif *arvif = (void *)vif->drv_priv; + struct ath10k_peer *peer; u32 bw, smps; spin_lock_bh(&ar->data_lock); + peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr); + if (!peer) { + spin_unlock_bh(&ar->data_lock); + ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n", + sta->addr, arvif->vdev_id); + return; + } + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", sta->addr, changed, sta->bandwidth, sta->rx_nss, diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index c70782e8f07bd704b2ff495339eb5ab6b65864bc..b5802e37ab242a448f23058c357ee564d0b32f82 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -939,7 +939,10 @@ static int open_file_eeprom(struct inode *inode, struct file *file) } for (i = 0; i < eesize; ++i) { - AR5K_EEPROM_READ(i, val); + if (!ath5k_hw_nvram_read(ah, i, &val)) { + ret = -EIO; + goto freebuf; + } buf[i] = val; } diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 2ea3589f709f5587685cb19e6e92a22ef83228b0..b7ab8455ffbd9561e3f31e664073d2251d17dd4b 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -180,6 +180,9 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, ssize_t len; int r; + if (count < 1) + return -EINVAL; + if (sc->cur_chan->nvifs > 1) return -EOPNOTSUPP; @@ -187,6 +190,8 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, if (copy_from_user(buf, user_buf, len)) return -EFAULT; + buf[len] = '\0'; + if (strtobool(buf, &start)) return -EINVAL; diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 06ea6cc9e30a5e07c379116a8e1ec0996e3f189e..62077bda8dde0e7dd9b119162bcf0038bb71feba 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -254,8 +254,12 @@ bool ath_is_49ghz_allowed(u16 regdomain) EXPORT_SYMBOL(ath_is_49ghz_allowed); /* Frequency is one where radar detection is required */ -static bool ath_is_radar_freq(u16 center_freq) +static bool ath_is_radar_freq(u16 center_freq, + struct ath_regulatory *reg) + { + if (reg->country_code == CTRY_INDIA) + return (center_freq >= 5500 && center_freq <= 5700); return (center_freq >= 5260 && center_freq <= 5700); } @@ -306,7 +310,7 @@ __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ieee80211_channel *ch) { - if (ath_is_radar_freq(ch->center_freq) || + if (ath_is_radar_freq(ch->center_freq, reg) || (ch->flags & IEEE80211_CHAN_RADAR)) return; @@ -395,8 +399,9 @@ ath_reg_apply_ir_flags(struct wiphy *wiphy, } } -/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ -static void ath_reg_apply_radar_flags(struct wiphy *wiphy) +/* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */ +static void ath_reg_apply_radar_flags(struct wiphy *wiphy, + struct ath_regulatory *reg) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; @@ -409,7 +414,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy) for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; - if (!ath_is_radar_freq(ch->center_freq)) + if (!ath_is_radar_freq(ch->center_freq, reg)) continue; /* We always enable radar detection/DFS on this * frequency range. Additionally we also apply on @@ -505,7 +510,7 @@ void ath_reg_notifier_apply(struct wiphy *wiphy, struct ath_common *common = container_of(reg, struct ath_common, regulatory); /* We always apply this */ - ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_radar_flags(wiphy, reg); /* * This would happen when we have sent a custom regulatory request @@ -653,7 +658,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, } wiphy_apply_custom_regulatory(wiphy, regd); - ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_radar_flags(wiphy, reg); ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); return 0; } diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 37f53bd8fcb13ad1b7f850924383a4e9a297f7af..184b6810cde9903a2d48a43d876710e1c9b68170 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -68,12 +68,14 @@ enum CountryCode { CTRY_AUSTRALIA = 36, CTRY_AUSTRIA = 40, CTRY_AZERBAIJAN = 31, + CTRY_BAHAMAS = 44, CTRY_BAHRAIN = 48, CTRY_BANGLADESH = 50, CTRY_BARBADOS = 52, CTRY_BELARUS = 112, CTRY_BELGIUM = 56, CTRY_BELIZE = 84, + CTRY_BERMUDA = 60, CTRY_BOLIVIA = 68, CTRY_BOSNIA_HERZ = 70, CTRY_BRAZIL = 76, @@ -159,6 +161,7 @@ enum CountryCode { CTRY_ROMANIA = 642, CTRY_RUSSIA = 643, CTRY_SAUDI_ARABIA = 682, + CTRY_SERBIA = 688, CTRY_SERBIA_MONTENEGRO = 891, CTRY_SINGAPORE = 702, CTRY_SLOVAKIA = 703, @@ -170,11 +173,13 @@ enum CountryCode { CTRY_SWITZERLAND = 756, CTRY_SYRIA = 760, CTRY_TAIWAN = 158, + CTRY_TANZANIA = 834, CTRY_THAILAND = 764, CTRY_TRINIDAD_Y_TOBAGO = 780, CTRY_TUNISIA = 788, CTRY_TURKEY = 792, CTRY_UAE = 784, + CTRY_UGANDA = 800, CTRY_UKRAINE = 804, CTRY_UNITED_KINGDOM = 826, CTRY_UNITED_STATES = 840, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index bdd2b4d61f2f0f797dc40f9fe49b5d549ed6c129..15bbd1e0d912f5c799661b5adbb6c48e99da2819 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -35,6 +35,7 @@ enum EnumRd { FRANCE_RES = 0x31, FCC3_FCCA = 0x3A, FCC3_WORLD = 0x3B, + FCC3_ETSIC = 0x3F, ETSI1_WORLD = 0x37, ETSI3_ETSIA = 0x32, @@ -44,6 +45,7 @@ enum EnumRd { ETSI4_ETSIC = 0x38, ETSI5_WORLD = 0x39, ETSI6_WORLD = 0x34, + ETSI8_WORLD = 0x3D, ETSI_RESERVED = 0x33, MKK1_MKKA = 0x40, @@ -59,6 +61,7 @@ enum EnumRd { MKK1_MKKA1 = 0x4A, MKK1_MKKA2 = 0x4B, MKK1_MKKC = 0x4C, + APL2_FCCA = 0x4D, APL3_FCCA = 0x50, APL1_WORLD = 0x52, @@ -67,6 +70,7 @@ enum EnumRd { APL1_ETSIC = 0x55, APL2_ETSIC = 0x56, APL5_WORLD = 0x58, + APL13_WORLD = 0x5A, APL6_WORLD = 0x5B, APL7_FCCA = 0x5C, APL8_WORLD = 0x5D, @@ -168,6 +172,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, {FCC3_FCCA, CTL_FCC, CTL_FCC}, {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, {FCC4_FCCA, CTL_FCC, CTL_FCC}, {FCC5_FCCA, CTL_FCC, CTL_FCC}, {FCC6_FCCA, CTL_FCC, CTL_FCC}, @@ -179,6 +184,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI8_WORLD, CTL_ETSI, CTL_ETSI}, /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, @@ -188,9 +194,11 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC1_FCCA, CTL_FCC, CTL_FCC}, {APL1_WORLD, CTL_FCC, CTL_ETSI}, {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_FCCA, CTL_FCC, CTL_FCC}, {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL13_WORLD, CTL_ETSI, CTL_ETSI}, {APL6_WORLD, CTL_ETSI, CTL_ETSI}, {APL8_WORLD, CTL_ETSI, CTL_ETSI}, {APL9_WORLD, CTL_ETSI, CTL_ETSI}, @@ -298,6 +306,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"}, {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, {CTRY_BARBADOS, FCC2_WORLD, "BB"}, @@ -305,6 +314,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BERMUDA, FCC3_FCCA, "BM"}, {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"}, @@ -444,6 +454,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_ROMANIA, NULL1_WORLD, "RO"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA, ETSI1_WORLD, "RS"}, {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, {CTRY_SINGAPORE, APL6_WORLD, "SG"}, {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, @@ -455,10 +466,12 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_TANZANIA, APL1_WORLD, "TZ"}, {CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UGANDA, FCC3_WORLD, "UG"}, {CTRY_UKRAINE, NULL1_WORLD, "UA"}, {CTRY_UAE, NULL1_WORLD, "AE"}, {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index d6f79b80b7debc3a7a6da4b9645117bd08f66a98..6ff3931f35d8930d242a0da9ede1d031eb72c6f4 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -129,9 +129,15 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, u32 *d = dst; const volatile u32 __iomem *s = src; - /* size_t is unsigned, if (count%4 != 0) it will wrap */ - for (count += 4; count > 4; count -= 4) + for (; count >= 4; count -= 4) *d++ = __raw_readl(s++); + + if (unlikely(count)) { + /* count can be 1..3 */ + u32 tmp = __raw_readl(s); + + memcpy(d, &tmp, count); + } } void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, @@ -148,8 +154,16 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, volatile u32 __iomem *d = dst; const u32 *s = src; - for (count += 4; count > 4; count -= 4) + for (; count >= 4; count -= 4) __raw_writel(*s++, d++); + + if (unlikely(count)) { + /* count can be 1..3 */ + u32 tmp = 0; + + memcpy(&tmp, s, count); + __raw_writel(tmp, d); + } } void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index d20d4e6f391ae89706e422e2b817034ee030c0ae..f6d35d9a06eb7e0bb1e8218c51adaaeb2c9c4678 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -4201,6 +4201,13 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); if (bus) { + /* Stop watchdog task */ + if (bus->watchdog_tsk) { + send_sig(SIGTERM, bus->watchdog_tsk, 1); + kthread_stop(bus->watchdog_tsk); + bus->watchdog_tsk = NULL; + } + /* De-register interrupt handler */ brcmf_sdiod_intr_unregister(bus->sdiodev); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index d54c58a32faa52bf9b6dc2cb36edd35c07993302..0d7a01a5adcf1f4b7734868e238964bb735772d0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -460,25 +460,23 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) * @dev_addr: optional device address. * * P2P needs mac addresses for P2P device and interface. If no device - * address it specified, these are derived from the primary net device, ie. - * the permanent ethernet address of the device. + * address it specified, these are derived from a random ethernet + * address. */ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr) { - struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; - bool local_admin = false; + bool random_addr = false; - if (!dev_addr || is_zero_ether_addr(dev_addr)) { - dev_addr = pri_ifp->mac_addr; - local_admin = true; - } + if (!dev_addr || is_zero_ether_addr(dev_addr)) + random_addr = true; - /* Generate the P2P Device Address. This consists of the device's - * primary MAC address with the locally administered bit set. + /* Generate the P2P Device Address obtaining a random ethernet + * address with the locally administered bit set. */ - memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); - if (local_admin) - p2p->dev_addr[0] |= 0x02; + if (random_addr) + eth_random_addr(p2p->dev_addr); + else + memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); /* Generate the P2P Interface Address. If the discovery and connection * BSSCFGs need to simultaneously co-exist, then this address must be diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 084f18f4f95039c921b1c82c548c904fcb6ccf67..498f437e7738249bdeefc1a09b2f8185496bb427 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -14764,8 +14764,8 @@ static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi) } static void -wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys, - u8 len) +wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, const u8 *events, + const u8 *dlys, u8 len) { u32 t1_offset, t2_offset; u8 ctr; @@ -15240,16 +15240,16 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi) static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) { u16 currband; - s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 }; - s8 *lna1_gain_db = NULL; - s8 *lna1_gain_db_2 = NULL; - s8 *lna2_gain_db = NULL; - s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 }; - s8 *tia_gain_db; - s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 }; - s8 *tia_gainbits; - u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f }; - u16 *rfseq_init_gain; + static const s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 }; + const s8 *lna1_gain_db = NULL; + const s8 *lna1_gain_db_2 = NULL; + const s8 *lna2_gain_db = NULL; + static const s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 }; + const s8 *tia_gain_db; + static const s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 }; + const s8 *tia_gainbits; + static const u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f }; + const u16 *rfseq_init_gain; u16 init_gaincode; u16 clip1hi_gaincode; u16 clip1md_gaincode = 0; @@ -15310,10 +15310,9 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) if ((freq <= 5080) || (freq == 5825)) { - s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 }; - s8 lna1A_gain_db_2_rev7[] = { - 11, 17, 22, 25}; - s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; + static const s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 }; + static const s8 lna1A_gain_db_2_rev7[] = { 11, 17, 22, 25}; + static const s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; crsminu_th = 0x3e; lna1_gain_db = lna1A_gain_db_rev7; @@ -15321,10 +15320,9 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) lna2_gain_db = lna2A_gain_db_rev7; } else if ((freq >= 5500) && (freq <= 5700)) { - s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 }; - s8 lna1A_gain_db_2_rev7[] = { - 12, 18, 22, 26}; - s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 }; + static const s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 }; + static const s8 lna1A_gain_db_2_rev7[] = { 12, 18, 22, 26}; + static const s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 }; crsminu_th = 0x45; clip1md_gaincode_B = 0x14; @@ -15335,10 +15333,9 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) lna2_gain_db = lna2A_gain_db_rev7; } else { - s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 }; - s8 lna1A_gain_db_2_rev7[] = { - 12, 18, 22, 26}; - s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; + static const s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 }; + static const s8 lna1A_gain_db_2_rev7[] = { 12, 18, 22, 26}; + static const s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; crsminu_th = 0x41; lna1_gain_db = lna1A_gain_db_rev7; @@ -15450,65 +15447,65 @@ static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) NPHY_RFSEQ_CMD_CLR_HIQ_DIS, NPHY_RFSEQ_CMD_SET_HPF_BW }; - u8 rfseq_updategainu_dlys[] = { 10, 30, 1 }; - s8 lna1G_gain_db[] = { 7, 11, 16, 23 }; - s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 }; - s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 }; - s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 }; - s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 }; - s8 lna1A_gain_db[] = { 7, 11, 17, 23 }; - s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 }; - s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 }; - s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 }; - s8 *lna1_gain_db = NULL; - s8 lna2G_gain_db[] = { -5, 6, 10, 14 }; - s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 }; - s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 }; - s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 }; - s8 lna2A_gain_db[] = { -6, 2, 6, 10 }; - s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 }; - s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 }; - s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 }; - s8 *lna2_gain_db = NULL; - s8 tiaG_gain_db[] = { + static const u8 rfseq_updategainu_dlys[] = { 10, 30, 1 }; + static const s8 lna1G_gain_db[] = { 7, 11, 16, 23 }; + static const s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 }; + static const s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 }; + static const s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 }; + static const s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 }; + static const s8 lna1A_gain_db[] = { 7, 11, 17, 23 }; + static const s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 }; + static const s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 }; + static const s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 }; + const s8 *lna1_gain_db = NULL; + static const s8 lna2G_gain_db[] = { -5, 6, 10, 14 }; + static const s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 }; + static const s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 }; + static const s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 }; + static const s8 lna2A_gain_db[] = { -6, 2, 6, 10 }; + static const s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 }; + static const s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 }; + static const s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 }; + const s8 *lna2_gain_db = NULL; + static const s8 tiaG_gain_db[] = { 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A }; - s8 tiaA_gain_db[] = { + static const s8 tiaA_gain_db[] = { 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 }; - s8 tiaA_gain_db_rev4[] = { + static const s8 tiaA_gain_db_rev4[] = { 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; - s8 tiaA_gain_db_rev5[] = { + static const s8 tiaA_gain_db_rev5[] = { 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; - s8 tiaA_gain_db_rev6[] = { + static const s8 tiaA_gain_db_rev6[] = { 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; - s8 *tia_gain_db; - s8 tiaG_gainbits[] = { + const s8 *tia_gain_db; + static const s8 tiaG_gainbits[] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; - s8 tiaA_gainbits[] = { + static const s8 tiaA_gainbits[] = { 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 }; - s8 tiaA_gainbits_rev4[] = { + static const s8 tiaA_gainbits_rev4[] = { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; - s8 tiaA_gainbits_rev5[] = { + static const s8 tiaA_gainbits_rev5[] = { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; - s8 tiaA_gainbits_rev6[] = { + static const s8 tiaA_gainbits_rev6[] = { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; - s8 *tia_gainbits; - s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 }; - s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 }; - u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f }; - u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f }; - u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f }; - u16 rfseqG_init_gain_rev5_elna[] = { + const s8 *tia_gainbits; + static const s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 }; + static const s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 }; + static const u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f }; + static const u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f }; + static const u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f }; + static const u16 rfseqG_init_gain_rev5_elna[] = { 0x013f, 0x013f, 0x013f, 0x013f }; - u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f }; - u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f }; - u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f }; - u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f }; - u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f }; - u16 rfseqA_init_gain_rev4_elna[] = { + static const u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f }; + static const u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f }; + static const u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f }; + static const u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f }; + static const u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f }; + static const u16 rfseqA_init_gain_rev4_elna[] = { 0x314f, 0x314f, 0x314f, 0x314f }; - u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f }; - u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f }; - u16 *rfseq_init_gain; + static const u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f }; + static const u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f }; + const u16 *rfseq_init_gain; u16 initG_gaincode = 0x627e; u16 initG_gaincode_rev4 = 0x527e; u16 initG_gaincode_rev5 = 0x427e; @@ -15538,10 +15535,10 @@ static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) u16 clip1mdA_gaincode_rev6 = 0x2084; u16 clip1md_gaincode = 0; u16 clip1loG_gaincode = 0x0074; - u16 clip1loG_gaincode_rev5[] = { + static const u16 clip1loG_gaincode_rev5[] = { 0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c }; - u16 clip1loG_gaincode_rev6[] = { + static const u16 clip1loG_gaincode_rev6[] = { 0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e }; u16 clip1loG_gaincode_rev6_224B0 = 0x1074; @@ -16066,7 +16063,7 @@ static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) { - u8 rfseq_rx2tx_events[] = { + static const u8 rfseq_rx2tx_events[] = { NPHY_RFSEQ_CMD_NOP, NPHY_RFSEQ_CMD_RXG_FBW, NPHY_RFSEQ_CMD_TR_SWITCH, @@ -16076,7 +16073,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) NPHY_RFSEQ_CMD_EXT_PA }; u8 rfseq_rx2tx_dlys[] = { 8, 6, 6, 2, 4, 60, 1 }; - u8 rfseq_tx2rx_events[] = { + static const u8 rfseq_tx2rx_events[] = { NPHY_RFSEQ_CMD_NOP, NPHY_RFSEQ_CMD_EXT_PA, NPHY_RFSEQ_CMD_TX_GAIN, @@ -16085,8 +16082,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) NPHY_RFSEQ_CMD_RXG_FBW, NPHY_RFSEQ_CMD_CLR_HIQ_DIS }; - u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 }; - u8 rfseq_tx2rx_events_rev3[] = { + static const u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 }; + static const u8 rfseq_tx2rx_events_rev3[] = { NPHY_REV3_RFSEQ_CMD_EXT_PA, NPHY_REV3_RFSEQ_CMD_INT_PA_PU, NPHY_REV3_RFSEQ_CMD_TX_GAIN, @@ -16096,7 +16093,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, NPHY_REV3_RFSEQ_CMD_END }; - u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 }; + static const u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 }; u8 rfseq_rx2tx_events_rev3[] = { NPHY_REV3_RFSEQ_CMD_NOP, NPHY_REV3_RFSEQ_CMD_RXG_FBW, @@ -16110,7 +16107,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) }; u8 rfseq_rx2tx_dlys_rev3[] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 }; - u8 rfseq_rx2tx_events_rev3_ipa[] = { + static const u8 rfseq_rx2tx_events_rev3_ipa[] = { NPHY_REV3_RFSEQ_CMD_NOP, NPHY_REV3_RFSEQ_CMD_RXG_FBW, NPHY_REV3_RFSEQ_CMD_TR_SWITCH, @@ -16121,15 +16118,15 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) NPHY_REV3_RFSEQ_CMD_INT_PA_PU, NPHY_REV3_RFSEQ_CMD_END }; - u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; - u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f }; + static const u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; + static const u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f }; s16 alpha0, alpha1, alpha2; s16 beta0, beta1, beta2; u32 leg_data_weights, ht_data_weights, nss1_data_weights, stbc_data_weights; u8 chan_freq_range = 0; - u16 dac_control = 0x0002; + static const u16 dac_control = 0x0002; u16 aux_adc_vmid_rev7_core0[] = { 0x8e, 0x96, 0x96, 0x96 }; u16 aux_adc_vmid_rev7_core1[] = { 0x8f, 0x9f, 0x9f, 0x96 }; u16 aux_adc_vmid_rev4[] = { 0xa2, 0xb4, 0xb4, 0x89 }; @@ -16139,8 +16136,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) u16 aux_adc_gain_rev4[] = { 0x02, 0x02, 0x02, 0x00 }; u16 aux_adc_gain_rev3[] = { 0x02, 0x02, 0x02, 0x00 }; u16 *aux_adc_gain; - u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 }; - u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 }; + static const u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 }; + static const u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 }; s32 min_nvar_val = 0x18d; s32 min_nvar_offset_6mbps = 20; u8 pdetrange; @@ -16151,9 +16148,9 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) u16 rfseq_rx2tx_lpf_h_hpc_rev7 = 0x77; u16 rfseq_tx2rx_lpf_h_hpc_rev7 = 0x77; u16 rfseq_pktgn_lpf_h_hpc_rev7 = 0x77; - u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 }; - u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; - u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; + static const u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 }; + static const u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; + static const u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; u16 ipalvlshift_3p3_war_en = 0; u16 rccal_bcap_val, rccal_scap_val; u16 rccal_tx20_11b_bcap = 0; @@ -24298,13 +24295,13 @@ static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core) u16 bbmult; u16 tblentry; - struct nphy_txiqcal_ladder ladder_lo[] = { + static const struct nphy_txiqcal_ladder ladder_lo[] = { {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5}, {25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7} }; - struct nphy_txiqcal_ladder ladder_iq[] = { + static const struct nphy_txiqcal_ladder ladder_iq[] = { {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, {25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1}, {100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7} @@ -25780,67 +25777,67 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, u16 cal_gain[2]; struct nphy_iqcal_params cal_params[2]; u32 tbl_len; - void *tbl_ptr; + const void *tbl_ptr; bool ladder_updated[2]; u8 mphase_cal_lastphase = 0; int bcmerror = 0; bool phyhang_avoid_state = false; - u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { + static const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { 0x0300, 0x0500, 0x0700, 0x0900, 0x0d00, 0x1100, 0x1900, 0x1901, 0x1902, 0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 0x2407, 0x3207, 0x4607, 0x6407 }; - u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { + static const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { 0x0200, 0x0300, 0x0600, 0x0900, 0x0d00, 0x1100, 0x1900, 0x2400, 0x3200, 0x4600, 0x6400, 0x6401, 0x6402, 0x6403, 0x6404, 0x6405, 0x6406, 0x6407 }; - u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { + static const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { 0x0200, 0x0300, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1201, 0x1202, 0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 0x1907, 0x2307, 0x3207, 0x4707 }; - u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { + static const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { 0x0100, 0x0200, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1900, 0x2300, 0x3200, 0x4700, 0x4701, 0x4702, 0x4703, 0x4704, 0x4705, 0x4706, 0x4707 }; - u16 tbl_tx_iqlo_cal_startcoefs[] = { + static const u16 tbl_tx_iqlo_cal_startcoefs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; - u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { + static const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { 0x8123, 0x8264, 0x8086, 0x8245, 0x8056, 0x9123, 0x9264, 0x9086, 0x9245, 0x9056 }; - u16 tbl_tx_iqlo_cal_cmds_recal[] = { + static const u16 tbl_tx_iqlo_cal_cmds_recal[] = { 0x8101, 0x8253, 0x8053, 0x8234, 0x8034, 0x9101, 0x9253, 0x9053, 0x9234, 0x9034 }; - u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = { + static const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; - u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { + static const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234, 0x9434, 0x9334, 0x9084, 0x9267, 0x9056, 0x9234 }; - u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { + static const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { 0x8423, 0x8323, 0x8073, 0x8256, 0x8045, 0x8223, 0x9423, 0x9323, 0x9073, 0x9256, 0x9045, 0x9223 }; diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c index 7d2f3760d5db1cb34624375ddc2bc2a00f58cd74..d1dac11244c002a96af35276bc9758e3ac0ae819 100644 --- a/drivers/net/wireless/cnss/cnss_common.c +++ b/drivers/net/wireless/cnss/cnss_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -437,6 +437,18 @@ int cnss_common_register_tsf_captured_handler(struct device *dev, } EXPORT_SYMBOL(cnss_common_register_tsf_captured_handler); +int cnss_common_set_sleep_power_mode(struct device *dev, + enum cnss_sleep_power_mode mode) +{ + struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev); + + if (pf_ops && pf_ops->set_sleep_power_mode) + return pf_ops->set_sleep_power_mode(mode); + + return -EINVAL; +} +EXPORT_SYMBOL(cnss_common_set_sleep_power_mode); + int cnss_common_unregister_tsf_captured_handler(struct device *dev, void *ctx) { diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h index 0835b062685e59102aeda7ec9f4b856f734418fa..8d6522f6a64ba4b677b7599b0219092f8fb6f1ba 100644 --- a/drivers/net/wireless/cnss/cnss_common.h +++ b/drivers/net/wireless/cnss/cnss_common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -16,6 +16,11 @@ /* max 20mhz channel count */ #define CNSS_MAX_CH_NUM 45 +enum cnss_state { + CNSS_SUSPEND, + CNSS_RESUME, +}; + struct cnss_cap_tsf_info { int irq_num; void *context; @@ -35,6 +40,7 @@ struct cnss_dev_platform_ops { int (*register_tsf_captured_handler)(irq_handler_t handler, void *adapter); int (*unregister_tsf_captured_handler)(void *adapter); + int (*set_sleep_power_mode)(enum cnss_sleep_power_mode mode); }; int cnss_pci_request_bus_bandwidth(int bandwidth); @@ -62,4 +68,7 @@ int cnss_sdio_power_down(struct device *dev); int cnss_pcie_power_up(struct device *dev); int cnss_pcie_power_down(struct device *dev); const char *cnss_wlan_get_evicted_data_file(void); + +int cnss_pci_set_sleep_power_mode(enum cnss_sleep_power_mode mode); +int cnss_sdio_set_sleep_power_mode(enum cnss_sleep_power_mode mode); #endif /* _NET_CNSS_COMMON_H_ */ diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 0fb6d9c3143c5c05c3bcbfac3bf0dedcf62313e5..8bd94abaab5133a24922f7cfd34e0c5eaca3f31c 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * 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 @@ -287,6 +287,7 @@ static struct cnss_data { bool monitor_wake_intr; struct cnss_dual_wifi dual_wifi_info; struct cnss_dev_platform_ops platform_ops; + enum cnss_sleep_power_mode sleep_power_mode; } *penv; static unsigned int pcie_link_down_panic; @@ -1594,6 +1595,7 @@ static void cnss_pcie_set_platform_ops(struct device *dev) pf_ops->set_wlan_mac_address = cnss_pcie_set_wlan_mac_address; pf_ops->power_up = cnss_pcie_power_up; pf_ops->power_down = cnss_pcie_power_down; + pf_ops->set_sleep_power_mode = cnss_pci_set_sleep_power_mode; dev->platform_data = pf_ops; } @@ -1746,35 +1748,85 @@ static void cnss_wlan_pci_remove(struct pci_dev *pdev) cnss_smmu_remove(&pdev->dev); } +static int cnss_powerup(const struct subsys_desc *subsys); + +static int cnss_pci_change_power_mode(struct pci_dev *pdev, + enum cnss_state state, + enum cnss_sleep_power_mode sleep_mode) +{ + int ret = 0; + struct cnss_wlan_driver *wdriver; + + if (!penv || !penv->driver || !pdev) + return ret; + + if (sleep_mode != CNSS_SLEEP_POWER_MODE_RESET && + sleep_mode != CNSS_SLEEP_POWER_MODE_CUT_PWR) { + pr_err("wrong sleep power mode!\n"); + return -EINVAL; + } + + wdriver = penv->driver; + if (CNSS_SUSPEND == state && wdriver->shutdown) { + wdriver->shutdown(pdev); + if (penv->pcie_link_state) { + if (cnss_msm_pcie_pm_control( + MSM_PCIE_SUSPEND, + cnss_get_pci_dev_bus_number(pdev), + pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) + pr_err("%s: shutdown PCIe link fail\n", + __func__); + + penv->saved_state = NULL; + penv->pcie_link_state = PCIE_LINK_DOWN; + } + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + if (sleep_mode == CNSS_SLEEP_POWER_MODE_CUT_PWR) { + if (cnss_wlan_vreg_set(&penv->vreg_info, + VREG_OFF)) + pr_err("%s: set WLAN VREG_OFF fail\n", + __func__); + } + } else if (CNSS_RESUME == state) { + cnss_powerup(NULL); + } else { + pr_err("fail to change power mode!\n"); + ret = -EINVAL; + } + + return ret; +} + static int cnss_wlan_pci_suspend(struct device *dev) { int ret = 0; struct cnss_wlan_driver *wdriver; struct pci_dev *pdev = to_pci_dev(dev); + enum cnss_sleep_power_mode sleep_mode; pm_message_t state = { .event = PM_EVENT_SUSPEND }; - if (!penv) - goto out; - - if (!penv->pcie_link_state) - goto out; - + if (!penv || !penv->pcie_link_state || !penv->driver) + return ret; wdriver = penv->driver; - if (!wdriver) - goto out; - if (wdriver->suspend) { - ret = wdriver->suspend(pdev, state); + sleep_mode = penv->sleep_power_mode; + if (CNSS_SLEEP_POWER_MODE_NONE != sleep_mode) { + ret = cnss_pci_change_power_mode(pdev, CNSS_SUSPEND, + sleep_mode); + } else { + if (wdriver->suspend) { + ret = wdriver->suspend(pdev, state); - if (penv->pcie_link_state) { - pci_save_state(pdev); - penv->saved_state = cnss_pci_store_saved_state(pdev); + if (penv->pcie_link_state) { + pci_save_state(pdev); + penv->saved_state = + cnss_pci_store_saved_state(pdev); + } } } penv->monitor_wake_intr = false; -out: return ret; } @@ -1783,27 +1835,29 @@ static int cnss_wlan_pci_resume(struct device *dev) int ret = 0; struct cnss_wlan_driver *wdriver; struct pci_dev *pdev = to_pci_dev(dev); + enum cnss_sleep_power_mode sleep_mode; - if (!penv) - goto out; - - if (!penv->pcie_link_state) - goto out; - + if (!penv || !penv->driver) + return ret; wdriver = penv->driver; - if (!wdriver) - goto out; - - if (wdriver->resume && !penv->pcie_link_down_ind) { - if (penv->saved_state) - cnss_pci_load_and_free_saved_state( - pdev, &penv->saved_state); - pci_restore_state(pdev); - ret = wdriver->resume(pdev); + sleep_mode = penv->sleep_power_mode; + if (CNSS_SLEEP_POWER_MODE_NONE != sleep_mode) { + ret = cnss_pci_change_power_mode(pdev, CNSS_RESUME, + sleep_mode); + } else { + if (!penv->pcie_link_state) + return ret; + if (wdriver->resume && !penv->pcie_link_down_ind) { + if (penv->saved_state) + cnss_pci_load_and_free_saved_state( + pdev, &penv->saved_state); + pci_restore_state(pdev); + + ret = wdriver->resume(pdev); + } } -out: return ret; } @@ -2471,10 +2525,6 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) return; } - if (penv->bus_client) - msm_bus_scale_client_update_request(penv->bus_client, - CNSS_BUS_WIDTH_NONE); - if (!pdev) { pr_err("%d: invalid pdev\n", __LINE__); goto cut_power; @@ -2496,7 +2546,7 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev), pdev, PM_OPTIONS)) { pr_err("Failed to shutdown PCIe link\n"); - return; + goto bus_request; } } else if (penv->pcie_link_state && penv->pcie_link_down_ind) { penv->saved_state = NULL; @@ -2505,7 +2555,7 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev), pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) { pr_err("Failed to shutdown PCIe link (with linkdown option)\n"); - return; + goto bus_request; } } penv->pcie_link_state = PCIE_LINK_DOWN; @@ -2519,6 +2569,10 @@ cut_power: cnss_configure_wlan_en_gpio(WLAN_EN_LOW); if (cnss_wlan_vreg_set(vreg_info, VREG_OFF)) pr_err("wlan vreg OFF failed\n"); +bus_request: + if (penv->bus_client) + msm_bus_scale_client_update_request(penv->bus_client, + CNSS_BUS_WIDTH_NONE); } EXPORT_SYMBOL(cnss_wlan_unregister_driver); @@ -2731,10 +2785,14 @@ err_pcie_link_up: cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { - pr_err("%d: Unregistering pci device\n", __LINE__); - pci_unregister_driver(&cnss_wlan_pci_driver); - penv->pdev = NULL; - penv->pci_register_again = true; + if (wdrv && wdrv->update_status) + wdrv->update_status(penv->pdev, CNSS_SSR_FAIL); + if (!penv->recovery_in_progress) { + pr_err("%d: Unregistering pci device\n", __LINE__); + pci_unregister_driver(&cnss_wlan_pci_driver); + penv->pdev = NULL; + penv->pci_register_again = true; + } } err_wlan_vreg_on: @@ -2911,6 +2969,7 @@ static int cnss_probe(struct platform_device *pdev) penv->vreg_info.state = VREG_OFF; penv->pci_register_again = false; mutex_init(&penv->fw_setup_stat_lock); + penv->sleep_power_mode = CNSS_SLEEP_POWER_MODE_NONE; ret = cnss_wlan_get_resources(pdev); if (ret) @@ -3352,6 +3411,27 @@ int cnss_get_bmi_setup(void) } EXPORT_SYMBOL(cnss_get_bmi_setup); +int cnss_pci_set_sleep_power_mode(enum cnss_sleep_power_mode mode) +{ + int ret = 0; + + if (!penv) + return -ENODEV; + + switch (mode) { + case CNSS_SLEEP_POWER_MODE_NONE: + case CNSS_SLEEP_POWER_MODE_RESET: + case CNSS_SLEEP_POWER_MODE_CUT_PWR: + penv->sleep_power_mode = mode; + break; + default: + pr_err("%s: Invalid sleep power mode %d", __func__, mode); + ret = -EINVAL; + } + + return ret; +} + #ifdef CONFIG_CNSS_SECURE_FW int cnss_get_sha_hash(const u8 *data, u32 data_len, u8 *hash_idx, u8 *out) { diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c index a2ca99f77aa3f96a713bc9ee0855868a50c5122f..0d9dee829884ff1e989bab4480ce6d4ef91b62b2 100644 --- a/drivers/net/wireless/cnss/cnss_sdio.c +++ b/drivers/net/wireless/cnss/cnss_sdio.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * 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 @@ -80,7 +80,9 @@ struct cnss_sdio_info { const struct sdio_device_id *id; bool skip_wlan_en_toggle; bool cnss_hw_state; + int tsf_gpio; struct cnss_cap_tsf_info cap_tsf_info; + enum cnss_sleep_power_mode sleep_power_mode; }; struct cnss_ssr_info { @@ -814,6 +816,9 @@ static void cnss_sdio_tsf_deinit(struct cnss_cap_tsf_info *tsf_info) static void cnss_sdio_set_platform_ops(struct device *dev) { struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops; + struct cnss_sdio_info *info; + + info = &cnss_pdata->cnss_sdio_info; pf_ops->power_up = cnss_sdio_power_up; pf_ops->power_down = cnss_sdio_power_down; @@ -824,10 +829,14 @@ static void cnss_sdio_set_platform_ops(struct device *dev) pf_ops->set_wlan_mac_address = cnss_sdio_set_wlan_mac_address; pf_ops->schedule_recovery_work = cnss_sdio_schedule_recovery_work; pf_ops->request_bus_bandwidth = cnss_sdio_request_bus_bandwidth; - pf_ops->register_tsf_captured_handler = - cnss_sdio_register_tsf_captured_handler; - pf_ops->unregister_tsf_captured_handler = - cnss_sdio_unregister_tsf_captured_handler; + pf_ops->set_sleep_power_mode = cnss_sdio_set_sleep_power_mode; + + if (info->tsf_gpio >= 0) { + pf_ops->register_tsf_captured_handler = + cnss_sdio_register_tsf_captured_handler; + pf_ops->unregister_tsf_captured_handler = + cnss_sdio_unregister_tsf_captured_handler; + } dev->platform_data = pf_ops; } @@ -869,13 +878,84 @@ static void cnss_sdio_wlan_removed(struct sdio_func *func) info->id = NULL; } +static int cnss_set_pinctrl_state(struct cnss_sdio_data *pdata, bool state); + +static int cnss_sdio_change_power_mode(enum cnss_state state, + enum cnss_sleep_power_mode sleep_mode) +{ + struct cnss_sdio_wlan_driver *wdrv; + struct cnss_sdio_info *cnss_info; + struct sdio_func *func; + int ret = 0; + + cnss_info = &cnss_pdata->cnss_sdio_info; + func = cnss_pdata->cnss_sdio_info.func; + wdrv = cnss_pdata->cnss_sdio_info.wdrv; + if (!wdrv) { + /* This can happen when no wlan driver loaded (no register to + * platform driver). + */ + sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + pr_debug("wlan driver not registered\n"); + return ret; + } + + if (sleep_mode != CNSS_SLEEP_POWER_MODE_RESET && + sleep_mode != CNSS_SLEEP_POWER_MODE_CUT_PWR) { + pr_err("wrong sleep power mode!\n"); + return -EINVAL; + } + + if (CNSS_SUSPEND == state && wdrv->shutdown) { + wdrv->shutdown(func); + ret = cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP); + if (ret) + pr_err("%s: Fail to set pinctrl to SLEEP\n", + __func__); + if (sleep_mode == CNSS_SLEEP_POWER_MODE_CUT_PWR) { + if (cnss_pdata->regulator.wlan_vreg) { + ret = regulator_disable( + cnss_pdata->regulator.wlan_vreg); + if (ret) + pr_err("cut wlan_vreg fail\n"); + } else { + pr_warn("invalid wlan_vreg\n"); + } + } + } else if (CNSS_RESUME == state && wdrv->reinit) { + if (sleep_mode == CNSS_SLEEP_POWER_MODE_CUT_PWR) { + if (cnss_pdata->regulator.wlan_vreg) { + ret = regulator_enable( + cnss_pdata->regulator.wlan_vreg); + if (ret) + pr_err("wlan_vreg on fail\n"); + } else { + pr_err("invalid regulator!\n"); + } + } + ret = cnss_set_pinctrl_state(cnss_pdata, + PINCTRL_ACTIVE); + if (ret) + pr_err("%s: Fail to set pinctrl to ACTIVE\n", + __func__); + ret = wdrv->reinit(cnss_info->func, cnss_info->id); + if (ret) + pr_err("wlan reinit error=%d\n", ret); + } else { + pr_err("fail to change power mode!\n"); + ret = -EINVAL; + } + + return ret; +} + #if defined(CONFIG_PM) static int cnss_sdio_wlan_suspend(struct device *dev) { struct cnss_sdio_wlan_driver *wdrv; struct cnss_sdio_bus_bandwidth *bus_bandwidth; struct sdio_func *func; - + enum cnss_sleep_power_mode sleep_mode; int error = 0; if (!cnss_pdata) @@ -897,10 +977,17 @@ static int cnss_sdio_wlan_suspend(struct device *dev) pr_debug("wlan driver not registered\n"); return 0; } - if (wdrv->suspend) { - error = wdrv->suspend(dev); - if (error) - pr_err("wlan suspend failed error=%d\n", error); + + sleep_mode = cnss_pdata->cnss_sdio_info.sleep_power_mode; + if (CNSS_SLEEP_POWER_MODE_NONE != sleep_mode) { + error = cnss_sdio_change_power_mode(CNSS_SUSPEND, sleep_mode); + } else { + if (wdrv->suspend) { + error = wdrv->suspend(dev); + if (error) + pr_err("wlan suspend failed error=%d\n", + error); + } } return error; @@ -910,6 +997,8 @@ static int cnss_sdio_wlan_resume(struct device *dev) { struct cnss_sdio_wlan_driver *wdrv; struct cnss_sdio_bus_bandwidth *bus_bandwidth; + struct cnss_sdio_info *cnss_info; + enum cnss_sleep_power_mode sleep_mode; int error = 0; if (!cnss_pdata) @@ -922,6 +1011,7 @@ static int cnss_sdio_wlan_resume(struct device *dev) bus_bandwidth->current_bandwidth_vote); } + cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_pdata->cnss_sdio_info.wdrv; if (!wdrv) { /* This can happen when no wlan driver loaded (no register to @@ -930,11 +1020,19 @@ static int cnss_sdio_wlan_resume(struct device *dev) pr_debug("wlan driver not registered\n"); return 0; } - if (wdrv->resume) { - error = wdrv->resume(dev); - if (error) - pr_err("wlan resume failed error=%d\n", error); + + sleep_mode = cnss_pdata->cnss_sdio_info.sleep_power_mode; + if (CNSS_SLEEP_POWER_MODE_NONE != sleep_mode) { + error = cnss_sdio_change_power_mode(CNSS_RESUME, sleep_mode); + } else { + if (wdrv->resume) { + error = wdrv->resume(dev); + if (error) + pr_err("wlan resume failed error=%d\n", + error); + } } + return error; } #endif @@ -981,6 +1079,30 @@ int cnss_sdio_configure_spdt(bool state) } EXPORT_SYMBOL(cnss_sdio_configure_spdt); +int cnss_sdio_set_sleep_power_mode(enum cnss_sleep_power_mode mode) +{ + int ret = 0; + struct cnss_sdio_info *cnss_info; + + if (!cnss_pdata) + return -ENODEV; + + cnss_info = &cnss_pdata->cnss_sdio_info; + + switch (mode) { + case CNSS_SLEEP_POWER_MODE_NONE: + case CNSS_SLEEP_POWER_MODE_RESET: + case CNSS_SLEEP_POWER_MODE_CUT_PWR: + cnss_info->sleep_power_mode = mode; + break; + default: + pr_err("%s: Invalid sleep power mode %d", __func__, mode); + ret = -EINVAL; + } + + return ret; +} + /** * cnss_sdio_wlan_register_driver() - cnss wlan register API * @driver: sdio wlan driver interface from wlan driver. @@ -1466,7 +1588,12 @@ static int cnss_sdio_probe(struct platform_device *pdev) "qcom,skip-wlan-en-toggle"); info->cnss_hw_state = CNSS_HW_ACTIVE; - cnss_sdio_tsf_init(dev, &info->cap_tsf_info); + info->tsf_gpio = of_get_named_gpio(dev->of_node, + WLAN_GPIO_CAPTSF_NAME, 0); + if (info->tsf_gpio >= 0) + cnss_sdio_tsf_init(dev, &info->cap_tsf_info); + + info->sleep_power_mode = CNSS_SLEEP_POWER_MODE_NONE; error = cnss_sdio_wlan_init(); if (error) { @@ -1519,15 +1646,18 @@ err_wlan_enable_regulator: static int cnss_sdio_remove(struct platform_device *pdev) { struct cnss_sdio_info *info; - struct cnss_cap_tsf_info *tsf_info; if (!cnss_pdata) return -ENODEV; info = &cnss_pdata->cnss_sdio_info; - tsf_info = &info->cap_tsf_info; - cnss_sdio_tsf_deinit(tsf_info); + if (info->tsf_gpio >= 0) { + struct cnss_cap_tsf_info *tsf_info; + + tsf_info = &info->cap_tsf_info; + cnss_sdio_tsf_deinit(tsf_info); + } cnss_sdio_deinit_bus_bandwidth(); cnss_sdio_wlan_exit(); cnss_subsys_exit(); diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile index 9d383c8daa435d1a40d8c3567e6c0604eb4f3f16..b49d0898178b3dc5387208d8ee0f6715d4c7fa7d 100644 --- a/drivers/net/wireless/cnss2/Makefile +++ b/drivers/net/wireless/cnss2/Makefile @@ -5,5 +5,4 @@ cnss2-y += debug.o cnss2-y += pci.o cnss2-y += power.o cnss2-y += qmi.o -cnss2-y += utils.o cnss2-y += wlan_firmware_service_v01.o diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c index c69f0a488c52260bdfa33c03c29c97e2fc29023a..047a988736f30f7eeb7e82d75389dd826fd652b9 100644 --- a/drivers/net/wireless/cnss2/debug.c +++ b/drivers/net/wireless/cnss2/debug.c @@ -158,6 +158,7 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp, } else if (sysfs_streq(cmd, "enumerate")) { ret = cnss_pci_init(plat_priv); } else if (sysfs_streq(cmd, "download")) { + set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state); ret = cnss_pci_start_mhi(plat_priv->bus_priv); } else if (sysfs_streq(cmd, "linkup")) { ret = cnss_resume_pci_link(plat_priv->bus_priv); diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 8277de861d63df320da6944b1a7fdf0555ca6590..d0622cb28fffcabfd02932decc8e6019191c4fbf 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -58,6 +58,7 @@ MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest"); enum cnss_debug_quirks { LINK_DOWN_SELF_RECOVERY, SKIP_DEVICE_BOOT, + USE_CORE_ONLY_FW, }; unsigned long quirks; @@ -188,19 +189,20 @@ static void cnss_pm_relax(struct cnss_plat_data *plat_priv) pm_relax(&plat_priv->plat_dev->dev); } -void cnss_lock_pm_sem(void) +void cnss_lock_pm_sem(struct device *dev) { down_read(&cnss_pm_sem); } EXPORT_SYMBOL(cnss_lock_pm_sem); -void cnss_release_pm_sem(void) +void cnss_release_pm_sem(struct device *dev) { up_read(&cnss_pm_sem); } EXPORT_SYMBOL(cnss_release_pm_sem); -int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files, +int cnss_get_fw_files_for_target(struct device *dev, + struct cnss_fw_files *pfw_files, u32 target_type, u32 target_version) { if (!pfw_files) @@ -222,10 +224,10 @@ int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files, } EXPORT_SYMBOL(cnss_get_fw_files_for_target); -int cnss_request_bus_bandwidth(int bandwidth) +int cnss_request_bus_bandwidth(struct device *dev, int bandwidth) { int ret = 0; - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct cnss_bus_bw_info *bus_bw_info; if (!plat_priv) @@ -257,9 +259,9 @@ int cnss_request_bus_bandwidth(int bandwidth) } EXPORT_SYMBOL(cnss_request_bus_bandwidth); -int cnss_get_platform_cap(struct cnss_platform_cap *cap) +int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); if (!plat_priv) return -ENODEV; @@ -288,20 +290,9 @@ int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info) } EXPORT_SYMBOL(cnss_get_soc_info); -void cnss_set_driver_status(enum cnss_driver_status driver_status) -{ - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); - - if (!plat_priv) - return; - - plat_priv->driver_status = driver_status; -} -EXPORT_SYMBOL(cnss_set_driver_status); - -void cnss_request_pm_qos(u32 qos_val) +void cnss_request_pm_qos(struct device *dev, u32 qos_val) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); if (!plat_priv) return; @@ -311,9 +302,9 @@ void cnss_request_pm_qos(u32 qos_val) } EXPORT_SYMBOL(cnss_request_pm_qos); -void cnss_remove_pm_qos(void) +void cnss_remove_pm_qos(struct device *dev) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); if (!plat_priv) return; @@ -322,31 +313,6 @@ void cnss_remove_pm_qos(void) } EXPORT_SYMBOL(cnss_remove_pm_qos); -u8 *cnss_common_get_wlan_mac_address(struct device *dev, u32 *num) -{ - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); - struct cnss_wlan_mac_info *wlan_mac_info; - struct cnss_wlan_mac_addr *addr; - - if (!plat_priv) - goto out; - - wlan_mac_info = &plat_priv->wlan_mac_info; - if (!wlan_mac_info->is_wlan_mac_set) { - cnss_pr_info("Platform driver doesn't have any MAC address!\n"); - goto out; - } - - addr = &wlan_mac_info->wlan_mac_addr; - *num = addr->no_of_mac_addr_set; - - return &addr->mac_addr[0][0]; -out: - *num = 0; - return NULL; -} -EXPORT_SYMBOL(cnss_common_get_wlan_mac_address); - int cnss_wlan_enable(struct device *dev, struct cnss_wlan_enable_cfg *config, enum cnss_driver_mode mode, @@ -589,16 +555,23 @@ out: static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv) { - int ret; + int ret = 0; struct cnss_pci_data *pci_priv = plat_priv->bus_priv; + if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) { + clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); + cnss_pr_dbg("Skip driver probe\n"); + goto out; + } + if (!plat_priv->driver_ops) { cnss_pr_err("driver_ops is NULL\n"); ret = -EINVAL; goto out; } - if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { + if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) && + test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev, pci_priv->pci_device_id); if (ret) { @@ -615,6 +588,7 @@ static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv) ret); goto out; } + clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state); set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); } @@ -629,12 +603,20 @@ static int cnss_driver_call_remove(struct cnss_plat_data *plat_priv) { struct cnss_pci_data *pci_priv = plat_priv->bus_priv; + if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) || + test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) || + test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) { + cnss_pr_dbg("Skip driver remove\n"); + return 0; + } + if (!plat_priv->driver_ops) { cnss_pr_err("driver_ops is NULL\n"); return -EINVAL; } - if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { + if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) && + test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { plat_priv->driver_ops->shutdown(pci_priv->pci_dev); } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { plat_priv->driver_ops->remove(pci_priv->pci_dev); @@ -672,7 +654,9 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv) complete(&plat_priv->power_up_complete); } - if (ret) + if (ret && test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) + goto out; + else if (ret) goto shutdown; return 0; @@ -682,6 +666,10 @@ shutdown: cnss_suspend_pci_link(plat_priv->bus_priv); cnss_power_off_device(plat_priv); + clear_bit(CNSS_FW_READY, &plat_priv->driver_state); + clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state); + +out: return ret; } @@ -1022,11 +1010,6 @@ static int cnss_qca6174_powerup(struct cnss_plat_data *plat_priv) return -ENODEV; } - if (!plat_priv->driver_ops) { - cnss_pr_err("driver_ops is NULL!\n"); - return -EINVAL; - } - ret = cnss_power_on_device(plat_priv); if (ret) { cnss_pr_err("Failed to power on device, err = %d\n", ret); @@ -1060,16 +1043,12 @@ static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv) if (!pci_priv) return -ENODEV; - if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) - goto skip_driver_remove; - - if (!plat_priv->driver_ops) - return -EINVAL; + cnss_pm_request_resume(pci_priv); cnss_driver_call_remove(plat_priv); -skip_driver_remove: - cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); + cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev, + CNSS_BUS_WIDTH_NONE); cnss_pci_set_monitor_wake_intr(pci_priv, false); cnss_pci_set_auto_suspended(pci_priv, 0); @@ -1135,6 +1114,12 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) return 0; } + if (test_bit(USE_CORE_ONLY_FW, &quirks)) { + clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state); + clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); + return 0; + } + cnss_set_pin_connect_status(plat_priv); if (qmi_bypass) { @@ -1165,18 +1150,12 @@ static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv) if (!pci_priv) return -ENODEV; - if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) || - test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) || - test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) - goto skip_driver_remove; - - if (!plat_priv->driver_ops) - return -EINVAL; + cnss_pm_request_resume(pci_priv); cnss_driver_call_remove(plat_priv); -skip_driver_remove: - cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); + cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev, + CNSS_BUS_WIDTH_NONE); cnss_pci_set_monitor_wake_intr(pci_priv, false); cnss_pci_set_auto_suspended(pci_priv, 0); @@ -1205,8 +1184,10 @@ static void cnss_qca6290_crash_shutdown(struct cnss_plat_data *plat_priv) if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) || test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) || - test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) + test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { + cnss_pr_dbg("Ignore crash shutdown\n"); return; + } ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC); if (ret) { @@ -1217,26 +1198,9 @@ static void cnss_qca6290_crash_shutdown(struct cnss_plat_data *plat_priv) cnss_pci_collect_dump_info(pci_priv); } -static int cnss_powerup(const struct subsys_desc *subsys_desc) +static int cnss_powerup(struct cnss_plat_data *plat_priv) { - int ret = 0; - struct cnss_plat_data *plat_priv; - - if (!subsys_desc->dev) { - cnss_pr_err("dev from subsys_desc is NULL\n"); - return -ENODEV; - } - - plat_priv = dev_get_drvdata(subsys_desc->dev); - if (!plat_priv) { - cnss_pr_err("plat_priv is NULL!\n"); - return -ENODEV; - } - - if (!plat_priv->driver_state) { - cnss_pr_dbg("Powerup is ignored.\n"); - return 0; - } + int ret; switch (plat_priv->device_id) { case QCA6174_DEVICE_ID: @@ -1255,21 +1219,9 @@ static int cnss_powerup(const struct subsys_desc *subsys_desc) return ret; } -static int cnss_shutdown(const struct subsys_desc *subsys_desc, bool force_stop) +static int cnss_shutdown(struct cnss_plat_data *plat_priv) { - int ret = 0; - struct cnss_plat_data *plat_priv; - - if (!subsys_desc->dev) { - cnss_pr_err("dev from subsys_desc is NULL\n"); - return -ENODEV; - } - - plat_priv = dev_get_drvdata(subsys_desc->dev); - if (!plat_priv) { - cnss_pr_err("plat_priv is NULL!\n"); - return -ENODEV; - } + int ret; switch (plat_priv->device_id) { case QCA6174_DEVICE_ID: @@ -1288,6 +1240,53 @@ static int cnss_shutdown(const struct subsys_desc *subsys_desc, bool force_stop) return ret; } +static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc) +{ + struct cnss_plat_data *plat_priv; + + if (!subsys_desc->dev) { + cnss_pr_err("dev from subsys_desc is NULL\n"); + return -ENODEV; + } + + plat_priv = dev_get_drvdata(subsys_desc->dev); + if (!plat_priv) { + cnss_pr_err("plat_priv is NULL\n"); + return -ENODEV; + } + + if (!plat_priv->driver_state) { + cnss_pr_dbg("Powerup is ignored\n"); + return 0; + } + + return cnss_powerup(plat_priv); +} + +static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc, + bool force_stop) +{ + struct cnss_plat_data *plat_priv; + + if (!subsys_desc->dev) { + cnss_pr_err("dev from subsys_desc is NULL\n"); + return -ENODEV; + } + + plat_priv = dev_get_drvdata(subsys_desc->dev); + if (!plat_priv) { + cnss_pr_err("plat_priv is NULL\n"); + return -ENODEV; + } + + if (!plat_priv->driver_state) { + cnss_pr_dbg("shutdown is ignored\n"); + return 0; + } + + return cnss_shutdown(plat_priv); +} + static int cnss_qca6290_ramdump(struct cnss_plat_data *plat_priv) { struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2; @@ -1343,7 +1342,8 @@ static int cnss_qca6174_ramdump(struct cnss_plat_data *plat_priv) return ret; } -static int cnss_ramdump(int enable, const struct subsys_desc *subsys_desc) +static int cnss_subsys_ramdump(int enable, + const struct subsys_desc *subsys_desc) { int ret = 0; struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev); @@ -1373,9 +1373,9 @@ static int cnss_ramdump(int enable, const struct subsys_desc *subsys_desc) return ret; } -void *cnss_get_virt_ramdump_mem(unsigned long *size) +void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct cnss_ramdump_info *ramdump_info; if (!plat_priv) @@ -1388,9 +1388,9 @@ void *cnss_get_virt_ramdump_mem(unsigned long *size) } EXPORT_SYMBOL(cnss_get_virt_ramdump_mem); -void cnss_device_crashed(void) +void cnss_device_crashed(struct device *dev) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct cnss_subsys_info *subsys_info; if (!plat_priv) @@ -1405,7 +1405,7 @@ void cnss_device_crashed(void) } EXPORT_SYMBOL(cnss_device_crashed); -static void cnss_crash_shutdown(const struct subsys_desc *subsys_desc) +static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc) { struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev); @@ -1494,8 +1494,8 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, return 0; self_recovery: - cnss_shutdown(&subsys_info->subsys_desc, false); - cnss_powerup(&subsys_info->subsys_desc); + cnss_shutdown(plat_priv); + cnss_powerup(plat_priv); return 0; } @@ -1534,11 +1534,6 @@ static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv, if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { set_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state); - } else if (test_bit(CNSS_DRIVER_LOADING, - &plat_priv->driver_state)) { - cnss_pr_err("Driver probe is in progress, ignore recovery\n"); - ret = -EINVAL; - goto out; } break; } @@ -1613,7 +1608,7 @@ int cnss_force_fw_assert(struct device *dev) if (plat_priv->device_id == QCA6174_DEVICE_ID) { cnss_pr_info("Forced FW assert is not supported\n"); - return -EINVAL; + return -EOPNOTSUPP; } if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { @@ -1644,12 +1639,11 @@ static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data) { int ret = 0; - struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state); plat_priv->driver_ops = data; - ret = cnss_powerup(&subsys_info->subsys_desc); + ret = cnss_powerup(plat_priv); if (ret) { clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state); plat_priv->driver_ops = NULL; @@ -1660,10 +1654,8 @@ static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv, static int cnss_unregister_driver_hdlr(struct cnss_plat_data *plat_priv) { - struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; - set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); - cnss_shutdown(&subsys_info->subsys_desc, false); + cnss_shutdown(plat_priv); plat_priv->driver_ops = NULL; return 0; @@ -1672,10 +1664,9 @@ static int cnss_unregister_driver_hdlr(struct cnss_plat_data *plat_priv) static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv) { int ret = 0; - struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); - ret = cnss_powerup(&subsys_info->subsys_desc); + ret = cnss_powerup(plat_priv); if (ret) clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); @@ -1684,10 +1675,8 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv) static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv) { - struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; - cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01); - cnss_shutdown(&subsys_info->subsys_desc, false); + cnss_shutdown(plat_priv); clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); return 0; @@ -1695,16 +1684,12 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv) static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv) { - struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; - - return cnss_powerup(&subsys_info->subsys_desc); + return cnss_powerup(plat_priv); } static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv) { - struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; - - cnss_shutdown(&subsys_info->subsys_desc, false); + cnss_shutdown(plat_priv); return 0; } @@ -1829,10 +1814,10 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv) } subsys_info->subsys_desc.owner = THIS_MODULE; - subsys_info->subsys_desc.powerup = cnss_powerup; - subsys_info->subsys_desc.shutdown = cnss_shutdown; - subsys_info->subsys_desc.ramdump = cnss_ramdump; - subsys_info->subsys_desc.crash_shutdown = cnss_crash_shutdown; + subsys_info->subsys_desc.powerup = cnss_subsys_powerup; + subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown; + subsys_info->subsys_desc.ramdump = cnss_subsys_ramdump; + subsys_info->subsys_desc.crash_shutdown = cnss_subsys_crash_shutdown; subsys_info->subsys_desc.dev = &plat_priv->plat_dev->dev; subsys_info->subsys_device = subsys_register(&subsys_info->subsys_desc); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 89ada0b2e1f08c2762c2495e6d07b7b6e64a69c3..f34f4a31560f10000cf74a2ad7d2845a4a91beed 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -97,16 +97,6 @@ struct cnss_bus_bw_info { int current_bw_vote; }; -struct cnss_wlan_mac_addr { - u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN]; - u32 no_of_mac_addr_set; -}; - -struct cnss_wlan_mac_info { - struct cnss_wlan_mac_addr wlan_mac_addr; - bool is_wlan_mac_set; -}; - struct cnss_fw_mem { size_t size; void *va; @@ -185,7 +175,6 @@ struct cnss_plat_data { struct cnss_wlan_driver *driver_ops; enum cnss_driver_status driver_status; u32 recovery_count; - struct cnss_wlan_mac_info wlan_mac_info; unsigned long driver_state; struct list_head event_list; spinlock_t event_lock; /* spinlock for driver work event handling */ diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 5007d03c0c7ba0f6543fc99e57cc8e79f7962111..8af92b1220e3afa408cf60886da4579bdc3fe4d6 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 +134,7 @@ int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv) if (!pci_priv) return -ENODEV; + cnss_pr_dbg("Suspending PCI link\n"); if (!pci_priv->pci_link_state) { cnss_pr_info("PCI link is already suspended!\n"); goto out; @@ -167,6 +168,7 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv) if (!pci_priv) return -ENODEV; + cnss_pr_dbg("Resuming PCI link\n"); if (pci_priv->pci_link_state) { cnss_pr_info("PCI link is already resumed!\n"); goto out; @@ -385,27 +387,37 @@ static int cnss_pci_suspend(struct device *dev) driver_ops = plat_priv->driver_ops; if (driver_ops && driver_ops->suspend) { ret = driver_ops->suspend(pci_dev, state); - if (pci_priv->pci_link_state) { - if (cnss_pci_set_mhi_state(pci_priv, - CNSS_MHI_SUSPEND)) { + if (ret) { + cnss_pr_err("Failed to suspend host driver, err = %d\n", + ret); + ret = -EAGAIN; + goto out; + } + } + + if (pci_priv->pci_link_state) { + ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND); + if (ret) { + if (driver_ops && driver_ops->resume) driver_ops->resume(pci_dev); - ret = -EAGAIN; - goto out; - } + ret = -EAGAIN; + goto out; + } - cnss_set_pci_config_space(pci_priv, - SAVE_PCI_CONFIG_SPACE); - pci_disable_device(pci_dev); + cnss_set_pci_config_space(pci_priv, + SAVE_PCI_CONFIG_SPACE); + pci_disable_device(pci_dev); - ret = pci_set_power_state(pci_dev, PCI_D3hot); - if (ret) - cnss_pr_err("Failed to set D3Hot, err = %d\n", - ret); - } + ret = pci_set_power_state(pci_dev, PCI_D3hot); + if (ret) + cnss_pr_err("Failed to set D3Hot, err = %d\n", + ret); } cnss_pci_set_monitor_wake_intr(pci_priv, false); + return 0; + out: return ret; } @@ -425,23 +437,30 @@ static int cnss_pci_resume(struct device *dev) if (!plat_priv) goto out; - driver_ops = plat_priv->driver_ops; - if (driver_ops && driver_ops->resume && !pci_priv->pci_link_down_ind) { - ret = pci_enable_device(pci_dev); - if (ret) - cnss_pr_err("Failed to enable PCI device, err = %d\n", - ret); + if (pci_priv->pci_link_down_ind) + goto out; - if (pci_priv->saved_state) - cnss_set_pci_config_space(pci_priv, - RESTORE_PCI_CONFIG_SPACE); + ret = pci_enable_device(pci_dev); + if (ret) + cnss_pr_err("Failed to enable PCI device, err = %d\n", ret); - pci_set_master(pci_dev); - cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME); + if (pci_priv->saved_state) + cnss_set_pci_config_space(pci_priv, + RESTORE_PCI_CONFIG_SPACE); + pci_set_master(pci_dev); + cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME); + + driver_ops = plat_priv->driver_ops; + if (driver_ops && driver_ops->resume) { ret = driver_ops->resume(pci_dev); + if (ret) + cnss_pr_err("Failed to resume host driver, err = %d\n", + ret); } + return 0; + out: return ret; } @@ -566,9 +585,9 @@ static int cnss_pci_runtime_idle(struct device *dev) return -EBUSY; } -int cnss_wlan_pm_control(bool vote) +int cnss_wlan_pm_control(struct device *dev, bool vote) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct cnss_pci_data *pci_priv; struct pci_dev *pci_dev; @@ -588,10 +607,10 @@ int cnss_wlan_pm_control(bool vote) } EXPORT_SYMBOL(cnss_wlan_pm_control); -int cnss_auto_suspend(void) +int cnss_auto_suspend(struct device *dev) { int ret = 0; - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct pci_dev *pci_dev; struct cnss_pci_data *pci_priv; struct cnss_bus_bw_info *bus_bw_info; @@ -617,14 +636,17 @@ int cnss_auto_suspend(void) ret = pci_set_power_state(pci_dev, PCI_D3hot); if (ret) cnss_pr_err("Failed to set D3Hot, err = %d\n", ret); + + cnss_pr_dbg("Suspending PCI link\n"); if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) { - cnss_pr_err("Failed to shutdown PCI link!\n"); + cnss_pr_err("Failed to suspend PCI link!\n"); ret = -EAGAIN; goto resume_mhi; } + + pci_priv->pci_link_state = PCI_LINK_DOWN; } - pci_priv->pci_link_state = PCI_LINK_DOWN; cnss_pci_set_auto_suspended(pci_priv, 1); cnss_pci_set_monitor_wake_intr(pci_priv, true); @@ -643,10 +665,10 @@ out: } EXPORT_SYMBOL(cnss_auto_suspend); -int cnss_auto_resume(void) +int cnss_auto_resume(struct device *dev) { int ret = 0; - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct pci_dev *pci_dev; struct cnss_pci_data *pci_priv; struct cnss_bus_bw_info *bus_bw_info; @@ -660,21 +682,24 @@ int cnss_auto_resume(void) pci_dev = pci_priv->pci_dev; if (!pci_priv->pci_link_state) { + cnss_pr_dbg("Resuming PCI link\n"); if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) { cnss_pr_err("Failed to resume PCI link!\n"); ret = -EAGAIN; goto out; } pci_priv->pci_link_state = PCI_LINK_UP; + ret = pci_enable_device(pci_dev); if (ret) cnss_pr_err("Failed to enable PCI device, err = %d\n", ret); + + cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE); + pci_set_master(pci_dev); + cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME); } - cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE); - pci_set_master(pci_dev); - cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME); cnss_pci_set_auto_suspended(pci_priv, 0); bus_bw_info = &plat_priv->bus_bw_info; @@ -685,6 +710,20 @@ out: } EXPORT_SYMBOL(cnss_auto_resume); +int cnss_pm_request_resume(struct cnss_pci_data *pci_priv) +{ + struct pci_dev *pci_dev; + + if (!pci_priv) + return -ENODEV; + + pci_dev = pci_priv->pci_dev; + if (!pci_dev) + return -ENODEV; + + return pm_request_resume(&pci_dev->dev); +} + int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; @@ -1120,6 +1159,10 @@ static void cnss_mhi_notify_status(enum MHI_CB_REASON reason, void *priv) cnss_pr_dbg("MHI status cb is called with reason %d\n", reason); + if (plat_priv->driver_ops && plat_priv->driver_ops->update_status) + plat_priv->driver_ops->update_status(pci_priv->pci_dev, + CNSS_FW_DOWN); + set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state); del_timer(&plat_priv->fw_boot_timer); diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h index 4dc29c3c1f102eefc3ef6c468e8262ee7e9367b8..ac549685c2e3ac3a5af95e0081068aea95aaae8d 100644 --- a/drivers/net/wireless/cnss2/pci.h +++ b/drivers/net/wireless/cnss2/pci.h @@ -137,5 +137,6 @@ int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv); void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv); void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv); void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv); +int cnss_pm_request_resume(struct cnss_pci_data *pci_priv); #endif /* _CNSS_PCI_H */ diff --git a/drivers/net/wireless/cnss2/utils.c b/drivers/net/wireless/cnss2/utils.c deleted file mode 100644 index 9ffe386e36775094e40448042f418b4d2a4c07a2..0000000000000000000000000000000000000000 --- a/drivers/net/wireless/cnss2/utils.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#define CNSS_MAX_CH_NUM 45 - -#include -#include - -static DEFINE_MUTEX(unsafe_channel_list_lock); -static DEFINE_MUTEX(dfs_nol_info_lock); - -static struct cnss_unsafe_channel_list { - u16 unsafe_ch_count; - u16 unsafe_ch_list[CNSS_MAX_CH_NUM]; -} unsafe_channel_list; - -static struct cnss_dfs_nol_info { - void *dfs_nol_info; - u16 dfs_nol_info_len; -} dfs_nol_info; - -int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count) -{ - mutex_lock(&unsafe_channel_list_lock); - if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) { - mutex_unlock(&unsafe_channel_list_lock); - return -EINVAL; - } - - unsafe_channel_list.unsafe_ch_count = ch_count; - - if (ch_count != 0) { - memcpy((char *)unsafe_channel_list.unsafe_ch_list, - (char *)unsafe_ch_list, ch_count * sizeof(u16)); - } - mutex_unlock(&unsafe_channel_list_lock); - - return 0; -} -EXPORT_SYMBOL(cnss_set_wlan_unsafe_channel); - -int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, - u16 *ch_count, u16 buf_len) -{ - mutex_lock(&unsafe_channel_list_lock); - if (!unsafe_ch_list || !ch_count) { - mutex_unlock(&unsafe_channel_list_lock); - return -EINVAL; - } - - if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) { - mutex_unlock(&unsafe_channel_list_lock); - return -ENOMEM; - } - - *ch_count = unsafe_channel_list.unsafe_ch_count; - memcpy((char *)unsafe_ch_list, - (char *)unsafe_channel_list.unsafe_ch_list, - unsafe_channel_list.unsafe_ch_count * sizeof(u16)); - mutex_unlock(&unsafe_channel_list_lock); - - return 0; -} -EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel); - -int cnss_wlan_set_dfs_nol(const void *info, u16 info_len) -{ - void *temp; - struct cnss_dfs_nol_info *dfs_info; - - mutex_lock(&dfs_nol_info_lock); - if (!info || !info_len) { - mutex_unlock(&dfs_nol_info_lock); - return -EINVAL; - } - - temp = kmalloc(info_len, GFP_KERNEL); - if (!temp) { - mutex_unlock(&dfs_nol_info_lock); - return -ENOMEM; - } - - memcpy(temp, info, info_len); - dfs_info = &dfs_nol_info; - kfree(dfs_info->dfs_nol_info); - - dfs_info->dfs_nol_info = temp; - dfs_info->dfs_nol_info_len = info_len; - mutex_unlock(&dfs_nol_info_lock); - - return 0; -} -EXPORT_SYMBOL(cnss_wlan_set_dfs_nol); - -int cnss_wlan_get_dfs_nol(void *info, u16 info_len) -{ - int len; - struct cnss_dfs_nol_info *dfs_info; - - mutex_lock(&dfs_nol_info_lock); - if (!info || !info_len) { - mutex_unlock(&dfs_nol_info_lock); - return -EINVAL; - } - - dfs_info = &dfs_nol_info; - - if (!dfs_info->dfs_nol_info || dfs_info->dfs_nol_info_len == 0) { - mutex_unlock(&dfs_nol_info_lock); - return -ENOENT; - } - - len = min(info_len, dfs_info->dfs_nol_info_len); - - memcpy(info, dfs_info->dfs_nol_info, len); - mutex_unlock(&dfs_nol_info_lock); - - return len; -} -EXPORT_SYMBOL(cnss_wlan_get_dfs_nol); diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index af956f68cbd629caab1bf1edeed18900c273b20e..522cbf4e93dbddf6c513bd6842e725398ad59655 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2012,2014-2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012, 2014-2016, 2018 The Linux Foundation. All rights + * reserved. * * 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 @@ -35,7 +36,7 @@ static struct dentry *debug_base; struct wcnss_prealloc { int occupied; - unsigned int size; + size_t size; void *ptr; #ifdef CONFIG_SLUB_DEBUG unsigned long stack_trace[WCNSS_MAX_STACK_TRACE]; @@ -213,7 +214,7 @@ static inline void wcnss_prealloc_save_stack_trace(struct wcnss_prealloc *entry) } #endif -void *wcnss_prealloc_get(unsigned int size) +void *wcnss_prealloc_get(size_t size) { int i = 0; unsigned long flags; @@ -233,8 +234,8 @@ void *wcnss_prealloc_get(unsigned int size) } spin_unlock_irqrestore(&alloc_lock, flags); - pr_err("wcnss: %s: prealloc not available for size: %d\n", - __func__, size); + pr_err("wcnss: %s: prealloc not available for size: %zu\n", + __func__, size); return NULL; } @@ -322,8 +323,8 @@ void wcnss_prealloc_check_memory_leak(void) leak_detected = true; } - pr_err("Size: %u, addr: %pK, backtrace:\n", - wcnss_allocs[i].size, wcnss_allocs[i].ptr); + pr_err("Size: %zu, addr: %pK, backtrace:\n", + wcnss_allocs[i].size, wcnss_allocs[i].ptr); print_stack_trace(&wcnss_allocs[i].trace, 1); } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c30cd5daaacf68bc7acb1a35eba874966f3e1f5c..39431f66741783289641f6d0cf6e2699d6513309 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -412,6 +412,9 @@ struct mac80211_hwsim_data { struct mac_address addresses[2]; int channels, idx; bool use_chanctx; + bool destroy_on_close; + struct work_struct destroy_work; + u32 portid; struct ieee80211_channel *tmp_chan; struct delayed_work roc_done; @@ -476,6 +479,14 @@ static struct genl_family hwsim_genl_family = { .maxattr = HWSIM_ATTR_MAX, }; +enum hwsim_multicast_groups { + HWSIM_MCGRP_CONFIG, +}; + +static const struct genl_multicast_group hwsim_mcgrps[] = { + [HWSIM_MCGRP_CONFIG] = { .name = "config", }, +}; + /* MAC80211_HWSIM netlink policy */ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { @@ -496,6 +507,9 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, + [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG }, + [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING }, + [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG }, }; static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, @@ -600,22 +614,22 @@ static int hwsim_fops_ps_write(void *dat, u64 val) old_ps = data->ps; data->ps = val; + local_bh_disable(); if (val == PS_MANUAL_POLL) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_ps_poll, data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_ps_poll, data); data->ps_poll_pending = true; } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_ps, - data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_ps, data); } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_no_ps, - data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_no_ps, data); } + local_bh_enable(); return 0; } @@ -862,7 +876,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, if (skb_queue_len(&data->pending) >= MAX_QUEUE) { /* Droping until WARN_QUEUE level */ while (skb_queue_len(&data->pending) >= WARN_QUEUE) - skb_dequeue(&data->pending); + ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); } skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); @@ -876,8 +890,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, goto nla_put_failure; } - if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, - ETH_ALEN, data->addresses[1].addr)) + if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2)) goto nla_put_failure; /* We get the skb->data */ @@ -921,6 +934,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, nla_put_failure: printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); + ieee80211_free_txskb(hw, my_skb); } static bool hwsim_chans_compat(struct ieee80211_channel *c1, @@ -1943,10 +1957,124 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { static struct ieee80211_ops mac80211_hwsim_mchan_ops; -static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, - const struct ieee80211_regdomain *regd, - bool reg_strict, bool p2p_device, - bool use_chanctx) +struct hwsim_new_radio_params { + unsigned int channels; + const char *reg_alpha2; + const struct ieee80211_regdomain *regd; + bool reg_strict; + bool p2p_device; + bool use_chanctx; + bool destroy_on_close; + const char *hwname; + bool no_vif; +}; + +static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, + struct genl_info *info) +{ + if (info) + genl_notify(&hwsim_genl_family, mcast_skb, + genl_info_net(info), info->snd_portid, + HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL); + else + genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0, + HWSIM_MCGRP_CONFIG, GFP_KERNEL); +} + +static struct sk_buff *build_radio_msg(int cmd, int id, + struct hwsim_new_radio_params *param) +{ + struct sk_buff *skb; + void *data; + int ret; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return NULL; + + data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, cmd); + if (!data) + goto error; + + ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); + if (ret < 0) + goto error; + + if (param->channels) { + ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); + if (ret < 0) + goto error; + } + + if (param->reg_alpha2) { + ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, + param->reg_alpha2); + if (ret < 0) + goto error; + } + + if (param->regd) { + int i; + + for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) { + if (hwsim_world_regdom_custom[i] != param->regd) + continue; + + ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); + if (ret < 0) + goto error; + break; + } + } + + if (param->reg_strict) { + ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); + if (ret < 0) + goto error; + } + + if (param->p2p_device) { + ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); + if (ret < 0) + goto error; + } + + if (param->use_chanctx) { + ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); + if (ret < 0) + goto error; + } + + if (param->hwname) { + ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, + strlen(param->hwname), param->hwname); + if (ret < 0) + goto error; + } + + genlmsg_end(skb, data); + + return skb; + +error: + nlmsg_free(skb); + return NULL; +} + +static void hswim_mcast_new_radio(int id, struct genl_info *info, + struct hwsim_new_radio_params *param) +{ + struct sk_buff *mcast_skb; + + mcast_skb = build_radio_msg(HWSIM_CMD_NEW_RADIO, id, param); + if (!mcast_skb) + return; + + hwsim_mcast_config_msg(mcast_skb, info); +} + +static int mac80211_hwsim_new_radio(struct genl_info *info, + struct hwsim_new_radio_params *param) { int err; u8 addr[ETH_ALEN]; @@ -1956,16 +2084,16 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, const struct ieee80211_ops *ops = &mac80211_hwsim_ops; int idx; - if (WARN_ON(channels > 1 && !use_chanctx)) + if (WARN_ON(param->channels > 1 && !param->use_chanctx)) return -EINVAL; spin_lock_bh(&hwsim_radio_lock); idx = hwsim_radio_idx++; spin_unlock_bh(&hwsim_radio_lock); - if (use_chanctx) + if (param->use_chanctx) ops = &mac80211_hwsim_mchan_ops; - hw = ieee80211_alloc_hw(sizeof(*data), ops); + hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname); if (!hw) { printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); err = -ENOMEM; @@ -2003,9 +2131,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, hw->wiphy->n_addresses = 2; hw->wiphy->addresses = data->addresses; - data->channels = channels; - data->use_chanctx = use_chanctx; + data->channels = param->channels; + data->use_chanctx = param->use_chanctx; data->idx = idx; + data->destroy_on_close = param->destroy_on_close; + if (info) + data->portid = info->snd_portid; if (data->use_chanctx) { hw->wiphy->max_scan_ssids = 255; @@ -2014,12 +2145,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, /* For channels > 1 DFS is not allowed */ hw->wiphy->n_iface_combinations = 1; hw->wiphy->iface_combinations = &data->if_combination; - if (p2p_device) + if (param->p2p_device) data->if_combination = hwsim_if_comb_p2p_dev[0]; else data->if_combination = hwsim_if_comb[0]; data->if_combination.num_different_channels = data->channels; - } else if (p2p_device) { + } else if (param->p2p_device) { hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev; hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb_p2p_dev); @@ -2040,7 +2171,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - if (p2p_device) + if (param->p2p_device) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE); hw->flags = IEEE80211_HW_MFP_CAPABLE | @@ -2142,15 +2273,18 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, hw->max_rates = 4; hw->max_rate_tries = 11; - if (reg_strict) + if (param->reg_strict) hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; - if (regd) { + if (param->regd) { hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(hw->wiphy, regd); + wiphy_apply_custom_regulatory(hw->wiphy, param->regd); /* give the regulatory workqueue a chance to run */ schedule_timeout_interruptible(1); } + if (param->no_vif) + hw->flags |= IEEE80211_HW_NO_AUTO_VIF; + err = ieee80211_register_hw(hw); if (err < 0) { printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", @@ -2160,8 +2294,8 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); - if (reg_alpha2) - regulatory_hint(hw->wiphy, reg_alpha2); + if (param->reg_alpha2) + regulatory_hint(hw->wiphy, param->reg_alpha2); data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); @@ -2180,6 +2314,9 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, list_add_tail(&data->list, &hwsim_radios); spin_unlock_bh(&hwsim_radio_lock); + if (idx > 0) + hswim_mcast_new_radio(idx, info, param); + return idx; failed_hw: @@ -2192,8 +2329,46 @@ failed: return err; } -static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) +static void hwsim_mcast_del_radio(int id, const char *hwname, + struct genl_info *info) +{ + struct sk_buff *skb; + void *data; + int ret; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return; + + data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, + HWSIM_CMD_DEL_RADIO); + if (!data) + goto error; + + ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); + if (ret < 0) + goto error; + + ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), + hwname); + if (ret < 0) + goto error; + + genlmsg_end(skb, data); + + hwsim_mcast_config_msg(skb, info); + + return; + +error: + nlmsg_free(skb); +} + +static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data, + const char *hwname, + struct genl_info *info) { + hwsim_mcast_del_radio(data->idx, hwname, info); debugfs_remove_recursive(data->debugfs); ieee80211_unregister_hw(data->hw); device_release_driver(data->dev); @@ -2211,7 +2386,8 @@ static void mac80211_hwsim_free(void) list))) { list_del(&data->list); spin_unlock_bh(&hwsim_radio_lock); - mac80211_hwsim_destroy_radio(data); + mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), + NULL); spin_lock_bh(&hwsim_radio_lock); } spin_unlock_bh(&hwsim_radio_lock); @@ -2243,7 +2419,7 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) spin_lock_bh(&hwsim_radio_lock); list_for_each_entry(data, &hwsim_radios, list) { - if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) { + if (mac80211_hwsim_addr_match(data, addr)) { _found = true; break; } @@ -2430,58 +2606,93 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2, return 0; } -static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) +static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) { - unsigned int chans = channels; - const char *alpha2 = NULL; - const struct ieee80211_regdomain *regd = NULL; - bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; - bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; - bool use_chanctx; + struct hwsim_new_radio_params param = { 0 }; + const char *hwname = NULL; + int ret; + + param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; + param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; + param.channels = channels; + param.destroy_on_close = + info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; if (info->attrs[HWSIM_ATTR_CHANNELS]) - chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); + param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); + + if (info->attrs[HWSIM_ATTR_NO_VIF]) + param.no_vif = true; + + if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { + hwname = kasprintf(GFP_KERNEL, "%.*s", + nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), + (char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME])); + if (!hwname) + return -ENOMEM; + param.hwname = hwname; + } if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) - use_chanctx = true; + param.use_chanctx = true; else - use_chanctx = (chans > 1); + param.use_chanctx = (param.channels > 1); if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) - alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); + param.reg_alpha2 = + nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) return -EINVAL; - regd = hwsim_world_regdom_custom[idx]; + param.regd = hwsim_world_regdom_custom[idx]; } - return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict, - p2p_device, use_chanctx); + ret = mac80211_hwsim_new_radio(info, ¶m); + kfree(hwname); + return ret; } -static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) +static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) { struct mac80211_hwsim_data *data; - int idx; - - if (!info->attrs[HWSIM_ATTR_RADIO_ID]) + s64 idx = -1; + const char *hwname = NULL; + + if (info->attrs[HWSIM_ATTR_RADIO_ID]) { + idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); + } else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { + hwname = kasprintf(GFP_KERNEL, "%.*s", + nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), + (char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME])); + if (!hwname) + return -ENOMEM; + } else return -EINVAL; - idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); spin_lock_bh(&hwsim_radio_lock); list_for_each_entry(data, &hwsim_radios, list) { - if (data->idx != idx) - continue; + if (idx >= 0) { + if (data->idx != idx) + continue; + } else { + if (!hwname || + strcmp(hwname, wiphy_name(data->hw->wiphy))) + continue; + } + list_del(&data->list); spin_unlock_bh(&hwsim_radio_lock); - mac80211_hwsim_destroy_radio(data); + mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), + info); + kfree(hwname); return 0; } spin_unlock_bh(&hwsim_radio_lock); + kfree(hwname); return -ENODEV; } @@ -2504,19 +2715,42 @@ static const struct genl_ops hwsim_ops[] = { .doit = hwsim_tx_info_frame_received_nl, }, { - .cmd = HWSIM_CMD_CREATE_RADIO, + .cmd = HWSIM_CMD_NEW_RADIO, .policy = hwsim_genl_policy, - .doit = hwsim_create_radio_nl, + .doit = hwsim_new_radio_nl, .flags = GENL_ADMIN_PERM, }, { - .cmd = HWSIM_CMD_DESTROY_RADIO, + .cmd = HWSIM_CMD_DEL_RADIO, .policy = hwsim_genl_policy, - .doit = hwsim_destroy_radio_nl, + .doit = hwsim_del_radio_nl, .flags = GENL_ADMIN_PERM, }, }; +static void destroy_radio(struct work_struct *work) +{ + struct mac80211_hwsim_data *data = + container_of(work, struct mac80211_hwsim_data, destroy_work); + + mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL); +} + +static void remove_user_radios(u32 portid) +{ + struct mac80211_hwsim_data *entry, *tmp; + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) { + if (entry->destroy_on_close && entry->portid == portid) { + list_del(&entry->list); + INIT_WORK(&entry->destroy_work, destroy_radio); + schedule_work(&entry->destroy_work); + } + } + spin_unlock_bh(&hwsim_radio_lock); +} + static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, unsigned long state, void *_notify) @@ -2526,6 +2760,8 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, if (state != NETLINK_URELEASE) return NOTIFY_DONE; + remove_user_radios(notify->portid); + if (notify->portid == wmediumd_portid) { printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" " socket, switching to perfect channel medium\n"); @@ -2545,7 +2781,9 @@ static int hwsim_init_netlink(void) printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); - rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops); + rc = genl_register_family_with_ops_groups(&hwsim_genl_family, + hwsim_ops, + hwsim_mcgrps); if (rc) goto failure; @@ -2606,69 +2844,73 @@ static int __init init_mac80211_hwsim(void) goto out_unregister_driver; } + err = hwsim_init_netlink(); + if (err < 0) + goto out_unregister_driver; + for (i = 0; i < radios; i++) { - const char *reg_alpha2 = NULL; - const struct ieee80211_regdomain *regd = NULL; - bool reg_strict = false; + struct hwsim_new_radio_params param = { 0 }; + + param.channels = channels; switch (regtest) { case HWSIM_REGTEST_DIFF_COUNTRY: if (i < ARRAY_SIZE(hwsim_alpha2s)) - reg_alpha2 = hwsim_alpha2s[i]; + param.reg_alpha2 = hwsim_alpha2s[i]; break; case HWSIM_REGTEST_DRIVER_REG_FOLLOW: if (!i) - reg_alpha2 = hwsim_alpha2s[0]; + param.reg_alpha2 = hwsim_alpha2s[0]; break; case HWSIM_REGTEST_STRICT_ALL: - reg_strict = true; + param.reg_strict = true; case HWSIM_REGTEST_DRIVER_REG_ALL: - reg_alpha2 = hwsim_alpha2s[0]; + param.reg_alpha2 = hwsim_alpha2s[0]; break; case HWSIM_REGTEST_WORLD_ROAM: if (i == 0) - regd = &hwsim_world_regdom_custom_01; + param.regd = &hwsim_world_regdom_custom_01; break; case HWSIM_REGTEST_CUSTOM_WORLD: - regd = &hwsim_world_regdom_custom_01; + param.regd = &hwsim_world_regdom_custom_01; break; case HWSIM_REGTEST_CUSTOM_WORLD_2: if (i == 0) - regd = &hwsim_world_regdom_custom_01; + param.regd = &hwsim_world_regdom_custom_01; else if (i == 1) - regd = &hwsim_world_regdom_custom_02; + param.regd = &hwsim_world_regdom_custom_02; break; case HWSIM_REGTEST_STRICT_FOLLOW: if (i == 0) { - reg_strict = true; - reg_alpha2 = hwsim_alpha2s[0]; + param.reg_strict = true; + param.reg_alpha2 = hwsim_alpha2s[0]; } break; case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: if (i == 0) { - reg_strict = true; - reg_alpha2 = hwsim_alpha2s[0]; + param.reg_strict = true; + param.reg_alpha2 = hwsim_alpha2s[0]; } else if (i == 1) { - reg_alpha2 = hwsim_alpha2s[1]; + param.reg_alpha2 = hwsim_alpha2s[1]; } break; case HWSIM_REGTEST_ALL: switch (i) { case 0: - regd = &hwsim_world_regdom_custom_01; + param.regd = &hwsim_world_regdom_custom_01; break; case 1: - regd = &hwsim_world_regdom_custom_02; + param.regd = &hwsim_world_regdom_custom_02; break; case 2: - reg_alpha2 = hwsim_alpha2s[0]; + param.reg_alpha2 = hwsim_alpha2s[0]; break; case 3: - reg_alpha2 = hwsim_alpha2s[1]; + param.reg_alpha2 = hwsim_alpha2s[1]; break; case 4: - reg_strict = true; - reg_alpha2 = hwsim_alpha2s[2]; + param.reg_strict = true; + param.reg_alpha2 = hwsim_alpha2s[2]; break; } break; @@ -2676,10 +2918,10 @@ static int __init init_mac80211_hwsim(void) break; } - err = mac80211_hwsim_create_radio(channels, reg_alpha2, - regd, reg_strict, - support_p2p_device, - channels > 1); + param.p2p_device = support_p2p_device; + param.use_chanctx = channels > 1; + + err = mac80211_hwsim_new_radio(NULL, ¶m); if (err < 0) goto out_free_radios; } @@ -2705,10 +2947,6 @@ static int __init init_mac80211_hwsim(void) } rtnl_unlock(); - err = hwsim_init_netlink(); - if (err < 0) - goto out_free_mon; - return 0; out_free_mon: diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index c9d0315575bab27035378378d396a46db828bf4c..448e64b619cbd5faccc4054606f014757ab34cdc 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -65,9 +65,10 @@ enum hwsim_tx_control_flags { * kernel, uses: * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE - * @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters, - * returns the radio ID (>= 0) or negative on errors - * @HWSIM_CMD_DESTROY_RADIO: destroy a radio + * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters, + * returns the radio ID (>= 0) or negative on errors, if successful + * then multicast the result + * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted * @__HWSIM_CMD_MAX: enum limit */ enum { @@ -75,12 +76,15 @@ enum { HWSIM_CMD_REGISTER, HWSIM_CMD_FRAME, HWSIM_CMD_TX_INFO_FRAME, - HWSIM_CMD_CREATE_RADIO, - HWSIM_CMD_DESTROY_RADIO, + HWSIM_CMD_NEW_RADIO, + HWSIM_CMD_DEL_RADIO, __HWSIM_CMD_MAX, }; #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) +#define HWSIM_CMD_CREATE_RADIO HWSIM_CMD_NEW_RADIO +#define HWSIM_CMD_DESTROY_RADIO HWSIM_CMD_DEL_RADIO + /** * enum hwsim_attrs - hwsim netlink attributes * @@ -111,6 +115,10 @@ enum { * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO * command to force use of channel contexts even when only a * single channel is supported + * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO + * command to force radio removal when process that created the radio dies + * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666 + * @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio. * @__HWSIM_ATTR_MAX: enum limit */ @@ -132,6 +140,9 @@ enum { HWSIM_ATTR_REG_STRICT_REG, HWSIM_ATTR_SUPPORT_P2P_DEVICE, HWSIM_ATTR_USE_CHANCTX, + HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, + HWSIM_ATTR_RADIO_NAME, + HWSIM_ATTR_NO_VIF, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 4371e12b36f38af6e0946969288ce918dc8487b1..3f239f1ad203fe738e28af0bd544f4c7c147c1d2 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -556,6 +556,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) MWIFIEX_FUNC_SHUTDOWN); } + if (adapter->workqueue) + flush_workqueue(adapter->workqueue); + mwifiex_usb_free(card); dev_dbg(adapter->dev, "%s: removing card\n", __func__); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 8330fa33e50b1e2f933f813ee187c407184780ae..52a91137f49c08ab27a7cc0304ca74a5cbb65485 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -247,7 +247,10 @@ static const UCHAR b4_default_startup_parms[] = { 0x04, 0x08, /* Noise gain, limit offset */ 0x28, 0x28, /* det rssi, med busy offsets */ 7, /* det sync thresh */ - 0, 2, 2 /* test mode, min, max */ + 0, 2, 2, /* test mode, min, max */ + 0, /* rx/tx delay */ + 0, 0, 0, 0, 0, 0, /* current BSS id */ + 0 /* hop set */ }; /*===========================================================================*/ @@ -598,7 +601,7 @@ static void init_startup_params(ray_dev_t *local) * a_beacon_period = hops a_beacon_period = KuS *//* 64ms = 010000 */ if (local->fw_ver == 0x55) { - memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms, + memcpy(&local->sparm.b4, b4_default_startup_parms, sizeof(struct b4_startup_params)); /* Translate sane kus input values to old build 4/5 format */ /* i = hop time in uS truncated to 3 bytes */ diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 700d6bf4889003d5b624ed2e2c170e4a37c6df5b..f70f6bb6c318b9aa2d214bb565ced1fb73fcbcf2 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2919,6 +2919,8 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, while (buflen >= sizeof(*auth_req)) { auth_req = (void *)buf; + if (buflen < le32_to_cpu(auth_req->length)) + return; type = "unknown"; flags = le32_to_cpu(auth_req->flags); pairwise_error = false; @@ -3425,6 +3427,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); + if (!priv->workqueue) { + wiphy_free(wiphy); + return -ENOMEM; + } INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8428858204a6763a6d4ccfbeb6c2c81a12e7a33f..fc895b466ebb1843c114e05539e319742c5d4fcc 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -155,7 +155,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) int err; struct mmc_card *card = pfunction->card; struct mmc_host *host = card->host; - s32 bit = (fls(host->ocr_avail) - 1); u8 cmd52_resp; u32 clock, resp, i; u16 rca; @@ -175,7 +174,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) msleep(20); /* Initialize the SDIO card */ - host->ios.vdd = bit; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 15527d8aa015f03bd992f3901f61dd5732a5e591..8720b8ae991c1249f4ad6ff42da7c4028b609095 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1200,8 +1200,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc; - wl1251_acx_arp_ip_filter(wl, enable, addr); - + ret = wl1251_acx_arp_ip_filter(wl, enable, addr); if (ret < 0) goto out_sleep; } diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 57dad571628cea5146dc2386c383993ace522a2b..7b6d1f40f7b66b72cfa28ed2badc46a140114226 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -35,6 +35,7 @@ #include "wl12xx_80211.h" #include "cmd.h" #include "event.h" +#include "ps.h" #include "tx.h" #include "hw_ops.h" @@ -187,6 +188,10 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + return ret; + do { if (time_after(jiffies, timeout_time)) { wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", @@ -218,6 +223,7 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, } while (!event); out: + wl1271_ps_elp_sleep(wl); kfree(events_vector); return ret; } diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index c172da56b550b8a59f88f5206a0160c1a878f5bb..e4a8280cea83242bef62c3bff211a218d5b92901 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -388,6 +388,11 @@ static int wl1271_suspend(struct device *dev) mmc_pm_flag_t sdio_flags; int ret = 0; + if (!wl) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index d62ce26ff1378430e01072a23148968478505f85..674c2151fc3a7c50fd0d901dd48bf32e865372a8 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -187,6 +187,7 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_MAX_BUILD_VER_LEN 256 #define WCNSS_MAX_CMD_LEN (128) #define WCNSS_MIN_CMD_LEN (3) +#define WCNSS_CMD_INFO_LEN 2 /* control messages from userspace */ #define WCNSS_USR_CTRL_MSG_START 0x00000000 @@ -194,7 +195,6 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_USR_WLAN_MAC_ADDR (WCNSS_USR_CTRL_MSG_START + 3) #define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" -#define SHOW_MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x\n" #define WCNSS_USER_MAC_ADDR_LENGTH 18 /* message types */ @@ -457,11 +457,7 @@ static ssize_t wcnss_wlan_macaddr_store(struct device *dev, (char *)&macAddr[index], sizeof(char)); } - pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); - + pr_info("%s: Write MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); return count; } @@ -471,10 +467,7 @@ static ssize_t wcnss_wlan_macaddr_show(struct device *dev, if (!penv) return -ENODEV; - return scnprintf(buf, PAGE_SIZE, SHOW_MAC_ADDRESS_STR, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + return scnprintf(buf, PAGE_SIZE, "%pM\n", penv->wlan_nv_macAddr); } static DEVICE_ATTR(wcnss_mac_addr, S_IRUSR | S_IWUSR, @@ -1663,10 +1656,8 @@ int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE]) return -ENODEV; memcpy(mac_addr, penv->wlan_nv_macAddr, WLAN_MAC_ADDR_SIZE); - pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + pr_debug("%s: Get MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); + return 0; } EXPORT_SYMBOL(wcnss_get_wlan_mac_address); @@ -2649,57 +2640,57 @@ static int wcnss_ctrl_open(struct inode *inode, struct file *file) return rc; } - -void process_usr_ctrl_cmd(u8 *buf, size_t len) +static ssize_t wcnss_ctrl_write(struct file *fp, const char __user + *user_buffer, size_t count, loff_t *position) { - u16 cmd = buf[0] << 8 | buf[1]; + int rc = 0; + u16 cmd; + u8 buf[WCNSS_MAX_CMD_LEN]; - switch (cmd) { + if (!penv || !penv->ctrl_device_opened || + WCNSS_MAX_CMD_LEN < count || WCNSS_MIN_CMD_LEN > count) + return -EFAULT; + mutex_lock(&penv->ctrl_lock); + rc = copy_from_user(buf, user_buffer, count); + if (rc) { + pr_err("%s: Failed to copy ctrl data\n", __func__); + goto exit; + } + + cmd = buf[0] << 8 | buf[1]; + switch (cmd) { case WCNSS_USR_HAS_CAL_DATA: - if (1 < buf[2]) - pr_err("%s: Invalid data for cal %d\n", __func__, - buf[2]); + if (buf[2] > 1) { + pr_err("%s: Invalid cal data %d\n", __func__, buf[2]); + rc = -EINVAL; + goto exit; + } has_calibrated_data = buf[2]; break; case WCNSS_USR_WLAN_MAC_ADDR: - memcpy(&penv->wlan_nv_macAddr, &buf[2], - sizeof(penv->wlan_nv_macAddr)); + if ((count - WCNSS_CMD_INFO_LEN) != WLAN_MAC_ADDR_SIZE) { + pr_err("%s: Invalid Mac addr %d\n", __func__, buf[2]); + rc = -EINVAL; + goto exit; + } - pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + memcpy(&penv->wlan_nv_macAddr, &buf[2], + sizeof(penv->wlan_nv_macAddr)); + pr_debug("%s:MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); break; - default: pr_err("%s: Invalid command %d\n", __func__, cmd); + rc = -EINVAL; break; } -} - -static ssize_t wcnss_ctrl_write(struct file *fp, const char __user - *user_buffer, size_t count, loff_t *position) -{ - int rc = 0; - u8 buf[WCNSS_MAX_CMD_LEN]; - - if (!penv || !penv->ctrl_device_opened || WCNSS_MAX_CMD_LEN < count - || WCNSS_MIN_CMD_LEN > count) - return -EFAULT; - - mutex_lock(&penv->ctrl_lock); - rc = copy_from_user(buf, user_buffer, count); - if (0 == rc) - process_usr_ctrl_cmd(buf, count); +exit: mutex_unlock(&penv->ctrl_lock); - return rc; } - static const struct file_operations wcnss_ctrl_fops = { .owner = THIS_MODULE, .open = wcnss_ctrl_open, diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 7a85ff54a39f33472b33807fdfef2271cd9a0bac..50b7731025c1b86130a6fa79a45ba5a94757e315 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -67,6 +67,7 @@ module_param(rx_drain_timeout_msecs, uint, 0444); unsigned int rx_stall_timeout_msecs = 60000; module_param(rx_stall_timeout_msecs, uint, 0444); +#define MAX_QUEUES_DEFAULT 8 unsigned int xenvif_max_queues; module_param_named(max_queues, xenvif_max_queues, uint, 0644); MODULE_PARM_DESC(max_queues, @@ -2189,11 +2190,12 @@ static int __init netback_init(void) if (!xen_domain()) return -ENODEV; - /* Allow as many queues as there are CPUs if user has not + /* Allow as many queues as there are CPUs but max. 8 if user has not * specified a value. */ if (xenvif_max_queues == 0) - xenvif_max_queues = num_online_cpus(); + xenvif_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT, + num_online_cpus()); if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8f45be1592ca285efb7e856ece337e7699d62e73..3bbfb09af65fcad69b84cd2d0719b7a0883e0778 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -85,6 +85,8 @@ struct netfront_cb { /* IRQ name is queue name with "-tx" or "-rx" appended */ #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3) +static DECLARE_WAIT_QUEUE_HEAD(module_wq); + struct netfront_stats { u64 rx_packets; u64 tx_packets; @@ -900,7 +902,6 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, struct sk_buff *skb, struct sk_buff_head *list) { - struct skb_shared_info *shinfo = skb_shinfo(skb); RING_IDX cons = queue->rx.rsp_cons; struct sk_buff *nskb; @@ -909,15 +910,16 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, RING_GET_RESPONSE(&queue->rx, ++cons); skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0]; - if (shinfo->nr_frags == MAX_SKB_FRAGS) { + if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) { unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to; BUG_ON(pull_to <= skb_headlen(skb)); __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); } - BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS); + BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS); - skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag), + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + skb_frag_page(nfrag), rx->offset, rx->status, PAGE_SIZE); skb_shinfo(nskb)->nr_frags = 0; @@ -1356,6 +1358,12 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); + xenbus_switch_state(dev, XenbusStateInitialising); + wait_event(module_wq, + xenbus_read_driver_state(dev->otherend) != + XenbusStateClosed && + xenbus_read_driver_state(dev->otherend) != + XenbusStateUnknown); return netdev; exit: @@ -2059,6 +2067,8 @@ static void netback_changed(struct xenbus_device *dev, dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state)); + wake_up_all(&module_wq); + switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: @@ -2305,6 +2315,22 @@ static int xennet_remove(struct xenbus_device *dev) dev_dbg(&dev->dev, "%s\n", dev->nodename); + if (xenbus_read_driver_state(dev->otherend) != XenbusStateClosed) { + xenbus_switch_state(dev, XenbusStateClosing); + wait_event(module_wq, + xenbus_read_driver_state(dev->otherend) == + XenbusStateClosing || + xenbus_read_driver_state(dev->otherend) == + XenbusStateUnknown); + + xenbus_switch_state(dev, XenbusStateClosed); + wait_event(module_wq, + xenbus_read_driver_state(dev->otherend) == + XenbusStateClosed || + xenbus_read_driver_state(dev->otherend) == + XenbusStateUnknown); + } + xennet_disconnect_backend(info); xennet_sysfs_delif(info->netdev); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 84ccec9c34cc83737ab79743ff0e0e4c62b43db7..98760bbbb93a8ccdfcc9c6edc9a15b3256d9c24d 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -1,11 +1,15 @@ config DTC bool -config OF - bool +menuconfig OF + bool "Device Tree and Open Firmware support" + help + This option enables the device tree infrastructure. + It is automatically selected by platforms that need it or can + be enabled manually for unittests, overlays or + compile-coverage. -menu "Device Tree and Open Firmware support" - depends on OF +if OF config OF_UNITTEST bool "Device Tree runtime unit tests" @@ -38,7 +42,7 @@ config OF_DYNAMIC config OF_ADDRESS def_bool y - depends on !SPARC + depends on !SPARC && HAS_IOMEM select OF_ADDRESS_PCI if PCI config OF_ADDRESS_PCI @@ -111,4 +115,4 @@ config OF_OVERLAY select OF_DYNAMIC select OF_RESOLVE -endmenu # OF +endif # OF diff --git a/drivers/of/device.c b/drivers/of/device.c index 493b21bd1199adf609586751ff853ddf445747d0..6601cc62a9901f7e69d8e87473621f83990e7488 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -210,7 +210,7 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) str[i] = '_'; } - return tsize; + return repend; } EXPORT_SYMBOL_GPL(of_device_get_modalias); diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index dee9270ba5471e730518b0ddc647469c8a52776f..24e025f7929932cb1dcf8c0a834b308a30b99fe2 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -333,7 +333,7 @@ static DEFINE_IDR(ov_idr); * of the overlay in a list. This list can be used to prevent * illegal overlay removals. * - * Returns the id of the created overlay, or an negative error number + * Returns the id of the created overlay, or a negative error number */ int of_overlay_create(struct device_node *tree) { @@ -481,7 +481,7 @@ static int overlay_removal_is_ok(struct of_overlay *ov) * * Removes an overlay if it is permissible. * - * Returns 0 on success, or an negative error number + * Returns 0 on success, or a negative error number */ int of_overlay_destroy(int id) { @@ -528,7 +528,7 @@ EXPORT_SYMBOL_GPL(of_overlay_destroy); * * Removes all overlays from the system in the correct order. * - * Returns 0 on success, or an negative error number + * Returns 0 on success, or a negative error number */ int of_overlay_destroy_all(void) { diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index e5fa3e91f82f157beb58b39992b001110ee73c08..5b297548f9b2170732df5cb4977fb097b5b3b46d 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -526,7 +526,8 @@ static void __init of_selftest_changeset(void) /* Make sure node names are constructed correctly */ selftest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")), "'%s' not added\n", n21->full_name); - of_node_put(np); + if (np) + of_node_put(np); mutex_lock(&of_mutex); selftest(!of_changeset_revert(&chgset), "revert failed\n"); diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 4590515a275c1548f7a85a22fd8a95b53f67e0a0..dd8ed9771768eb0edd9ed7fcb5925b8fd03d2693 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1366,9 +1366,27 @@ lba_hw_init(struct lba_device *d) WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG); } - /* Set HF mode as the default (vs. -1 mode). */ + + /* + * Hard Fail vs. Soft Fail on PCI "Master Abort". + * + * "Master Abort" means the MMIO transaction timed out - usually due to + * the device not responding to an MMIO read. We would like HF to be + * enabled to find driver problems, though it means the system will + * crash with a HPMC. + * + * In SoftFail mode "~0L" is returned as a result of a timeout on the + * pci bus. This is like how PCI busses on x86 and most other + * architectures behave. In order to increase compatibility with + * existing (x86) PCI hardware and existing Linux drivers we enable + * Soft Faul mode on PA-RISC now too. + */ stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); +#if defined(ENABLE_HARDFAIL) WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); +#else + WRITE_REG32(stat & ~HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); +#endif /* ** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal @@ -1652,3 +1670,36 @@ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) iounmap(base_addr); } + +/* + * The design of the Diva management card in rp34x0 machines (rp3410, rp3440) + * seems rushed, so that many built-in components simply don't work. + * The following quirks disable the serial AUX port and the built-in ATI RV100 + * Radeon 7000 graphics card which both don't have any external connectors and + * thus are useless, and even worse, e.g. the AUX port occupies ttyS0 and as + * such makes those machines the only PARISC machines on which we can't use + * ttyS0 as boot console. + */ +static void quirk_diva_ati_card(struct pci_dev *dev) +{ + if (dev->subsystem_vendor != PCI_VENDOR_ID_HP || + dev->subsystem_device != 0x1292) + return; + + dev_info(&dev->dev, "Hiding Diva built-in ATI card"); + dev->device = 0; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY, + quirk_diva_ati_card); + +static void quirk_diva_aux_disable(struct pci_dev *dev) +{ + if (dev->subsystem_vendor != PCI_VENDOR_ID_HP || + dev->subsystem_device != 0x1291) + return; + + dev_info(&dev->dev, "Hiding Diva built-in AUX serial device"); + dev->device = 0; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX, + quirk_diva_aux_disable); diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index f721299eb1baee70059a2ac33bdb8b73ba249dae..cc00a3a426bf33a5bd58f7b922a7c88aa210aa43 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2646,6 +2646,7 @@ enum parport_pc_pci_cards { netmos_9901, netmos_9865, quatech_sppxp100, + wch_ch382l, }; @@ -2708,6 +2709,7 @@ static struct parport_pc_pci { /* netmos_9901 */ { 1, { { 0, -1 }, } }, /* netmos_9865 */ { 1, { { 0, -1 }, } }, /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, + /* wch_ch382l */ { 1, { { 2, -1 }, } }, }; static const struct pci_device_id parport_pc_pci_tbl[] = { @@ -2797,6 +2799,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { /* Quatech SPPXP-100 Parallel port PCI ExpressCard */ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, + /* WCH CH382L PCI-E single parallel port card */ + { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl); diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index dffd6d0bd15b7795ec1a1d796b5652e8c540944c..634a243734e3076a53d891df2b1ded87975607a9 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -286,12 +286,16 @@ static int bpp_probe(struct platform_device *op) ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations), GFP_KERNEL); - if (!ops) + if (!ops) { + err = -ENOMEM; goto out_unmap; + } dprintk(("register_port\n")); - if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) + if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) { + err = -ENOMEM; goto out_free_ops; + } p->size = size; p->dev = &op->dev; diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 8a2707885735b7c34721d757baba47e55549ca7b..f27a43558177b61a0c527839635bc9a6bc70af27 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -179,14 +179,16 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie, } /* interrupt controller is in a child node */ - *np_temp = of_find_node_by_name(np_pcie, controller); + *np_temp = of_get_child_by_name(np_pcie, controller); if (!(*np_temp)) { dev_err(dev, "Node for %s is absent\n", controller); goto out; } temp = of_irq_count(*np_temp); - if (!temp) + if (!temp) { + of_node_put(*np_temp); goto out; + } if (temp > max_host_irqs) dev_warn(dev, "Too many %s interrupts defined %u\n", (legacy ? "legacy" : "MSI"), temp); @@ -200,6 +202,9 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie, if (host_irqs[temp] < 0) break; } + + of_node_put(*np_temp); + if (temp) { *num_irqs = temp; ret = 0; diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index d27b8446a6cfaa40999b9db21edf18ec13f1161b..10605efa9d83ac8a974674127ed68d5f99ff48ea 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. * * 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 @@ -292,6 +292,7 @@ #define PERST_PROPAGATION_DELAY_US_MIN 1000 #define PERST_PROPAGATION_DELAY_US_MAX 1005 +#define SWITCH_DELAY_MAX 20 #define REFCLK_STABILIZATION_DELAY_US_MIN 1000 #define REFCLK_STABILIZATION_DELAY_US_MAX 1005 #define LINK_UP_TIMEOUT_US_MIN 5000 @@ -616,6 +617,10 @@ struct msm_pcie_dev_t { bool l0s_supported; bool l1_supported; bool l1ss_supported; + bool l1_1_pcipm_supported; + bool l1_2_pcipm_supported; + bool l1_1_aspm_supported; + bool l1_2_aspm_supported; bool common_clk_en; bool clk_power_manage_en; bool aux_clk_sync; @@ -626,6 +631,7 @@ struct msm_pcie_dev_t { bool ext_ref_clk; bool common_phy; uint32_t ep_latency; + uint32_t switch_latency; uint32_t wr_halt_size; uint32_t cpl_timeout; uint32_t current_bdf; @@ -838,6 +844,17 @@ static const struct msm_pcie_irq_info_t msm_pcie_msi_info[MSM_PCIE_MAX_MSI] = { {"msi_28", 0}, {"msi_29", 0}, {"msi_30", 0}, {"msi_31", 0} }; +static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev, + struct pci_bus *bus); +static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev, + struct pci_bus *bus); +static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev, + struct pci_bus *bus); +static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev); +static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev); +static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev); +static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev); +static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable); #ifdef CONFIG_ARM #define PCIE_BUS_PRIV_DATA(bus) \ (((struct pci_sys_data *)bus->sysdata)->private_data) @@ -888,6 +905,17 @@ static inline void msm_pcie_write_reg_field(void *base, u32 offset, wmb(); } +static inline void msm_pcie_config_clear_set_dword(struct pci_dev *pdev, + int pos, u32 clear, u32 set) +{ + u32 val; + + pci_read_config_dword(pdev, pos, &val); + val &= ~clear; + val |= set; + pci_write_config_dword(pdev, pos, val); +} + #if defined(CONFIG_ARCH_FSM9010) #define PCIE20_PARF_PHY_STTS 0x3c #define PCIE2_PHY_RESET_CTRL 0x44 @@ -1936,6 +1964,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->common_phy); PCIE_DBG_FS(dev, "ep_latency: %dms\n", dev->ep_latency); + PCIE_DBG_FS(dev, "switch_latency: %dms\n", + dev->switch_latency); PCIE_DBG_FS(dev, "wr_halt_size: 0x%x\n", dev->wr_halt_size); PCIE_DBG_FS(dev, "cpl_timeout: 0x%x\n", @@ -2008,10 +2038,9 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, u32 base_sel_size = 0; u32 val = 0; u32 current_offset = 0; - u32 ep_l1sub_ctrl1_offset = 0; - u32 ep_l1sub_cap_reg1_offset = 0; u32 ep_link_ctrlstts_offset = 0; u32 ep_dev_ctrl2stts2_offset = 0; + u32 wr_ofst = 0; if (testcase >= 5 && testcase <= 10) { current_offset = @@ -2113,231 +2142,59 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, case 5: /* disable L0s */ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n", dev->rc_idx); - msm_pcie_write_mask(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS, - BIT(0), 0); - msm_pcie_write_mask(dev->conf + - ep_link_ctrlstts_offset, - BIT(0), 0); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] = - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS); - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); - } - PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS)); - PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset)); + if (dev->link_status == MSM_PCIE_LINK_ENABLED) + msm_pcie_config_l0s_disable_all(dev, dev->dev->bus); + dev->l0s_supported = false; break; case 6: /* enable L0s */ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L0s\n\n", dev->rc_idx); - msm_pcie_write_mask(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS, - 0, BIT(0)); - msm_pcie_write_mask(dev->conf + - ep_link_ctrlstts_offset, - 0, BIT(0)); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] = - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS); - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); - } - PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS)); - PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset)); + dev->l0s_supported = true; + if (dev->link_status == MSM_PCIE_LINK_ENABLED) + msm_pcie_config_l0s_enable_all(dev); break; case 7: /* disable L1 */ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1\n\n", dev->rc_idx); - msm_pcie_write_mask(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS, - BIT(1), 0); - msm_pcie_write_mask(dev->conf + - ep_link_ctrlstts_offset, - BIT(1), 0); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] = - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS); - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); - } - PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS)); - PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset)); + if (dev->link_status == MSM_PCIE_LINK_ENABLED) + msm_pcie_config_l1_disable_all(dev, dev->dev->bus); + dev->l1_supported = false; break; case 8: /* enable L1 */ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1\n\n", dev->rc_idx); - msm_pcie_write_mask(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS, - 0, BIT(1)); - msm_pcie_write_mask(dev->conf + - ep_link_ctrlstts_offset, - 0, BIT(1)); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] = - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS); - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); + dev->l1_supported = true; + if (dev->link_status == MSM_PCIE_LINK_ENABLED) { + /* enable l1 mode, clear bit 5 (REQ_NOT_ENTR_L1) */ + msm_pcie_write_mask(dev->parf + + PCIE20_PARF_PM_CTRL, BIT(5), 0); + + msm_pcie_config_l1_enable_all(dev); } - PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS)); - PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset)); break; case 9: /* disable L1ss */ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1ss\n\n", dev->rc_idx); - current_offset = PCIE_EXT_CAP_OFFSET; - while (current_offset) { - val = readl_relaxed(dev->conf + current_offset); - if ((val & 0xffff) == L1SUB_CAP_ID) { - ep_l1sub_ctrl1_offset = - current_offset + 0x8; - break; - } - current_offset = val >> 20; - } - if (!ep_l1sub_ctrl1_offset) { - PCIE_DBG_FS(dev, - "PCIe: RC%d endpoint does not support l1ss registers\n", - dev->rc_idx); - break; - } - - PCIE_DBG_FS(dev, "PCIe: RC%d: ep_l1sub_ctrl1_offset: 0x%x\n", - dev->rc_idx, ep_l1sub_ctrl1_offset); - - msm_pcie_write_reg_field(dev->dm_core, - PCIE20_L1SUB_CONTROL1, - 0xf, 0); - msm_pcie_write_mask(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2, - BIT(10), 0); - msm_pcie_write_reg_field(dev->conf, - ep_l1sub_ctrl1_offset, - 0xf, 0); - msm_pcie_write_mask(dev->conf + - ep_dev_ctrl2stts2_offset, - BIT(10), 0); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_L1SUB_CONTROL1 / 4] = - readl_relaxed(dev->dm_core + - PCIE20_L1SUB_CONTROL1); - dev->rc_shadow[PCIE20_DEVICE_CONTROL2_STATUS2 / 4] = - readl_relaxed(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2); - dev->ep_shadow[0][ep_l1sub_ctrl1_offset / 4] = - readl_relaxed(dev->conf + - ep_l1sub_ctrl1_offset); - dev->ep_shadow[0][ep_dev_ctrl2stts2_offset / 4] = - readl_relaxed(dev->conf + - ep_dev_ctrl2stts2_offset); - } - PCIE_DBG_FS(dev, "PCIe: RC's L1SUB_CONTROL1:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_L1SUB_CONTROL1)); - PCIE_DBG_FS(dev, "PCIe: RC's DEVICE_CONTROL2_STATUS2:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2)); - PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CONTROL1:0x%x\n", - readl_relaxed(dev->conf + - ep_l1sub_ctrl1_offset)); - PCIE_DBG_FS(dev, "PCIe: EP's DEVICE_CONTROL2_STATUS2:0x%x\n", - readl_relaxed(dev->conf + - ep_dev_ctrl2stts2_offset)); + if (dev->link_status == MSM_PCIE_LINK_ENABLED) + msm_pcie_config_l1ss_disable_all(dev, dev->dev->bus); + dev->l1ss_supported = false; + dev->l1_1_pcipm_supported = false; + dev->l1_2_pcipm_supported = false; + dev->l1_1_aspm_supported = false; + dev->l1_2_aspm_supported = false; break; case 10: /* enable L1ss */ PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1ss\n\n", dev->rc_idx); - current_offset = PCIE_EXT_CAP_OFFSET; - while (current_offset) { - val = readl_relaxed(dev->conf + current_offset); - if ((val & 0xffff) == L1SUB_CAP_ID) { - ep_l1sub_cap_reg1_offset = - current_offset + 0x4; - ep_l1sub_ctrl1_offset = - current_offset + 0x8; - break; - } - current_offset = val >> 20; + dev->l1ss_supported = true; + dev->l1_1_pcipm_supported = true; + dev->l1_2_pcipm_supported = true; + dev->l1_1_aspm_supported = true; + dev->l1_2_aspm_supported = true; + if (dev->link_status == MSM_PCIE_LINK_ENABLED) { + msm_pcie_check_l1ss_support_all(dev); + msm_pcie_config_l1ss_enable_all(dev); } - if (!ep_l1sub_ctrl1_offset) { - PCIE_DBG_FS(dev, - "PCIe: RC%d endpoint does not support l1ss registers\n", - dev->rc_idx); - break; - } - - val = readl_relaxed(dev->conf + - ep_l1sub_cap_reg1_offset); - - PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CAPABILITY_REG_1: 0x%x\n", - val); - PCIE_DBG_FS(dev, "PCIe: RC%d: ep_l1sub_ctrl1_offset: 0x%x\n", - dev->rc_idx, ep_l1sub_ctrl1_offset); - - val &= 0xf; - - msm_pcie_write_reg_field(dev->dm_core, - PCIE20_L1SUB_CONTROL1, - 0xf, val); - msm_pcie_write_mask(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2, - 0, BIT(10)); - msm_pcie_write_reg_field(dev->conf, - ep_l1sub_ctrl1_offset, - 0xf, val); - msm_pcie_write_mask(dev->conf + - ep_dev_ctrl2stts2_offset, - 0, BIT(10)); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_L1SUB_CONTROL1 / 4] = - readl_relaxed(dev->dm_core + - PCIE20_L1SUB_CONTROL1); - dev->rc_shadow[PCIE20_DEVICE_CONTROL2_STATUS2 / 4] = - readl_relaxed(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2); - dev->ep_shadow[0][ep_l1sub_ctrl1_offset / 4] = - readl_relaxed(dev->conf + - ep_l1sub_ctrl1_offset); - dev->ep_shadow[0][ep_dev_ctrl2stts2_offset / 4] = - readl_relaxed(dev->conf + - ep_dev_ctrl2stts2_offset); - } - PCIE_DBG_FS(dev, "PCIe: RC's L1SUB_CONTROL1:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_L1SUB_CONTROL1)); - PCIE_DBG_FS(dev, "PCIe: RC's DEVICE_CONTROL2_STATUS2:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2)); - PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CONTROL1:0x%x\n", - readl_relaxed(dev->conf + - ep_l1sub_ctrl1_offset)); - PCIE_DBG_FS(dev, "PCIe: EP's DEVICE_CONTROL2_STATUS2:0x%x\n", - readl_relaxed(dev->conf + - ep_dev_ctrl2stts2_offset)); break; case 11: /* enumerate PCIe */ PCIE_DBG_FS(dev, "\n\nPCIe: attempting to enumerate RC%d\n\n", @@ -2373,22 +2230,24 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, break; } + wr_ofst = wr_offset; + PCIE_DBG_FS(dev, "base: %s: 0x%p\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n", dev->res[base_sel - 1].name, dev->res[base_sel - 1].base, - wr_offset, wr_mask, wr_value); + wr_ofst, wr_mask, wr_value); base_sel_size = resource_size(dev->res[base_sel - 1].resource); - if (wr_offset > base_sel_size - 4 || - msm_pcie_check_align(dev, wr_offset)) + if (wr_ofst > base_sel_size - 4 || + msm_pcie_check_align(dev, wr_ofst)) PCIE_DBG_FS(dev, "PCIe: RC%d: Invalid wr_offset: 0x%x. wr_offset should be no more than 0x%x\n", - dev->rc_idx, wr_offset, base_sel_size - 4); + dev->rc_idx, wr_ofst, base_sel_size - 4); else msm_pcie_write_reg_field(dev->res[base_sel - 1].base, - wr_offset, wr_mask, wr_value); + wr_ofst, wr_mask, wr_value); break; case 13: /* dump all registers of base_sel */ @@ -2448,8 +2307,6 @@ int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base, return -ENODEV; } - pdev = PCIE_BUS_PRIV_DATA(dev->bus); - if (option == 12 || option == 13) { if (!base || base > 5) { PCIE_DBG_FS(pdev, "Invalid base_sel: 0x%x\n", base); @@ -2476,6 +2333,7 @@ int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base, } } + pdev = PCIE_BUS_PRIV_DATA(dev->bus); rc_sel = 1 << pdev->rc_idx; msm_pcie_sel_debug_testcase(pdev, option); @@ -3810,194 +3668,6 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev) } } -static void msm_pcie_config_link_state(struct msm_pcie_dev_t *dev) -{ - u32 val; - u32 current_offset; - u32 ep_l1sub_ctrl1_offset = 0; - u32 ep_l1sub_cap_reg1_offset = 0; - u32 ep_link_cap_offset = 0; - u32 ep_link_ctrlstts_offset = 0; - u32 ep_dev_ctrl2stts2_offset = 0; - - /* Enable the AUX Clock and the Core Clk to be synchronous for L1SS*/ - if (!dev->aux_clk_sync && dev->l1ss_supported) - msm_pcie_write_mask(dev->parf + - PCIE20_PARF_SYS_CTRL, BIT(3), 0); - - current_offset = readl_relaxed(dev->conf + PCIE_CAP_PTR_OFFSET) & 0xff; - - while (current_offset) { - if (msm_pcie_check_align(dev, current_offset)) - return; - - val = readl_relaxed(dev->conf + current_offset); - if ((val & 0xff) == PCIE20_CAP_ID) { - ep_link_cap_offset = current_offset + 0x0c; - ep_link_ctrlstts_offset = current_offset + 0x10; - ep_dev_ctrl2stts2_offset = current_offset + 0x28; - break; - } - current_offset = (val >> 8) & 0xff; - } - - if (!ep_link_cap_offset) { - PCIE_DBG(dev, - "RC%d endpoint does not support PCIe capability registers\n", - dev->rc_idx); - return; - } else { - PCIE_DBG(dev, - "RC%d: ep_link_cap_offset: 0x%x\n", - dev->rc_idx, ep_link_cap_offset); - } - - if (dev->common_clk_en) { - msm_pcie_write_mask(dev->dm_core + PCIE20_CAP_LINKCTRLSTATUS, - 0, BIT(6)); - - msm_pcie_write_mask(dev->conf + ep_link_ctrlstts_offset, - 0, BIT(6)); - - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] = - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS); - - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); - } - - PCIE_DBG2(dev, "RC's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS)); - PCIE_DBG2(dev, "EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + ep_link_ctrlstts_offset)); - } - - if (dev->clk_power_manage_en) { - val = readl_relaxed(dev->conf + ep_link_cap_offset); - if (val & BIT(18)) { - msm_pcie_write_mask(dev->conf + ep_link_ctrlstts_offset, - 0, BIT(8)); - - if (dev->shadow_en) - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); - - PCIE_DBG2(dev, "EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset)); - } - } - - if (dev->l0s_supported) { - msm_pcie_write_mask(dev->dm_core + PCIE20_CAP_LINKCTRLSTATUS, - 0, BIT(0)); - msm_pcie_write_mask(dev->conf + ep_link_ctrlstts_offset, - 0, BIT(0)); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] = - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS); - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); - } - PCIE_DBG2(dev, "RC's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS)); - PCIE_DBG2(dev, "EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + ep_link_ctrlstts_offset)); - } - - if (dev->l1_supported) { - msm_pcie_write_mask(dev->dm_core + PCIE20_CAP_LINKCTRLSTATUS, - 0, BIT(1)); - msm_pcie_write_mask(dev->conf + ep_link_ctrlstts_offset, - 0, BIT(1)); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] = - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS); - dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] = - readl_relaxed(dev->conf + - ep_link_ctrlstts_offset); - } - PCIE_DBG2(dev, "RC's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_CAP_LINKCTRLSTATUS)); - PCIE_DBG2(dev, "EP's CAP_LINKCTRLSTATUS:0x%x\n", - readl_relaxed(dev->conf + ep_link_ctrlstts_offset)); - } - - if (dev->l1ss_supported) { - current_offset = PCIE_EXT_CAP_OFFSET; - while (current_offset) { - if (msm_pcie_check_align(dev, current_offset)) - return; - - val = readl_relaxed(dev->conf + current_offset); - if ((val & 0xffff) == L1SUB_CAP_ID) { - ep_l1sub_cap_reg1_offset = current_offset + 0x4; - ep_l1sub_ctrl1_offset = current_offset + 0x8; - break; - } - current_offset = val >> 20; - } - if (!ep_l1sub_ctrl1_offset) { - PCIE_DBG(dev, - "RC%d endpoint does not support l1ss registers\n", - dev->rc_idx); - return; - } - - val = readl_relaxed(dev->conf + ep_l1sub_cap_reg1_offset); - - PCIE_DBG2(dev, "EP's L1SUB_CAPABILITY_REG_1: 0x%x\n", val); - PCIE_DBG2(dev, "RC%d: ep_l1sub_ctrl1_offset: 0x%x\n", - dev->rc_idx, ep_l1sub_ctrl1_offset); - - val &= 0xf; - - msm_pcie_write_reg_field(dev->dm_core, PCIE20_L1SUB_CONTROL1, - 0xf, val); - msm_pcie_write_mask(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2, - 0, BIT(10)); - msm_pcie_write_reg_field(dev->conf, ep_l1sub_ctrl1_offset, - 0xf, val); - msm_pcie_write_mask(dev->conf + ep_dev_ctrl2stts2_offset, - 0, BIT(10)); - if (dev->shadow_en) { - dev->rc_shadow[PCIE20_L1SUB_CONTROL1 / 4] = - readl_relaxed(dev->dm_core + - PCIE20_L1SUB_CONTROL1); - dev->rc_shadow[PCIE20_DEVICE_CONTROL2_STATUS2 / 4] = - readl_relaxed(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2); - dev->ep_shadow[0][ep_l1sub_ctrl1_offset / 4] = - readl_relaxed(dev->conf + - ep_l1sub_ctrl1_offset); - dev->ep_shadow[0][ep_dev_ctrl2stts2_offset / 4] = - readl_relaxed(dev->conf + - ep_dev_ctrl2stts2_offset); - } - PCIE_DBG2(dev, "RC's L1SUB_CONTROL1:0x%x\n", - readl_relaxed(dev->dm_core + PCIE20_L1SUB_CONTROL1)); - PCIE_DBG2(dev, "RC's DEVICE_CONTROL2_STATUS2:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_DEVICE_CONTROL2_STATUS2)); - PCIE_DBG2(dev, "EP's L1SUB_CONTROL1:0x%x\n", - readl_relaxed(dev->conf + ep_l1sub_ctrl1_offset)); - PCIE_DBG2(dev, "EP's DEVICE_CONTROL2_STATUS2:0x%x\n", - readl_relaxed(dev->conf + - ep_dev_ctrl2stts2_offset)); - } -} - void msm_pcie_config_msi_controller(struct msm_pcie_dev_t *dev) { int i; @@ -4377,7 +4047,7 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) /* assert PCIe reset link to keep EP in reset */ - PCIE_DBG(dev, "PCIe: Assert the reset of endpoint of RC%d.\n", + PCIE_INFO(dev, "PCIe: Assert the reset of endpoint of RC%d.\n", dev->rc_idx); gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num, dev->gpio[MSM_PCIE_GPIO_PERST].on); @@ -4504,7 +4174,7 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) dev->rc_idx, retries); if (pcie_phy_is_ready(dev)) - PCIE_DBG(dev, "PCIe RC%d PHY is ready!\n", dev->rc_idx); + PCIE_INFO(dev, "PCIe RC%d PHY is ready!\n", dev->rc_idx); else { PCIE_ERR(dev, "PCIe PHY RC%d failed to come up!\n", dev->rc_idx); @@ -4524,7 +4194,7 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) /* de-assert PCIe reset link to bring EP out of reset */ - PCIE_DBG(dev, "PCIe: Release the reset of endpoint of RC%d.\n", + PCIE_INFO(dev, "PCIe: Release the reset of endpoint of RC%d.\n", dev->rc_idx); gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num, 1 - dev->gpio[MSM_PCIE_GPIO_PERST].on); @@ -4551,9 +4221,9 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) msm_pcie_confirm_linkup(dev, false, false, NULL)) { PCIE_DBG(dev, "Link is up after %d checkings\n", link_check_count); - PCIE_DBG(dev, "PCIe RC%d link initialized\n", dev->rc_idx); + PCIE_INFO(dev, "PCIe RC%d link initialized\n", dev->rc_idx); } else { - PCIE_DBG(dev, "PCIe: Assert the reset of endpoint of RC%d.\n", + PCIE_INFO(dev, "PCIe: Assert the reset of endpoint of RC%d.\n", dev->rc_idx); gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num, dev->gpio[MSM_PCIE_GPIO_PERST].on); @@ -4563,13 +4233,21 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) goto link_fail; } + if (dev->switch_latency) { + PCIE_DBG(dev, "switch_latency: %dms\n", + dev->switch_latency); + if (dev->switch_latency <= SWITCH_DELAY_MAX) + usleep_range(dev->switch_latency * 1000, + dev->switch_latency * 1000); + else + msleep(dev->switch_latency); + } + msm_pcie_config_controller(dev); if (!dev->msi_gicm_addr) msm_pcie_config_msi_controller(dev); - msm_pcie_config_link_state(dev); - dev->link_status = MSM_PCIE_LINK_ENABLED; dev->power_on = true; dev->suspending = false; @@ -4581,6 +4259,9 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) usleep_range(dev->ep_latency * 1000, dev->ep_latency * 1000); } + if (dev->enumerated) + msm_pcie_config_link_pm(dev, true); + goto out; link_fail: @@ -4632,7 +4313,7 @@ void msm_pcie_disable(struct msm_pcie_dev_t *dev, u32 options) dev->power_on = false; dev->link_turned_off_counter++; - PCIE_DBG(dev, "PCIe: Assert the reset of endpoint of RC%d.\n", + PCIE_INFO(dev, "PCIe: Assert the reset of endpoint of RC%d.\n", dev->rc_idx); gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num, @@ -5046,6 +4727,9 @@ int msm_pcie_enumerate(u32 rc_idx) ret = -ENODEV; goto out; } + + msm_pcie_check_l1ss_support_all(dev); + msm_pcie_config_link_pm(dev, true); } else { PCIE_ERR(dev, "PCIe: failed to enable RC%d.\n", dev->rc_idx); @@ -5913,6 +5597,413 @@ void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev) disable_irq(dev->wake_n); } +static bool msm_pcie_check_l0s_support(struct pci_dev *pdev, + struct msm_pcie_dev_t *pcie_dev) +{ + struct pci_dev *parent = pdev->bus->self; + u32 val; + + /* check parent supports L0s */ + if (parent) { + u32 val2; + + pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, + &val); + pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, + &val2); + val = (val & BIT(10)) && (val2 & PCI_EXP_LNKCTL_ASPM_L0S); + if (!val) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L0s\n", + pcie_dev->rc_idx, parent->bus->number, + PCI_SLOT(parent->devfn), + PCI_FUNC(parent->devfn)); + return false; + } + } + + pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); + if (!(val & BIT(10))) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: PCI device %02x:%02x.%01x does not support L0s\n", + pcie_dev->rc_idx, pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + return false; + } + + return true; +} + +static bool msm_pcie_check_l1_support(struct pci_dev *pdev, + struct msm_pcie_dev_t *pcie_dev) +{ + struct pci_dev *parent = pdev->bus->self; + u32 val; + + /* check parent supports L1 */ + if (parent) { + u32 val2; + + pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, + &val); + pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, + &val2); + val = (val & BIT(11)) && (val2 & PCI_EXP_LNKCTL_ASPM_L1); + if (!val) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L1\n", + pcie_dev->rc_idx, parent->bus->number, + PCI_SLOT(parent->devfn), + PCI_FUNC(parent->devfn)); + return false; + } + } + + pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); + if (!(val & BIT(11))) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: PCI device %02x:%02x.%01x does not support L1\n", + pcie_dev->rc_idx, pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + return false; + } + + return true; +} + +static int msm_pcie_check_l1ss_support(struct pci_dev *pdev, void *dev) +{ + struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; + u32 val; + u32 l1ss_cap_id_offset, l1ss_cap_offset, l1ss_ctl1_offset; + + if (!pcie_dev->l1ss_supported) + return -ENXIO; + + l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); + if (!l1ss_cap_id_offset) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n", + pcie_dev->rc_idx, pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + pcie_dev->l1ss_supported = 0; + return -ENXIO; + } + + l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP; + l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1; + + pci_read_config_dword(pdev, l1ss_cap_offset, &val); + pcie_dev->l1_1_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_1)); + pcie_dev->l1_2_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_2)); + pcie_dev->l1_1_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_1)); + pcie_dev->l1_2_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_2)); + if (!pcie_dev->l1_1_pcipm_supported && + !pcie_dev->l1_2_pcipm_supported && + !pcie_dev->l1_1_aspm_supported && + !pcie_dev->l1_2_aspm_supported) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: PCI device %02x:%02x.%01x does not support any L1ss\n", + pcie_dev->rc_idx, pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + pcie_dev->l1ss_supported = 0; + return -ENXIO; + } + + return 0; +} + +static int msm_pcie_config_common_clock_enable(struct pci_dev *pdev, + void *dev) +{ + struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; + + PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", + pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + + msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, + 0, PCI_EXP_LNKCTL_CCC); + + return 0; +} + +static void msm_pcie_config_common_clock_enable_all(struct msm_pcie_dev_t *dev) +{ + if (dev->common_clk_en) + pci_walk_bus(dev->dev->bus, + msm_pcie_config_common_clock_enable, dev); +} + +static int msm_pcie_config_clock_power_management_enable(struct pci_dev *pdev, + void *dev) +{ + struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; + u32 val; + + /* enable only for upstream ports */ + if (pci_is_root_bus(pdev->bus)) + return 0; + + PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", + pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + + pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); + if (val & PCI_EXP_LNKCAP_CLKPM) + msm_pcie_config_clear_set_dword(pdev, + pdev->pcie_cap + PCI_EXP_LNKCTL, 0, + PCI_EXP_LNKCTL_CLKREQ_EN); + else + PCIE_DBG(pcie_dev, + "PCIe: RC%d: PCI device %02x:%02x.%01x does not support clock power management\n", + pcie_dev->rc_idx, pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + + return 0; +} + +static void msm_pcie_config_clock_power_management_enable_all( + struct msm_pcie_dev_t *dev) +{ + if (dev->clk_power_manage_en) + pci_walk_bus(dev->dev->bus, + msm_pcie_config_clock_power_management_enable, dev); +} + +static void msm_pcie_config_l0s(struct msm_pcie_dev_t *dev, + struct pci_dev *pdev, bool enable) +{ + u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; + int ret; + + PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", + dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); + + if (enable) { + ret = msm_pcie_check_l0s_support(pdev, dev); + if (!ret) + return; + + msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, + PCI_EXP_LNKCTL_ASPM_L0S); + } else { + msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, + PCI_EXP_LNKCTL_ASPM_L0S, 0); + } +} + +static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev, + struct pci_bus *bus) +{ + struct pci_dev *pdev; + + if (!dev->l0s_supported) + return; + + list_for_each_entry(pdev, &bus->devices, bus_list) { + struct pci_bus *child; + + child = pdev->subordinate; + if (child) + msm_pcie_config_l0s_disable_all(dev, child); + msm_pcie_config_l0s(dev, pdev, false); + } +} + +static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev) +{ + struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; + + msm_pcie_config_l0s(pcie_dev, pdev, true); + return 0; +} + +static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev) +{ + if (dev->l0s_supported) + pci_walk_bus(dev->dev->bus, msm_pcie_config_l0s_enable, dev); +} + +static void msm_pcie_config_l1(struct msm_pcie_dev_t *dev, + struct pci_dev *pdev, bool enable) +{ + u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; + int ret; + + PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", + dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); + + if (enable) { + ret = msm_pcie_check_l1_support(pdev, dev); + if (!ret) + return; + + msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, + PCI_EXP_LNKCTL_ASPM_L1); + } else { + msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, + PCI_EXP_LNKCTL_ASPM_L1, 0); + } +} + +static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev, + struct pci_bus *bus) +{ + struct pci_dev *pdev; + + if (!dev->l1_supported) + return; + + list_for_each_entry(pdev, &bus->devices, bus_list) { + struct pci_bus *child; + + child = pdev->subordinate; + if (child) + msm_pcie_config_l1_disable_all(dev, child); + msm_pcie_config_l1(dev, pdev, false); + } +} + +static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev) +{ + struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; + + msm_pcie_config_l1(pcie_dev, pdev, true); + return 0; +} + +static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev) +{ + if (dev->l1_supported) + pci_walk_bus(dev->dev->bus, msm_pcie_config_l1_enable, dev); +} + +static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev, + struct pci_dev *pdev, bool enable) +{ + u32 val, val2; + u32 l1ss_cap_id_offset, l1ss_ctl1_offset; + u32 devctl2_offset = pdev->pcie_cap + PCI_EXP_DEVCTL2; + + PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", + dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); + + l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); + if (!l1ss_cap_id_offset) { + PCIE_DBG(dev, + "PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n", + dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + return; + } + + l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1; + + /* Enable the AUX Clock and the Core Clk to be synchronous for L1ss */ + if (pci_is_root_bus(pdev->bus) && !dev->aux_clk_sync) { + if (enable) + msm_pcie_write_mask(dev->parf + + PCIE20_PARF_SYS_CTRL, BIT(3), 0); + else + msm_pcie_write_mask(dev->parf + + PCIE20_PARF_SYS_CTRL, 0, BIT(3)); + } + + if (enable) { + msm_pcie_config_clear_set_dword(pdev, devctl2_offset, 0, + PCI_EXP_DEVCTL2_LTR_EN); + + msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset, 0, + (dev->l1_1_pcipm_supported ? + PCI_L1SS_CTL1_PCIPM_L1_1 : 0) | + (dev->l1_2_pcipm_supported ? + PCI_L1SS_CTL1_PCIPM_L1_2 : 0) | + (dev->l1_1_aspm_supported ? + PCI_L1SS_CTL1_ASPM_L1_1 : 0) | + (dev->l1_2_aspm_supported ? + PCI_L1SS_CTL1_ASPM_L1_2 : 0)); + } else { + msm_pcie_config_clear_set_dword(pdev, devctl2_offset, + PCI_EXP_DEVCTL2_LTR_EN, 0); + + msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset, + PCI_L1SS_CTL1_PCIPM_L1_1 | PCI_L1SS_CTL1_PCIPM_L1_2 | + PCI_L1SS_CTL1_ASPM_L1_1 | PCI_L1SS_CTL1_ASPM_L1_2, 0); + } + + pci_read_config_dword(pdev, l1ss_ctl1_offset, &val); + PCIE_DBG2(dev, "PCIe: RC%d: L1SUB_CONTROL1:0x%x\n", dev->rc_idx, val); + + pci_read_config_dword(pdev, devctl2_offset, &val2); + PCIE_DBG2(dev, "PCIe: RC%d: DEVICE_CONTROL2_STATUS2::0x%x\n", + dev->rc_idx, val2); +} + +static int msm_pcie_config_l1ss_disable(struct pci_dev *pdev, void *dev) +{ + struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; + + msm_pcie_config_l1ss(pcie_dev, pdev, false); + return 0; +} + +static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev, + struct pci_bus *bus) +{ + struct pci_dev *pdev; + + if (!dev->l1ss_supported) + return; + + list_for_each_entry(pdev, &bus->devices, bus_list) { + struct pci_bus *child; + + child = pdev->subordinate; + if (child) + msm_pcie_config_l1ss_disable_all(dev, child); + msm_pcie_config_l1ss_disable(pdev, dev); + } +} + +static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev) +{ + struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; + + msm_pcie_config_l1ss(pcie_dev, pdev, true); + return 0; +} + +static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev) +{ + if (dev->l1ss_supported) + pci_walk_bus(dev->dev->bus, msm_pcie_config_l1ss_enable, dev); +} + +static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable) +{ + struct pci_bus *bus = dev->dev->bus; + + if (enable) { + msm_pcie_config_common_clock_enable_all(dev); + msm_pcie_config_clock_power_management_enable_all(dev); + msm_pcie_config_l1ss_enable_all(dev); + msm_pcie_config_l1_enable_all(dev); + msm_pcie_config_l0s_enable_all(dev); + } else { + msm_pcie_config_l0s_disable_all(dev, bus); + msm_pcie_config_l1_disable_all(dev, bus); + msm_pcie_config_l1ss_disable_all(dev, bus); + } +} + +static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev) +{ + pci_walk_bus(dev->dev->bus, msm_pcie_check_l1ss_support, dev); +} static int msm_pcie_probe(struct platform_device *pdev) { @@ -5956,6 +6047,15 @@ static int msm_pcie_probe(struct platform_device *pdev) "qcom,l1ss-supported"); PCIE_DBG(&msm_pcie_dev[rc_idx], "L1ss is %s supported.\n", msm_pcie_dev[rc_idx].l1ss_supported ? "" : "not"); + msm_pcie_dev[rc_idx].l1_1_aspm_supported = + msm_pcie_dev[rc_idx].l1ss_supported; + msm_pcie_dev[rc_idx].l1_2_aspm_supported = + msm_pcie_dev[rc_idx].l1ss_supported; + msm_pcie_dev[rc_idx].l1_1_pcipm_supported = + msm_pcie_dev[rc_idx].l1ss_supported; + msm_pcie_dev[rc_idx].l1_2_pcipm_supported = + msm_pcie_dev[rc_idx].l1ss_supported; + msm_pcie_dev[rc_idx].common_clk_en = of_property_read_bool((&pdev->dev)->of_node, "qcom,common-clk-en"); @@ -6059,6 +6159,20 @@ static int msm_pcie_probe(struct platform_device *pdev) PCIE_DBG(&msm_pcie_dev[rc_idx], "RC%d: ep-latency: 0x%x.\n", rc_idx, msm_pcie_dev[rc_idx].ep_latency); + msm_pcie_dev[rc_idx].switch_latency = 0; + ret = of_property_read_u32((&pdev->dev)->of_node, + "qcom,switch-latency", + &msm_pcie_dev[rc_idx].switch_latency); + + if (ret) + PCIE_DBG(&msm_pcie_dev[rc_idx], + "RC%d: switch-latency does not exist.\n", + rc_idx); + else + PCIE_DBG(&msm_pcie_dev[rc_idx], + "RC%d: switch-latency: 0x%x.\n", + rc_idx, msm_pcie_dev[rc_idx].switch_latency); + msm_pcie_dev[rc_idx].wr_halt_size = 0; ret = of_property_read_u32(pdev->dev.of_node, "qcom,wr-halt-size", diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index b0b1816900559017cd9397d21bea18591d3f74c6..580ec3ad226a690c18e6e5eed024df3c2598e3c3 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -937,7 +937,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->realio.start = PCIBIOS_MIN_IO; pcie->realio.end = min_t(resource_size_t, IO_SPACE_LIMIT, - resource_size(&pcie->io)); + resource_size(&pcie->io) - 1); } else pcie->realio = pcie->io; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b60309ee80ed0b1cbeefd1d432b5bf925378601e..031f64da6151712481abde0edfc07fac28a0dd10 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -587,6 +587,7 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) { unsigned long long sta = 0; struct acpiphp_func *func; + u32 dvid; list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_STA) { @@ -597,19 +598,27 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) if (ACPI_SUCCESS(status) && sta) break; } else { - u32 dvid; - - pci_bus_read_config_dword(slot->bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { + if (pci_bus_read_dev_vendor_id(slot->bus, + PCI_DEVFN(slot->device, func->function), + &dvid, 0)) { sta = ACPI_STA_ALL; break; } } } + if (!sta) { + /* + * Check for the slot itself since it may be that the + * ACPI slot is a device below PCIe upstream port so in + * that case it may not even be reachable yet. + */ + if (pci_bus_read_dev_vendor_id(slot->bus, + PCI_DEVFN(slot->device, 0), &dvid, 0)) { + sta = ACPI_STA_ALL; + } + } + return (unsigned int)sta; } diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 56d8486dc16704d1f93726d03131cbedfe0b4bed..cdc109ec5b82a9ba0531cad609b35533ce8d2645 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -457,8 +457,17 @@ int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, list_add(&slot->slot_list, &pci_hotplug_slot_list); result = fs_add_slot(pci_slot); + if (result) + goto err_list_del; + kobject_uevent(&pci_slot->kobj, KOBJ_ADD); dbg("Added slot %s to the list\n", name); + goto out; + +err_list_del: + list_del(&slot->slot_list); + pci_slot->hotplug = NULL; + pci_destroy_slot(pci_slot); out: mutex_unlock(&pci_hp_mutex); return result; diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index b11521953485bb99892b85dd4c2c3e93378c2d56..8b58e7a009c1c8b4d7c848d3f3013ffe0045ae1f 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -144,7 +144,7 @@ struct controller *pcie_init(struct pcie_device *dev); int pcie_init_notification(struct controller *ctrl); int pciehp_enable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot); -void pcie_enable_notification(struct controller *ctrl); +void pcie_reenable_notification(struct controller *ctrl); int pciehp_power_on_slot(struct slot *slot); void pciehp_power_off_slot(struct slot *slot); void pciehp_get_power_status(struct slot *slot, u8 *status); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 07aa722bb12cd61a6a3a8767b2efe1dd826e6952..688bf665991bd4088623da361e26a6b5607eac5e 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -332,7 +332,7 @@ static int pciehp_resume(struct pcie_device *dev) ctrl = get_service_data(dev); /* reinitialize the chipset's event detection logic */ - pcie_enable_notification(ctrl); + pcie_reenable_notification(ctrl); slot = ctrl->slot; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 6d6868811e56ec93b8b615c079e6daea45c21b0d..fc7f48a7e8af186fcd54a810f909fe5b54a0d21b 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -602,7 +602,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_HANDLED; } -void pcie_enable_notification(struct controller *ctrl) +static void pcie_enable_notification(struct controller *ctrl) { u16 cmd, mask; @@ -642,6 +642,17 @@ void pcie_enable_notification(struct controller *ctrl) pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); } +void pcie_reenable_notification(struct controller *ctrl) +{ + /* + * Clear both Presence and Data Link Layer Changed to make sure + * those events still fire after we have re-enabled them. + */ + pcie_capability_write_word(ctrl->pcie->port, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); + pcie_enable_notification(ctrl); +} + static void pcie_disable_notification(struct controller *ctrl) { u16 mask; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 7d223e9080efb34aef5b1d02f77732c77b812402..77dddee2753a00d4cc914a930901527a1509041d 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -1062,6 +1062,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) if (rc) { ctrl_info(ctrl, "Can't get msi for the hotplug controller\n"); ctrl_info(ctrl, "Use INTx for the hotplug controller\n"); + } else { + pci_set_master(pdev); } rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 4d109c07294a8d7326583e43ffb594569cf1c1e7..9c0254638cc88a8da3cf3dced79c2ae3dfb28e66 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -106,7 +106,6 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); - pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); if (rc) @@ -117,6 +116,8 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE); + pci_bus_add_device(virtfn); + return 0; failed2: diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e7adfbd2d4829536722038d658d062e07063e350..cf4f3ade9233e8fac4bfb6edca74c4f6d32302e4 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -924,7 +924,12 @@ static int pci_pm_thaw_noirq(struct device *dev) if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_resume_early(dev); - pci_update_current_state(pci_dev, PCI_D0); + /* + * pci_restore_state() requires the device to be in D0 (because of MSI + * restoration among other things), so force it into D0 in case the + * driver's "freeze" callbacks put it into a low-power state directly. + */ + pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); if (drv && drv->pm && drv->pm->thaw_noirq) @@ -1115,11 +1120,14 @@ static int pci_pm_runtime_suspend(struct device *dev) int error; /* - * If pci_dev->driver is not set (unbound), the device should - * always remain in D0 regardless of the runtime PM status + * If pci_dev->driver is not set (unbound), we leave the device in D0, + * but it may go to D3cold when the bridge above it runtime suspends. + * Save its config space in case that happens. */ - if (!pci_dev->driver) + if (!pci_dev->driver) { + pci_save_state(pci_dev); return 0; + } if (!pm || !pm->runtime_suspend) return -ENOSYS; @@ -1158,16 +1166,18 @@ static int pci_pm_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; /* - * If pci_dev->driver is not set (unbound), the device should - * always remain in D0 regardless of the runtime PM status + * Restoring config space is necessary even if the device is not bound + * to a driver because although we left it in D0, it may have gone to + * D3cold when the bridge above it runtime suspended. */ + pci_restore_standard_config(pci_dev); + if (!pci_dev->driver) return 0; if (!pm || !pm->runtime_resume) return -ENOSYS; - pci_restore_standard_config(pci_dev); pci_fixup_device(pci_fixup_resume_early, pci_dev); __pci_enable_wake(pci_dev, PCI_D0, true, false); pci_fixup_device(pci_fixup_resume, pci_dev); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 318707870cb252ee3c0cf64e76082d84120fc75c..6b66f9950b5713894e9e0db384ead6ecb45a128d 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -199,13 +199,16 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!val) { - if (pci_is_enabled(pdev)) - pci_disable_device(pdev); - else - result = -EIO; - } else + device_lock(dev); + if (dev->driver) + result = -EBUSY; + else if (val) result = pci_enable_device(pdev); + else if (pci_is_enabled(pdev)) + pci_disable_device(pdev); + else + result = -EIO; + device_unlock(dev); return result < 0 ? result : count; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 727c67bbdbdc5205b3efa5e8cb58172b3392bb37..82d78aec6af587a76c7351db649a4406563f171e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1024,12 +1024,12 @@ int pci_save_state(struct pci_dev *dev) EXPORT_SYMBOL(pci_save_state); static void pci_restore_config_dword(struct pci_dev *pdev, int offset, - u32 saved_val, int retry) + u32 saved_val, int retry, bool force) { u32 val; pci_read_config_dword(pdev, offset, &val); - if (val == saved_val) + if (!force && val == saved_val) return; for (;;) { @@ -1048,25 +1048,36 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset, } static void pci_restore_config_space_range(struct pci_dev *pdev, - int start, int end, int retry) + int start, int end, int retry, + bool force) { int index; for (index = end; index >= start; index--) pci_restore_config_dword(pdev, 4 * index, pdev->saved_config_space[index], - retry); + retry, force); } static void pci_restore_config_space(struct pci_dev *pdev) { if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) { - pci_restore_config_space_range(pdev, 10, 15, 0); + pci_restore_config_space_range(pdev, 10, 15, 0, false); /* Restore BARs before the command register. */ - pci_restore_config_space_range(pdev, 4, 9, 0); - pci_restore_config_space_range(pdev, 0, 3, 0); + pci_restore_config_space_range(pdev, 4, 9, 0, false); + pci_restore_config_space_range(pdev, 0, 3, 0, false); + } else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_restore_config_space_range(pdev, 12, 15, 0, false); + + /* + * Force rewriting of prefetch registers to avoid S3 resume + * issues on Intel PCI bridges that occur when these + * registers are not explicitly written. + */ + pci_restore_config_space_range(pdev, 9, 11, 0, true); + pci_restore_config_space_range(pdev, 0, 8, 0, false); } else { - pci_restore_config_space_range(pdev, 0, 15, 0); + pci_restore_config_space_range(pdev, 0, 15, 0, false); } } @@ -3581,6 +3592,10 @@ static bool pci_bus_resetable(struct pci_bus *bus) { struct pci_dev *dev; + + if (bus->self && (bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)) + return false; + list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || (dev->subordinate && !pci_bus_resetable(dev->subordinate))) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index b60a325234c5266676486b9db4cf9b2556a82713..cca4b4789ac41c6319b706d4c708ce9342343342 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -360,7 +360,14 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, * If the error is reported by an end point, we think this * error is related to the upstream link of the end point. */ - pci_walk_bus(dev->bus, cb, &result_data); + if (state == pci_channel_io_normal) + /* + * the error is non fatal so the bus is ok, just invoke + * the callback for the function that logged the error. + */ + cb(dev, &result_data); + else + pci_walk_bus(dev->bus, cb, &result_data); } return result_data.result; diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 63fc63911295e7c0be875b39436c889c6850234e..deb9031129746d86e6549c9a8db548f3dfb4334b 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -233,6 +233,9 @@ static void pcie_pme_work_fn(struct work_struct *work) break; pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta); + if (rtsta == (u32) ~0) + break; + if (rtsta & PCI_EXP_RTSTA_PME) { /* * Clear PME status of the port. If there are other @@ -280,7 +283,7 @@ static irqreturn_t pcie_pme_irq(int irq, void *context) spin_lock_irqsave(&data->lock, flags); pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta); - if (!(rtsta & PCI_EXP_RTSTA_PME)) { + if (rtsta == (u32) ~0 || !(rtsta & PCI_EXP_RTSTA_PME)) { spin_unlock_irqrestore(&data->lock, flags); return IRQ_NONE; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 96b4c99327b7228ac1e9d5284a6488fa9148512b..a638cf8ea3bf75cf03bb9d5268a5fe3dcb72e498 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1378,8 +1378,16 @@ static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp) { - if (hpp) - dev_warn(&dev->dev, "PCI-X settings not supported\n"); + int pos; + + if (!hpp) + return; + + pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); + if (!pos) + return; + + dev_warn(&dev->dev, "PCI-X settings not supported\n"); } static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) @@ -1390,6 +1398,9 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) if (!hpp) return; + if (!pci_is_pcie(dev)) + return; + if (hpp->revision > 1) { dev_warn(&dev->dev, "PCIe settings rev %d not supported\n", hpp->revision); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b3e63f567c56cd67af43d7442deab3f7e2ac393b..9e86ace9583281bfe443b88b59e4a4f287794962 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3559,6 +3559,8 @@ static void quirk_dma_func1_alias(struct pci_dev *dev) */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123, quirk_dma_func1_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9128, + quirk_dma_func1_alias); /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130, quirk_dma_func1_alias); @@ -3571,6 +3573,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x917a, /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0, quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220, + quirk_dma_func1_alias); /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c49 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230, quirk_dma_func1_alias); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 8bd76c9ba21cf4e5c5a4b58cb40ccd990cfacc5e..edb4e3a83918cbd25ef5a80f56b2141a918656f7 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -20,9 +20,9 @@ static void pci_stop_dev(struct pci_dev *dev) pci_pme_active(dev, false); if (dev->is_added) { + device_release_driver(&dev->dev); pci_proc_detach_device(dev); pci_remove_sysfs_dev_files(dev); - device_release_driver(&dev->dev); dev->is_added = 0; } diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 75c62907b99d7a0d374aa4f6c43be26533e0e17e..c7d277099cf20ba5b65813e5386de85c46b4f775 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -319,6 +319,10 @@ static struct phy *_of_phy_get(struct device_node *np, int index) if (ret) return ERR_PTR(-ENODEV); + /* This phy type handled by the usb-phy subsystem for now */ + if (of_device_is_compatible(args.np, "usb-nop-xceiv")) + return ERR_PTR(-ENODEV); + mutex_lock(&phy_provider_mutex); phy_provider = of_phy_provider_lookup(args.np); if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) { diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index c6a66de6ed72d0d4e96d061737d4ba3b9a4f3cd3..b916a0eb799f79e1de30161971efb6082c613c61 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -28,7 +28,8 @@ config DEBUG_PINCTRL config PINCTRL_ADI2 bool "ADI pin controller driver" - depends on BLACKFIN + depends on (BF54x || BF60x) + depends on !GPIO_ADI select PINMUX select IRQ_DOMAIN help diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 18ee2089df4ae84e7edb6f665146be84ca43b83f..db43f8b34e2a800671316f571c2682c9161a5515 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -977,19 +977,16 @@ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, EXPORT_SYMBOL_GPL(pinctrl_lookup_state); /** - * pinctrl_select_state() - select/activate/program a pinctrl state to HW + * pinctrl_commit_state() - select/activate/program a pinctrl state to HW * @p: the pinctrl handle for the device that requests configuration * @state: the state handle to select/activate/program */ -int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) +static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) { struct pinctrl_setting *setting, *setting2; struct pinctrl_state *old_state = p->state; int ret; - if (p->state == state) - return 0; - if (p->state) { /* * For each pinmux setting in the old state, forget SW's record @@ -1053,6 +1050,19 @@ unapply_new_state: return ret; } + +/** + * pinctrl_select_state() - select/activate/program a pinctrl state to HW + * @p: the pinctrl handle for the device that requests configuration + * @state: the state handle to select/activate/program + */ +int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) +{ + if (p->state == state) + return 0; + + return pinctrl_commit_state(p, state); +} EXPORT_SYMBOL_GPL(pinctrl_select_state); static void devm_pinctrl_release(struct device *dev, void *res) @@ -1221,7 +1231,7 @@ void pinctrl_unregister_map(struct pinctrl_map const *map) int pinctrl_force_sleep(struct pinctrl_dev *pctldev) { if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_sleep)) - return pinctrl_select_state(pctldev->p, pctldev->hog_sleep); + return pinctrl_commit_state(pctldev->p, pctldev->hog_sleep); return 0; } EXPORT_SYMBOL_GPL(pinctrl_force_sleep); @@ -1233,7 +1243,7 @@ EXPORT_SYMBOL_GPL(pinctrl_force_sleep); int pinctrl_force_default(struct pinctrl_dev *pctldev) { if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_default)) - return pinctrl_select_state(pctldev->p, pctldev->hog_default); + return pinctrl_commit_state(pctldev->p, pctldev->hog_default); return 0; } EXPORT_SYMBOL_GPL(pinctrl_force_default); diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index 5ac59fbb2440ffdc5ea7130ffc6c3ca0548617fa..d6115d3835ee039b33772d7f5e9e39a94e13d44b 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -435,7 +435,7 @@ static void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, const char *name; int i, ret; - if (group > info->ngroups) + if (group >= info->ngroups) return; seq_puts(s, "\n"); diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 0774fe4d29aaaaae1e3557c458bc09dfa4fdc256..3b03857d8f422cacfb01e60aaf43abeb05fb3097 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -3,7 +3,8 @@ menu "Qualcomm MSM specific device drivers" config MSM_AVTIMER tristate "Avtimer Driver" - depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3 + depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3 || \ + MSM_QDSP6_APRV2_VM help This driver gets the Q6 out of power collapsed state and exposes ioctl control to read avtimer tick. @@ -194,16 +195,6 @@ config IPA_UT The user interface to run and control the tests is debugfs file system. -config SSM - tristate "QTI Secure Service Module" - depends on QSEECOM - depends on MSM_SMD - help - Provides an interface for OEM driver to communicate with Trustzone - and modem for key exchange and mode change. - This driver uses Secure Channel Manager interface for trustzone - communication and communicates with modem over SMD channel. - config MSM_MHI tristate "Modem Host Interface Driver" help diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index a658056b468e9740b14f8de7c29de34da6aa0a95..5507a12a7ed34a5cddaf1455e960a90aeb07d810 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -25,8 +25,3 @@ obj-$(CONFIG_QPNP_VIBRATOR) += qpnp-vibrator.o obj-$(CONFIG_MSM_AVTIMER) += avtimer.o obj-$(CONFIG_MSM_11AD) += msm_11ad/ obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/ -obj-$(CONFIG_SSM) += ssm.o - -#TODO: remove me b/62058353 -subdir-ccflags-y += \ - -Wno-enum-conversion diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c index 4331af8890c0bd31490187728fcd29e08043e7f8..56ffb52ad73689a13348445a35e83614c8408f27 100644 --- a/drivers/platform/msm/avtimer.c +++ b/drivers/platform/msm/avtimer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * 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 @@ -91,6 +91,13 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv) } payload1 = data->payload; + + if (data->payload_size < 2 * sizeof(uint32_t)) { + pr_err("%s: payload has invalid size %d\n", + __func__, data->payload_size); + return -EINVAL; + } + switch (payload1[0]) { case AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST: pr_debug("%s: Cmd = TIMER RELEASE status[0x%x]\n", @@ -116,6 +123,11 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv) } case AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST: + if (data->payload_size < sizeof(uint32_t)) { + pr_err("%s: payload has invalid size %d\n", + __func__, data->payload_size); + return -EINVAL; + } payload1 = data->payload; pr_debug("%s: RSP_REMOTE_AVTIMER_VOTE_REQUEST handle %x\n", __func__, payload1[0]); diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index aa7d0ea50f2471ce16acc0c10b8e50d33f0a8643..b2dcbc2b0083b37cb4f458a9b758814ecb4f0f69 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -338,10 +338,13 @@ struct ep_pcie_dev_t { bool l23_ready; bool l1ss_enabled; struct ep_pcie_msi_config msi_cfg; + bool no_notify; + bool client_ready; struct ep_pcie_register_event *event_reg; struct work_struct handle_perst_work; struct work_struct handle_bme_work; + struct work_struct handle_d3cold_work; }; extern struct ep_pcie_dev_t ep_pcie_dev; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index fb64ca6ef8636bd5d07fbf6ce1c48a91f0c02f8d..283af52886f766c191d756bd684c2e4050644fb6 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -1033,6 +1033,10 @@ static void ep_pcie_release_resources(struct ep_pcie_dev_t *dev) static void ep_pcie_enumeration_complete(struct ep_pcie_dev_t *dev) { + unsigned long irqsave_flags; + + spin_lock_irqsave(&dev->isr_lock, irqsave_flags); + dev->enumerated = true; dev->link_status = EP_PCIE_LINK_ENABLED; @@ -1059,7 +1063,14 @@ static void ep_pcie_enumeration_complete(struct ep_pcie_dev_t *dev) "PCIe V%d: register driver for device 0x%x.\n", ep_pcie_dev.rev, hw_drv.device_id); ep_pcie_register_drv(&hw_drv); - ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKUP); + if (!dev->no_notify) + ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKUP); + else + EP_PCIE_DBG(dev, + "PCIe V%d: do not notify client about linkup.\n", + dev->rev); + + spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); return; } @@ -1453,8 +1464,9 @@ static irqreturn_t ep_pcie_handle_bme_irq(int irq, void *data) schedule_work(&dev->handle_bme_work); } else { EP_PCIE_DBG(dev, - "PCIe V%d:BME is set again after the enumeration has completed\n", + "PCIe V%d:BME is set again after the enumeration has completed; callback client for link ready.\n", dev->rev); + ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKUP); } } else { EP_PCIE_DBG(dev, @@ -1558,7 +1570,13 @@ static irqreturn_t ep_pcie_handle_dstate_change_irq(int irq, void *data) "PCIe V%d: No. %ld change to D3 state.\n", dev->rev, dev->d3_counter); ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(1)); - ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_HOT); + + if (dev->enumerated) + ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_HOT); + else + EP_PCIE_DBG(dev, + "PCIe V%d: do not notify client about this D3 hot event since enumeration by HLOS is not done yet.\n", + dev->rev); } else if (dstate == 0) { dev->l23_ready = false; dev->d0_counter++; @@ -1622,9 +1640,25 @@ static void handle_perst_func(struct work_struct *work) struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t, handle_perst_work); + EP_PCIE_DBG(dev, + "PCIe V%d: Start enumeration due to PERST deassertion.\n", + dev->rev); + ep_pcie_enumeration(dev); } +static void handle_d3cold_func(struct work_struct *work) +{ + struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t, + handle_d3cold_work); + + EP_PCIE_DBG(dev, + "PCIe V%d: shutdown PCIe link due to PERST assertion before BME is set.\n", + dev->rev); + ep_pcie_core_disable_endpoint(); + dev->no_notify = false; +} + static void handle_bme_func(struct work_struct *work) { struct ep_pcie_dev_t *dev = container_of(work, @@ -1647,10 +1681,14 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data) EP_PCIE_DBG(dev, "PCIe V%d: PCIe is not enumerated yet; PERST is %sasserted.\n", dev->rev, perst ? "de" : ""); - if ((!dev->perst_enum) || !perst) - goto out; - /* start work for link enumeration with the host side */ - schedule_work(&dev->handle_perst_work); + if (perst) { + /* start work for link enumeration with the host side */ + schedule_work(&dev->handle_perst_work); + } else { + dev->no_notify = true; + /* shutdown the link if the link is already on */ + schedule_work(&dev->handle_d3cold_work); + } goto out; } @@ -1668,7 +1706,16 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data) EP_PCIE_DBG(dev, "PCIe V%d: No. %ld PERST assertion.\n", dev->rev, dev->perst_ast_counter); - ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_COLD); + + if (dev->client_ready) { + ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_COLD); + } else { + dev->no_notify = true; + EP_PCIE_DBG(dev, + "PCIe V%d: Client driver is not ready when this PERST assertion happens; shutdown link now.\n", + dev->rev); + schedule_work(&dev->handle_d3cold_work); + } } out: @@ -1753,6 +1800,7 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev) /* Initialize all works to be performed before registering for IRQs*/ INIT_WORK(&dev->handle_perst_work, handle_perst_func); INIT_WORK(&dev->handle_bme_work, handle_bme_func); + INIT_WORK(&dev->handle_d3cold_work, handle_d3cold_func); if (dev->aggregated_irq) { ret = devm_request_irq(pdev, @@ -1906,6 +1954,8 @@ int ep_pcie_core_register_event(struct ep_pcie_register_event *reg) "PCIe V%d: Event 0x%x is registered\n", ep_pcie_dev.rev, reg->events); + ep_pcie_dev.client_ready = true; + return 0; } @@ -1942,6 +1992,12 @@ enum ep_pcie_link_status ep_pcie_core_get_linkstatus(void) "PCIe V%d: PCIe link is up and BME is enabled; current SW link status:%d.\n", dev->rev, dev->link_status); dev->link_status = EP_PCIE_LINK_ENABLED; + if (dev->no_notify) { + EP_PCIE_DBG(dev, + "PCIe V%d: BME is set now, but do not tell client about BME enable.\n", + dev->rev); + return EP_PCIE_LINK_UP; + } } else { EP_PCIE_DBG(dev, "PCIe V%d: PCIe link is up but BME is disabled; current SW link status:%d.\n", diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c index f9afd7f62ce49165076ede91d4130d0fefdc1639..cc7822ccc9d83b77173cb6f886fc7915b0b3c2d3 100644 --- a/drivers/platform/msm/gpio-usbdetect.c +++ b/drivers/platform/msm/gpio-usbdetect.c @@ -37,8 +37,15 @@ struct gpio_usbdetect { struct regulator *vdd33; struct regulator *vdd12; int gpio_usbdetect; + + int id; + int id_det_gpio; + int id_det_irq; + bool notify_host_mode; bool disable_device_mode; + + int dpdm_switch_gpio; }; static int gpio_enable_ldos(struct gpio_usbdetect *usb, int on) @@ -154,15 +161,28 @@ disable_vin: return ret; } -static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data) +static irqreturn_t gpio_usbdetect_irq(int irq, void *data) { struct gpio_usbdetect *usb = data; + if (gpio_is_valid(usb->id_det_gpio)) { + usb->id = gpio_get_value(usb->id_det_gpio); + if (usb->id) { + dev_dbg(&usb->pdev->dev, "ID\n"); + usb->vbus = gpio_get_value(usb->gpio_usbdetect); + goto queue_chg_work; + } + dev_dbg(&usb->pdev->dev, "!ID\n"); + schedule_delayed_work(&usb->chg_work, 0); + return IRQ_HANDLED; + } + if (gpio_is_valid(usb->gpio_usbdetect)) usb->vbus = gpio_get_value(usb->gpio_usbdetect); else usb->vbus = !!irq_read_line(irq); +queue_chg_work: pm_wakeup_event(&usb->pdev->dev, WAKEUP_SRC_TIMEOUT_MS); if (!usb->vbus) schedule_delayed_work(&usb->chg_work, 0); @@ -200,6 +220,37 @@ static void gpio_usbdetect_chg_work(struct work_struct *w) struct gpio_usbdetect *usb = container_of(w, struct gpio_usbdetect, chg_work.work); + if (gpio_is_valid(usb->id_det_gpio)) { + dev_dbg(&usb->pdev->dev, "ID:%d VBUS:%d\n", + usb->id, usb->vbus); + if (!usb->id) { + gpio_usbdetect_notify_usb_type(usb, + POWER_SUPPLY_TYPE_UNKNOWN); + power_supply_set_present(usb->usb_psy, 0); + power_supply_set_usb_otg(usb->usb_psy, 1); + if (gpio_is_valid(usb->dpdm_switch_gpio)) + gpio_set_value(usb->dpdm_switch_gpio, 1); + + return; + } + + power_supply_set_usb_otg(usb->usb_psy, 0); + if (gpio_is_valid(usb->dpdm_switch_gpio)) + gpio_set_value(usb->dpdm_switch_gpio, 0); + + if (usb->vbus) { + gpio_usbdetect_notify_usb_type(usb, + POWER_SUPPLY_TYPE_USB); + power_supply_set_present(usb->usb_psy, usb->vbus); + } else { + gpio_usbdetect_notify_usb_type(usb, + POWER_SUPPLY_TYPE_UNKNOWN); + power_supply_set_present(usb->usb_psy, usb->vbus); + } + + return; + } + if (usb->vbus) { if (usb->notify_host_mode) power_supply_set_usb_otg(usb->usb_psy, 0); @@ -276,7 +327,7 @@ static int gpio_usbdetect_probe(struct platform_device *pdev) } rc = devm_request_irq(&pdev->dev, usb->vbus_det_irq, - gpio_usbdetect_vbus_irq, + gpio_usbdetect_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "vbus_det_irq", usb); if (rc) { @@ -285,14 +336,48 @@ static int gpio_usbdetect_probe(struct platform_device *pdev) goto disable_ldo; } + usb->id_det_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,id-det-gpio", 0); + if (gpio_is_valid(usb->id_det_gpio)) { + rc = devm_gpio_request(&pdev->dev, usb->id_det_gpio, + "GPIO_ID_DET"); + if (rc) { + dev_err(&pdev->dev, "gpio req failed for gpio_%d\n", + usb->id_det_gpio); + goto disable_ldo; + } + + usb->id_det_irq = gpio_to_irq(usb->id_det_gpio); + if (usb->id_det_irq < 0) { + dev_err(&pdev->dev, "get id_det_irq failed\n"); + goto disable_ldo; + } + rc = devm_request_irq(&pdev->dev, usb->id_det_irq, + gpio_usbdetect_irq, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "id_det_irq", + usb); + if (rc) { + dev_err(&pdev->dev, "request for id_det_irq failed:%d\n", + rc); + goto disable_ldo; + } + } + + usb->dpdm_switch_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,dpdm_switch_gpio", 0); + dev_dbg(&pdev->dev, "is dpdm_switch_gpio valid:%d\n", + gpio_is_valid(usb->dpdm_switch_gpio)); + device_init_wakeup(&pdev->dev, 1); enable_irq_wake(usb->vbus_det_irq); + enable_irq_wake(usb->id_det_irq); dev_set_drvdata(&pdev->dev, usb); /* Read and report initial VBUS state */ local_irq_save(flags); - gpio_usbdetect_vbus_irq(usb->vbus_det_irq, usb); + gpio_usbdetect_irq(usb->vbus_det_irq, usb); local_irq_restore(flags); return 0; diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index fa2b947dd34c3422a145a78f4d633435ff4133cb..43d99b9c30d9429308e613d0d0538125f93589bc 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -21,7 +21,7 @@ #include "gsi.h" #include "gsi_reg.h" -#define GSI_CMD_TIMEOUT 5000 +#define GSI_CMD_TIMEOUT (5*HZ) #define GSI_STOP_CMD_TIMEOUT_MS 20 #define GSI_MAX_CH_LOW_WEIGHT 15 #define GSI_MHI_ER_START 10 @@ -1149,8 +1149,7 @@ int gsi_alloc_evt_ring(struct gsi_evt_ring_props *props, unsigned long dev_hdl, GSI_EE_n_EV_CH_CMD_OPCODE_BMSK)); gsi_writel(val, gsi_ctx->base + GSI_EE_n_EV_CH_CMD_OFFS(ee)); - res = wait_for_completion_timeout(&ctx->compl, - msecs_to_jiffies(GSI_CMD_TIMEOUT)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); if (res == 0) { GSIERR("evt_id=%lu timed out\n", evt_id); if (!props->evchid_valid) @@ -1278,8 +1277,7 @@ int gsi_dealloc_evt_ring(unsigned long evt_ring_hdl) GSI_EE_n_EV_CH_CMD_OPCODE_BMSK)); gsi_writel(val, gsi_ctx->base + GSI_EE_n_EV_CH_CMD_OFFS(gsi_ctx->per.ee)); - res = wait_for_completion_timeout(&ctx->compl, - msecs_to_jiffies(GSI_CMD_TIMEOUT)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); if (res == 0) { GSIERR("evt_id=%lu timed out\n", evt_ring_hdl); mutex_unlock(&gsi_ctx->mlock); @@ -1403,8 +1401,7 @@ int gsi_reset_evt_ring(unsigned long evt_ring_hdl) GSI_EE_n_EV_CH_CMD_OPCODE_BMSK)); gsi_writel(val, gsi_ctx->base + GSI_EE_n_EV_CH_CMD_OFFS(gsi_ctx->per.ee)); - res = wait_for_completion_timeout(&ctx->compl, - msecs_to_jiffies(GSI_CMD_TIMEOUT)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); if (res == 0) { GSIERR("evt_id=%lu timed out\n", evt_ring_hdl); mutex_unlock(&gsi_ctx->mlock); @@ -1706,8 +1703,7 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); gsi_writel(val, gsi_ctx->base + GSI_EE_n_GSI_CH_CMD_OFFS(ee)); - res = wait_for_completion_timeout(&ctx->compl, - msecs_to_jiffies(GSI_CMD_TIMEOUT)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); if (res == 0) { GSIERR("chan_hdl=%u timed out\n", props->ch_id); mutex_unlock(&gsi_ctx->mlock); @@ -1938,8 +1934,7 @@ int gsi_start_channel(unsigned long chan_hdl) GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); gsi_writel(val, gsi_ctx->base + GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee)); - res = wait_for_completion_timeout(&ctx->compl, - msecs_to_jiffies(GSI_CMD_TIMEOUT)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); if (res == 0) { GSIERR("chan_hdl=%lu timed out\n", chan_hdl); mutex_unlock(&gsi_ctx->mlock); @@ -2145,8 +2140,7 @@ reset: GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); gsi_writel(val, gsi_ctx->base + GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee)); - res = wait_for_completion_timeout(&ctx->compl, - msecs_to_jiffies(GSI_CMD_TIMEOUT)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); if (res == 0) { GSIERR("chan_hdl=%lu timed out\n", chan_hdl); mutex_unlock(&gsi_ctx->mlock); @@ -2213,8 +2207,7 @@ int gsi_dealloc_channel(unsigned long chan_hdl) GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); gsi_writel(val, gsi_ctx->base + GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee)); - res = wait_for_completion_timeout(&ctx->compl, - msecs_to_jiffies(GSI_CMD_TIMEOUT)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); if (res == 0) { GSIERR("chan_hdl=%lu timed out\n", chan_hdl); mutex_unlock(&gsi_ctx->mlock); diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index f61fe3e0c93a01cfa42d63a3fe053a9a970a7ce0..941fc6d9977569c59d21d5884af7744a9166df5e 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 @@ -2205,12 +2205,12 @@ int ipa_remove_interrupt_handler(enum ipa_irq_type interrupt) EXPORT_SYMBOL(ipa_remove_interrupt_handler); /** - * ipa_restore_suspend_handler() - restores the original suspend IRQ handler - * as it was registered in the IPA init sequence. - * Return codes: - * 0: success - * -EPERM: failed to remove current handler or failed to add original handler - */ +* ipa_restore_suspend_handler() - restores the original suspend IRQ handler +* as it was registered in the IPA init sequence. +* Return codes: +* 0: success +* -EPERM: failed to remove current handler or failed to add original handler +* */ int ipa_restore_suspend_handler(void) { int ret; diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index 82a004b06602363e87dfcceef6057ea56bdc5d96..8e53dbd52d280925497e5bab19eb98e9b52298e8 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index 6ecd136d96242abb60d746e1d3477c951c0f32fc..a15a9d82c01ca9a6ed31b146a8e668f1757ac966 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -358,7 +358,7 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp, result = ipa_rm_request_resource(IPA_RM_RESOURCE_ETHERNET_PROD); if (result == -EINPROGRESS) { if (wait_for_completion_timeout(&ntn_ctx->ntn_completion, - msecs_to_jiffies(10000)) == 0) { + 10*HZ) == 0) { IPA_UC_OFFLOAD_ERR("ETH_PROD resource req time out\n"); result = -EFAULT; goto fail; diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h index 89088a8143582f7d896f15eb62ea20f0358094d6..c2683fffc3ba40a456ec96086bda8e612c8eeeb1 100644 --- a/drivers/platform/msm/ipa/ipa_common_i.h +++ b/drivers/platform/msm/ipa/ipa_common_i.h @@ -19,6 +19,10 @@ #include #include #include +#include + +#define WARNON_RATELIMIT_BURST 1 +#define IPA_RATELIMIT_BURST 1 #define __FILENAME__ \ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) @@ -104,6 +108,39 @@ ipa_dec_client_disable_clks(&log_info); \ } while (0) +/* + * Printing one warning message in 5 seconds if multiple warning messages + * are coming back to back. + */ + +#define WARN_ON_RATELIMIT_IPA(condition) \ +({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + DEFAULT_RATELIMIT_INTERVAL, \ + WARNON_RATELIMIT_BURST); \ + int rtn = !!(condition); \ + \ + if (unlikely(rtn && __ratelimit(&_rs))) \ + WARN_ON(rtn); \ +}) + +/* + * Printing one error message in 5 seconds if multiple error messages + * are coming back to back. + */ + +#define pr_err_ratelimited_ipa(fmt, ...) \ + printk_ratelimited_ipa(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) +#define printk_ratelimited_ipa(fmt, ...) \ +({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + DEFAULT_RATELIMIT_INTERVAL, \ + IPA_RATELIMIT_BURST); \ + \ + if (__ratelimit(&_rs)) \ + printk(fmt, ##__VA_ARGS__); \ +}) + #define ipa_assert_on(condition)\ do {\ if (unlikely(condition))\ diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c index 58defd3a5c4777670a82556f5a34b817a5b33c13..d5babfa5699dc20abeb5fe7ac8408d7269c99d53 100644 --- a/drivers/platform/msm/ipa/ipa_rm.c +++ b/drivers/platform/msm/ipa/ipa_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * 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 @@ -155,6 +155,21 @@ int ipa_rm_delete_resource(enum ipa_rm_resource_name resource_name) result = -EINVAL; goto bail; } + + if (resource->state == IPA_RM_GRANTED) { + /* There might pending timer work to + * release release the resource + */ + if (resource->release_work != NULL) { + if (flush_delayed_work(&resource->release_work->work) + == true) { + IPA_RM_DBG("Flushed the pending work\n"); + } else { + IPA_RM_DBG("Work was already idle\n"); + } + } + } + result = ipa_rm_resource_delete(resource); if (result) { IPA_RM_ERR("ipa_rm_resource_delete() failed\n"); @@ -269,7 +284,7 @@ static int _ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name, time = wait_for_completion_timeout( &((struct ipa_rm_resource_cons *)consumer)-> request_consumer_in_progress, - msecs_to_jiffies(1000)); + HZ * 5); result = 0; if (!time) { IPA_RM_ERR("TIMEOUT waiting for %s GRANT event.", @@ -464,6 +479,8 @@ void delayed_release_work_func(struct work_struct *work) bail: spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags); kfree(rwork); + if (resource) + resource->release_work = NULL; } @@ -478,7 +495,6 @@ int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name) { unsigned long flags; struct ipa_rm_resource *resource; - struct ipa_rm_delayed_release_work_type *release_work; int result; if (!IPA_RM_RESORCE_IS_CONS(resource_name)) { @@ -502,16 +518,18 @@ int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name) goto bail; } - release_work = kzalloc(sizeof(*release_work), GFP_ATOMIC); - if (!release_work) { + resource->release_work = + kzalloc(sizeof(*resource->release_work), GFP_ATOMIC); + if (!resource->release_work) { result = -ENOMEM; goto bail; } - release_work->resource_name = resource->name; - release_work->needed_bw = 0; - release_work->dec_usage_count = false; - INIT_DELAYED_WORK(&release_work->work, delayed_release_work_func); - schedule_delayed_work(&release_work->work, + resource->release_work->resource_name = resource->name; + resource->release_work->needed_bw = 0; + resource->release_work->dec_usage_count = false; + INIT_DELAYED_WORK(&resource->release_work->work, + delayed_release_work_func); + schedule_delayed_work(&resource->release_work->work, msecs_to_jiffies(IPA_RM_RELEASE_DELAY_IN_MSEC)); result = 0; bail: diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c index b90aac672b7145637538c7eb36af5f1e5b574bbb..5066f7def2c0d0ee160737b6ced3568b52093aec 100644 --- a/drivers/platform/msm/ipa/ipa_rm_resource.c +++ b/drivers/platform/msm/ipa/ipa_rm_resource.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * 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 @@ -122,11 +122,20 @@ int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer, bool dec_client_on_err) { int driver_result; + int result = 0; IPA_RM_DBG_LOW("calling driver CB\n"); driver_result = consumer->request_resource(); IPA_RM_DBG_LOW("driver CB returned with %d\n", driver_result); - if (driver_result == 0) { + + if (driver_result == 0 || + driver_result == -EPERM) { + /* + * Go ahead and handle suspend of + * resources in case of -EPERM return, + * as the client driver is unloaded and + * Holb drop is enabled + */ if (notify_completion) { ipa_rm_resource_consumer_handle_cb(consumer, IPA_RM_RESOURCE_GRANTED); @@ -140,9 +149,11 @@ int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer, consumer->resource.needed_bw -= prod_needed_bw; if (dec_client_on_err) consumer->usage_count--; - } + result = driver_result; + } else + result = driver_result; - return driver_result; + return result; } int ipa_rm_resource_consumer_request( diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h index da149c51c96cc2d0ba79ed1c7bb4ad2236619890..557a6545939b1de9e4febe7531643bead72c779b 100644 --- a/drivers/platform/msm/ipa/ipa_rm_resource.h +++ b/drivers/platform/msm/ipa/ipa_rm_resource.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016,2018 The Linux Foundation. All rights reserved. * * 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 @@ -65,6 +65,7 @@ struct ipa_rm_resource { u32 needed_bw; enum ipa_rm_resource_state state; struct ipa_rm_peers_list *peers_list; + struct ipa_rm_delayed_release_work_type *release_work; }; /** diff --git a/drivers/platform/msm/ipa/ipa_v2/Makefile b/drivers/platform/msm/ipa/ipa_v2/Makefile index 69b8a4c94461d8ed85c1004855ea08d55b53dd44..fb039709261e4a586023e02e188f8343881dde9a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/Makefile +++ b/drivers/platform/msm/ipa/ipa_v2/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_IPA) += ipat.o ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \ ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \ - ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o + ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \ + ipa_wdi3_i.o obj-$(CONFIG_RMNET_IPA) += rmnet_ipa.o ipa_qmi_service_v01.o ipa_qmi_service.o rmnet_ipa_fd_ioctl.o diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index a0a94aa5e181b08de3502d02ed8e297e94cd2b40..7b93792f0fe112741ca571b44e4cc535882cdb20 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -554,8 +554,8 @@ static void ipa_wan_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } -static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type, - bool is_cache) +static int ipa_send_wan_msg(unsigned long usr_param, + uint8_t msg_type, bool is_cache) { int retval; struct ipa_wan_msg *wan_msg; @@ -1520,7 +1520,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /** * ipa_setup_dflt_rt_tables() - Setup default routing tables - +* * Return codes: * 0: success * -ENOMEM: failed to allocate memory @@ -2043,6 +2043,7 @@ static int ipa_q6_set_ex_path_dis_agg(void) int index; struct ipa_register_write *reg_write; int retval; + gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); desc = kcalloc(ipa_ctx->ipa_num_pipes, sizeof(struct ipa_desc), GFP_KERNEL); @@ -2060,7 +2061,7 @@ static int ipa_q6_set_ex_path_dis_agg(void) if (ipa_ctx->ep[ep_idx].valid && ipa_ctx->ep[ep_idx].skip_ep_cfg) { BUG_ON(num_descs >= ipa_ctx->ipa_num_pipes); - reg_write = kzalloc(sizeof(*reg_write), GFP_KERNEL); + reg_write = kzalloc(sizeof(*reg_write), flag); if (!reg_write) { IPAERR("failed to allocate memory\n"); @@ -2093,7 +2094,7 @@ static int ipa_q6_set_ex_path_dis_agg(void) continue; if (IPA_CLIENT_IS_Q6_NON_ZIP_CONS(client_idx) || IPA_CLIENT_IS_Q6_ZIP_CONS(client_idx)) { - reg_write = kzalloc(sizeof(*reg_write), GFP_KERNEL); + reg_write = kzalloc(sizeof(*reg_write), flag); if (!reg_write) { IPAERR("failed to allocate memory\n"); @@ -3940,7 +3941,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, ipa_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); if (ipa_ctx->logbuf == NULL) - IPAERR("failed to create IPC log, continue...\n"); + IPADBG("failed to create IPC log, continue...\n"); ipa_ctx->pdev = ipa_dev; ipa_ctx->uc_pdev = ipa_dev; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_client.c b/drivers/platform/msm/ipa/ipa_v2/ipa_client.c index 66e329a03df70688c9b003fbf787c546953121b6..14bf75652bb749245b118cc10bccc7ea6ed70eff 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -97,8 +97,8 @@ int ipa_disable_data_path(u32 clnt_hdl) static int ipa2_smmu_map_peer_bam(unsigned long dev) { - phys_addr_t base; - u32 size; + phys_addr_t base = 0; + u32 size = 0; struct iommu_domain *smmu_domain; struct ipa_smmu_cb_ctx *cb = ipa2_get_smmu_ctx(); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index c46b3542839ec391a03a94ca6da578981095f657..23645d49dec3a3e1c2aaf90542398fa6791511d7 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -583,6 +583,15 @@ static int ipa_attrib_dump(struct ipa_rule_attrib *attrib, if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) pr_err("ether_type:%x ", attrib->ether_type); + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) + pr_err("l2tp inner ip type: %d ", attrib->type); + + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) { + addr[0] = htonl(attrib->u.v4.dst_addr); + mask[0] = htonl(attrib->u.v4.dst_addr_mask); + pr_err("dst_addr:%pI4 dst_addr_mask:%pI4 ", addr, mask); + } + pr_err("\n"); return 0; } @@ -1891,7 +1900,7 @@ static ssize_t ipa_enable_ipc_low(struct file *file, ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa_low", 0); if (ipa_ipc_low_buff == NULL) - IPAERR("failed to get logbuf_low\n"); + IPADBG("failed to get logbuf_low\n"); } ipa_ctx->logbuf_low = ipa_ipc_low_buff; } else { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index f70826d53b6d7044c784874305d7abf05e8116f6..7860ad412b731954bd51e38e11dba56bf96c8045 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -435,16 +435,16 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, &dma_addr); if (!transfer.iovec) { IPAERR("fail to alloc dma mem for sps xfr buff\n"); - return -EFAULT; + return -ENOMEM; } } else { transfer.iovec = kmalloc(size, flag); if (!transfer.iovec) { IPAERR("fail to alloc mem for sps xfr buff "); IPAERR("num_desc = %d size = %d\n", num_desc, size); - return -EFAULT; + return -ENOMEM; } - dma_addr = dma_map_single(ipa_ctx->pdev, + dma_addr = dma_map_single(ipa_ctx->pdev, transfer.iovec, size, DMA_TO_DEVICE); if (dma_mapping_error(ipa_ctx->pdev, dma_addr)) { IPAERR("dma_map_single failed for sps xfr buff\n"); @@ -459,9 +459,10 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, for (i = 0; i < num_desc; i++) { tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, - mem_flag); + GFP_ATOMIC); if (!tx_pkt) { IPAERR("failed to alloc tx wrapper\n"); + ret = -ENOMEM; goto failure; } /* @@ -515,6 +516,7 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, if (dma_mapping_error(ipa_ctx->pdev, tx_pkt->mem.phys_base)) { IPAERR("dma_map_single failed\n"); + ret = -EFAULT; goto failure_dma_map; } @@ -564,6 +566,7 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, result = sps_transfer(sys->ep->ep_hdl, &transfer); if (result) { IPAERR("sps_transfer failed rc=%d\n", result); + ret = -EFAULT; goto failure; } @@ -605,7 +608,7 @@ failure: } } spin_unlock_bh(&sys->spinlock); - return -EFAULT; + return ret; } /** @@ -2012,8 +2015,10 @@ static void ipa_replenish_rx_cache(struct ipa_sys_context *sys) goto fail_dma_mapping; } + spin_lock_bh(&sys->spinlock); list_add_tail(&rx_pkt->link, &sys->head_desc_list); rx_len_cached = ++sys->len; + spin_unlock_bh(&sys->spinlock); ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->data.dma_addr, sys->rx_buff_sz, rx_pkt, 0); @@ -2027,8 +2032,10 @@ static void ipa_replenish_rx_cache(struct ipa_sys_context *sys) return; fail_sps_transfer: + spin_lock_bh(&sys->spinlock); list_del(&rx_pkt->link); rx_len_cached = --sys->len; + spin_unlock_bh(&sys->spinlock); dma_unmap_single(ipa_ctx->pdev, rx_pkt->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); fail_dma_mapping: @@ -2098,8 +2105,10 @@ static void ipa_replenish_rx_cache_recycle(struct ipa_sys_context *sys) } } + spin_lock_bh(&sys->spinlock); list_add_tail(&rx_pkt->link, &sys->head_desc_list); rx_len_cached = ++sys->len; + spin_unlock_bh(&sys->spinlock); ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->data.dma_addr, sys->rx_buff_sz, rx_pkt, 0); @@ -2112,9 +2121,11 @@ static void ipa_replenish_rx_cache_recycle(struct ipa_sys_context *sys) return; fail_sps_transfer: + spin_lock_bh(&sys->spinlock); rx_len_cached = --sys->len; list_del(&rx_pkt->link); INIT_LIST_HEAD(&rx_pkt->link); + spin_unlock_bh(&sys->spinlock); dma_unmap_single(ipa_ctx->pdev, rx_pkt->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); fail_dma_mapping: @@ -2143,7 +2154,9 @@ static void ipa_fast_replenish_rx_cache(struct ipa_sys_context *sys) break; rx_pkt = sys->repl.cache[curr]; + spin_lock_bh(&sys->spinlock); list_add_tail(&rx_pkt->link, &sys->head_desc_list); + spin_unlock_bh(&sys->spinlock); ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->data.dma_addr, sys->rx_buff_sz, rx_pkt, 0); @@ -2202,6 +2215,7 @@ static void ipa_cleanup_rx(struct ipa_sys_context *sys) u32 head; u32 tail; + spin_lock_bh(&sys->spinlock); list_for_each_entry_safe(rx_pkt, r, &sys->head_desc_list, link) { list_del(&rx_pkt->link); @@ -2219,6 +2233,7 @@ static void ipa_cleanup_rx(struct ipa_sys_context *sys) sys->free_skb(rx_pkt->data.skb); kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt); } + spin_unlock_bh(&sys->spinlock); if (sys->repl.cache) { head = atomic_read(&sys->repl.head_idx); @@ -2819,10 +2834,12 @@ void ipa_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) struct ipa_ep_context *ep; unsigned int src_pipe; u32 metadata; + u8 ucp; status = (struct ipa_hw_pkt_status *)rx_skb->data; src_pipe = status->endp_src_idx; metadata = status->metadata; + ucp = status->ucp; ep = &ipa_ctx->ep[src_pipe]; if (unlikely(src_pipe >= ipa_ctx->ipa_num_pipes || !ep->valid || @@ -2845,8 +2862,10 @@ void ipa_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) ------------------------------------------ */ *(u16 *)rx_skb->cb = ((metadata >> 16) & 0xFFFF); + *(u8 *)(rx_skb->cb + 4) = ucp; IPADBG_LOW("meta_data: 0x%x cb: 0x%x\n", - metadata, *(u32 *)rx_skb->cb); + metadata, *(u32 *)rx_skb->cb); + IPADBG_LOW("ucp: %d\n", *(u8 *)(rx_skb->cb + 4)); ep->client_notify(ep->priv, IPA_RECEIVE, (unsigned long)(rx_skb)); } @@ -2867,8 +2886,10 @@ static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size) struct ipa_rx_pkt_wrapper *rx_pkt_expected; struct sk_buff *rx_skb; + spin_lock_bh(&sys->spinlock); if (unlikely(list_empty(&sys->head_desc_list))) { WARN_ON(1); + spin_unlock_bh(&sys->spinlock); return; } rx_pkt_expected = list_first_entry(&sys->head_desc_list, @@ -2876,6 +2897,7 @@ static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size) link); list_del(&rx_pkt_expected->link); sys->len--; + spin_unlock_bh(&sys->spinlock); if (size) rx_pkt_expected->len = size; rx_skb = rx_pkt_expected->data.skb; @@ -2896,8 +2918,10 @@ static void ipa_wlan_wq_rx_common(struct ipa_sys_context *sys, u32 size) struct ipa_rx_pkt_wrapper *rx_pkt_expected; struct sk_buff *rx_skb; + spin_lock_bh(&sys->spinlock); if (unlikely(list_empty(&sys->head_desc_list))) { WARN_ON(1); + spin_unlock_bh(&sys->spinlock); return; } rx_pkt_expected = list_first_entry(&sys->head_desc_list, @@ -2905,6 +2929,7 @@ static void ipa_wlan_wq_rx_common(struct ipa_sys_context *sys, u32 size) link); list_del(&rx_pkt_expected->link); sys->len--; + spin_unlock_bh(&sys->spinlock); if (size) rx_pkt_expected->len = size; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c index 807644c98a530608e8d9002ed83abecf03582435..c29cbdf9505727f127f2d9310495242c8a30ef28 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c @@ -23,10 +23,10 @@ static int ipa_generate_hw_rule_from_eq( const struct ipa_ipfltri_rule_eq *attrib, u8 **buf) { - int num_offset_meq_32 = attrib->num_offset_meq_32; - int num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16; - int num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32; - int num_offset_meq_128 = attrib->num_offset_meq_128; + uint8_t num_offset_meq_32 = attrib->num_offset_meq_32; + uint8_t num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16; + uint8_t num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32; + uint8_t num_offset_meq_128 = attrib->num_offset_meq_128; int i; if (attrib->tos_eq_present) { @@ -1039,6 +1039,11 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip, goto error; } } + } else { + if (rule->rt_tbl_idx > 0) { + IPAERR_RL("invalid RT tbl\n"); + goto error; + } } entry = kmem_cache_zalloc(ipa_ctx->flt_rule_cache, GFP_KERNEL); @@ -1161,6 +1166,11 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule, goto error; } } + } else { + if (frule->rule.rt_tbl_idx > 0) { + IPAERR_RL("invalid RT tbl\n"); + goto error; + } } entry->rule = frule->rule; @@ -1485,8 +1495,16 @@ int ipa2_reset_flt(enum ipa_ip_type ip, bool user_only) } } } - mutex_unlock(&ipa_ctx->lock); + /* commit the change to IPA-HW */ + if (ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v4) || + ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v6)) { + IPAERR_RL("fail to commit flt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa_ctx->lock); + return -EPERM; + } + mutex_unlock(&ipa_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index 19dc7c44cdb85b7088681c1b3d50f7e2e5f5a6f7..9e098887771befa3b69e0b8f1d744e3635ac167c 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c @@ -1249,6 +1249,8 @@ int ipa2_reset_hdr(bool user_only) struct ipa_hdr_offset_entry *off_next; struct ipa_hdr_proc_ctx_offset_entry *ctx_off_entry; struct ipa_hdr_proc_ctx_offset_entry *ctx_off_next; + struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl; + struct ipa_hdr_proc_ctx_tbl *htbl_proc = &ipa_ctx->hdr_proc_ctx_tbl; int i; /* @@ -1294,8 +1296,15 @@ int ipa2_reset_hdr(bool user_only) entry->hdr_len, DMA_TO_DEVICE); entry->proc_ctx = NULL; + } else { + /* move the offset entry to free list */ + entry->offset_entry->ipacm_installed = 0; + list_move(&entry->offset_entry->link, + &htbl->head_free_offset_list[ + entry->offset_entry->bin]); } list_del(&entry->link); + htbl->hdr_cnt--; entry->ref_cnt = 0; entry->cookie = 0; @@ -1304,40 +1313,35 @@ int ipa2_reset_hdr(bool user_only) kmem_cache_free(ipa_ctx->hdr_cache, entry); } } - for (i = 0; i < IPA_HDR_BIN_MAX; i++) { - list_for_each_entry_safe(off_entry, off_next, - &ipa_ctx->hdr_tbl.head_offset_list[i], - link) { - - /* - * do not remove the default exception header which is - * at offset 0 - */ - if (off_entry->offset == 0) - continue; - if (!user_only || - off_entry->ipacm_installed) { + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_BIN_MAX; i++) { + list_for_each_entry_safe(off_entry, off_next, + &ipa_ctx->hdr_tbl.head_offset_list[i], + link) { + /** + * do not remove the default exception + * header which is at offset 0 + */ + if (off_entry->offset == 0) + continue; list_del(&off_entry->link); kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry); } - } - list_for_each_entry_safe(off_entry, off_next, + list_for_each_entry_safe(off_entry, off_next, &ipa_ctx->hdr_tbl.head_free_offset_list[i], link) { - - if (!user_only || - off_entry->ipacm_installed) { list_del(&off_entry->link); kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry); } } + /* there is one header of size 8 */ + ipa_ctx->hdr_tbl.end = 8; + ipa_ctx->hdr_tbl.hdr_cnt = 1; } - /* there is one header of size 8 */ - ipa_ctx->hdr_tbl.end = 8; - ipa_ctx->hdr_tbl.hdr_cnt = 1; IPADBG("reset hdr proc ctx\n"); list_for_each_entry_safe( @@ -1348,13 +1352,18 @@ int ipa2_reset_hdr(bool user_only) if (ipa_id_find(ctx_entry->id) == NULL) { mutex_unlock(&ipa_ctx->lock); - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); return -EFAULT; } if (!user_only || ctx_entry->ipacm_installed) { + /* move the offset entry to appropriate free list */ + list_move(&ctx_entry->offset_entry->link, + &htbl_proc->head_free_offset_list[ + ctx_entry->offset_entry->bin]); list_del(&ctx_entry->link); + htbl_proc->proc_ctx_cnt--; ctx_entry->ref_cnt = 0; ctx_entry->cookie = 0; @@ -1364,36 +1373,40 @@ int ipa2_reset_hdr(bool user_only) ctx_entry); } } - for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa_ctx->hdr_proc_ctx_tbl.head_offset_list[i], link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); } - } - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, - &ipa_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i], - link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + &ipa_ctx->hdr_proc_ctx_tbl. + head_free_offset_list[i], link) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); } } + ipa_ctx->hdr_proc_ctx_tbl.end = 0; + ipa_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt = 0; } - ipa_ctx->hdr_proc_ctx_tbl.end = 0; - ipa_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt = 0; - mutex_unlock(&ipa_ctx->lock); + + /* commit the change to IPA-HW */ + if (ipa_ctx->ctrl->ipa_commit_hdr()) { + IPAERR_RL("fail to commit hdr\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa_ctx->lock); + return -EFAULT; + } + + mutex_unlock(&ipa_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 1e3ca2dc7bc3744de3e20dc629539c6c0ea95a1b..1de81004153c582972383c9cbcfa694c98c9a45e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -67,8 +67,6 @@ #define IPA_MAX_NUM_REQ_CACHE 10 -#define IPA_TIMEOUT(value) (msecs_to_jiffies(value * 1000)) - #define IPADBG(fmt, args...) \ do { \ pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\ @@ -1594,6 +1592,12 @@ int ipa2_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl); int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv); void ipa2_ntn_uc_dereg_rdyCB(void); +int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in, + struct ipa_wdi3_conn_out_params *out); +int ipa2_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx); +int ipa2_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx); +int ipa2_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx); + /* * To retrieve doorbell physical address of * wlan pipes diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c index da56a2ed1b8d3171cc39164a15072bf7ffd81aea..ed9be73bc63dde16e5a6fca951aa6f7b8cf31417 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * 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 @@ -507,7 +507,7 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff, } if (meta == NULL || (buff == NULL && callback != NULL) || - (buff != NULL && callback == NULL) || buff == NULL) { + (buff != NULL && callback == NULL)) { IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n", meta, buff, callback); return -EINVAL; @@ -735,6 +735,12 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, IPADBG("msg=%pK\n", msg); locked = 0; mutex_unlock(&ipa_ctx->msg_lock); + if (count < sizeof(struct ipa_msg_meta)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } if (copy_to_user(buf, &msg->meta, sizeof(struct ipa_msg_meta))) { kfree(msg); @@ -745,8 +751,15 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, buf += sizeof(struct ipa_msg_meta); count -= sizeof(struct ipa_msg_meta); if (msg->buff) { - if (copy_to_user(buf, msg->buff, - msg->meta.msg_len)) { + if (count >= msg->meta.msg_len) { + if (copy_to_user(buf, msg->buff, + msg->meta.msg_len)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } + } else { kfree(msg); msg = NULL; ret = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_mhi.c index 18d34aeb10e08829e3591e793e546ecbd68bed42..ddf3331c2fc19708423d1d57824ca2951ad9afdb 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * 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 @@ -58,7 +58,7 @@ bool ipa2_mhi_sps_channel_empty(enum ipa_client_type client) { u32 pipe_idx; - bool pending; + bool pending = 0; pipe_idx = ipa2_get_ep_mapping(client); if (sps_pipe_pending_desc(ipa_ctx->bam_handle, diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c index 5367bca5817e06d475e775c003e1ca080a2290c8..8bf1c80c9aa95306f01f59b3fc2f50e4e0a790ec 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c @@ -358,6 +358,9 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("Detected overflow\n"); return -EPERM; } + + mutex_lock(&ipa_ctx->nat_mem.lock); + /* Check Table Entry offset is not beyond allocated size */ tmp = init->ipv4_rules_offset + @@ -367,6 +370,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->ipv4_rules_offset, (init->table_entries + 1), tmp, ipa_ctx->nat_mem.size); + mutex_unlock(&ipa_ctx->nat_mem.lock); return -EPERM; } @@ -374,6 +378,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) if (init->expn_rules_offset > UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries)) { IPAERR_RL("Detected overflow\n"); + mutex_unlock(&ipa_ctx->nat_mem.lock); return -EPERM; } /* Check Expn Table Entry offset is not @@ -385,6 +390,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->expn_rules_offset, init->expn_table_entries, tmp, ipa_ctx->nat_mem.size); + mutex_unlock(&ipa_ctx->nat_mem.lock); return -EPERM; } @@ -392,6 +398,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) if (init->index_offset > UINT_MAX - (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1))) { IPAERR_RL("Detected overflow\n"); + mutex_unlock(&ipa_ctx->nat_mem.lock); return -EPERM; } /* Check Indx Table Entry offset is not @@ -403,6 +410,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_offset, (init->table_entries + 1), tmp, ipa_ctx->nat_mem.size); + mutex_unlock(&ipa_ctx->nat_mem.lock); return -EPERM; } @@ -410,6 +418,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) if (init->index_expn_offset > (UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries))) { IPAERR_RL("Detected overflow\n"); + mutex_unlock(&ipa_ctx->nat_mem.lock); return -EPERM; } /* Check Expn Table entry offset is not @@ -421,6 +430,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_expn_offset, init->expn_table_entries, tmp, ipa_ctx->nat_mem.size); + mutex_unlock(&ipa_ctx->nat_mem.lock); return -EPERM; } @@ -569,6 +579,7 @@ free_mem: free_nop: kfree(reg_write_nop); bail: + mutex_unlock(&ipa_ctx->nat_mem.lock); return result; } @@ -787,7 +798,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del) return -EPERM; } - if (ipa_ctx->nat_mem.public_ip_addr) { + if (!ipa_ctx->nat_mem.public_ip_addr) { IPAERR_RL("Public IP addr not assigned and trying to delete\n"); return -EPERM; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c index cce27119c45aac420ba6c7df4348d38ec39cde54..a44cc143baee83eb55cddfeff1286cbd563dd34f 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c @@ -29,7 +29,7 @@ #define IPA_Q6_SVC_VERS 1 #define IPA_A5_SVC_VERS 1 -#define Q6_QMI_COMPLETION_TIMEOUT 60000 +#define Q6_QMI_COMPLETION_TIMEOUT (60*HZ) #define IPA_A5_SERVICE_SVC_ID 0x31 #define IPA_A5_SERVICE_INS_ID 1 @@ -508,6 +508,7 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) struct ipa_install_fltr_rule_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; int rc; + int i; /* check if modem up */ if (!qmi_indication_fin || @@ -525,6 +526,38 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) req->filter_spec_list_len); } + if (req->filter_spec_list_len >= QMI_IPA_MAX_FILTERS_V01) { + IPAWANDBG( + "IPACM passes the number of filtering rules exceed limit\n"); + return -EINVAL; + } else if (req->source_pipe_index_valid != 0) { + IPAWANDBG( + "IPACM passes source_pipe_index_valid not zero 0 != %d\n", + req->source_pipe_index_valid); + return -EINVAL; + } else if (req->source_pipe_index >= ipa_ctx->ipa_num_pipes) { + IPAWANDBG( + "IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } + for (i = 0; i < req->filter_spec_list_len; i++) { + if ((req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V4_V01) && + (req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V6_V01)) + return -EINVAL; + if (req->filter_spec_list[i].is_mux_id_valid == false) + return -EINVAL; + if (req->filter_spec_list[i].is_routing_table_index_valid + == false) + return -EINVAL; + if ((req->filter_spec_list[i].filter_action <= + QMI_IPA_FILTER_ACTION_INVALID_V01) && + (req->filter_spec_list[i].filter_action > + QMI_IPA_FILTER_ACTION_EXCEPTION_V01)) + return -EINVAL; + } mutex_lock(&ipa_qmi_lock); if (ipa_qmi_ctx != NULL) { /* cache the qmi_filter_request */ @@ -656,7 +689,6 @@ int qmi_filter_notify_send(struct ipa_fltr_installed_notif_req_msg_v01 *req) if (req->filter_index_list_len == 0) { IPAWANERR(" delete UL filter rule for pipe %d\n", req->source_pipe_index); - return -EINVAL; } else if (req->filter_index_list_len > QMI_IPA_MAX_FILTERS_V01) { IPAWANERR(" UL filter rule for pipe %d exceed max (%u)\n", req->source_pipe_index, @@ -675,6 +707,27 @@ int qmi_filter_notify_send(struct ipa_fltr_installed_notif_req_msg_v01 *req) return -EINVAL; } + if (req->install_status != IPA_QMI_RESULT_SUCCESS_V01) { + IPAWANERR(" UL filter rule for pipe %d install_status = %d\n", + req->source_pipe_index, req->install_status); + return -EINVAL; + } else if (req->source_pipe_index >= ipa_ctx->ipa_num_pipes) { + IPAWANERR("IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } else if (((req->embedded_pipe_index_valid != true) || + (req->embedded_call_mux_id_valid != true)) && + ((req->embedded_pipe_index_valid != false) || + (req->embedded_call_mux_id_valid != false))) { + IPAWANERR( + "IPACM passes embedded pipe and mux valid not valid\n"); + return -EINVAL; + } else if (req->embedded_pipe_index >= ipa_ctx->ipa_num_pipes) { + IPAWANERR("IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } + mutex_lock(&ipa_qmi_lock); if (ipa_qmi_ctx != NULL) { /* cache the qmi_filter_request */ diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index e4a3a72ee67045775b608d1969f2bd50571aa00c..4fea1255b36052d6d557cb123a058c59631ac500 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -1342,6 +1342,8 @@ int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only) struct ipa_rt_entry *rule_next; struct ipa_rt_tbl_set *rset; u32 apps_start_idx; + struct ipa_hdr_entry *hdr_entry; + struct ipa_hdr_proc_ctx_entry *hdr_proc_entry; int id; bool tbl_user = false; @@ -1395,6 +1397,27 @@ int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only) if (!user_only || rule->ipacm_installed) { list_del(&rule->link); + if (rule->hdr) { + hdr_entry = ipa_id_find( + rule->rule.hdr_hdl); + if (!hdr_entry || + hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR_RL( + "Header already deleted\n"); + return -EINVAL; + } + } else if (rule->proc_ctx) { + hdr_proc_entry = + ipa_id_find( + rule->rule.hdr_proc_ctx_hdl); + if (!hdr_proc_entry || + hdr_proc_entry->cookie != + IPA_PROC_HDR_COOKIE) { + IPAERR_RL( + "Proc entry already deleted\n"); + return -EINVAL; + } + } tbl->rule_cnt--; if (rule->hdr) __ipa_release_hdr(rule->hdr->id); @@ -1443,6 +1466,15 @@ int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only) } } } + + /* commit the change to IPA-HW */ + if (ipa_ctx->ctrl->ipa_commit_rt(IPA_IP_v4) || + ipa_ctx->ctrl->ipa_commit_rt(IPA_IP_v6)) { + IPAERR("fail to commit rt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa_ctx->lock); + return -EPERM; + } mutex_unlock(&ipa_ctx->lock); return 0; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c index be0075086e1b082e3d76dff6788efe8e6999db15..347590b0809fa0d92db4b275e9911d43f92202cb 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c @@ -769,7 +769,7 @@ int ipa_uc_reset_pipe(enum ipa_client_type ipa_client) IPA_CLIENT_IS_PROD(ipa_client) ? "CONS" : "PROD", ep_idx); ret = ipa_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_RESET_PIPE, 0, - false, IPA_TIMEOUT(10)); + false, 10*HZ); return ret; } @@ -828,7 +828,7 @@ int ipa_uc_monitor_holb(enum ipa_client_type ipa_client, bool enable) ret = ipa_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_UPDATE_HOLB_MONITORING, 0, - false, IPA_TIMEOUT(10)); + false, 10*HZ); return ret; } @@ -898,7 +898,7 @@ int ipa_uc_update_hw_flags(u32 flags) memset(&cmd, 0, sizeof(cmd)); cmd.params.newFlags = flags; return ipa_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_UPDATE_FLAGS, 0, - false, IPA_TIMEOUT(1)); + false, HZ); } EXPORT_SYMBOL(ipa_uc_update_hw_flags); @@ -931,7 +931,7 @@ int ipa_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len) cmd->source_addr = src; cmd->source_buffer_size = len; res = ipa_uc_send_cmd((u32)mem.phys_base, IPA_CPU_2_HW_CMD_MEMCPY, 0, - true, IPA_TIMEOUT(10)); + true, 10 * HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); goto free_coherent; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_mhi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_mhi.c index 05315b833007255a1dd0274bfd4fd10d40f0d6c1..08d7363bfab3b8270cd51c156b4cd5dc9966717c 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_mhi.c @@ -656,7 +656,7 @@ int ipa_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr, init_cmd_data->firstChannelIndex = first_ch_idx; init_cmd_data->firstEventRingIndex = first_evt_idx; res = ipa_uc_send_cmd((u32)mem.phys_base, IPA_CPU_2_HW_CMD_MHI_INIT, 0, - false, IPA_TIMEOUT(1)); + false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); dma_free_coherent(ipa_ctx->pdev, mem.size, mem.base, @@ -681,7 +681,7 @@ int ipa_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr, msi_cmd->msiData = msi->data; msi_cmd->msiMask = msi->mask; res = ipa_uc_send_cmd((u32)mem.phys_base, - IPA_CPU_2_HW_CMD_MHI_UPDATE_MSI, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_UPDATE_MSI, 0, false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); dma_free_coherent(ipa_ctx->pdev, mem.size, mem.base, @@ -733,7 +733,7 @@ int ipa_uc_mhi_init_channel(int ipa_ep_idx, int channelHandle, init_cmd.params.channelDirection = channelDirection; res = ipa_uc_send_cmd(init_cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_INIT_CHANNEL, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_INIT_CHANNEL, 0, false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -771,7 +771,7 @@ int ipa2_uc_mhi_reset_channel(int channelHandle) cmd.params.requestedState = IPA_HW_MHI_CHANNEL_STATE_DISABLE; cmd.params.channelHandle = channelHandle; res = ipa_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -808,7 +808,7 @@ int ipa2_uc_mhi_suspend_channel(int channelHandle) cmd.params.requestedState = IPA_HW_MHI_CHANNEL_STATE_SUSPEND; cmd.params.channelHandle = channelHandle; res = ipa_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -846,7 +846,7 @@ int ipa_uc_mhi_resume_channel(int channelHandle, bool LPTransitionRejected) cmd.params.channelHandle = channelHandle; cmd.params.LPTransitionRejected = LPTransitionRejected; res = ipa_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -879,7 +879,7 @@ int ipa2_uc_mhi_stop_event_update_channel(int channelHandle) ipa_uc_mhi_ctx->expected_responseParams = cmd.raw32b; res = ipa_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_STOP_EVENT_UPDATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_STOP_EVENT_UPDATE, 0, false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -909,7 +909,7 @@ int ipa2_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd) IPA_ACTIVE_CLIENTS_INC_SIMPLE(); res = ipa_uc_send_cmd(cmd->raw32b, - IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO, 0, false, HZ); if (res) { IPAERR("ipa_uc_send_cmd failed %d\n", res); goto disable_clks; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c index 65f3e72c5bd1e82cb5fe7be9bf48cb692a3338bb..17fb24863b1131a9c46f103d99eef361f0b924a5 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c @@ -265,7 +265,7 @@ static int ipa2_uc_send_ntn_setup_pipe_cmd( result = ipa_uc_send_cmd((u32)(cmd.phys_base), IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP, IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) result = -EFAULT; @@ -427,7 +427,7 @@ int ipa2_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, result = ipa_uc_send_cmd((u32)(cmd.phys_base), IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN, IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { IPAERR("fail to tear down dl pipe\n"); result = -EFAULT; @@ -439,7 +439,7 @@ int ipa2_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, result = ipa_uc_send_cmd((u32)(cmd.phys_base), IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN, IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { IPAERR("fail to tear down ul pipe\n"); result = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h index 75cc897c378edd71a9afa679af1baf3fafb3cdfd..fb4986dd5e1c4e0de02d55126ef8faea0d4b0541 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h @@ -26,6 +26,9 @@ #define IPA_NTN_TX_DIR 1 #define IPA_NTN_RX_DIR 2 +#define IPA_WDI3_TX_DIR 1 +#define IPA_WDI3_RX_DIR 2 + /** * @brief Enum value determined based on the feature it * corresponds to @@ -45,16 +48,20 @@ * enum ipa_hw_features - Values that represent the features supported in IPA HW * @IPA_HW_FEATURE_COMMON : Feature related to common operation of IPA HW * @IPA_HW_FEATURE_MHI : Feature related to MHI operation in IPA HW + * @IPA_HW_FEATURE_POWER_COLLAPSE: Feature related to IPA Power collapse * @IPA_HW_FEATURE_WDI : Feature related to WDI operation in IPA HW * @IPA_HW_FEATURE_NTN : Feature related to NTN operation in IPA HW * @IPA_HW_FEATURE_OFFLOAD : Feature related to NTN operation in IPA HW + * @IPA_HW_FEATURE_WDI3 : Feature related to WDI operation in IPA HW */ enum ipa_hw_features { IPA_HW_FEATURE_COMMON = 0x0, IPA_HW_FEATURE_MHI = 0x1, + IPA_HW_FEATURE_POWER_COLLAPSE = 0x2, IPA_HW_FEATURE_WDI = 0x3, IPA_HW_FEATURE_NTN = 0x4, IPA_HW_FEATURE_OFFLOAD = 0x5, + IPA_HW_FEATURE_WDI3 = 0x6, IPA_HW_FEATURE_MAX = IPA_HW_NUM_FEATURES }; @@ -274,6 +281,33 @@ struct IpaHwNtnSetUpCmdData_t { } __packed; +struct IpaHwWdi3SetUpCmdData_t { + u32 transfer_ring_base_pa; + u32 transfer_ring_base_pa_hi; + + u32 transfer_ring_size; + + u32 transfer_ring_doorbell_pa; + u32 transfer_ring_doorbell_pa_hi; + + u32 event_ring_base_pa; + u32 event_ring_base_pa_hi; + + u32 event_ring_size; + + u32 event_ring_doorbell_pa; + u32 event_ring_doorbell_pa_hi; + + u16 num_pkt_buffers; + u8 ipa_pipe_number; + u8 dir; + + u16 pkt_offset; + u16 reserved0; + + u32 desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE]; +} __packed; + /** * struct IpaHwNtnCommonChCmdData_t - Structure holding the * parameters for Ntn Tear down command data params @@ -288,6 +322,13 @@ union IpaHwNtnCommonChCmdData_t { uint32_t raw32b; } __packed; +union IpaHwWdi3CommonChCmdData_t { + struct IpaHwWdi3CommonChCmdParams_t { + u32 ipa_pipe_number :8; + u32 reserved :24; + } __packed params; + u32 raw32b; +} __packed; /** * struct IpaHwNTNErrorEventData_t - Structure holding the @@ -405,13 +446,30 @@ struct IpaHwStatsNTNInfoData_t { * the offload commands from CPU * @IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP : Command to set up * Offload protocol's Tx/Rx Path - * @IPA_CPU_2_HW_CMD_OFFLOAD_RX_SET_UP : Command to tear down + * @IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN : Command to tear down + * Offload protocol's Tx/ Rx Path + * @IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE : Command to enable + * Offload protocol's Tx/Rx Path + * @IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE : Command to disable + * Offload protocol's Tx/ Rx Path + * @IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND : Command to suspend + * Offload protocol's Tx/Rx Path + * @IPA_CPU_2_HW_CMD_OFFLOAD_RESUME : Command to resume * Offload protocol's Tx/ Rx Path */ enum ipa_cpu_2_hw_offload_commands { IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP = FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 1), - IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN, + IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 2), + IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 3), + IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 4), + IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 5), + IPA_CPU_2_HW_CMD_OFFLOAD_RESUME = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 6), }; @@ -519,6 +577,7 @@ enum ipa_hw_2_cpu_cmd_resp_status { */ union IpaHwSetUpCmd { struct IpaHwNtnSetUpCmdData_t NtnSetupCh_params; + struct IpaHwWdi3SetUpCmdData_t Wdi3SetupCh_params; } __packed; /** @@ -539,6 +598,7 @@ struct IpaHwOffloadSetUpCmdData_t { */ union IpaHwCommonChCmd { union IpaHwNtnCommonChCmdData_t NtnCommonCh_params; + union IpaHwWdi3CommonChCmdData_t Wdi3CommonCh_params; } __packed; struct IpaHwOffloadCommonChCmdData_t { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c index d0946f1e2e8c3ecc6d18c87b8c485978220a1fef..797f616c69df1ef3aae0aa4bb4205aedb4f860b1 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c @@ -1157,7 +1157,7 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPA_CPU_2_HW_CMD_WDI_TX_SET_UP : IPA_CPU_2_HW_CMD_WDI_RX_SET_UP, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1250,7 +1250,7 @@ int ipa2_disconnect_wdi_pipe(u32 clnt_hdl) result = ipa_uc_send_cmd(tear.raw32b, IPA_CPU_2_HW_CMD_WDI_TEAR_DOWN, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1314,7 +1314,7 @@ int ipa2_enable_wdi_pipe(u32 clnt_hdl) result = ipa_uc_send_cmd(enable.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_ENABLE, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1438,7 +1438,7 @@ int ipa2_disable_wdi_pipe(u32 clnt_hdl) result = ipa_uc_send_cmd(disable.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_DISABLE, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1505,7 +1505,7 @@ int ipa2_resume_wdi_pipe(u32 clnt_hdl) result = ipa_uc_send_cmd(resume.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_RESUME, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1575,7 +1575,7 @@ int ipa2_suspend_wdi_pipe(u32 clnt_hdl) result = ipa_uc_send_cmd(suspend.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_SUSPEND, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1606,7 +1606,7 @@ int ipa2_suspend_wdi_pipe(u32 clnt_hdl) result = ipa_uc_send_cmd(suspend.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_SUSPEND, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1655,7 +1655,7 @@ int ipa_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id) result = ipa_uc_send_cmd(qmap.raw32b, IPA_CPU_2_HW_CMD_WDI_RX_EXT_CFG, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 88f2aa8527718df6465b73b316641b6ed46aaf80..4d2fe658ce79ec17b6e4362ff8797cbe9a80da17 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -37,7 +37,7 @@ #define IPA_TAG_SLEEP_MIN_USEC (1000) #define IPA_TAG_SLEEP_MAX_USEC (2000) -#define IPA_FORCE_CLOSE_TAG_PROCESS_TIMEOUT IPA_TIMEOUT(10) +#define IPA_FORCE_CLOSE_TAG_PROCESS_TIMEOUT (10 * HZ) #define IPA_BCR_REG_VAL (0x001FFF7F) #define IPA_AGGR_GRAN_MIN (1) #define IPA_AGGR_GRAN_MAX (32) @@ -49,6 +49,10 @@ #define UPPER_CUTOFF 50 #define LOWER_CUTOFF 10 +#define MAX_RETRY_ALLOC 10 +#define ALLOC_MIN_SLEEP_RX 100000 +#define ALLOC_MAX_SLEEP_RX 200000 + #define IPA_DEFAULT_SYS_YELLOW_WM 32 #define IPA_AGGR_BYTE_LIMIT (\ @@ -1527,6 +1531,37 @@ int ipa_generate_hw_rule(enum ipa_ip_type ip, ihl_ofst_meq32++; } + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 22 => offset of IP type after v6 header */ + *buf = ipa_write_8(22, *buf); + *buf = ipa_write_32(0xF0000000, *buf); + if (attrib->type == 0x40) + *buf = ipa_write_32(0x40000000, *buf); + else + *buf = ipa_write_32(0x60000000, *buf); + *buf = ipa_pad_to_32(*buf); + ihl_ofst_meq32++; + } + + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 38 => offset of inner IPv4 addr */ + *buf = ipa_write_8(38, *buf); + *buf = ipa_write_32(attrib->u.v4.dst_addr_mask, *buf); + *buf = ipa_write_32(attrib->u.v4.dst_addr, *buf); + *buf = ipa_pad_to_32(*buf); + ihl_ofst_meq32++; + } + if (attrib->attrib_mask & IPA_FLT_SRC_PORT) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { IPAERR("ran out of ihl_rng16 eq\n"); @@ -2126,6 +2161,36 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, ihl_ofst_meq32++; } + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 22 => offset of inner IP type after v6 header */ + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 22; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = + 0xF0000000; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = + (u32)attrib->type << 24; + ihl_ofst_meq32++; + } + + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 38 => offset of inner IPv4 addr */ + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 38; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = + attrib->u.v4.dst_addr_mask; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = + attrib->u.v4.dst_addr; + ihl_ofst_meq32++; + } + if (attrib->attrib_mask & IPA_FLT_SRC_PORT) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { IPAERR_RL("ran out of ihl_rng16 eq\n"); @@ -4565,6 +4630,7 @@ int ipa_tag_process(struct ipa_desc desc[], int res; struct ipa_tag_completion *comp; int ep_idx; + u32 retry_cnt = 0; gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); /* Not enough room for the required descriptors for the tag process */ @@ -4591,7 +4657,7 @@ int ipa_tag_process(struct ipa_desc desc[], } /* IP_PACKET_INIT IC for tag status to be sent to apps */ - pkt_init = kzalloc(sizeof(*pkt_init), GFP_KERNEL); + pkt_init = kzalloc(sizeof(*pkt_init), flag); if (!pkt_init) { IPAERR("failed to allocate memory\n"); res = -ENOMEM; @@ -4610,7 +4676,7 @@ int ipa_tag_process(struct ipa_desc desc[], desc_idx++; /* NO-OP IC for ensuring that IPA pipeline is empty */ - reg_write_nop = kzalloc(sizeof(*reg_write_nop), GFP_KERNEL); + reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag); if (!reg_write_nop) { IPAERR("no mem\n"); res = -ENOMEM; @@ -4629,7 +4695,7 @@ int ipa_tag_process(struct ipa_desc desc[], desc_idx++; /* status IC */ - status = kzalloc(sizeof(*status), GFP_KERNEL); + status = kzalloc(sizeof(*status), flag); if (!status) { IPAERR("no mem\n"); res = -ENOMEM; @@ -4665,7 +4731,7 @@ int ipa_tag_process(struct ipa_desc desc[], atomic_set(&comp->cnt, 2); /* dummy packet to send to IPA. packet payload is a completion object */ - dummy_skb = alloc_skb(sizeof(comp), GFP_KERNEL); + dummy_skb = alloc_skb(sizeof(comp), flag); if (!dummy_skb) { IPAERR("failed to allocate memory\n"); res = -ENOMEM; @@ -4681,9 +4747,22 @@ int ipa_tag_process(struct ipa_desc desc[], tag_desc[desc_idx].user1 = dummy_skb; desc_idx++; +retry_alloc: + /* send all descriptors to IPA with single EOT */ res = ipa_send(sys, desc_idx, tag_desc, true); if (res) { + if (res == -ENOMEM) { + if (retry_cnt < MAX_RETRY_ALLOC) { + IPADBG( + "Failed to alloc memory retry count %d\n", + retry_cnt); + retry_cnt++; + usleep_range(ALLOC_MIN_SLEEP_RX, + ALLOC_MAX_SLEEP_RX); + goto retry_alloc; + } + } IPAERR("failed to send TAG packets %d\n", res); res = -ENOMEM; goto fail_send; @@ -5028,7 +5107,7 @@ static int ipa2_generate_tag_process(void) { int res; - res = ipa_tag_process(NULL, 0, IPA_TIMEOUT(1)); + res = ipa_tag_process(NULL, 0, HZ); if (res) IPAERR("TAG process failed\n"); @@ -5210,6 +5289,10 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_get_pdev = ipa2_get_pdev; api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa2_ntn_uc_reg_rdyCB; api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa2_ntn_uc_dereg_rdyCB; + api_ctrl->ipa_conn_wdi3_pipes = ipa2_conn_wdi3_pipes; + api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes; + api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes; + api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes; return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c new file mode 100644 index 0000000000000000000000000000000000000000..fe527ffadd9b684bd2722df36d66d4780ecee4c7 --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c @@ -0,0 +1,406 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * 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 "ipa_i.h" +#include "ipa_uc_offload_i.h" +#include + +#define IPA_HW_WDI3_RX_MBOX_START_INDEX 48 +#define IPA_HW_WDI3_TX_MBOX_START_INDEX 50 + +static int ipa_send_wdi3_setup_pipe_cmd( + struct ipa_wdi3_setup_info *info, u8 dir) +{ + int ipa_ep_idx; + int result = 0; + struct ipa_mem_buffer cmd; + struct IpaHwWdi3SetUpCmdData_t *wdi3_params; + struct IpaHwOffloadSetUpCmdData_t *cmd_data; + + if (info == NULL) { + IPAERR("invalid input\n"); + return -EINVAL; + } + + ipa_ep_idx = ipa_get_ep_mapping(info->client); + IPAERR("ep number: %d\n", ipa_ep_idx); + if (ipa_ep_idx == -1) { + IPAERR("fail to get ep idx.\n"); + return -EFAULT; + } + + IPAERR("client=%d ep=%d\n", info->client, ipa_ep_idx); + IPAERR("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa); + IPAERR("ring_size = %hu\n", info->transfer_ring_size); + IPAERR("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa); + IPAERR("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa); + IPAERR("evt_ring_size = %hu\n", info->event_ring_size); + IPAERR("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa); + IPAERR("num_pkt_buffers = %hu\n", info->num_pkt_buffers); + IPAERR("pkt_offset = %d.\n", info->pkt_offset); + + cmd.size = sizeof(*cmd_data); + cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size, + &cmd.phys_base, GFP_KERNEL); + if (cmd.base == NULL) { + IPAERR("fail to get DMA memory.\n"); + return -ENOMEM; + } + IPAERR("suceeded in allocating memory.\n"); + + cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base; + cmd_data->protocol = IPA_HW_FEATURE_WDI3; + + wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params; + wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa; + wdi3_params->transfer_ring_base_pa_hi = + (u32)((u64)info->transfer_ring_base_pa >> 32); + wdi3_params->transfer_ring_size = info->transfer_ring_size; + wdi3_params->transfer_ring_doorbell_pa = + (u32)info->transfer_ring_doorbell_pa; + wdi3_params->transfer_ring_doorbell_pa_hi = + (u32)((u64)info->transfer_ring_doorbell_pa >> 32); + wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa; + wdi3_params->event_ring_base_pa_hi = + (u32)((u64)info->event_ring_base_pa >> 32); + wdi3_params->event_ring_size = info->event_ring_size; + wdi3_params->event_ring_doorbell_pa = + (u32)info->event_ring_doorbell_pa; + wdi3_params->event_ring_doorbell_pa_hi = + (u32)((u64)info->event_ring_doorbell_pa >> 32); + wdi3_params->num_pkt_buffers = info->num_pkt_buffers; + wdi3_params->ipa_pipe_number = ipa_ep_idx; + wdi3_params->dir = dir; + wdi3_params->pkt_offset = info->pkt_offset; + memcpy(wdi3_params->desc_format_template, info->desc_format_template, + sizeof(wdi3_params->desc_format_template)); + IPAERR("suceeded in populating the command memory.\n"); + + result = ipa_uc_send_cmd((u32)(cmd.phys_base), + IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP, + IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, + false, 10*HZ); + if (result) { + IPAERR("uc setup channel cmd failed: %d\n", result); + result = -EFAULT; + } + + dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base); + IPAERR("suceeded in freeing memory.\n"); + return result; +} + +int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in, + struct ipa_wdi3_conn_out_params *out) +{ + struct ipa_ep_context *ep_rx; + struct ipa_ep_context *ep_tx; + int ipa_ep_idx_rx; + int ipa_ep_idx_tx; + int result = 0; + + if (in == NULL || out == NULL) { + IPAERR("invalid input\n"); + return -EINVAL; + } + + ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client); + ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client); + if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) { + IPAERR("fail to alloc EP.\n"); + return -EFAULT; + } + + ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx]; + ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx]; + + if (ep_rx->valid || ep_tx->valid) { + IPAERR("EP already allocated.\n"); + return -EFAULT; + } + + memset(ep_rx, 0, offsetof(struct ipa_ep_context, sys)); + memset(ep_tx, 0, offsetof(struct ipa_ep_context, sys)); + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + /* setup rx ep cfg */ + ep_rx->valid = 1; + ep_rx->client = in->rx.client; + result = ipa_disable_data_path(ipa_ep_idx_rx); + if (result) { + IPAERR("disable data path failed res=%d clnt=%d.\n", result, + ipa_ep_idx_rx); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -EFAULT; + } + ep_rx->client_notify = in->notify; + ep_rx->priv = in->priv; + + memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg)); + + if (ipa_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) { + IPAERR("fail to setup rx pipe cfg\n"); + result = -EFAULT; + goto fail; + } + IPAERR("configured RX EP.\n"); + + if (ipa_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) { + IPAERR("fail to send cmd to uc for rx pipe\n"); + result = -EFAULT; + goto fail; + } + IPAERR("rx pipe was setup.\n"); + + ipa_install_dflt_flt_rules(ipa_ep_idx_rx); + out->rx_uc_db_pa = ipa_ctx->ipa_wrapper_base + + IPA_REG_BASE_OFST_v2_5 + + IPA_UC_MAILBOX_m_n_OFFS_v2_5( + IPA_HW_WDI3_RX_MBOX_START_INDEX/32, + IPA_HW_WDI3_RX_MBOX_START_INDEX % 32); + IPADBG("client %d (ep: %d) connected\n", in->rx.client, + ipa_ep_idx_rx); + + /* setup dl ep cfg */ + ep_tx->valid = 1; + ep_tx->client = in->tx.client; + result = ipa_disable_data_path(ipa_ep_idx_tx); + if (result) { + IPAERR("disable data path failed res=%d clnt=%d.\n", result, + ipa_ep_idx_tx); + result = -EFAULT; + goto fail; + } + + memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg)); + + if (ipa_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) { + IPAERR("fail to setup tx pipe cfg\n"); + result = -EFAULT; + goto fail; + } + IPAERR("configured TX EP in DMA mode.\n"); + + if (ipa_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) { + IPAERR("fail to send cmd to uc for tx pipe\n"); + result = -EFAULT; + goto fail; + } + IPAERR("tx pipe was setup.\n"); + + out->tx_uc_db_pa = ipa_ctx->ipa_wrapper_base + + IPA_REG_BASE_OFST_v2_5 + + IPA_UC_MAILBOX_m_n_OFFS_v2_5( + IPA_HW_WDI3_TX_MBOX_START_INDEX/32, + IPA_HW_WDI3_TX_MBOX_START_INDEX % 32); + out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4); + IPADBG("client %d (ep: %d) connected\n", in->tx.client, + ipa_ep_idx_tx); + +fail: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return result; +} + +static int ipa_send_wdi3_common_ch_cmd(int ipa_ep_idx, int command) +{ + struct ipa_mem_buffer cmd; + struct IpaHwOffloadCommonChCmdData_t *cmd_data; + union IpaHwWdi3CommonChCmdData_t *wdi3; + int result = 0; + + cmd.size = sizeof(*cmd_data); + cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size, + &cmd.phys_base, GFP_KERNEL); + if (cmd.base == NULL) { + IPAERR("fail to get DMA memory.\n"); + return -ENOMEM; + } + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + /* enable the TX pipe */ + cmd_data = (struct IpaHwOffloadCommonChCmdData_t *)cmd.base; + cmd_data->protocol = IPA_HW_FEATURE_WDI3; + + wdi3 = &cmd_data->CommonCh_params.Wdi3CommonCh_params; + wdi3->params.ipa_pipe_number = ipa_ep_idx; + IPAERR("cmd: %d ep_idx: %d\n", command, ipa_ep_idx); + result = ipa_uc_send_cmd((u32)(cmd.phys_base), command, + IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, + false, 10*HZ); + if (result) { + result = -EFAULT; + goto fail; + } + +fail: + dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return result; +} + +int ipa2_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) +{ + struct ipa_ep_context *ep_tx, *ep_rx; + int result = 0; + + IPADBG("ep_tx = %d\n", ipa_ep_idx_tx); + IPADBG("ep_rx = %d\n", ipa_ep_idx_rx); + + ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx]; + ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx]; + + /* tear down tx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx, + IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN)) { + IPAERR("fail to tear down tx pipe\n"); + result = -EFAULT; + goto fail; + } + ipa_disable_data_path(ipa_ep_idx_tx); + memset(ep_tx, 0, sizeof(struct ipa_ep_context)); + IPADBG("tx client (ep: %d) disconnected\n", ipa_ep_idx_tx); + + /* tear down rx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx, + IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN)) { + IPAERR("fail to tear down rx pipe\n"); + result = -EFAULT; + goto fail; + } + ipa_disable_data_path(ipa_ep_idx_rx); + ipa_delete_dflt_flt_rules(ipa_ep_idx_rx); + memset(ep_rx, 0, sizeof(struct ipa_ep_context)); + IPADBG("rx client (ep: %d) disconnected\n", ipa_ep_idx_rx); + +fail: + return result; +} + +int ipa2_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) +{ + struct ipa_ep_context *ep_tx, *ep_rx; + int result = 0; + + IPAERR("ep_tx = %d\n", ipa_ep_idx_tx); + IPAERR("ep_rx = %d\n", ipa_ep_idx_rx); + + ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx]; + ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx]; + + /* enable tx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx, + IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) { + IPAERR("fail to enable tx pipe\n"); + BUG(); + result = -EFAULT; + goto fail; + } + + /* resume tx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx, + IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) { + IPAERR("fail to resume tx pipe\n"); + BUG(); + result = -EFAULT; + goto fail; + } + + /* enable rx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx, + IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) { + IPAERR("fail to enable rx pipe\n"); + BUG(); + result = -EFAULT; + goto fail; + } + + /* resume rx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx, + IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) { + IPAERR("fail to resume rx pipe\n"); + BUG(); + result = -EFAULT; + goto fail; + } + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + /* enable data path */ + result = ipa_enable_data_path(ipa_ep_idx_rx); + if (result) { + IPAERR("enable data path failed res=%d clnt=%d.\n", result, + ipa_ep_idx_rx); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -EFAULT; + } + + result = ipa_enable_data_path(ipa_ep_idx_tx); + if (result) { + IPAERR("enable data path failed res=%d clnt=%d.\n", result, + ipa_ep_idx_tx); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -EFAULT; + } + + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + +fail: + return result; +} + +int ipa2_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) +{ + struct ipa_ep_context *ep_tx, *ep_rx; + int result = 0; + + IPADBG("ep_tx = %d\n", ipa_ep_idx_tx); + IPADBG("ep_rx = %d\n", ipa_ep_idx_rx); + + ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx]; + ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx]; + + /* suspend tx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx, + IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND)) { + IPAERR("fail to suspend tx pipe\n"); + result = -EFAULT; + goto fail; + } + + /* disable tx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx, + IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE)) { + IPAERR("fail to disable tx pipe\n"); + result = -EFAULT; + goto fail; + } + + /* suspend rx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx, + IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND)) { + IPAERR("fail to suspend rx pipe\n"); + result = -EFAULT; + goto fail; + } + + /* disable rx pipe */ + if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx, + IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE)) { + IPAERR("fail to disable rx pipe\n"); + result = -EFAULT; + goto fail; + } + +fail: + return result; +} diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index abff5aad1bccc2b5ecb8b807b93a0645a7c40031..3cafdece3bd1471f8996d021ada34b375b6bbd42 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -636,6 +636,8 @@ static int wwan_add_ul_flt_rule_to_ipa(void) return -ENOMEM; } + memset(req, 0, sizeof(struct ipa_fltr_installed_notif_req_msg_v01)); + param->commit = 1; param->ep = IPA_CLIENT_APPS_LAN_WAN_PROD; param->global = false; @@ -1114,8 +1116,9 @@ send: dev->stats.tx_bytes += skb->len; ret = NETDEV_TX_OK; out: - ipa_rm_inactivity_timer_release_resource( - IPA_RM_RESOURCE_WWAN_0_PROD); + if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) + ipa_rm_inactivity_timer_release_resource( + IPA_RM_RESOURCE_WWAN_0_PROD); return ret; } @@ -1167,10 +1170,12 @@ static void apps_ipa_tx_complete_notify(void *priv, wwan_ptr->outstanding_low); netif_wake_queue(wwan_ptr->net); } + + if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) + ipa_rm_inactivity_timer_release_resource( + IPA_RM_RESOURCE_WWAN_0_PROD); __netif_tx_unlock_bh(netdev_get_tx_queue(dev, 0)); dev_kfree_skb_any(skb); - ipa_rm_inactivity_timer_release_resource( - IPA_RM_RESOURCE_WWAN_0_PROD); } /** @@ -1401,8 +1406,8 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Get driver name */ case RMNET_IOCTL_GET_DRIVER_NAME: memcpy(&extend_ioctl_data.u.if_name, - ipa_netdevs[0]->name, - sizeof(IFNAMSIZ)); + ipa_netdevs[0]->name, IFNAMSIZ); + extend_ioctl_data.u.if_name[IFNAMSIZ - 1] = '\0'; if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data, &extend_ioctl_data, sizeof(struct rmnet_ioctl_extended_s))) @@ -1617,6 +1622,7 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) sizeof(wan_msg->upstream_ifname); strlcpy(wan_msg->upstream_ifname, extend_ioctl_data.u.if_name, len); + wan_msg->upstream_ifname[len - 1] = '\0'; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); msg_meta.msg_type = WAN_XLAT_CONNECT; msg_meta.msg_len = sizeof(struct ipa_wan_msg); @@ -2646,10 +2652,12 @@ int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, int pipe_len, rc; if (data != NULL) { + /* prevent string buffer overflows */ data->upstreamIface[IFNAMSIZ-1] = '\0'; data->tetherIface[IFNAMSIZ-1] = '\0'; - } else if (reset != false) { - /* Data can be NULL for reset stats, checking reset != False */ + } else if (reset == false) { + /* only reset can have data == NULL*/ + IPAWANERR("query without allocate tether_stats strucutre\n"); return -EINVAL; } @@ -2673,7 +2681,7 @@ int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, if (reset) { req->reset_stats_valid = true; req->reset_stats = true; - IPAWANERR("reset the pipe stats\n"); + IPAWANDBG("reset the pipe stats\n"); } else { /* print tethered-client enum */ if (data == NULL) @@ -2819,6 +2827,7 @@ int rmnet_ipa_query_tethering_stats_all( return rc; } + /** * ipa_broadcast_quota_reach_ind() - Send Netlink broadcast on Quota * @mux_id - The MUX ID on which the quota has been reached diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index a5b5c83ef61a53a40dba2b294a881beac1d3a3e4..fbcdbaa713546d91753d25b40b0b5db321aaca83 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -635,8 +635,8 @@ static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } -static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type, - bool is_cache) +static int ipa3_send_wan_msg(unsigned long usr_param, + uint8_t msg_type, bool is_cache) { int retval; struct ipa_wan_msg *wan_msg; @@ -2526,7 +2526,6 @@ static int ipa3_q6_set_ex_path_to_apps(void) struct ipahal_imm_cmd_register_write reg_write; struct ipahal_imm_cmd_pyld *cmd_pyld; int retval; - struct ipahal_reg_valmask valmask; desc = kcalloc(ipa3_ctx->ipa_num_pipes, sizeof(struct ipa3_desc), GFP_KERNEL); @@ -2541,40 +2540,10 @@ static int ipa3_q6_set_ex_path_to_apps(void) if (ep_idx == -1) continue; - if (ipa3_ctx->ep[ep_idx].valid && - ipa3_ctx->ep[ep_idx].skip_ep_cfg) { - BUG_ON(num_descs >= ipa3_ctx->ipa_num_pipes); - - reg_write.skip_pipeline_clear = false; - reg_write.pipeline_clear_options = - IPAHAL_HPS_CLEAR; - reg_write.offset = - ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n, - ep_idx); - ipahal_get_status_ep_valmask( - ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS), - &valmask); - reg_write.value = valmask.val; - reg_write.value_mask = valmask.mask; - cmd_pyld = ipahal_construct_imm_cmd( - IPA_IMM_CMD_REGISTER_WRITE, ®_write, false); - if (!cmd_pyld) { - IPAERR("fail construct register_write cmd\n"); - BUG(); - } - - desc[num_descs].opcode = ipahal_imm_cmd_get_opcode( - IPA_IMM_CMD_REGISTER_WRITE); - desc[num_descs].type = IPA_IMM_CMD_DESC; - desc[num_descs].callback = ipa3_destroy_imm; - desc[num_descs].user1 = cmd_pyld; - desc[num_descs].pyld = cmd_pyld->data; - desc[num_descs].len = cmd_pyld->len; - num_descs++; - } - - /* disable statuses for modem producers */ - if (IPA_CLIENT_IS_Q6_PROD(client_idx)) { + /* disable statuses for all modem controlled prod pipes */ + if (IPA_CLIENT_IS_Q6_PROD(client_idx) || + (ipa3_ctx->ep[ep_idx].valid && + ipa3_ctx->ep[ep_idx].skip_ep_cfg)) { ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes); reg_write.skip_pipeline_clear = false; @@ -2651,8 +2620,8 @@ void ipa3_q6_pre_shutdown_cleanup(void) BUG(); } /* Remove delay from Q6 PRODs to avoid pending descriptors - * on pipe reset procedure - */ + * on pipe reset procedure + */ ipa3_q6_pipe_delay(false); ipa3_set_reset_client_prod_pipe_delay(true, IPA_CLIENT_USB_PROD); @@ -4138,12 +4107,12 @@ void ipa3_suspend_handler(enum ipa_irq_type interrupt, } /** - * ipa3_restore_suspend_handler() - restores the original suspend IRQ handler - * as it was registered in the IPA init sequence. - * Return codes: - * 0: success - * -EPERM: failed to remove current handler or failed to add original handler - */ +* ipa3_restore_suspend_handler() - restores the original suspend IRQ handler +* as it was registered in the IPA init sequence. +* Return codes: +* 0: success +* -EPERM: failed to remove current handler or failed to add original handler +* */ int ipa3_restore_suspend_handler(void) { int result = 0; @@ -4602,6 +4571,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, ipa3_register_panic_hdlr(); ipa3_ctx->q6_proxy_clk_vote_valid = true; + ipa3_ctx->q6_proxy_clk_vote_cnt++; mutex_lock(&ipa3_ctx->lock); ipa3_ctx->ipa_initialization_complete = true; @@ -4632,7 +4602,7 @@ static void ipa3_post_init_wq(struct work_struct *work) static int ipa3_manual_load_ipa_fws(void) { int result; - const struct firmware *fw; + const struct firmware *fw = NULL; IPADBG("Manual FW loading process initiated\n"); @@ -4680,6 +4650,8 @@ static int ipa3_pil_load_ipa_fws(void) if (IS_ERR_OR_NULL(subsystem_get_retval)) { IPAERR("Unable to trigger PIL process for FW loading\n"); return -EINVAL; + } else { + subsystem_put(subsystem_get_retval); } IPADBG("PIL FW loading process is complete\n"); @@ -4704,6 +4676,9 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf, return -EFAULT; } + if (count > 0) + dbg_buff[count] = '\0'; + /* Prevent consequent calls from trying to load the FW again. */ if (ipa3_is_ready()) return count; @@ -4862,37 +4837,39 @@ static int ipa3_alloc_pkt_init(void) } /** - * ipa3_pre_init() - Initialize the IPA Driver. - * This part contains all initialization which doesn't require IPA HW, such - * as structure allocations and initializations, register writes, etc. - * - * @resource_p: contain platform specific values from DST file - * @pdev: The platform device structure representing the IPA driver - * - * Function initialization process: - * Allocate memory for the driver context data struct - * Initializing the ipa3_ctx with : - * 1)parsed values from the dts file - * 2)parameters passed to the module initialization - * 3)read HW values(such as core memory size) - * Map IPA core registers to CPU memory - * Restart IPA core(HW reset) - * Initialize the look-aside caches(kmem_cache/slab) for filter, - * routing and IPA-tree - * Create memory pool with 4 objects for DMA operations(each object - * is 512Bytes long), this object will be use for tx(A5->IPA) - * Initialize lists head(routing, hdr, system pipes) - * Initialize mutexes (for ipa_ctx and NAT memory mutexes) - * Initialize spinlocks (for list related to A5<->IPA pipes) - * Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq" - * Initialize Red-Black-Tree(s) for handles of header,routing rule, - * routing table ,filtering rule - * Initialize the filter block by committing IPV4 and IPV6 default rules - * Create empty routing table in system memory(no committing) - * Create a char-device for IPA - * Initialize IPA RM (resource manager) - * Configure GSI registers (in GSI case) - */ +* ipa3_pre_init() - Initialize the IPA Driver. +* This part contains all initialization which doesn't require IPA HW, such +* as structure allocations and initializations, register writes, etc. +* +* @resource_p: contain platform specific values from DST file +* @pdev: The platform device structure representing the IPA driver +* +* Function initialization process: +* * Allocate memory for the driver context data struct +* * Initializing the ipa3_ctx with: +* 1)parsed values from the dts file +* 2)parameters passed to the module initialization +* 3)read HW values(such as core memory size) +* * Map IPA core registers to CPU memory +* * Restart IPA core(HW reset) +* * Set configuration for IPA BAM via BAM_CNFG_BITS +* * Initialize the look-aside caches(kmem_cache/slab) for filter, +* routing and IPA-tree +* * Create memory pool with 4 objects for DMA operations(each object +* is 512Bytes long), this object will be use for tx(A5->IPA) +* * Initialize lists head(routing, hdr, system pipes) +* * Initialize mutexes (for ipa_ctx and NAT memory mutexes) +* * Initialize spinlocks (for list related to A5<->IPA pipes) +* * Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq" +* * Initialize Red-Black-Tree(s) for handles of header,routing rule, +* routing table ,filtering rule +* * Initialize the filter block by committing IPV4 and IPV6 default rules +* * Create empty routing table in system memory(no committing) +* * Initialize pipes memory pool with ipa3_pipe_mem_init for supported platforms +* * Create a char-device for IPA +* * Initialize IPA RM (resource manager) +* * Configure GSI registers (in GSI case) +*/ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, struct device *ipa_dev) { @@ -4912,7 +4889,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); if (ipa3_ctx->logbuf == NULL) - IPAERR("failed to create IPC log, continue...\n"); + IPADBG("failed to create IPC log, continue...\n"); ipa3_ctx->pdev = ipa_dev; ipa3_ctx->uc_pdev = ipa_dev; @@ -5236,6 +5213,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, mutex_init(&ipa3_ctx->nat_mem.lock); mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex); mutex_init(&ipa3_ctx->ipa_cne_evt_lock); + ipa3_ctx->q6_proxy_clk_vote_cnt = 0; idr_init(&ipa3_ctx->ipa_idr); spin_lock_init(&ipa3_ctx->idr_lock); @@ -5842,7 +5820,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) int bypass = 1; int fast = 1; int ret; - u32 iova_ap_mapping[2]; + u32 iova_ap_mapping[2] = {0}; IPADBG("UC CB PROBE sub pdev=%p\n", dev); @@ -5953,7 +5931,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) int atomic_ctx = 1; int fast = 1; int bypass = 1; - u32 iova_ap_mapping[2]; + u32 iova_ap_mapping[2] = {0}; u32 add_map_size; const u32 *add_map; void *smem_addr; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 9a6cda454435a9457a717aa595e7db785226f068..4ad2f1dd611b9a0f9b930174c5d8f2920428e7eb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -132,8 +132,8 @@ int ipa3_disable_data_path(u32 clnt_hdl) static int ipa3_smmu_map_peer_bam(unsigned long dev) { - phys_addr_t base; - u32 size; + phys_addr_t base = 0; + u32 size = 0; struct iommu_domain *smmu_domain; struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index a3b106143fa82502b400c9ecc811acb9469171b5..e461ce8bead137f951266b099781445b4323ad1b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -360,6 +360,8 @@ static ssize_t ipa3_read_hdr(struct file *file, char __user *ubuf, size_t count, list_for_each_entry(entry, &ipa3_ctx->hdr_tbl.head_hdr_entry_list, link) { + if (entry->cookie != IPA_HDR_COOKIE) + continue; nbytes = scnprintf( dbg_buff, IPA_MAX_MSG_LEN - 1, @@ -515,6 +517,15 @@ static int ipa3_attrib_dump(struct ipa_rule_attrib *attrib, if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) pr_err("tcp syn l2tp "); + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) + pr_err("l2tp inner ip type: %d ", attrib->type); + + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) { + addr[0] = htonl(attrib->u.v4.dst_addr); + mask[0] = htonl(attrib->u.v4.dst_addr_mask); + pr_err("dst_addr:%pI4 dst_addr_mask:%pI4 ", addr, mask); + } + pr_err("\n"); return 0; } @@ -539,7 +550,6 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->num_ihl_offset_range_16); return -EPERM; } - for (i = 0; i < attrib->num_ihl_offset_range_16; i++) { pr_err( "(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ", @@ -798,6 +808,7 @@ static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf, } } } + bail: mutex_unlock(&ipa3_ctx->lock); kfree(entry); @@ -901,7 +912,7 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, entry->rule.max_prio, entry->prio); if (eq) { res = ipa3_attrib_dump_eq( - &entry->rule.eq_attrib); + &entry->rule.eq_attrib); if (res) { IPAERR_RL("failed read attrib eq\n"); goto bail; @@ -1785,7 +1796,7 @@ static ssize_t ipa3_enable_ipc_low(struct file *file, "ipa_low", 0); } if (ipa_ipc_low_buff == NULL) - IPAERR("failed to get logbuf_low\n"); + IPADBG("failed to get logbuf_low\n"); ipa3_ctx->logbuf_low = ipa_ipc_low_buff; } else { ipa3_ctx->logbuf_low = NULL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index c362b69d87843e926d5e309c08afb5f3ee2f7941..4ebf4e80783beec2ad387755077e62cc7106b2b4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -1952,7 +1952,7 @@ static void ipa3_cleanup_wlan_rx_common_cache(void) &ipa3_ctx->wc_memb.wlan_comm_desc_list, link) { list_del(&rx_pkt->link); dma_unmap_single(ipa3_ctx->pdev, rx_pkt->data.dma_addr, - IPA_WLAN_COMM_RX_POOL_LOW, DMA_FROM_DEVICE); + IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE); dev_kfree_skb_any(rx_pkt->data.skb); kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt); ipa3_ctx->wc_memb.wlan_comm_free_cnt--; @@ -2246,6 +2246,9 @@ fail_provide_rx_buffer: dma_unmap_single(ipa3_ctx->pdev, rx_pkt->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); fail_dma_mapping: + /* Recycle skb before adding to recycle list if dma mapping failed */ + rx_pkt->data.dma_addr = 0; + ipa3_skb_recycle(rx_pkt->data.skb); spin_lock_bh(&sys->spinlock); list_add_tail(&rx_pkt->link, &sys->rcycl_list); INIT_LIST_HEAD(&rx_pkt->link); @@ -2915,10 +2918,12 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) struct ipa3_ep_context *ep; unsigned int src_pipe; u32 metadata; + u8 ucp; ipahal_pkt_status_parse(rx_skb->data, &status); src_pipe = status.endp_src_idx; metadata = status.metadata; + ucp = status.ucp; ep = &ipa3_ctx->ep[src_pipe]; if (unlikely(src_pipe >= ipa3_ctx->ipa_num_pipes || !ep->valid || @@ -2941,8 +2946,10 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) ------------------------------------------ */ *(u16 *)rx_skb->cb = ((metadata >> 16) & 0xFFFF); + *(u8 *)(rx_skb->cb + 4) = ucp; IPADBG_LOW("meta_data: 0x%x cb: 0x%x\n", metadata, *(u32 *)rx_skb->cb); + IPADBG_LOW("ucp: %d\n", *(u8 *)(rx_skb->cb + 4)); ep->client_notify(ep->priv, IPA_RECEIVE, (unsigned long)(rx_skb)); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index 822b183361ed9f2758371491f9331332c00e5340..e950fe2eff483673ee6110c86035e7097bf2f8a8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -220,7 +220,7 @@ static int ipa3_generate_flt_hw_rule(enum ipa_ip_type ip, hdr = (struct ipa3_flt_rule_hw_hdr *)buf; hdr->u.hdr.action = entry->rule.action; hdr->u.hdr.retain_hdr = entry->rule.retain_hdr; - if (entry->rt_tbl) + if (entry->rt_tbl && (!ipa3_check_idr_if_freed(entry->rt_tbl))) hdr->u.hdr.rt_tbl_idx = entry->rt_tbl->idx; else hdr->u.hdr.rt_tbl_idx = entry->rule.rt_tbl_idx; @@ -261,7 +261,7 @@ static int ipa3_generate_flt_hw_rule(enum ipa_ip_type ip, if (entry->hw_len == 0) { entry->hw_len = buf - start; } else if (entry->hw_len != (buf - start)) { - IPAERR("hw_len differs b/w passes passed=0x%x calc=0x%td\n", + IPAERR_RL("hw_len differs b/w passes passed=0x%x calc=0x%td\n", entry->hw_len, (buf - start)); return -EPERM; } @@ -634,7 +634,7 @@ static int ipa_generate_flt_hw_tbl_img(enum ipa_ip_type ip, } if (ipa_alloc_init_flt_tbl_hdr(ip, hash_hdr, nhash_hdr)) { - IPAERR("fail to alloc and init flt tbl hdr\n"); + IPAERR_RL("fail to alloc and init flt tbl hdr\n"); rc = -ENOMEM; goto no_flt_tbls; } @@ -684,13 +684,13 @@ static int ipa_generate_flt_hw_tbl_img(enum ipa_ip_type ip, if (ipa_translate_flt_tbl_to_hw_fmt(ip, IPA_RULE_HASHABLE, hash_bdy->base, hash_hdr->base, hash_bdy_start_ofst)) { - IPAERR("fail to translate hashable flt tbls to hw format\n"); + IPAERR_RL("fail to translate hashable flt tbls to hw format\n"); rc = -EPERM; goto translate_fail; } if (ipa_translate_flt_tbl_to_hw_fmt(ip, IPA_RULE_NON_HASHABLE, nhash_bdy->base, nhash_hdr->base, nhash_bdy_start_ofst)) { - IPAERR("fail to translate non-hash flt tbls to hw format\n"); + IPAERR_RL("fail to translate non-hash flt tbls to hw format\n"); rc = -EPERM; goto translate_fail; } @@ -872,7 +872,7 @@ int __ipa_commit_flt_v3(enum ipa_ip_type ip) if (ipa_generate_flt_hw_tbl_img(ip, &hash_hdr, &nhash_hdr, &hash_bdy, &nhash_bdy)) { - IPAERR("fail to generate FLT HW TBL image. IP %d\n", ip); + IPAERR_RL("fail to generate FLT HW TBL image. IP %d\n", ip); rc = -EFAULT; goto fail_gen; } @@ -1074,34 +1074,39 @@ static int __ipa_validate_flt_rule(const struct ipa_flt_rule *rule, if (rule->action != IPA_PASS_TO_EXCEPTION) { if (!rule->eq_attrib_type) { if (!rule->rt_tbl_hdl) { - IPAERR("invalid RT tbl\n"); + IPAERR_RL("invalid RT tbl\n"); goto error; } *rt_tbl = ipa3_id_find(rule->rt_tbl_hdl); if (*rt_tbl == NULL) { - IPAERR("RT tbl not found\n"); + IPAERR_RL("RT tbl not found\n"); goto error; } if ((*rt_tbl)->cookie != IPA_RT_TBL_COOKIE) { - IPAERR("RT table cookie is invalid\n"); + IPAERR_RL("RT table cookie is invalid\n"); goto error; } } else { if (rule->rt_tbl_idx > ((ip == IPA_IP_v4) ? IPA_MEM_PART(v4_modem_rt_index_hi) : IPA_MEM_PART(v6_modem_rt_index_hi))) { - IPAERR("invalid RT tbl\n"); + IPAERR_RL("invalid RT tbl\n"); goto error; } } + } else { + if (rule->rt_tbl_idx > 0) { + IPAERR("invalid RT tbl\n"); + goto error; + } } if (rule->rule_id) { - if (rule->rule_id >= IPA_RULE_ID_MIN_VAL && - rule->rule_id <= IPA_RULE_ID_MAX_VAL) { - IPAERR("invalid rule_id provided 0x%x\n" + if (rule->rule_id < IPA_RULE_ID_MIN || + rule->rule_id >= IPA_RULE_ID_MAX) { + IPAERR_RL("invalid rule_id provided 0x%x\n" "rule_id 0x%x - 0x%x are auto generated\n", rule->rule_id, IPA_RULE_ID_MIN_VAL, @@ -1137,8 +1142,8 @@ static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry, } else { id = ipa3_alloc_rule_id(&tbl->rule_ids); if (id < 0) { - IPAERR("failed to allocate rule id\n"); - WARN_ON(1); + IPAERR_RL("failed to allocate rule id\n"); + WARN_ON_RATELIMIT_IPA(1); goto rule_id_fail; } } @@ -1163,8 +1168,8 @@ static int __ipa_finish_flt_rule_add(struct ipa3_flt_tbl *tbl, entry->rt_tbl->ref_cnt++; id = ipa3_id_alloc(entry); if (id < 0) { - IPAERR("failed to add to tree\n"); - WARN_ON(1); + IPAERR_RL("failed to add to tree\n"); + WARN_ON_RATELIMIT_IPA(1); goto ipa_insert_failed; } *rule_hdl = id; @@ -1348,6 +1353,11 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule, goto error; } } + } else { + if (frule->rule.rt_tbl_idx > 0) { + IPAERR("invalid RT tbl\n"); + goto error; + } } entry->rule = frule->rule; @@ -1721,7 +1731,7 @@ int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only) list_for_each_entry_safe(entry, next, &tbl->head_flt_rule_list, link) { if (ipa3_id_find(entry->id) == NULL) { - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); mutex_unlock(&ipa3_ctx->lock); return -EFAULT; } @@ -1730,13 +1740,15 @@ int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only) entry->ipacm_installed) { list_del(&entry->link); entry->tbl->rule_cnt--; - if (entry->rt_tbl) + if (entry->rt_tbl && + (!ipa3_check_idr_if_freed( + entry->rt_tbl))) entry->rt_tbl->ref_cnt--; /* if rule id was allocated from idr, remove */ rule_id = entry->rule_id; id = entry->id; - if ((rule_id < ipahal_get_rule_id_hi_bit()) && - (rule_id >= ipahal_get_low_rule_id())) + if (rule_id >= IPA_RULE_ID_MIN_VAL && + rule_id <= IPA_RULE_ID_MAX_VAL) idr_remove(&entry->tbl->rule_ids, rule_id); entry->cookie = 0; @@ -1748,8 +1760,16 @@ int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only) } } } - mutex_unlock(&ipa3_ctx->lock); + /* commit the change to IPA-HW */ + if (ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v4) || + ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v6)) { + IPAERR("fail to commit flt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa3_ctx->lock); + return -EPERM; + } + mutex_unlock(&ipa3_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index 5fdcab2a5de3388db575c422698d4d040f190964..3d950c9cbcceb24fa3276c229993b287e104393a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -354,7 +354,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, } if (hdr_entry->cookie != IPA_HDR_COOKIE) { IPAERR_RL("Invalid header cookie %u\n", hdr_entry->cookie); - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); return -EINVAL; } IPADBG("Associated header is name=%s is_hdr_proc_ctx=%d\n", @@ -385,7 +385,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, bin = IPA_HDR_PROC_CTX_BIN1; } else { IPAERR_RL("unexpected needed len %d\n", needed_len); - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); goto bad_len; } @@ -432,8 +432,8 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, id = ipa3_id_alloc(entry); if (id < 0) { - IPAERR("failed to alloc id\n"); - WARN_ON(1); + IPAERR_RL("failed to alloc id\n"); + WARN_ON_RATELIMIT_IPA(1); goto ipa_insert_failed; } entry->id = id; @@ -572,8 +572,8 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr, bool user) id = ipa3_id_alloc(entry); if (id < 0) { - IPAERR("failed to alloc id\n"); - WARN_ON(1); + IPAERR_RL("failed to alloc id\n"); + WARN_ON_RATELIMIT_IPA(1); goto ipa_insert_failed; } entry->id = id; @@ -668,7 +668,6 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, return 0; } - int __ipa3_del_hdr(u32 hdr_hdl, bool by_user) { struct ipa3_hdr_entry *entry; @@ -1008,6 +1007,8 @@ int ipa3_reset_hdr(bool user_only) struct ipa_hdr_offset_entry *off_next; struct ipa3_hdr_proc_ctx_offset_entry *ctx_off_entry; struct ipa3_hdr_proc_ctx_offset_entry *ctx_off_next; + struct ipa3_hdr_tbl *htbl = &ipa3_ctx->hdr_tbl; + struct ipa3_hdr_proc_ctx_tbl *htbl_proc = &ipa3_ctx->hdr_proc_ctx_tbl; int i; /* @@ -1032,7 +1033,7 @@ int ipa3_reset_hdr(bool user_only) if (entry->is_hdr_proc_ctx) { IPAERR("default header is proc ctx\n"); mutex_unlock(&ipa3_ctx->lock); - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); return -EFAULT; } IPADBG("skip default header\n"); @@ -1042,7 +1043,7 @@ int ipa3_reset_hdr(bool user_only) if (ipa3_id_find(entry->id) == NULL) { mutex_unlock(&ipa3_ctx->lock); - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); return -EFAULT; } @@ -1053,50 +1054,51 @@ int ipa3_reset_hdr(bool user_only) entry->hdr_len, DMA_TO_DEVICE); entry->proc_ctx = NULL; + } else { + /* move the offset entry to free list */ + entry->offset_entry->ipacm_installed = 0; + list_move(&entry->offset_entry->link, + &htbl->head_free_offset_list[ + entry->offset_entry->bin]); } list_del(&entry->link); + htbl->hdr_cnt--; entry->ref_cnt = 0; entry->cookie = 0; - /* remove the handle from the database */ ipa3_id_remove(entry->id); kmem_cache_free(ipa3_ctx->hdr_cache, entry); } } - for (i = 0; i < IPA_HDR_BIN_MAX; i++) { - list_for_each_entry_safe(off_entry, off_next, + + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_BIN_MAX; i++) { + list_for_each_entry_safe(off_entry, off_next, &ipa3_ctx->hdr_tbl.head_offset_list[i], link) { - - /* - * do not remove the default exception header which is - * at offset 0 - */ - if (off_entry->offset == 0) - continue; - - if (!user_only || - off_entry->ipacm_installed) { + /** + * do not remove the default exception + * header which is at offset 0 + */ + if (off_entry->offset == 0) + continue; list_del(&off_entry->link); kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry); } - } - list_for_each_entry_safe(off_entry, off_next, + list_for_each_entry_safe(off_entry, off_next, &ipa3_ctx->hdr_tbl.head_free_offset_list[i], link) { - - if (!user_only || - off_entry->ipacm_installed) { list_del(&off_entry->link); kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry); } } + /* there is one header of size 8 */ + ipa3_ctx->hdr_tbl.end = 8; + ipa3_ctx->hdr_tbl.hdr_cnt = 1; } - /* there is one header of size 8 */ - ipa3_ctx->hdr_tbl.end = 8; - ipa3_ctx->hdr_tbl.hdr_cnt = 1; IPADBG("reset hdr proc ctx\n"); list_for_each_entry_safe( @@ -1107,13 +1109,18 @@ int ipa3_reset_hdr(bool user_only) if (ipa3_id_find(ctx_entry->id) == NULL) { mutex_unlock(&ipa3_ctx->lock); - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); return -EFAULT; } if (!user_only || ctx_entry->ipacm_installed) { + /* move the offset entry to appropriate free list */ + list_move(&ctx_entry->offset_entry->link, + &htbl_proc->head_free_offset_list[ + ctx_entry->offset_entry->bin]); list_del(&ctx_entry->link); + htbl_proc->proc_ctx_cnt--; ctx_entry->ref_cnt = 0; ctx_entry->cookie = 0; @@ -1123,36 +1130,40 @@ int ipa3_reset_hdr(bool user_only) ctx_entry); } } - for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i], link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa3_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); } - } - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, - &ipa3_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i], - link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + &ipa3_ctx->hdr_proc_ctx_tbl. + head_free_offset_list[i], link) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa3_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); } } + ipa3_ctx->hdr_proc_ctx_tbl.end = 0; + ipa3_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt = 0; } - ipa3_ctx->hdr_proc_ctx_tbl.end = 0; - ipa3_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt = 0; - mutex_unlock(&ipa3_ctx->lock); + /* commit the change to IPA-HW */ + if (ipa3_ctx->ctrl->ipa3_commit_hdr()) { + IPAERR("fail to commit hdr\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa3_ctx->lock); + return -EFAULT; + } + + mutex_unlock(&ipa3_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 4c69d2ce6599bba12dd8f6f2f9f0ea548f67f5b1..f6936c9cd6ff5575bf86305c56fdab31e045167f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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,8 +68,6 @@ #define IPA_PM_THRESHOLD_MAX 2 #define IPA_MAX_NUM_REQ_CACHE 10 -#define IPA_TIMEOUT(value) (msecs_to_jiffies(value * 1000)) - #define IPADBG(fmt, args...) \ do { \ pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\ @@ -102,7 +100,7 @@ #define IPAERR_RL(fmt, args...) \ do { \ - pr_err_ratelimited(DRV_NAME " %s:%d " fmt, __func__,\ + pr_err_ratelimited_ipa(DRV_NAME " %s:%d " fmt, __func__,\ __LINE__, ## args);\ if (ipa3_ctx) { \ IPA_IPC_LOGGING(ipa3_ctx->logbuf, \ @@ -209,6 +207,10 @@ #define IPA_RULE_ID_MAX_VAL (0x1FF) #define IPA_RULE_ID_RULE_MISS (0x3FF) +#define IPA_RULE_ID_MIN (0x200) +#define IPA_RULE_ID_MAX ((IPA_RULE_ID_MIN << 1) - 1) + + #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE 8 #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT(start_ofst) \ (((start_ofst) + IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE - 1) & \ @@ -1318,6 +1320,7 @@ struct ipa3_context { u32 curr_ipa_clk_rate; bool q6_proxy_clk_vote_valid; struct mutex q6_proxy_clk_vote_mutex; + u32 q6_proxy_clk_vote_cnt; u32 ipa_num_pipes; dma_addr_t pkt_init_imm[IPA3_MAX_NUM_PIPES]; @@ -2005,6 +2008,7 @@ int ipa3_enable_data_path(u32 clnt_hdl); int ipa3_disable_data_path(u32 clnt_hdl); int ipa3_alloc_rule_id(struct idr *rule_ids); int ipa3_id_alloc(void *ptr); +bool ipa3_check_idr_if_freed(void *ptr); void *ipa3_id_find(u32 id); void ipa3_id_remove(u32 id); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c index 73ef82cb3cb80f435f4afdd68716031a6cc54690..44fcecdacb412d2b7c7aad992dc0cc6c34c9ac39 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * 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,7 +222,7 @@ int ipa3_query_intf(struct ipa_ioc_query_intf *lookup) int result = -EINVAL; if (lookup == NULL) { - IPAERR("invalid param lookup=%p\n", lookup); + IPAERR_RL("invalid param lookup=%p\n", lookup); return result; } @@ -510,7 +510,7 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff, void *data = NULL; if (meta == NULL || (buff == NULL && callback != NULL) || - (buff != NULL && callback == NULL) || buff == NULL) { + (buff != NULL && callback == NULL)) { IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n", meta, buff, callback); return -EINVAL; @@ -740,6 +740,12 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, if (msg) { locked = 0; mutex_unlock(&ipa3_ctx->msg_lock); + if (count < sizeof(struct ipa_msg_meta)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } if (copy_to_user(buf, &msg->meta, sizeof(struct ipa_msg_meta))) { ret = -EFAULT; @@ -750,8 +756,15 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, buf += sizeof(struct ipa_msg_meta); count -= sizeof(struct ipa_msg_meta); if (msg->buff) { - if (copy_to_user(buf, msg->buff, - msg->meta.msg_len)) { + if (count >= msg->meta.msg_len) { + if (copy_to_user(buf, msg->buff, + msg->meta.msg_len)) { + ret = -EFAULT; + kfree(msg); + msg = NULL; + break; + } + } else { ret = -EFAULT; kfree(msg); msg = NULL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c index fde3d0dbaadd2bb2577827ffd343a7ed5727b014..890fe198b3909e15d4ea941e17ba4114ef9469a1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c @@ -382,6 +382,8 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("Detected overflow\n"); return -EPERM; } + mutex_lock(&ipa3_ctx->nat_mem.lock); + /* Check Table Entry offset is not beyond allocated size */ tmp = init->ipv4_rules_offset + @@ -391,6 +393,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->ipv4_rules_offset, (init->table_entries + 1), tmp, ipa3_ctx->nat_mem.size); + mutex_unlock(&ipa3_ctx->nat_mem.lock); return -EPERM; } @@ -398,6 +401,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) if (init->expn_rules_offset > (UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries))) { IPAERR_RL("Detected overflow\n"); + mutex_unlock(&ipa3_ctx->nat_mem.lock); return -EPERM; } /* Check Expn Table Entry offset is not @@ -409,6 +413,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->expn_rules_offset, init->expn_table_entries, tmp, ipa3_ctx->nat_mem.size); + mutex_unlock(&ipa3_ctx->nat_mem.lock); return -EPERM; } @@ -416,6 +421,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) if (init->index_offset > UINT_MAX - (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1))) { IPAERR_RL("Detected overflow\n"); + mutex_unlock(&ipa3_ctx->nat_mem.lock); return -EPERM; } /* Check Indx Table Entry offset is not @@ -427,6 +433,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_offset, (init->table_entries + 1), tmp, ipa3_ctx->nat_mem.size); + mutex_unlock(&ipa3_ctx->nat_mem.lock); return -EPERM; } @@ -434,6 +441,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) if (init->index_expn_offset > UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries)) { IPAERR_RL("Detected overflow\n"); + mutex_unlock(&ipa3_ctx->nat_mem.lock); return -EPERM; } /* Check Expn Table entry offset is not @@ -445,6 +453,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_expn_offset, init->expn_table_entries, tmp, ipa3_ctx->nat_mem.size); + mutex_unlock(&ipa3_ctx->nat_mem.lock); return -EPERM; } @@ -594,6 +603,7 @@ destroy_imm_cmd: free_nop: ipahal_destroy_imm_cmd(nop_cmd_pyld); bail: + mutex_unlock(&ipa3_ctx->nat_mem.lock); return result; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 277637c5005aead5a2731e168264971d66cc76ea..c6b026a57877f9a0da09f1d80b90fdd76e861401 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * 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 +28,7 @@ #define IPA_Q6_SVC_VERS 1 #define IPA_A5_SVC_VERS 1 -#define Q6_QMI_COMPLETION_TIMEOUT 60000 +#define Q6_QMI_COMPLETION_TIMEOUT (60*HZ) #define IPA_A5_SERVICE_SVC_ID 0x31 #define IPA_A5_SERVICE_INS_ID 1 @@ -600,6 +600,7 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) struct ipa_install_fltr_rule_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; int rc; + int i; /* check if modem up */ if (!ipa3_qmi_indication_fin || @@ -610,11 +611,44 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) } /* check if the filter rules from IPACM is valid */ - if (req->filter_spec_ex_list_len == 0) { + if (req->filter_spec_list_len == 0) { IPAWANDBG("IPACM pass zero rules to Q6\n"); } else { IPAWANDBG("IPACM pass %u rules to Q6\n", - req->filter_spec_ex_list_len); + req->filter_spec_list_len); + } + + if (req->filter_spec_list_len >= QMI_IPA_MAX_FILTERS_V01) { + IPAWANDBG( + "IPACM passes the number of filtering rules exceed limit\n"); + return -EINVAL; + } else if (req->source_pipe_index_valid != 0) { + IPAWANDBG( + "IPACM passes source_pipe_index_valid not zero 0 != %d\n", + req->source_pipe_index_valid); + return -EINVAL; + } else if (req->source_pipe_index >= ipa3_ctx->ipa_num_pipes) { + IPAWANDBG( + "IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } + for (i = 0; i < req->filter_spec_list_len; i++) { + if ((req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V4_V01) && + (req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V6_V01)) + return -EINVAL; + if (req->filter_spec_list[i].is_mux_id_valid == false) + return -EINVAL; + if (req->filter_spec_list[i].is_routing_table_index_valid + == false) + return -EINVAL; + if ((req->filter_spec_list[i].filter_action <= + QMI_IPA_FILTER_ACTION_INVALID_V01) && + (req->filter_spec_list[i].filter_action > + QMI_IPA_FILTER_ACTION_EXCEPTION_V01)) + return -EINVAL; } mutex_lock(&ipa3_qmi_lock); @@ -656,6 +690,7 @@ int ipa3_qmi_filter_request_ex_send( struct ipa_install_fltr_rule_resp_ex_msg_v01 resp; struct msg_desc req_desc, resp_desc; int rc; + int i; /* check if modem up */ if (!ipa3_qmi_indication_fin || @@ -673,6 +708,34 @@ int ipa3_qmi_filter_request_ex_send( req->filter_spec_ex_list_len); } + if (req->filter_spec_ex_list_len >= QMI_IPA_MAX_FILTERS_EX_V01) { + IPAWANDBG( + "IPACM pass the number of filtering rules exceed limit\n"); + return -EINVAL; + } else if (req->source_pipe_index_valid != 0) { + IPAWANDBG( + "IPACM passes source_pipe_index_valid not zero 0 != %d\n", + req->source_pipe_index_valid); + return -EINVAL; + } + + for (i = 0; i < req->filter_spec_ex_list_len; i++) { + if ((req->filter_spec_ex_list[i].ip_type != + QMI_IPA_IP_TYPE_V4_V01) && + (req->filter_spec_ex_list[i].ip_type != + QMI_IPA_IP_TYPE_V6_V01)) + return -EINVAL; + if (req->filter_spec_ex_list[i].is_mux_id_valid == false) + return -EINVAL; + if (req->filter_spec_ex_list[i].is_routing_table_index_valid + == false) + return -EINVAL; + if ((req->filter_spec_ex_list[i].filter_action <= + QMI_IPA_FILTER_ACTION_INVALID_V01) && + (req->filter_spec_ex_list[i].filter_action > + QMI_IPA_FILTER_ACTION_EXCEPTION_V01)) + return -EINVAL; + } mutex_lock(&ipa3_qmi_lock); if (ipa3_qmi_ctx != NULL) { /* cache the qmi_filter_request */ @@ -871,6 +934,32 @@ int ipa3_qmi_filter_notify_send( return -EINVAL; } + if (req->install_status != IPA_QMI_RESULT_SUCCESS_V01) { + IPAWANERR(" UL filter rule for pipe %d install_status = %d\n", + req->source_pipe_index, req->install_status); + return -EINVAL; + } else if (req->rule_id_valid != 1) { + IPAWANERR(" UL filter rule for pipe %d rule_id_valid = %d\n", + req->source_pipe_index, req->rule_id_valid); + return -EINVAL; + } else if (req->source_pipe_index >= ipa3_ctx->ipa_num_pipes) { + IPAWANDBG( + "IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } else if (((req->embedded_pipe_index_valid != true) || + (req->embedded_call_mux_id_valid != true)) && + ((req->embedded_pipe_index_valid != false) || + (req->embedded_call_mux_id_valid != false))) { + IPAWANERR( + "IPACM passes embedded pipe and mux valid not valid\n"); + return -EINVAL; + } else if (req->embedded_pipe_index >= ipa3_ctx->ipa_num_pipes) { + IPAWANERR("IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } + if (req->source_pipe_index == -1) { IPAWANERR("Source pipe index invalid\n"); return -EINVAL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 699b8e42cc8f77c3c5c1b7379b9e75f9d1524495..bcd60dbe949ffc77a8fc01b3807eed4b9625df81 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -70,13 +70,13 @@ int __ipa_generate_rt_hw_rule_v3_0(enum ipa_ip_type ip, rule_hdr = (struct ipa3_rt_rule_hw_hdr *)buf; pipe_idx = ipa3_get_ep_mapping(entry->rule.dst); if (pipe_idx == -1) { - IPAERR("Wrong destination pipe specified in RT rule\n"); + IPAERR_RL("Wrong destination pipe specified in RT rule\n"); WARN_ON(1); return -EPERM; } if (!IPA_CLIENT_IS_CONS(entry->rule.dst)) { - IPAERR("No RT rule on IPA_client_producer pipe.\n"); - IPAERR("pipe_idx: %d dst_pipe: %d\n", + IPAERR_RL("No RT rule on IPA_client_producer pipe.\n"); + IPAERR_RL("pipe_idx: %d dst_pipe: %d\n", pipe_idx, entry->rule.dst); WARN_ON(1); return -EPERM; @@ -106,6 +106,7 @@ int __ipa_generate_rt_hw_rule_v3_0(enum ipa_ip_type ip, struct ipa3_hdr_proc_ctx_entry *proc_ctx; proc_ctx = (entry->proc_ctx) ? : entry->hdr->proc_ctx; if ((proc_ctx == NULL) || + ipa3_check_idr_if_freed(proc_ctx) || (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) { rule_hdr->u.hdr.proc_ctx = 0; rule_hdr->u.hdr.hdr_offset = 0; @@ -199,7 +200,7 @@ static int ipa_translate_rt_tbl_to_hw_fmt(enum ipa_ip_type ip, dma_alloc_coherent(ipa3_ctx->pdev, tbl_mem.size, &tbl_mem.phys_base, GFP_KERNEL); if (!tbl_mem.base) { - IPAERR("fail to alloc DMA buf of size %d\n", + IPAERR_RL("fail to alloc DMA buf of size %d\n", tbl_mem.size); goto err; } @@ -226,7 +227,7 @@ static int ipa_translate_rt_tbl_to_hw_fmt(enum ipa_ip_type ip, entry, tbl_mem_buf); if (res) { - IPAERR("failed to gen HW RT rule\n"); + IPAERR_RL("failed to gen HW RT rule\n"); goto align_err; } tbl_mem_buf += entry->hw_len; @@ -263,7 +264,7 @@ static int ipa_translate_rt_tbl_to_hw_fmt(enum ipa_ip_type ip, entry, body_i); if (res) { - IPAERR("failed to gen HW RT rule\n"); + IPAERR_RL("failed to gen HW RT rule\n"); goto err; } body_i += entry->hw_len; @@ -426,7 +427,7 @@ static int ipa_prep_rt_tbl_for_cmt(enum ipa_ip_type ip, entry, NULL); if (res) { - IPAERR("failed to calculate HW RT rule size\n"); + IPAERR_RL("failed to calculate HW RT rule size\n"); return -EPERM; } @@ -441,8 +442,8 @@ static int ipa_prep_rt_tbl_for_cmt(enum ipa_ip_type ip, if ((tbl->sz[IPA_RULE_HASHABLE] + tbl->sz[IPA_RULE_NON_HASHABLE]) == 0) { - WARN_ON(1); - IPAERR("rt tbl %s is with zero total size\n", tbl->name); + WARN_ON_RATELIMIT_IPA(1); + IPAERR_RL("rt tbl %s is with zero total size\n", tbl->name); } if (tbl->sz[IPA_RULE_HASHABLE]) @@ -907,7 +908,8 @@ struct ipa3_rt_tbl *__ipa3_find_rt_tbl(enum ipa_ip_type ip, const char *name) set = &ipa3_ctx->rt_tbl_set[ip]; list_for_each_entry(entry, &set->head_rt_tbl_list, link) { - if (!strcmp(name, entry->name)) + if (!ipa3_check_idr_if_freed(entry) && + !strcmp(name, entry->name)) return entry; } @@ -1016,8 +1018,8 @@ static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip, id = ipa3_id_alloc(entry); if (id < 0) { - IPAERR("failed to add to tree\n"); - WARN_ON(1); + IPAERR_RL("failed to add to tree\n"); + WARN_ON_RATELIMIT_IPA(1); goto ipa_insert_failed; } entry->id = id; @@ -1056,7 +1058,7 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6]) ip = IPA_IP_v6; else { - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); return -EPERM; } @@ -1084,19 +1086,33 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) return 0; } +static int __ipa_rt_validate_rule_id(u16 rule_id) +{ + if (!rule_id) + return 0; + + if ((rule_id < IPA_RULE_ID_MIN) || + (rule_id >= IPA_RULE_ID_MAX)) { + IPAERR_RL("Invalid rule_id provided 0x%x\n", + rule_id); + return -EPERM; + } + + return 0; +} static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule, struct ipa3_hdr_entry **hdr, struct ipa3_hdr_proc_ctx_entry **proc_ctx) { if (rule->hdr_hdl && rule->hdr_proc_ctx_hdl) { - IPAERR("rule contains both hdr_hdl and hdr_proc_ctx_hdl\n"); + IPAERR_RL("rule contains both hdr_hdl and hdr_proc_ctx_hdl\n"); return -EPERM; } if (rule->hdr_hdl) { *hdr = ipa3_id_find(rule->hdr_hdl); if ((*hdr == NULL) || ((*hdr)->cookie != IPA_HDR_COOKIE)) { - IPAERR("rt rule does not point to valid hdr\n"); + IPAERR_RL("rt rule does not point to valid hdr\n"); return -EPERM; } } else if (rule->hdr_proc_ctx_hdl) { @@ -1104,7 +1120,7 @@ static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule, if ((*proc_ctx == NULL) || ((*proc_ctx)->cookie != IPA_PROC_HDR_COOKIE)) { - IPAERR("rt rule does not point to valid proc ctx\n"); + IPAERR_RL("rt rule does not point to valid proc ctx\n"); return -EPERM; } } @@ -1137,8 +1153,8 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry, } else { id = ipa3_alloc_rule_id(&tbl->rule_ids); if (id < 0) { - IPAERR("failed to allocate rule id\n"); - WARN_ON(1); + IPAERR_RL("failed to allocate rule id\n"); + WARN_ON_RATELIMIT_IPA(1); goto alloc_rule_id_fail; } } @@ -1165,8 +1181,8 @@ static int __ipa_finish_rt_rule_add(struct ipa3_rt_entry *entry, u32 *rule_hdl, entry->proc_ctx->ref_cnt++; id = ipa3_id_alloc(entry); if (id < 0) { - IPAERR("failed to add to tree\n"); - WARN_ON(1); + IPAERR_RL("failed to add to tree\n"); + WARN_ON_RATELIMIT_IPA(1); goto ipa_insert_failed; } IPADBG("add rt rule tbl_idx=%d rule_cnt=%d rule_id=%d\n", @@ -1199,6 +1215,8 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; + if (__ipa_rt_validate_rule_id(rule_id)) + goto error; tbl = __ipa_add_rt_tbl(ip, name); if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) { @@ -1207,13 +1225,12 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, goto error; } /* - * do not allow any rules to be added at end of the "default" routing - * tables + * do not allow any rule to be added at "default" routing + * table */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && - (tbl->rule_cnt > 0) && (at_rear != 0)) { - IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d at_rear=%d" - , tbl->rule_cnt, at_rear); + (tbl->rule_cnt > 0)) { + IPAERR_RL("cannot add rules to default rt table\n"); goto error; } @@ -1358,6 +1375,7 @@ int ipa3_add_rt_rule_ext(struct ipa_ioc_add_rt_rule_ext *rules) &rules->rules[i].rt_rule_hdl, rules->rules[i].rule_id, true)) { IPAERR_RL("failed to add rt rule %d\n", i); + rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; @@ -1435,13 +1453,12 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) } /* - * do not allow any rules to be added at end of the "default" routing - * tables + * do not allow any rule to be added at "default" routing + * table */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && - (&entry->link == tbl->head_rt_rule_list.prev)) { - IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d\n", - tbl->rule_cnt); + (tbl->rule_cnt > 0)) { + IPAERR_RL("cannot add rules to default rt table\n"); ret = -EINVAL; goto bail; } @@ -1648,6 +1665,8 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) struct ipa3_rt_entry *rule; struct ipa3_rt_entry *rule_next; struct ipa3_rt_tbl_set *rset; + struct ipa3_hdr_entry *hdr_entry; + struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; u32 apps_start_idx; int id; bool tbl_user = false; @@ -1680,7 +1699,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) list_for_each_entry_safe(rule, rule_next, &tbl->head_rt_rule_list, link) { if (ipa3_id_find(rule->id) == NULL) { - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); mutex_unlock(&ipa3_ctx->lock); return -EFAULT; } @@ -1701,14 +1720,41 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) if (!user_only || rule->ipacm_installed) { list_del(&rule->link); + if (rule->hdr) { + hdr_entry = ipa3_id_find( + rule->rule.hdr_hdl); + if (!hdr_entry || + hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR_RL( + "Header already deleted\n"); + return -EINVAL; + } + } else if (rule->proc_ctx && + (!ipa3_check_idr_if_freed( + rule->proc_ctx))) { + hdr_proc_entry = + ipa3_id_find( + rule->rule.hdr_proc_ctx_hdl); + if (!hdr_proc_entry || + hdr_proc_entry->cookie != + IPA_PROC_HDR_COOKIE) { + IPAERR_RL( + "Proc entry already deleted\n"); + return -EINVAL; + } + } tbl->rule_cnt--; if (rule->hdr) __ipa3_release_hdr(rule->hdr->id); - else if (rule->proc_ctx) + else if (rule->proc_ctx && + (!ipa3_check_idr_if_freed( + rule->proc_ctx))) __ipa3_release_hdr_proc_ctx( rule->proc_ctx->id); rule->cookie = 0; - idr_remove(&tbl->rule_ids, rule->rule_id); + if (!rule->rule_id_valid) + idr_remove(&tbl->rule_ids, + rule->rule_id); id = rule->id; kmem_cache_free(ipa3_ctx->rt_rule_cache, rule); @@ -1718,7 +1764,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) } if (ipa3_id_find(tbl->id) == NULL) { - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); mutex_unlock(&ipa3_ctx->lock); return -EFAULT; } @@ -1752,6 +1798,15 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) } } } + + /* commit the change to IPA-HW */ + if (ipa3_ctx->ctrl->ipa3_commit_rt(IPA_IP_v4) || + ipa3_ctx->ctrl->ipa3_commit_rt(IPA_IP_v6)) { + IPAERR("fail to commit rt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa3_ctx->lock); + return -EPERM; + } mutex_unlock(&ipa3_ctx->lock); return 0; @@ -1832,7 +1887,7 @@ int ipa3_put_rt_tbl(u32 rt_tbl_hdl) else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6]) ip = IPA_IP_v6; else { - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); result = -EINVAL; goto ret; } @@ -1864,7 +1919,6 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; struct ipa3_hdr_entry *hdr_entry; struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; - if (rtrule->rule.hdr_hdl) { hdr = ipa3_id_find(rtrule->rule.hdr_hdl); if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { @@ -1891,6 +1945,10 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) goto error; } + if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) { + IPAERR_RL("Default tbl rule cannot be modified\n"); + return -EINVAL; + } /* Adding check to confirm still * header entry present in header table or not */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c index 4cc8bebbffe302d422e94930730f1cff3517cec1..0c6d33c370ec7ff9434126d24e5a97e48dc5eb66 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c @@ -837,7 +837,7 @@ int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client) IPA_CLIENT_IS_PROD(ipa_client) ? "CONS" : "PROD", ep_idx); ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_RESET_PIPE, 0, - false, IPA_TIMEOUT(10)); + false, 10*HZ); return ret; } @@ -868,7 +868,7 @@ int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client) gsi_ep_info->ipa_gsi_chan_num); ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_GSI_CH_EMPTY, 0, - false, IPA_TIMEOUT(10)); + false, 10*HZ); return ret; } @@ -918,7 +918,7 @@ int ipa3_uc_update_hw_flags(u32 flags) memset(&cmd, 0, sizeof(cmd)); cmd.params.newFlags = flags; return ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_UPDATE_FLAGS, 0, - false, IPA_TIMEOUT(10)); + false, HZ); } /** @@ -983,7 +983,7 @@ int ipa3_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len) cmd->source_addr = src; cmd->source_buffer_size = len; res = ipa3_uc_send_cmd((u32)mem.phys_base, IPA_CPU_2_HW_CMD_MEMCPY, 0, - true, IPA_TIMEOUT(10)); + true, 10 * HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); goto free_coherent; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c index d2e5d5e021769facc72c2a5f18d57091885fa616..7949d91bd3a2bdf993a4cd32bcfe1e20e10dc302 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c @@ -656,7 +656,7 @@ int ipa3_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr, init_cmd_data->firstChannelIndex = first_ch_idx; init_cmd_data->firstEventRingIndex = first_evt_idx; res = ipa3_uc_send_cmd((u32)mem.phys_base, IPA_CPU_2_HW_CMD_MHI_INIT, 0, - false, IPA_TIMEOUT(1)); + false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, @@ -681,7 +681,7 @@ int ipa3_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr, msi_cmd->msiData = msi->data; msi_cmd->msiMask = msi->mask; res = ipa3_uc_send_cmd((u32)mem.phys_base, - IPA_CPU_2_HW_CMD_MHI_UPDATE_MSI, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_UPDATE_MSI, 0, false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, @@ -733,7 +733,7 @@ int ipa3_uc_mhi_init_channel(int ipa_ep_idx, int channelHandle, init_cmd.params.channelDirection = channelDirection; res = ipa3_uc_send_cmd(init_cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_INIT_CHANNEL, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_INIT_CHANNEL, 0, false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -770,7 +770,7 @@ int ipa3_uc_mhi_reset_channel(int channelHandle) cmd.params.requestedState = IPA_HW_MHI_CHANNEL_STATE_DISABLE; cmd.params.channelHandle = channelHandle; res = ipa3_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -806,7 +806,7 @@ int ipa3_uc_mhi_suspend_channel(int channelHandle) cmd.params.requestedState = IPA_HW_MHI_CHANNEL_STATE_SUSPEND; cmd.params.channelHandle = channelHandle; res = ipa3_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -843,7 +843,7 @@ int ipa3_uc_mhi_resume_channel(int channelHandle, bool LPTransitionRejected) cmd.params.channelHandle = channelHandle; cmd.params.LPTransitionRejected = LPTransitionRejected; res = ipa3_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_CHANGE_CHANNEL_STATE, 0, false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -875,7 +875,7 @@ int ipa3_uc_mhi_stop_event_update_channel(int channelHandle) ipa3_uc_mhi_ctx->expected_responseParams = cmd.raw32b; res = ipa3_uc_send_cmd(cmd.raw32b, - IPA_CPU_2_HW_CMD_MHI_STOP_EVENT_UPDATE, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_STOP_EVENT_UPDATE, 0, false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); goto disable_clks; @@ -905,7 +905,7 @@ int ipa3_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd) IPA_ACTIVE_CLIENTS_INC_SIMPLE(); res = ipa3_uc_send_cmd(cmd->raw32b, - IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO, 0, false, IPA_TIMEOUT(1)); + IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO, 0, false, HZ); if (res) { IPAERR("ipa3_uc_send_cmd failed %d\n", res); goto disable_clks; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c index c0509a1a663408bb33d2d17cba4bddc596bf7a33..5e4d49eb825d4983c4abb09633ed08a8b185004e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c @@ -250,7 +250,7 @@ static int ipa3_uc_send_ntn_setup_pipe_cmd( result = ipa3_uc_send_cmd((u32)(cmd.phys_base), IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP, IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) result = -EFAULT; @@ -414,7 +414,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, result = ipa3_uc_send_cmd((u32)(cmd.phys_base), IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN, IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { IPAERR("fail to tear down dl pipe\n"); result = -EFAULT; @@ -426,7 +426,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, result = ipa3_uc_send_cmd((u32)(cmd.phys_base), IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN, IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { IPAERR("fail to tear down ul pipe\n"); result = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 87d695f90b37aed00928d956ea76ff154cca1e09..9ceced0c924faa49e8443c2576031cafeeef1376 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -1167,7 +1167,7 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPA_CPU_2_HW_CMD_WDI_TX_SET_UP : IPA_CPU_2_HW_CMD_WDI_RX_SET_UP, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1256,7 +1256,7 @@ int ipa3_disconnect_wdi_pipe(u32 clnt_hdl) result = ipa3_uc_send_cmd(tear.raw32b, IPA_CPU_2_HW_CMD_WDI_TEAR_DOWN, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1314,7 +1314,7 @@ int ipa3_enable_wdi_pipe(u32 clnt_hdl) result = ipa3_uc_send_cmd(enable.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_ENABLE, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1431,7 +1431,7 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl) result = ipa3_uc_send_cmd(disable.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_DISABLE, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1491,7 +1491,7 @@ int ipa3_resume_wdi_pipe(u32 clnt_hdl) result = ipa3_uc_send_cmd(resume.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_RESUME, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1556,7 +1556,7 @@ int ipa3_suspend_wdi_pipe(u32 clnt_hdl) result = ipa3_uc_send_cmd(suspend.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_SUSPEND, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1587,7 +1587,7 @@ int ipa3_suspend_wdi_pipe(u32 clnt_hdl) result = ipa3_uc_send_cmd(suspend.raw32b, IPA_CPU_2_HW_CMD_WDI_CH_SUSPEND, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; @@ -1635,7 +1635,7 @@ int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id) result = ipa3_uc_send_cmd(qmap.raw32b, IPA_CPU_2_HW_CMD_WDI_RX_EXT_CFG, IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS, - false, IPA_TIMEOUT(10)); + false, 10*HZ); if (result) { result = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 6106243929f27cc4b45fe567e66f194bfd9e4b05..1a20241542a903453f58c7558ded539e12036462 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * 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 @@ -30,7 +30,7 @@ #define IPA_V3_5_CLK_RATE_NOMINAL (400 * 1000 * 1000UL) #define IPA_V3_5_CLK_RATE_TURBO (42640 * 10 * 1000UL) -#define IPA_V3_0_MAX_HOLB_TMR_VAL (4294967296 - 1) +#define IPA_MAX_HOLB_TMR_VAL (4294967296 - 1) #define IPA_V3_0_BW_THRESHOLD_TURBO_MBPS (1000) #define IPA_V3_0_BW_THRESHOLD_NOMINAL_MBPS (600) @@ -43,7 +43,7 @@ #define IPA_TAG_SLEEP_MIN_USEC (1000) #define IPA_TAG_SLEEP_MAX_USEC (2000) -#define IPA_FORCE_CLOSE_TAG_PROCESS_TIMEOUT IPA_TIMEOUT(10) +#define IPA_FORCE_CLOSE_TAG_PROCESS_TIMEOUT (10 * HZ) #define IPA_BCR_REG_VAL_v3_0 (0x00000001) #define IPA_BCR_REG_VAL_v3_5 (0x0000003B) #define IPA_AGGR_GRAN_MIN (1) @@ -2727,6 +2727,35 @@ static int ipa3_generate_hw_rule_ip6(u16 *en_rule, ihl_ofst_meq32 += 2; } + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + goto err; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 22 => offset of IP type after v6 header */ + extra = ipa3_write_8(22, extra); + rest = ipa3_write_32(0xF0000000, rest); + if (attrib->type == 0x40) + rest = ipa3_write_32(0x40000000, rest); + else + rest = ipa3_write_32(0x60000000, rest); + ihl_ofst_meq32++; + } + + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + goto err; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 38 => offset of inner IPv4 addr */ + extra = ipa3_write_8(38, extra); + rest = ipa3_write_32(attrib->u.v4.dst_addr_mask, rest); + rest = ipa3_write_32(attrib->u.v4.dst_addr, rest); + ihl_ofst_meq32++; + } + if (attrib->attrib_mask & IPA_FLT_META_DATA) { *en_rule |= IPA_METADATA_COMPARE; rest = ipa3_write_32(attrib->meta_data_mask, rest); @@ -3546,6 +3575,36 @@ int ipa3_generate_flt_eq_ip6(enum ipa_ip_type ip, ihl_ofst_meq32 += 2; } + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 22 => offset of inner IP type after v6 header */ + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 22; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = + 0xF0000000; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = + (u32)attrib->type << 24; + ihl_ofst_meq32++; + } + + if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) { + if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } + *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; + /* 38 => offset of inner IPv4 addr */ + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 38; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = + attrib->u.v4.dst_addr_mask; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = + attrib->u.v4.dst_addr; + ihl_ofst_meq32++; + } + if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) { if (ipa_ofst_meq32[ofst_meq32] == -1) { IPAERR("ran out of meq128 eq\n"); @@ -5326,6 +5385,7 @@ int ipa3_controller_static_bind(struct ipa3_controller *ctrl, ctrl->ipa_init_hdr = _ipa_init_hdr_v3_0; ctrl->ipa_generate_rt_hw_rule = __ipa_generate_rt_hw_rule_v3_0; + ctrl->max_holb_tmr_val = IPA_MAX_HOLB_TMR_VAL; return 0; } @@ -5374,6 +5434,22 @@ void *ipa3_id_find(u32 id) return ptr; } +bool ipa3_check_idr_if_freed(void *ptr) +{ + int id; + void *iter_ptr; + + spin_lock(&ipa3_ctx->idr_lock); + idr_for_each_entry(&ipa3_ctx->ipa_idr, iter_ptr, id) { + if ((uintptr_t)ptr == (uintptr_t)iter_ptr) { + spin_unlock(&ipa3_ctx->idr_lock); + return false; + } + } + spin_unlock(&ipa3_ctx->idr_lock); + return true; +} + void ipa3_id_remove(u32 id) { spin_lock(&ipa3_ctx->idr_lock); @@ -5748,7 +5824,9 @@ void ipa3_proxy_clk_unvote(void) mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex); if (ipa3_ctx->q6_proxy_clk_vote_valid) { IPA_ACTIVE_CLIENTS_DEC_SPECIAL("PROXY_CLK_VOTE"); - ipa3_ctx->q6_proxy_clk_vote_valid = false; + ipa3_ctx->q6_proxy_clk_vote_cnt--; + if (ipa3_ctx->q6_proxy_clk_vote_cnt == 0) + ipa3_ctx->q6_proxy_clk_vote_valid = false; } mutex_unlock(&ipa3_ctx->q6_proxy_clk_vote_mutex); } @@ -5764,8 +5842,10 @@ void ipa3_proxy_clk_vote(void) return; mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex); - if (!ipa3_ctx->q6_proxy_clk_vote_valid) { + if (!ipa3_ctx->q6_proxy_clk_vote_valid || + (ipa3_ctx->q6_proxy_clk_vote_cnt > 0)) { IPA_ACTIVE_CLIENTS_INC_SPECIAL("PROXY_CLK_VOTE"); + ipa3_ctx->q6_proxy_clk_vote_cnt++; ipa3_ctx->q6_proxy_clk_vote_valid = true; } mutex_unlock(&ipa3_ctx->q6_proxy_clk_vote_mutex); @@ -6322,7 +6402,7 @@ void ipa3_set_resorce_groups_min_max_limits(void) static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep) { - bool empty; + bool empty = 0; IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl); gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL); @@ -6834,8 +6914,8 @@ int ipa3_load_fws(const struct firmware *firmware, phys_addr_t gsi_mem_base) { const struct elf32_hdr *ehdr; const struct elf32_phdr *phdr; - unsigned long gsi_iram_ofst; - unsigned long gsi_iram_size; + unsigned long gsi_iram_ofst = 0; + unsigned long gsi_iram_size = 0; phys_addr_t ipa_reg_mem_base; u32 ipa_reg_ofst; int rc; @@ -6954,14 +7034,14 @@ bool ipa3_is_msm_device(void) } /** -* ipa3_disable_prefetch() - disable\enable tx prefetch -* -* @client: the client which is related to the TX where prefetch will be -* disabled -* -* Return value: Non applicable -* -*/ + * ipa3_disable_prefetch() - disable\enable tx prefetch + * + * @client: the client which is related to the TX where prefetch will be + * disabled + * + * Return value: Non applicable + * + */ void ipa3_disable_prefetch(enum ipa_client_type client) { struct ipahal_reg_tx_cfg cfg; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 407530173438ce2e99b8f65e0f7be2b538a1e8bc..7ee4adf4c70aefe85ca05d53158c01c9d38759a7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -1559,6 +1559,8 @@ void ipahal_get_aggr_force_close_valmask(int ep_idx, return; } + memset(valmask, 0, sizeof(struct ipahal_reg_valmask)); + if (ipahal_ctx->hw_type <= IPA_HW_v3_1) { shft = IPA_AGGR_FORCE_CLOSE_AGGR_FORCE_CLOSE_PIPE_BITMAP_SHFT; bmsk = IPA_AGGR_FORCE_CLOSE_AGGR_FORCE_CLOSE_PIPE_BITMAP_BMSK; @@ -1605,20 +1607,3 @@ void ipahal_get_fltrt_hash_flush_valmask( valmask->mask = valmask->val; } - -void ipahal_get_status_ep_valmask(int pipe_num, - struct ipahal_reg_valmask *valmask) -{ - if (!valmask) { - IPAHAL_ERR("Input error\n"); - return; - } - - valmask->val = - (pipe_num & IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK) << - IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT; - - valmask->mask = - IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK << - IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT; -} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h index ecb96e1d049fbf9f5096bf573f63dac6ed066e8c..f37ddd974f3bac0b7dfd9d840d4a16afbc370595 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h @@ -464,8 +464,6 @@ void ipahal_get_aggr_force_close_valmask(int ep_idx, void ipahal_get_fltrt_hash_flush_valmask( struct ipahal_reg_fltrt_hash_flush *flush, struct ipahal_reg_valmask *valmask); -void ipahal_get_status_ep_valmask(int pipe_num, - struct ipahal_reg_valmask *valmask); #endif /* _IPAHAL_REG_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 725ad4d2407695567e4a2ba4fe1c726ee1af5436..cdd928dfb3cf1ed4ac67f6301e1d9f4779566fca 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -667,6 +667,8 @@ static int ipa3_wwan_add_ul_flt_rule_to_ipa(void) param->global = false; param->num_rules = (uint8_t)1; + memset(req, 0, sizeof(struct ipa_fltr_installed_notif_req_msg_v01)); + for (i = 0; i < rmnet_ipa3_ctx->num_q6_rules; i++) { param->ip = ipa3_qmi_ctx->q6_ul_filter_rule[i].ip; memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); @@ -1538,8 +1540,8 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Get driver name */ case RMNET_IOCTL_GET_DRIVER_NAME: memcpy(&extend_ioctl_data.u.if_name, - IPA_NETDEV()->name, - sizeof(IFNAMSIZ)); + IPA_NETDEV()->name, IFNAMSIZ); + extend_ioctl_data.u.if_name[IFNAMSIZ - 1] = '\0'; if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data, &extend_ioctl_data, sizeof(struct rmnet_ioctl_extended_s))) @@ -1708,6 +1710,7 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) sizeof(wan_msg->upstream_ifname); strlcpy(wan_msg->upstream_ifname, extend_ioctl_data.u.if_name, len); + wan_msg->upstream_ifname[len-1] = '\0'; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); msg_meta.msg_type = WAN_XLAT_CONNECT; msg_meta.msg_len = sizeof(struct ipa_wan_msg); @@ -2807,10 +2810,12 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, int pipe_len, rc; if (data != NULL) { + /* prevent string buffer overflows */ data->upstreamIface[IFNAMSIZ-1] = '\0'; data->tetherIface[IFNAMSIZ-1] = '\0'; - } else if (reset != false) { - /* Data can be NULL for reset stats, checking reset != False */ + } else if (reset == false) { + /* only reset can have data == NULL */ + IPAWANERR("query without allocate tether_stats strucutre\n"); return -EINVAL; } @@ -2834,7 +2839,7 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, if (reset) { req->reset_stats_valid = true; req->reset_stats = true; - IPAWANERR("reset the pipe stats\n"); + IPAWANDBG("reset the pipe stats\n"); } else { /* print tethered-client enum */ if (data == NULL) @@ -3307,6 +3312,15 @@ int rmnet_ipa3_send_lan_client_msg( IPAWANERR("Can't allocate memory for tether_info\n"); return -ENOMEM; } + + if (data->client_event != IPA_PER_CLIENT_STATS_CONNECT_EVENT && + data->client_event != IPA_PER_CLIENT_STATS_DISCONNECT_EVENT) { + IPAWANERR("Wrong event given. Event:- %d\n", + data->client_event); + kfree(lan_client); + return -EINVAL; + } + data->lan_client.lanIface[IPA_RESOURCE_NAME_MAX-1] = '\0'; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); memcpy(lan_client, &data->lan_client, sizeof(struct ipa_lan_client_msg)); diff --git a/drivers/platform/msm/ipa/test/ipa_test_mhi.c b/drivers/platform/msm/ipa/test/ipa_test_mhi.c index b6da969342b7f57583c9cf1a485a32fbcef4979c..64340591d970066410e4af901de5000e3d55c935 100644 --- a/drivers/platform/msm/ipa/test/ipa_test_mhi.c +++ b/drivers/platform/msm/ipa/test/ipa_test_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -612,7 +612,8 @@ static int ipa_mhi_test_config_channel_context( p_events[ev_ring_idx].rp = (u32)event_ring_bufs[ev_ring_idx].phys_base; p_events[ev_ring_idx].wp = - (u32)event_ring_bufs[ev_ring_idx].phys_base; + (u32)event_ring_bufs[ev_ring_idx].phys_base + + event_ring_bufs[ev_ring_idx].size - 16; } else { IPA_UT_LOG("Skip configuring event ring - already done\n"); } @@ -905,8 +906,7 @@ static int ipa_mhi_test_initialize_driver(bool skip_start_and_conn) } IPA_UT_LOG("Wait async ready event\n"); - if (wait_for_completion_timeout(&mhi_test_ready_comp, - IPA_TIMEOUT(10)) == 0) { + if (wait_for_completion_timeout(&mhi_test_ready_comp, 10 * HZ) == 0) { IPA_UT_LOG("timeout waiting for READY event"); IPA_UT_TEST_FAIL_REPORT("failed waiting for state ready"); return -ETIME; @@ -1304,6 +1304,7 @@ static int ipa_mhi_test_q_transfer_re(struct ipa_mem_buffer *mmio, u32 next_wp_ofst; int i; u32 num_of_ed_to_queue; + u32 avail_ev; IPA_UT_LOG("Entry\n"); @@ -1341,6 +1342,8 @@ static int ipa_mhi_test_q_transfer_re(struct ipa_mem_buffer *mmio, wp_ofst = (u32)(p_events[event_ring_index].wp - p_events[event_ring_index].rbase); + rp_ofst = (u32)(p_events[event_ring_index].rp - + p_events[event_ring_index].rbase); if (p_events[event_ring_index].rlen & 0xFFFFFFFF00000000) { IPA_UT_LOG("invalid ev rlen %llu\n", @@ -1348,23 +1351,48 @@ static int ipa_mhi_test_q_transfer_re(struct ipa_mem_buffer *mmio, return -EFAULT; } - next_wp_ofst = (wp_ofst + num_of_ed_to_queue * - sizeof(struct ipa_mhi_event_ring_element)) % - (u32)p_events[event_ring_index].rlen; + if (wp_ofst > rp_ofst) { + avail_ev = (wp_ofst - rp_ofst) / + sizeof(struct ipa_mhi_event_ring_element); + } else { + avail_ev = (u32)p_events[event_ring_index].rlen - + (rp_ofst - wp_ofst); + avail_ev /= sizeof(struct ipa_mhi_event_ring_element); + } - /* set next WP */ - p_events[event_ring_index].wp = - (u32)p_events[event_ring_index].rbase + next_wp_ofst; + IPA_UT_LOG("wp_ofst=0x%x rp_ofst=0x%x rlen=%llu avail_ev=%u\n", + wp_ofst, rp_ofst, p_events[event_ring_index].rlen, avail_ev); + + if (num_of_ed_to_queue > ((u32)p_events[event_ring_index].rlen / + sizeof(struct ipa_mhi_event_ring_element))) { + IPA_UT_LOG("event ring too small for %u credits\n", + num_of_ed_to_queue); + return -EFAULT; + } - /* write value to event ring doorbell */ - IPA_UT_LOG("DB to event 0x%llx: base %pa ofst 0x%x\n", - p_events[event_ring_index].wp, - &(gsi_ctx->per.phys_addr), GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS( + if (num_of_ed_to_queue > avail_ev) { + IPA_UT_LOG("Need to add event credits (needed=%u)\n", + num_of_ed_to_queue - avail_ev); + + next_wp_ofst = (wp_ofst + (num_of_ed_to_queue - avail_ev) * + sizeof(struct ipa_mhi_event_ring_element)) % + (u32)p_events[event_ring_index].rlen; + + /* set next WP */ + p_events[event_ring_index].wp = + (u32)p_events[event_ring_index].rbase + next_wp_ofst; + + /* write value to event ring doorbell */ + IPA_UT_LOG("DB to event 0x%llx: base %pa ofst 0x%x\n", + p_events[event_ring_index].wp, + &(gsi_ctx->per.phys_addr), + GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS( event_ring_index + IPA_MHI_GSI_ER_START, 0)); - iowrite32(p_events[event_ring_index].wp, - test_mhi_ctx->gsi_mmio + - GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS( + iowrite32(p_events[event_ring_index].wp, + test_mhi_ctx->gsi_mmio + + GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS( event_ring_index + IPA_MHI_GSI_ER_START, 0)); + } for (i = 0; i < buf_array_size; i++) { /* calculate virtual pointer for current WP and RP */ @@ -1867,8 +1895,7 @@ static int ipa_mhi_test_suspend_aggr_open(bool force) IPA_UT_LOG("AFTER suspend\n"); if (force) { - if (!wait_for_completion_timeout(&mhi_test_wakeup_comp, - IPA_TIMEOUT(10))) { + if (!wait_for_completion_timeout(&mhi_test_wakeup_comp, HZ)) { IPA_UT_LOG("timeout waiting for wakeup event\n"); IPA_UT_TEST_FAIL_REPORT("timeout waitinf wakeup event"); return -ETIME; @@ -1983,8 +2010,7 @@ static int ipa_mhi_test_suspend_host_wakeup(void) return rc; } - if (wait_for_completion_timeout(&mhi_test_wakeup_comp, - IPA_TIMEOUT(10)) == 0) { + if (wait_for_completion_timeout(&mhi_test_wakeup_comp, HZ) == 0) { IPA_UT_LOG("timeout waiting for wakeup event\n"); IPA_UT_TEST_FAIL_REPORT("timeout waiting for wakeup event"); return -ETIME; @@ -3264,11 +3290,11 @@ IPA_UT_DEFINE_SUITE_START(mhi, "MHI for GSI", IPA_UT_ADD_TEST(suspend_resume_with_open_aggr, "several suspend/resume iterations with open aggregation frame", ipa_mhi_test_in_loop_suspend_resume_aggr_open, - true, IPA_HW_v3_0, IPA_HW_MAX), + true, IPA_HW_v3_0, IPA_HW_v3_5_1), IPA_UT_ADD_TEST(force_suspend_resume_with_open_aggr, "several force suspend/resume iterations with open aggregation frame", ipa_mhi_test_in_loop_force_suspend_resume_aggr_open, - true, IPA_HW_v3_0, IPA_HW_MAX), + true, IPA_HW_v3_0, IPA_HW_v3_5_1), IPA_UT_ADD_TEST(suspend_resume_with_host_wakeup, "several suspend and host wakeup resume iterations", ipa_mhi_test_in_loop_suspend_host_wakeup, diff --git a/drivers/platform/msm/ipa/test/ipa_ut_framework.c b/drivers/platform/msm/ipa/test/ipa_ut_framework.c index 3bf9ac11f2d10ecf01179bc5e776a5b123415dca..dfc8442e0862c0de30cbf665569fc133cfa5e9f3 100644 --- a/drivers/platform/msm/ipa/test/ipa_ut_framework.c +++ b/drivers/platform/msm/ipa/test/ipa_ut_framework.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * 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 @@ -215,6 +215,10 @@ static ssize_t ipa_ut_dbgfs_meta_test_write(struct file *file, IPA_UT_DBG("Entry\n"); mutex_lock(&ipa_ut_ctx->lock); + if (file == NULL) { + rc = -EFAULT; + goto unlock_mutex; + } suite = file->f_inode->i_private; ipa_assert_on(!suite); meta_type = (long)(file->private_data); @@ -470,6 +474,10 @@ static ssize_t ipa_ut_dbgfs_test_write(struct file *file, IPA_UT_DBG("Entry\n"); mutex_lock(&ipa_ut_ctx->lock); + if (file == NULL) { + rc = -EFAULT; + goto unlock_mutex; + } test = file->f_inode->i_private; ipa_assert_on(!test); diff --git a/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c index 6d9dc58cd5dfcb3a7360995f1946fa61a786bcd1..486e017b8328c7794fb3b55d382474cc62eac459 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c @@ -552,7 +552,8 @@ static uint64_t aggregate_bus_req(struct msm_bus_node_device_type *bus_dev, uint64_t max_ab = 0; uint64_t sum_ab = 0; - if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) { + if (!bus_dev || !bus_dev->node_info->bus_device || + !to_msm_bus_node(bus_dev->node_info->bus_device)) { MSM_BUS_ERR("Bus node pointer is Invalid"); goto exit_agg_bus_req; } @@ -1016,7 +1017,7 @@ static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata) src = pdata->usecase->vectors[i].src; dest = pdata->usecase->vectors[i].dst; - if ((src < 0) || (dest < 0)) { + if ((src < 0) || (dest < 0) || (src == dest)) { MSM_BUS_ERR("%s:Invalid src/dst.src %d dest %d", __func__, src, dest); goto exit_invalid_data; diff --git a/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c index 4c17f1cb4c0aaea0a05e3f9c6b787d8ed2efbb2e..f3722a5eb559ce1241461aeff1d3a23a85f4be0d 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c @@ -52,6 +52,13 @@ ssize_t bw_show(struct device *dev, struct device_attribute *attr, bus_node->lnode_list[i].lnode_ab[ACTIVE_CTX], bus_node->lnode_list[i].lnode_ib[DUAL_CTX], bus_node->lnode_list[i].lnode_ab[DUAL_CTX]); + trace_printk( + "[%d]:%s:Act_IB %llu Act_AB %llu Slp_IB %llu Slp_AB %llu\n", + i, bus_node->lnode_list[i].cl_name, + bus_node->lnode_list[i].lnode_ib[ACTIVE_CTX], + bus_node->lnode_list[i].lnode_ab[ACTIVE_CTX], + bus_node->lnode_list[i].lnode_ib[DUAL_CTX], + bus_node->lnode_list[i].lnode_ab[DUAL_CTX]); } off += scnprintf((buf + off), PAGE_SIZE, "Max_Act_IB %llu Sum_Act_AB %llu Act_Util_fact %d Act_Vrail_comp %d\n", @@ -65,6 +72,18 @@ ssize_t bw_show(struct device *dev, struct device_attribute *attr, bus_node->node_bw[DUAL_CTX].sum_ab, bus_node->node_bw[DUAL_CTX].util_used, bus_node->node_bw[DUAL_CTX].vrail_used); + trace_printk( + "Max_Act_IB %llu Sum_Act_AB %llu Act_Util_fact %d Act_Vrail_comp %d\n", + bus_node->node_bw[ACTIVE_CTX].max_ib, + bus_node->node_bw[ACTIVE_CTX].sum_ab, + bus_node->node_bw[ACTIVE_CTX].util_used, + bus_node->node_bw[ACTIVE_CTX].vrail_used); + trace_printk( + "Max_Slp_IB %llu Sum_Slp_AB %lluSlp_Util_fact %d Slp_Vrail_comp %d\n", + bus_node->node_bw[DUAL_CTX].max_ib, + bus_node->node_bw[DUAL_CTX].sum_ab, + bus_node->node_bw[DUAL_CTX].util_used, + bus_node->node_bw[DUAL_CTX].vrail_used); return off; } @@ -570,8 +589,7 @@ exit_disable_node_qos_clk: return ret; } -static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node, - bool *no_defer) +static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node) { struct msm_bus_node_device_type *bus_node = NULL; int i; @@ -584,13 +602,6 @@ static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node, } bus_node = to_msm_bus_node(node->node_info->bus_device); - if (!bus_node->num_node_qos_clks) { - MSM_BUS_DBG("%s: Num of clks is zero\n", __func__); - ret = -EINVAL; - *no_defer = true; - goto exit_enable_node_qos_clk; - } - for (i = 0; i < bus_node->num_node_qos_clks; i++) { if (!bus_node->node_qos_clks[i].enable_only_clk) { rounded_rate = @@ -696,16 +707,15 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data) if (node_dev->ap_owned && (node_dev->node_info->qos_params.mode) != -1) { - bool no_defer = false; if (bus_node_info->fabdev->bypass_qos_prg) goto exit_init_qos; - ret = msm_bus_enable_node_qos_clk(node_dev, &no_defer); + ret = msm_bus_enable_node_qos_clk(node_dev); if (ret < 0) { MSM_BUS_DBG("Can't Enable QoS clk %d\n", node_dev->node_info->id); - node_dev->node_info->defer_qos = !no_defer; + node_dev->node_info->defer_qos = true; goto exit_init_qos; } @@ -1002,10 +1012,8 @@ static struct device *msm_bus_device_init( bus_node = kzalloc(sizeof(struct msm_bus_node_device_type), GFP_KERNEL); if (!bus_node) { - MSM_BUS_ERR("%s:Bus node alloc failed\n", __func__); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; + ret = -ENOMEM; + goto err_device_init; } bus_dev = &bus_node->dev; device_initialize(bus_dev); @@ -1013,47 +1021,36 @@ static struct device *msm_bus_device_init( node_info = devm_kzalloc(bus_dev, sizeof(struct msm_bus_node_info_type), GFP_KERNEL); if (!node_info) { - MSM_BUS_ERR("%s:Bus node info alloc failed\n", __func__); - devm_kfree(bus_dev, bus_node); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; + ret = -ENOMEM; + goto err_put_device; } bus_node->node_info = node_info; bus_node->ap_owned = pdata->ap_owned; bus_dev->of_node = pdata->of_node; - if (msm_bus_copy_node_info(pdata, bus_dev) < 0) { - devm_kfree(bus_dev, bus_node); - devm_kfree(bus_dev, node_info); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; - } + ret = msm_bus_copy_node_info(pdata, bus_dev); + if (ret) + goto err_put_device; bus_dev->bus = &msm_bus_type; dev_set_name(bus_dev, bus_node->node_info->name); ret = device_add(bus_dev); - if (ret < 0) { + if (ret) { MSM_BUS_ERR("%s: Error registering device %d", __func__, pdata->node_info->id); - devm_kfree(bus_dev, bus_node); - devm_kfree(bus_dev, node_info->dev_connections); - devm_kfree(bus_dev, node_info->connections); - devm_kfree(bus_dev, node_info->black_connections); - devm_kfree(bus_dev, node_info->black_listed_connections); - devm_kfree(bus_dev, node_info); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; + goto err_put_device; } device_create_file(bus_dev, &dev_attr_bw); INIT_LIST_HEAD(&bus_node->devlist); - -exit_device_init: return bus_dev; +err_put_device: + put_device(bus_dev); + bus_dev = NULL; + kfree(bus_node); +err_device_init: + return ERR_PTR(ret); } static int msm_bus_setup_dev_conn(struct device *bus_dev, void *data) @@ -1248,10 +1245,10 @@ static int msm_bus_device_probe(struct platform_device *pdev) node_dev = msm_bus_device_init(&pdata->info[i]); - if (!node_dev) { + if (IS_ERR(node_dev)) { MSM_BUS_ERR("%s: Error during dev init for %d", __func__, pdata->info[i].node_info->id); - ret = -ENXIO; + ret = PTR_ERR(node_dev); goto exit_device_probe; } diff --git a/drivers/platform/msm/qpnp-haptic.c b/drivers/platform/msm/qpnp-haptic.c index 5ddd841a609eb9d983b5fb697aa804648254c2fa..0df6434fa8d92a596c723073f6cf8526955bfdb1 100644 --- a/drivers/platform/msm/qpnp-haptic.c +++ b/drivers/platform/msm/qpnp-haptic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * 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 @@ -343,9 +343,6 @@ struct qpnp_hap { struct qpnp_pwm_info pwm_info; struct mutex lock; struct mutex wf_lock; - struct mutex set_lock; - spinlock_t td_lock; - struct work_struct td_work; struct completion completion; enum qpnp_hap_mode play_mode; enum qpnp_hap_high_z lra_high_z; @@ -360,9 +357,6 @@ struct qpnp_hap { u32 timeout_ms; u32 time_required_to_generate_back_emf_us; u32 vmax_mv; - u32 vtg_min; - u32 vtg_max; - u32 vtg_default; u32 ilim_ma; u32 sc_deb_cycles; u32 int_pwm_freq_khz; @@ -399,7 +393,6 @@ struct qpnp_hap { bool correct_lra_drive_freq; bool misc_trim_error_rc19p2_clk_reg_present; bool perform_lra_auto_resonance_search; - int td_value; }; static struct qpnp_hap *ghap; @@ -792,16 +785,16 @@ static int qpnp_hap_vmax_config(struct qpnp_hap *hap) u8 reg = 0; int rc, temp; - if (hap->vmax_mv < hap->vtg_min) - hap->vmax_mv = hap->vtg_min; - else if (hap->vmax_mv > hap->vtg_max) - hap->vmax_mv = hap->vtg_max; + if (hap->vmax_mv < QPNP_HAP_VMAX_MIN_MV) + hap->vmax_mv = QPNP_HAP_VMAX_MIN_MV; + else if (hap->vmax_mv > QPNP_HAP_VMAX_MAX_MV) + hap->vmax_mv = QPNP_HAP_VMAX_MAX_MV; rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_VMAX_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_VMAX_MASK; - temp = hap->vmax_mv / hap->vtg_min; + temp = hap->vmax_mv / QPNP_HAP_VMAX_MIN_MV; reg |= (temp << QPNP_HAP_VMAX_SHIFT); rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_VMAX_REG(hap->base)); if (rc) @@ -1386,79 +1379,6 @@ static ssize_t qpnp_hap_ramp_test_data_show(struct device *dev, } -static ssize_t qpnp_hap_vmax_mv_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct timed_output_dev *timed_dev = dev_get_drvdata(dev); - struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, - timed_dev); - - return snprintf(buf, PAGE_SIZE, "%d\n", hap->vmax_mv); -} - -static ssize_t qpnp_hap_vmax_mv_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct timed_output_dev *timed_dev = dev_get_drvdata(dev); - struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, - timed_dev); - u32 data; - int rc; - - if (sscanf(buf, "%d", &data) != 1) - return -EINVAL; - - if (data < hap->vtg_min) { - pr_err("%s: mv %d not in range (%d - %d), using min.", __func__, data, - hap->vtg_min, hap->vtg_max); - data = hap->vtg_min; - } else if (data > hap->vtg_max) { - pr_err("%s: mv %d not in range (%d - %d), using max.", __func__, data, - hap->vtg_min, hap->vtg_max); - data = hap->vtg_max; - } - - hap->vmax_mv = data; - rc = qpnp_hap_vmax_config(hap); - if (rc) - pr_info("qpnp: error while writing vibration control register\n"); - - return strnlen(buf, count); -} - -static ssize_t qpnp_hap_min_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct timed_output_dev *timed_dev = dev_get_drvdata(dev); - struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, - timed_dev); - - return scnprintf(buf, PAGE_SIZE, "%d\n", hap->vtg_min); -} - -static ssize_t qpnp_hap_max_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct timed_output_dev *timed_dev = dev_get_drvdata(dev); - struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, - timed_dev); - - return scnprintf(buf, PAGE_SIZE, "%d\n", hap->vtg_max); -} - -static ssize_t qpnp_hap_default_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct timed_output_dev *timed_dev = dev_get_drvdata(dev); - struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, - timed_dev); - - return scnprintf(buf, PAGE_SIZE, "%d\n", hap->vtg_default); -} - /* sysfs attributes */ static struct device_attribute qpnp_hap_attrs[] = { __ATTR(wf_s0, (S_IRUGO | S_IWUSR | S_IWGRP), @@ -1506,18 +1426,6 @@ static struct device_attribute qpnp_hap_attrs[] = { __ATTR(min_max_test, (S_IRUGO | S_IWUSR | S_IWGRP), qpnp_hap_min_max_test_data_show, qpnp_hap_min_max_test_data_store), - __ATTR(vtg_level, (S_IRUGO | S_IWUSR | S_IWGRP), - qpnp_hap_vmax_mv_show, - qpnp_hap_vmax_mv_store), - __ATTR(vtg_min, S_IRUGO, - qpnp_hap_min_show, - NULL), - __ATTR(vtg_max, S_IRUGO, - qpnp_hap_max_show, - NULL), - __ATTR(vtg_default, S_IRUGO, - qpnp_hap_default_show, - NULL), }; static int calculate_lra_code(struct qpnp_hap *hap) @@ -1683,8 +1591,6 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) unsigned long timeout_ns = POLL_TIME_AUTO_RES_ERR_NS; u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us; - mutex_lock(&hap->set_lock); - if (hap->play_mode == QPNP_HAP_PWM) { if (on) rc = pwm_enable(hap->pwm_info.pwm_dev); @@ -1718,10 +1624,8 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) qpnp_hap_auto_res_enable(hap, 0); rc = qpnp_hap_mod_enable(hap, on); - if (rc < 0) { - mutex_unlock(&hap->set_lock); + if (rc < 0) return rc; - } rc = qpnp_hap_play(hap, on); @@ -1731,10 +1635,8 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) usleep_range(back_emf_delay_us, back_emf_delay_us + 1); rc = qpnp_hap_auto_res_enable(hap, 1); - if (rc < 0) { - mutex_unlock(&hap->set_lock); + if (rc < 0) return rc; - } } if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && @@ -1751,10 +1653,8 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) } } else { rc = qpnp_hap_play(hap, on); - if (rc < 0) { - mutex_unlock(&hap->set_lock); + if (rc < 0) return rc; - } if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && @@ -1771,25 +1671,14 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) } } - mutex_unlock(&hap->set_lock); return rc; } -static void qpnp_timed_enable_worker(struct work_struct *work) +/* enable interface from timed output class */ +static void qpnp_hap_td_enable(struct timed_output_dev *dev, int value) { - struct qpnp_hap *hap = container_of(work, struct qpnp_hap, - td_work); - int value; - - spin_lock(&hap->td_lock); - value = hap->td_value; - spin_unlock(&hap->td_lock); - - /* Vibrator already disabled */ - if (!value && !hap->state) - return; - - flush_work(&hap->work); + struct qpnp_hap *hap = container_of(dev, struct qpnp_hap, + timed_dev); mutex_lock(&hap->lock); @@ -1810,30 +1699,12 @@ static void qpnp_timed_enable_worker(struct work_struct *work) value = (value > hap->timeout_ms ? hap->timeout_ms : value); hap->state = 1; - } - mutex_unlock(&hap->lock); - if (hap->play_mode == QPNP_HAP_DIRECT) - qpnp_hap_set(hap, hap->state); - else - schedule_work(&hap->work); - - if (value) hrtimer_start(&hap->hap_timer, ktime_set(value / 1000, (value % 1000) * 1000000), HRTIMER_MODE_REL); -} - -/* enable interface from timed output class */ -static void qpnp_hap_td_enable(struct timed_output_dev *dev, int value) -{ - struct qpnp_hap *hap = container_of(dev, struct qpnp_hap, - timed_dev); - - spin_lock(&hap->td_lock); - hap->td_value = value; - spin_unlock(&hap->td_lock); - - schedule_work(&hap->td_work); + } + mutex_unlock(&hap->lock); + schedule_work(&hap->work); } /* play pwm bytes */ @@ -1952,10 +1823,6 @@ static enum hrtimer_restart qpnp_hap_timer(struct hrtimer *timer) struct qpnp_hap *hap = container_of(timer, struct qpnp_hap, hap_timer); - /* Vibrator already disabled */ - if (!hap->state) - return HRTIMER_NORESTART; - hap->state = 0; schedule_work(&hap->work); @@ -2523,33 +2390,6 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) return rc; } - hap->vtg_min = QPNP_HAP_VMAX_MIN_MV; - rc = of_property_read_u32(spmi->dev.of_node, - "qcom,hap-vtg-min-mv", &temp); - if (!rc) { - hap->vtg_min = temp; - } else if (rc != -EINVAL) { - dev_err(&spmi->dev, "Unable to read vtg_min\n"); - return rc; - } - - hap->vtg_max = QPNP_HAP_VMAX_MAX_MV; - rc = of_property_read_u32(spmi->dev.of_node, - "qcom,hap-vtg-max-mv", &temp); - if (!rc) { - hap->vtg_max = temp; - } else if (rc != -EINVAL) { - dev_err(&spmi->dev, "Unable to read vtg_max\n"); - return rc; - } - - if (hap->vmax_mv < hap->vtg_min) - hap->vmax_mv = hap->vtg_min; - else if (hap->vmax_mv > hap->vtg_max) - hap->vmax_mv = hap->vtg_max; - - hap->vtg_default = hap->vmax_mv; - hap->ilim_ma = QPNP_HAP_ILIM_MIN_MV; rc = of_property_read_u32(spmi->dev.of_node, "qcom,ilim-ma", &temp); @@ -2720,13 +2560,9 @@ static int qpnp_haptic_probe(struct spmi_device *spmi) mutex_init(&hap->lock); mutex_init(&hap->wf_lock); - mutex_init(&hap->set_lock); - spin_lock_init(&hap->td_lock); - INIT_WORK(&hap->work, qpnp_hap_worker); INIT_DELAYED_WORK(&hap->sc_work, qpnp_handle_sc_irq); init_completion(&hap->completion); - INIT_WORK(&hap->td_work, qpnp_timed_enable_worker); hrtimer_init(&hap->hap_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hap->hap_timer.function = qpnp_hap_timer; @@ -2815,6 +2651,16 @@ static int qpnp_haptic_remove(struct spmi_device *spmi) return 0; } +static void qpnp_haptic_shutdown(struct spmi_device *spmi) +{ + struct qpnp_hap *hap = dev_get_drvdata(&spmi->dev); + + cancel_work_sync(&hap->work); + + /* disable haptics */ + qpnp_hap_mod_enable(hap, false); +} + static struct of_device_id spmi_match_table[] = { { .compatible = "qcom,qpnp-haptic", }, { }, @@ -2828,6 +2674,7 @@ static struct spmi_driver qpnp_haptic_driver = { }, .probe = qpnp_haptic_probe, .remove = qpnp_haptic_remove, + .shutdown = qpnp_haptic_shutdown, }; static int __init qpnp_haptic_init(void) diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c index ac58ba30990bd7c364624c7b6eeae1843e5e1610..f7f0f739fbd7aa8be63908f2ece6ab94a08a2094 100644 --- a/drivers/platform/msm/qpnp-power-on.c +++ b/drivers/platform/msm/qpnp-power-on.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #define CREATE_MASK(NUM_BITS, POS) \ ((unsigned char) (((1 << (NUM_BITS)) - 1) << (POS))) @@ -207,6 +209,7 @@ struct qpnp_pon { struct list_head list; struct delayed_work bark_work; struct dentry *debugfs; + struct device_node *pbs_dev_node; int pon_trigger_reason; int pon_power_off_reason; int num_pon_reg; @@ -222,10 +225,13 @@ struct qpnp_pon { u8 pon_ver; u8 warm_reset_reason1; u8 warm_reset_reason2; + u8 twm_state; bool is_spon; bool store_hard_reset_reason; bool kpdpwr_dbc_enable; + bool support_twm_config; ktime_t kpdpwr_last_release_time; + struct notifier_block pon_nb; }; static struct qpnp_pon *sys_reset_dev; @@ -488,13 +494,53 @@ static ssize_t qpnp_pon_dbc_store(struct device *dev, return size; } +static struct qpnp_pon_config * +qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) +{ + int i; + + for (i = 0; i < pon->num_pon_config; i++) { + if (pon_type == pon->pon_cfg[i].pon_type) + return &pon->pon_cfg[i]; + } + + return NULL; +} + static DEVICE_ATTR(debounce_us, 0664, qpnp_pon_dbc_show, qpnp_pon_dbc_store); +#define PON_TWM_ENTRY_PBS_BIT BIT(0) static int qpnp_pon_reset_config(struct qpnp_pon *pon, enum pon_power_off_type type) { int rc; u16 rst_en_reg; + struct qpnp_pon_config *cfg; + + /* Ignore the PS_HOLD reset config if TWM ENTRY is enabled */ + if (pon->support_twm_config && pon->twm_state == PMIC_TWM_ENABLE) { + rc = qpnp_pbs_trigger_event(pon->pbs_dev_node, + PON_TWM_ENTRY_PBS_BIT); + if (rc < 0) { + pr_err("Unable to trigger PBS trigger for TWM entry rc=%d\n", + rc); + return rc; + } + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); + if (cfg) { + /* configure KPDPWR_S2 to Hard reset */ + rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr, + QPNP_PON_S2_CNTL_TYPE_MASK, + PON_POWER_OFF_HARD_RESET); + if (rc < 0) + pr_err("Unable to config KPDPWR_N S2 for hard-reset rc=%d\n", + rc); + } + + pr_crit("PMIC configured for TWM entry\n"); + return 0; + } if (pon->pon_ver == QPNP_PON_GEN1_V1) rst_en_reg = QPNP_PON_PS_HOLD_RST_CTL(pon); @@ -776,19 +822,6 @@ static int qpnp_pon_store_and_clear_warm_reset(struct qpnp_pon *pon) return 0; } -static struct qpnp_pon_config * -qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) -{ - int i; - - for (i = 0; i < pon->num_pon_config; i++) { - if (pon_type == pon->pon_cfg[i].pon_type) - return &pon->pon_cfg[i]; - } - - return NULL; -} - static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) { @@ -1984,6 +2017,35 @@ static int read_gen2_pon_off_reason(struct qpnp_pon *pon, u16 *reason, return 0; } +static int pon_twm_notifier_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct qpnp_pon *pon = container_of(nb, struct qpnp_pon, pon_nb); + + if (action != PMIC_TWM_CLEAR && + action != PMIC_TWM_ENABLE) { + pr_debug("Unsupported option %lu\n", action); + return NOTIFY_OK; + } + + pon->twm_state = (u8)action; + pr_debug("TWM state = %d\n", pon->twm_state); + + return NOTIFY_OK; +} + +static int pon_register_twm_notifier(struct qpnp_pon *pon) +{ + int rc; + + pon->pon_nb.notifier_call = pon_twm_notifier_cb; + rc = qpnp_misc_twm_notifier_register(&pon->pon_nb); + if (rc < 0) + pr_err("Failed to register pon_twm_notifier_cb rc=%d\n", rc); + + return rc; +} + static int qpnp_pon_probe(struct spmi_device *spmi) { struct qpnp_pon *pon; @@ -2241,6 +2303,22 @@ static int qpnp_pon_probe(struct spmi_device *spmi) return rc; } + if (of_property_read_bool(pon->spmi->dev.of_node, + "qcom,support-twm-config")) { + pon->support_twm_config = true; + rc = pon_register_twm_notifier(pon); + if (rc < 0) { + pr_err("Failed to register TWM notifier rc=%d\n", rc); + return rc; + } + pon->pbs_dev_node = of_parse_phandle(pon->spmi->dev.of_node, + "qcom,pbs-client", 0); + if (!pon->pbs_dev_node) { + pr_err("Missing qcom,pbs-client property\n"); + return -EINVAL; + } + } + rc = of_property_read_u32(pon->spmi->dev.of_node, "qcom,pon-dbc-delay", &delay); if (rc) { diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index 03cc14aa7e2918a94d13676e7befcddb9b6034ea..9c0ae05788f389d7836aba1cf6ed0c11404b2911 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * 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 @@ -677,7 +677,8 @@ int sps_get_bam_debug_info(unsigned long dev, u32 option, u32 para, /* Search for the target BAM device */ bam = sps_h2bam(dev); if (bam == NULL) { - pr_err("sps:Can't find any BAM with handle 0x%lx.", dev); + pr_err("sps:Can't find any BAM with handle 0x%pK.", + (void *)dev); mutex_unlock(&sps->lock); return SPS_ERROR; } @@ -1006,8 +1007,6 @@ static void sps_device_de_init(void) "sps:%s:BAMs are still registered", __func__); sps_map_de_init(); - - kfree(sps); } sps_mem_de_init(); @@ -1214,7 +1213,7 @@ struct sps_bam *sps_h2bam(unsigned long h) { struct sps_bam *bam; - SPS_DBG1(sps, "sps:%s: BAM handle:0x%lx.", __func__, h); + SPS_DBG1(sps, "sps:%s: BAM handle:0x%pK.", __func__, (void *)h); if (h == SPS_DEV_HANDLE_MEM || h == SPS_DEV_HANDLE_INVALID) return NULL; @@ -1224,7 +1223,7 @@ struct sps_bam *sps_h2bam(unsigned long h) return bam; } - SPS_ERR(sps, "sps:Can't find BAM device for handle 0x%lx.", h); + SPS_ERR(sps, "sps:Can't find BAM device for handle 0x%pK.", (void *)h); return NULL; } @@ -1329,16 +1328,17 @@ int sps_connect(struct sps_pipe *h, struct sps_connect *connect) bam = sps_h2bam(dev); if (bam == NULL) { - SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%lx", dev); + SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%pK", + (void *)dev); result = SPS_ERROR; goto exit_err; } mutex_lock(&bam->lock); - SPS_DBG2(bam, "sps:sps_connect: bam %pa src 0x%lx dest 0x%lx mode %s", + SPS_DBG2(bam, "sps:sps_connect: bam %pa src 0x%pK dest 0x%pK mode %s", BAM_ID(bam), - connect->source, - connect->destination, + (void *)connect->source, + (void *)connect->destination, connect->mode == SPS_MODE_SRC ? "SRC" : "DEST"); /* Allocate resources for the specified connection */ @@ -1402,10 +1402,10 @@ int sps_disconnect(struct sps_pipe *h) } SPS_DBG2(bam, - "sps:sps_disconnect: bam %pa src 0x%lx dest 0x%lx mode %s", + "sps:sps_disconnect: bam %pa src 0x%pK dest 0x%pK mode %s", BAM_ID(bam), - pipe->connect.source, - pipe->connect.destination, + (void *)pipe->connect.source, + (void *)pipe->connect.destination, pipe->connect.mode == SPS_MODE_SRC ? "SRC" : "DEST"); result = SPS_ERROR; @@ -1797,7 +1797,8 @@ int sps_device_reset(unsigned long dev) /* Search for the target BAM device */ bam = sps_h2bam(dev); if (bam == NULL) { - SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%lx", dev); + SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%pK", + (void *)dev); result = SPS_ERROR; goto exit_err; } @@ -1808,7 +1809,8 @@ int sps_device_reset(unsigned long dev) result = sps_bam_reset(bam); mutex_unlock(&bam->lock); if (result) { - SPS_ERR(sps, "sps:Fail to reset BAM device: 0x%lx", dev); + SPS_ERR(sps, "sps:Fail to reset BAM device: 0x%pK", + (void *)dev); goto exit_err; } @@ -2989,6 +2991,7 @@ static struct platform_driver msm_sps_driver = { .name = SPS_DRV_NAME, .owner = THIS_MODULE, .of_match_table = msm_sps_match, + .suppress_bind_attrs = true, }, .remove = msm_sps_remove, }; diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 908203b3fb641397a3600ebc2c7e5e36342994bd..12617af4ff8ed55b96c093d7a86d9a4c2c465048 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * 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 @@ -274,6 +274,7 @@ int sps_bam_enable(struct sps_bam *dev) int result; int rc; int MTIenabled; + unsigned long irq_arg = 0; /* Is this BAM enabled? */ if ((dev->state & BAM_STATE_ENABLED)) @@ -285,6 +286,9 @@ int sps_bam_enable(struct sps_bam *dev) return SPS_ERROR; } + if (dev->props.options & SPS_BAM_OPT_IRQ_NO_SUSPEND) + irq_arg = IRQF_NO_SUSPEND; + /* Set interrupt handling */ if ((dev->props.options & SPS_BAM_OPT_IRQ_DISABLED) != 0 || dev->props.irq == SPS_IRQ_INVALID) { @@ -297,14 +301,16 @@ int sps_bam_enable(struct sps_bam *dev) if (dev->props.options & SPS_BAM_RES_CONFIRM) { result = request_irq(dev->props.irq, (irq_handler_t) bam_isr, - IRQF_TRIGGER_RISING, "sps", dev); + (IRQF_TRIGGER_RISING | irq_arg), + "sps", dev); SPS_DBG3(dev, "sps:BAM %pa uses edge for IRQ# %d\n", BAM_ID(dev), dev->props.irq); } else { result = request_irq(dev->props.irq, (irq_handler_t) bam_isr, - IRQF_TRIGGER_HIGH, "sps", dev); + (IRQF_TRIGGER_HIGH | irq_arg), + "sps", dev); SPS_DBG3(dev, "sps:BAM %pa uses level for IRQ# %d\n", BAM_ID(dev), dev->props.irq); @@ -891,8 +897,8 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, else iova = bam_pipe->connect.source_iova; SPS_DBG2(dev, - "sps:BAM %pa pipe %d uses IOVA 0x%lx.\n", - BAM_ID(dev), pipe_index, iova); + "sps:BAM %pa pipe %d uses IOVA 0x%pK.\n", + BAM_ID(dev), pipe_index, (void *)iova); hw_params.peer_phys_addr = (u32)iova; } else { hw_params.peer_phys_addr = peer_bam->props.phys_addr; @@ -914,9 +920,9 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, hw_params.data_base = (phys_addr_t)bam_pipe->connect.data.iova; SPS_DBG2(dev, - "sps:BAM %pa pipe %d uses IOVA 0x%lx for data FIFO.\n", + "sps:BAM %pa pipe %d uses IOVA 0x%pK for data FIFO.\n", BAM_ID(dev), pipe_index, - bam_pipe->connect.data.iova); + (void *)(bam_pipe->connect.data.iova)); } else { hw_params.data_base = map->data.phys_base; } @@ -967,9 +973,9 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, hw_params.desc_base = (phys_addr_t)bam_pipe->connect.desc.iova; SPS_DBG2(dev, - "sps:BAM %pa pipe %d uses IOVA 0x%lx for desc FIFO.\n", + "sps:BAM %pa pipe %d uses IOVA 0x%pK for desc FIFO.\n", BAM_ID(dev), pipe_index, - bam_pipe->connect.desc.iova); + (void *)(bam_pipe->connect.desc.iova)); } else { hw_params.desc_base = map->desc.phys_base; } @@ -1419,8 +1425,9 @@ int sps_bam_pipe_transfer_one(struct sps_bam *dev, u32 next_write; static int show_recom; - SPS_DBG(dev, "sps:BAM %pa pipe %d addr 0x%x size 0x%x flags 0x%x\n", - BAM_ID(dev), pipe_index, addr, size, flags); + SPS_DBG(dev, "sps:BAM %pa pipe %d addr 0x%pK size 0x%x flags 0x%x\n", + BAM_ID(dev), pipe_index, + (void *)(long)addr, size, flags); /* Is this a BAM-to-BAM or satellite connection? */ if ((pipe->state & (BAM_STATE_BAM2BAM | BAM_STATE_REMOTE))) { @@ -1944,8 +1951,8 @@ static void pipe_handler_eot(struct sps_bam *dev, struct sps_pipe *pipe) user = &pipe->sys.user_ptrs[offset / sizeof(struct sps_iovec)]; for (;;) { SPS_DBG(dev, - "sps:%s; pipe index:%d; iovec addr:0x%x; size:0x%x; flags:0x%x; enabled:0x%x; *user is %s NULL.\n", - __func__, pipe->pipe_index, cache->addr, + "sps:%s; pipe index:%d; iovec addr:0x%pK; size:0x%x; flags:0x%x; enabled:0x%x; *user is %s NULL.\n", + __func__, pipe->pipe_index, (void *)(long)cache->addr, cache->size, cache->flags, enabled, (*user == NULL) ? "" : "not"); @@ -2233,8 +2240,8 @@ int sps_bam_pipe_get_iovec(struct sps_bam *dev, u32 pipe_index, pipe->sys.acked_offset = 0; SPS_DBG(dev, - "sps:%s; pipe index:%d; iovec addr:0x%x; size:0x%x; flags:0x%x; acked_offset:0x%x.\n", - __func__, pipe->pipe_index, desc->addr, + "sps:%s; pipe index:%d; iovec addr:0x%pK; size:0x%x; flags:0x%x; acked_offset:0x%x.\n", + __func__, pipe->pipe_index, (void *)(long)desc->addr, desc->size, desc->flags, pipe->sys.acked_offset); return 0; diff --git a/drivers/platform/msm/sps/sps_dma.c b/drivers/platform/msm/sps/sps_dma.c index 545a21e85203e416c2a5562fbe172335920f5c30..9385fa24202f1da42c26ad622f090299523fad54 100644 --- a/drivers/platform/msm/sps/sps_dma.c +++ b/drivers/platform/msm/sps/sps_dma.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2011-2013, 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, 2015, 2019 The Linux Foundation. + * All rights reserved. * * 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 @@ -380,7 +381,7 @@ int sps_dma_device_de_init(unsigned long h) dev = sps_dma_find_device(h); if (dev == NULL) { - SPS_ERR(sps, "sps:BAM-DMA: not registered: %lx", h); + SPS_ERR(sps, "sps:BAM-DMA: not registered: %pK", (void *)h); result = SPS_ERROR; goto exit_err; } @@ -546,8 +547,8 @@ int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc, dev = sps_dma_find_device(alloc->dev); if (dev == NULL) { - SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %lx", - alloc->dev); + SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK", + (void *)alloc->dev); goto exit_err; } @@ -620,7 +621,8 @@ int sps_free_dma_chan(struct sps_dma_chan *chan) dev = sps_dma_find_device(chan->dev); if (dev == NULL) { - SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %lx", chan->dev); + SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK", + (void *)chan->dev); result = SPS_ERROR; goto exit_err; } diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c index db36e64f96d8bb624be59de4b768b25dd4e8552b..3aee9090e4ac2d40c1ed95208f9fd9051b0f0a9d 100644 --- a/drivers/platform/msm/sps/sps_mem.c +++ b/drivers/platform/msm/sps/sps_mem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 2015, 2017, The Linux Foundation. +/* Copyright (c) 2011-2013, 2015, 2017, 2019, The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -75,8 +75,8 @@ phys_addr_t sps_mem_alloc_io(u32 bytes) return SPS_ADDR_INVALID; } - SPS_DBG3(sps, "sps:sps_mem_alloc_io.phys=%pa.virt=0x%lx.size=0x%x.", - &phys_addr, virt_addr, bytes); + SPS_DBG3(sps, "sps:sps_mem_alloc_io.phys=%pa.virt=0x%pK.size=0x%x.", + &phys_addr, (void *)virt_addr, bytes); return phys_addr; } @@ -92,8 +92,8 @@ void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes) iomem_offset = phys_addr - iomem_phys; virt_addr = (uintptr_t) iomem_virt + iomem_offset; - SPS_DBG3(sps, "sps:sps_mem_free_io.phys=%pa.virt=0x%lx.size=0x%x.", - &phys_addr, virt_addr, bytes); + SPS_DBG3(sps, "sps:sps_mem_free_io.phys=%pa.virt=0x%pK.size=0x%x.", + &phys_addr, (void *)virt_addr, bytes); gen_pool_free(pool, virt_addr, bytes); total_free += bytes; diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index db5db28d5f9ecdc737f629b5a17bb6c671c08264..176f8715e707e0b1a8ce6ba386763da6d364388e 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017, 2019, The Linux Foundation. + * All rights reserved. * * 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 @@ -380,8 +381,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) map->src.bam = sps_h2bam(map->src.dev); if (map->src.bam == NULL) { if (map->src.dev != SPS_DEV_HANDLE_MEM) { - SPS_ERR(sps, "sps:Invalid BAM handle: %pa", - &map->src.dev); + SPS_ERR(sps, "sps:Invalid BAM handle: %pK", + (void *)(&map->src.dev)); goto exit_err; } map->src.pipe_index = SPS_BAM_PIPE_INVALID; @@ -389,8 +390,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) map->dest.bam = sps_h2bam(map->dest.dev); if (map->dest.bam == NULL) { if (map->dest.dev != SPS_DEV_HANDLE_MEM) { - SPS_ERR(sps, "sps:Invalid BAM handle: %pa", - &map->dest.dev); + SPS_ERR(sps, "sps:Invalid BAM handle: %pK", + (void *)(&map->dest.dev)); goto exit_err; } map->dest.pipe_index = SPS_BAM_PIPE_INVALID; @@ -399,8 +400,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) /* Check the BAM device for the pipe */ if ((dir == SPS_MODE_SRC && map->src.bam == NULL) || (dir != SPS_MODE_SRC && map->dest.bam == NULL)) { - SPS_ERR(sps, "sps:Invalid BAM endpt: dir %d src %pa dest %pa", - dir, &map->src.dev, &map->dest.dev); + SPS_ERR(sps, "sps:Invalid BAM endpt: dir %d src %pK dest %pK", + dir, (void *)(&map->src.dev), (void *)(&map->dest.dev)); goto exit_err; } diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c deleted file mode 100644 index 6a2909b8c5f46a4138bdbbe6753bf8b68e59502f..0000000000000000000000000000000000000000 --- a/drivers/platform/msm/ssm.c +++ /dev/null @@ -1,516 +0,0 @@ -/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. - * - * 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. - */ -/* - * QTI Secure Service Module(SSM) driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../misc/qseecom_kernel.h" -#include "ssm.h" - -/* Macros */ -#define SSM_DEV_NAME "ssm" -#define MPSS_SUBSYS 0 -#define SSM_INFO_CMD_ID 1 -#define MAX_APP_NAME_SIZE 32 -#define SSM_MSG_LEN 200 -#define SSM_MSG_FIELD_LEN 11 -#define ATOM_MSG_LEN (SSM_MSG_FIELD_LEN + SSM_MSG_LEN + 40) - -#define TZAPP_NAME "SsmApp" -#define CHANNEL_NAME "SSM_RTR_MODEM_APPS" - -/* SSM driver structure.*/ -struct ssm_driver { - int32_t app_status; - int32_t update_status; - unsigned char *channel_name; - unsigned char *smd_buffer; - struct device *dev; - smd_channel_t *ch; - struct work_struct ipc_work; - struct mutex mutex; - struct qseecom_handle *qseecom_handle; - struct tzapp_get_mode_info_rsp *resp; - bool key_status; - bool ready; -}; - -static struct ssm_driver *ssm_drv; - -static unsigned int getint(char *buff, unsigned long *res) -{ - char value[SSM_MSG_FIELD_LEN]; - - memcpy(value, buff, SSM_MSG_FIELD_LEN); - value[SSM_MSG_FIELD_LEN - 1] = '\0'; - - return kstrtoul(skip_spaces(value), 10, res); -} - -/* - * Setup CMD/RSP pointers. - */ -static void setup_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd, - int *cmd_len, void **resp, int *resp_len) -{ - *cmd = handle->sbuf; - if (*cmd_len & QSEECOM_ALIGN_MASK) - *cmd_len = QSEECOM_ALIGN(*cmd_len); - - *resp = handle->sbuf + *cmd_len; - if (*resp_len & QSEECOM_ALIGN_MASK) - *resp_len = QSEECOM_ALIGN(*resp_len); -} - -/* - * Send packet to modem over SMD channel. - */ -static int update_modem(enum ssm_ipc_req ipc_req, struct ssm_driver *ssm, - int length, char *data) -{ - unsigned int packet_len = length + SSM_MSG_FIELD_LEN; - int rc = 0, count; - - snprintf(ssm->smd_buffer, SSM_MSG_FIELD_LEN + 1, "%10u|", ipc_req); - memcpy(ssm->smd_buffer + SSM_MSG_FIELD_LEN, data, length); - - if (smd_write_avail(ssm->ch) < packet_len) { - dev_err(ssm->dev, "Not enough space dropping request\n"); - rc = -ENOSPC; - goto out; - } - - count = smd_write(ssm->ch, ssm->smd_buffer, packet_len); - if (count < packet_len) { - dev_err(ssm->dev, "smd_write failed for %d\n", ipc_req); - rc = -EIO; - } - -out: - return rc; -} - -/* - * Header Format - * Each member of header is of 10 byte (ASCII). - * Each entry is separated by '|' delimiter. - * |<-10 bytes->|<-10 bytes->| - * |-------------------------| - * | IPC code | error code | - * |-------------------------| - * - */ -static int decode_packet(char *buffer, struct ssm_common_msg *pkt) -{ - int rc; - - rc = getint(buffer, (unsigned long *)&pkt->ipc_req); - if (rc < 0) - return -EINVAL; - - buffer += SSM_MSG_FIELD_LEN; - rc = getint(buffer, (unsigned long *)&pkt->err_code); - if (rc < 0) - return -EINVAL; - - dev_dbg(ssm_drv->dev, "req %d error code %d\n", - pkt->ipc_req, pkt->err_code); - return 0; -} - -static void process_message(struct ssm_common_msg pkt, struct ssm_driver *ssm) -{ - - switch (pkt.ipc_req) { - - case SSM_MTOA_MODE_UPDATE_STATUS: - if (pkt.err_code) { - dev_err(ssm->dev, "Modem mode update failed\n"); - ssm->update_status = FAILED; - } else - ssm->update_status = SUCCESS; - - dev_dbg(ssm->dev, "Modem mode update status %d\n", - pkt.err_code); - break; - - default: - dev_dbg(ssm->dev, "Invalid message\n"); - break; - }; -} - -/* - * Work function to handle and process packets coming from modem. - */ -static void ssm_app_modem_work_fn(struct work_struct *work) -{ - int sz, rc; - struct ssm_common_msg pkt; - struct ssm_driver *ssm; - - ssm = container_of(work, struct ssm_driver, ipc_work); - - mutex_lock(&ssm->mutex); - sz = smd_cur_packet_size(ssm->ch); - if ((sz < SSM_MSG_FIELD_LEN) || (sz > ATOM_MSG_LEN)) { - dev_dbg(ssm_drv->dev, "Garbled message size\n"); - goto unlock; - } - - if (smd_read_avail(ssm->ch) < sz) { - dev_err(ssm_drv->dev, "SMD error data in channel\n"); - goto unlock; - } - - if (smd_read(ssm->ch, ssm->smd_buffer, sz) != sz) { - dev_err(ssm_drv->dev, "Incomplete data\n"); - goto unlock; - } - - rc = decode_packet(ssm->smd_buffer, &pkt); - if (rc < 0) { - dev_err(ssm_drv->dev, "Corrupted header\n"); - goto unlock; - } - - process_message(pkt, ssm); - -unlock: - mutex_unlock(&ssm->mutex); -} - -/* - * MODEM-APPS smd channel callback function. - */ -static void modem_request(void *ctxt, unsigned event) -{ - struct ssm_driver *ssm; - - ssm = (struct ssm_driver *)ctxt; - - switch (event) { - case SMD_EVENT_OPEN: - case SMD_EVENT_CLOSE: - dev_dbg(ssm->dev, "SMD port status changed\n"); - break; - case SMD_EVENT_DATA: - if (smd_read_avail(ssm->ch) > 0) - schedule_work(&ssm->ipc_work); - break; - }; -} - -/* - * Load SSM application in TZ and start application: - */ -static int ssm_load_app(struct ssm_driver *ssm) -{ - int rc; - - /* Load the APP */ - rc = qseecom_start_app(&ssm->qseecom_handle, TZAPP_NAME, SZ_4K); - if (rc < 0) { - dev_err(ssm->dev, "Unable to load SSM app\n"); - ssm->app_status = FAILED; - return -EIO; - } - - ssm->app_status = SUCCESS; - return 0; -} - -static struct ssm_platform_data *populate_ssm_pdata(struct device *dev) -{ - struct ssm_platform_data *pdata; - - pdata = devm_kzalloc(dev, sizeof(struct ssm_platform_data), - GFP_KERNEL); - if (!pdata) - return NULL; - - pdata->need_key_exchg = - of_property_read_bool(dev->of_node, "qcom,need-keyexhg"); - - pdata->channel_name = CHANNEL_NAME; - - return pdata; -} - -static int ssm_probe(struct platform_device *pdev) -{ - int rc; - struct ssm_platform_data *pdata; - struct ssm_driver *drv; - - if (pdev->dev.of_node) - pdata = populate_ssm_pdata(&pdev->dev); - else - pdata = pdev->dev.platform_data; - - if (!pdata) { - dev_err(&pdev->dev, "Empty platform data\n"); - return -ENOMEM; - } - - drv = devm_kzalloc(&pdev->dev, sizeof(struct ssm_driver), - GFP_KERNEL); - if (!drv) - return -ENOMEM; - - /* Allocate response buffer */ - drv->resp = devm_kzalloc(&pdev->dev, - sizeof(struct tzapp_get_mode_info_rsp), - GFP_KERNEL); - if (!drv->resp) { - devm_kfree(&pdev->dev, drv); - rc = -ENOMEM; - goto exit; - } - - /* Initialize the driver structure */ - drv->app_status = RETRY; - drv->ready = false; - drv->update_status = FAILED; - mutex_init(&drv->mutex); - drv->key_status = !pdata->need_key_exchg; - drv->channel_name = (char *)pdata->channel_name; - INIT_WORK(&drv->ipc_work, ssm_app_modem_work_fn); - - /* Allocate memory for smd buffer */ - drv->smd_buffer = devm_kzalloc(&pdev->dev, - (sizeof(char) * ATOM_MSG_LEN), GFP_KERNEL); - if (!drv->smd_buffer) { - devm_kfree(&pdev->dev, drv->resp); - devm_kfree(&pdev->dev, drv); - rc = -ENOMEM; - goto exit; - } - - drv->dev = &pdev->dev; - ssm_drv = drv; - platform_set_drvdata(pdev, ssm_drv); - - dev_dbg(&pdev->dev, "probe success\n"); - return 0; - -exit: - mutex_destroy(&drv->mutex); - platform_set_drvdata(pdev, NULL); - return rc; - -} - -static int ssm_remove(struct platform_device *pdev) -{ - - if (!ssm_drv) - return 0; - /* - * Step to exit - * 1. set ready to 0 (oem access closed). - * 2. Close SMD modem connection closed. - * 3. cleanup ion. - */ - ssm_drv->ready = false; - smd_close(ssm_drv->ch); - flush_work(&ssm_drv->ipc_work); - - /* Shutdown tzapp */ - dev_dbg(&pdev->dev, "Shutting down TZapp\n"); - qseecom_shutdown_app(&ssm_drv->qseecom_handle); - - /* freeing the memory allocations - for the driver and the buffer */ - devm_kfree(&pdev->dev, ssm_drv->smd_buffer); - devm_kfree(&pdev->dev, ssm_drv->resp); - devm_kfree(&pdev->dev, ssm_drv); - - return 0; -} - -static struct of_device_id ssm_match_table[] = { - { - .compatible = "qcom,ssm", - }, - {} -}; - -static struct platform_driver ssm_pdriver = { - .probe = ssm_probe, - .remove = ssm_remove, - .driver = { - .name = SSM_DEV_NAME, - .owner = THIS_MODULE, - .of_match_table = ssm_match_table, - }, -}; -module_platform_driver(ssm_pdriver); - -/* - * Interface for external OEM driver. - * This interface supports following functionalities: - * 1. Set mode (encrypted mode and it's length is passed as parameter). - * 2. Set mode from TZ (read encrypted mode from TZ) - * 3. Get status of mode update. - * - */ -int ssm_oem_driver_intf(int cmd, char *mode, int len) -{ - int rc, req_len, resp_len; - struct tzapp_get_mode_info_req *get_mode_req; - struct tzapp_get_mode_info_rsp *get_mode_resp; - - /* If ssm_drv is NULL, probe failed */ - if (!ssm_drv) - return -ENODEV; - - mutex_lock(&ssm_drv->mutex); - - if (ssm_drv->app_status == RETRY) { - /* Load TZAPP */ - rc = ssm_load_app(ssm_drv); - if (rc) { - rc = -ENODEV; - goto unlock; - } - } else if (ssm_drv->app_status == FAILED) { - rc = -ENODEV; - goto unlock; - } - - /* Open modem SMD interface */ - if (!ssm_drv->ready) { - rc = smd_named_open_on_edge(ssm_drv->channel_name, - SMD_APPS_MODEM, - &ssm_drv->ch, - ssm_drv, - modem_request); - if (rc) { - rc = -EAGAIN; - goto unlock; - } else - ssm_drv->ready = true; - } - - /* Try again modem key-exchange not yet done.*/ - if (!ssm_drv->key_status) { - rc = -EAGAIN; - goto unlock; - } - - /* Set return status to success */ - rc = 0; - - switch (cmd) { - case SSM_READY: - break; - - case SSM_MODE_INFO_READY: - ssm_drv->update_status = RETRY; - /* Fill command structure */ - req_len = sizeof(struct tzapp_get_mode_info_req); - resp_len = sizeof(struct tzapp_get_mode_info_rsp); - setup_cmd_rsp_buffers(ssm_drv->qseecom_handle, - (void **)&get_mode_req, &req_len, - (void **)&get_mode_resp, &resp_len); - get_mode_req->tzapp_ssm_cmd = GET_ENC_MODE; - - rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 1); - if (rc) { - ssm_drv->update_status = FAILED; - dev_err(ssm_drv->dev, "set bandwidth failed\n"); - rc = -EIO; - break; - } - rc = qseecom_send_command(ssm_drv->qseecom_handle, - (void *)get_mode_req, req_len, - (void *)get_mode_resp, resp_len); - if (rc || get_mode_resp->status) { - ssm_drv->update_status = FAILED; - break; - } - rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 0); - if (rc) { - ssm_drv->update_status = FAILED; - dev_err(ssm_drv->dev, "clear bandwidth failed\n"); - rc = -EIO; - break; - } - - if (get_mode_resp->enc_mode_len > ENC_MODE_MAX_SIZE) { - ssm_drv->update_status = FAILED; - rc = -EINVAL; - break; - } - /* Send mode_info to modem */ - rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv, - get_mode_resp->enc_mode_len, - get_mode_resp->enc_mode_info); - if (rc) - ssm_drv->update_status = FAILED; - break; - - case SSM_SET_MODE: - ssm_drv->update_status = RETRY; - - if (len > ENC_MODE_MAX_SIZE) { - ssm_drv->update_status = FAILED; - rc = -EINVAL; - break; - } - memcpy(ssm_drv->resp->enc_mode_info, mode, len); - ssm_drv->resp->enc_mode_len = len; - - /* Send mode_info to modem */ - rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv, - ssm_drv->resp->enc_mode_len, - ssm_drv->resp->enc_mode_info); - if (rc) - ssm_drv->update_status = FAILED; - break; - - case SSM_GET_MODE_STATUS: - rc = ssm_drv->update_status; - break; - - default: - rc = -EINVAL; - dev_err(ssm_drv->dev, "Invalid command\n"); - break; - }; - -unlock: - mutex_unlock(&ssm_drv->mutex); - return rc; -} - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("QTI Secure Service Module"); - diff --git a/drivers/platform/msm/ssm.h b/drivers/platform/msm/ssm.h deleted file mode 100644 index ee4f1bc1d83f3284c79fc51bf97f3c0c53f290ef..0000000000000000000000000000000000000000 --- a/drivers/platform/msm/ssm.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef __SSM_H_ -#define __SSM_H_ - -#define MAX_APP_NAME_SIZE 32 -#define ENC_MODE_MAX_SIZE 200 - -/* tzapp response.*/ -enum tz_response { - RESULT_SUCCESS = 0, - RESULT_FAILURE = 0xFFFFFFFF, -}; - -/* tzapp command list.*/ -enum tz_commands { - ENC_MODE, - GET_ENC_MODE, - KEY_EXCHANGE = 11, -}; - -/* MODEM/SSM command list.*/ -enum ssm_ipc_req { - SSM_IPC_MIN = 0x0000AAAB, - SSM_ATOM_MODE_UPDATE, - SSM_MTOA_MODE_UPDATE_STATUS = SSM_IPC_MIN + 4, - SSM_INVALID_REQ, -}; - -/* OEM request commands list.*/ -enum oem_req { - SSM_READY, - SSM_MODE_INFO_READY, - SSM_SET_MODE, - SSM_GET_MODE_STATUS, - SSM_INVALID, -}; - -/* Modem mode update status.*/ -enum modem_mode_status { - SUCCESS, - RETRY, - FAILED = -1, -}; - -/* tzapp encode mode request.*/ -__packed struct tzapp_mode_enc_req { - uint32_t tzapp_ssm_cmd; - uint8_t mode_info[4]; -}; - -/* tzapp encode mode response.*/ -__packed struct tzapp_mode_enc_rsp { - uint32_t tzapp_ssm_cmd; - uint8_t enc_mode_info[ENC_MODE_MAX_SIZE]; - uint32_t enc_mode_len; - uint32_t status; -}; - -/* tzapp get mode request.*/ -__packed struct tzapp_get_mode_info_req { - uint32_t tzapp_ssm_cmd; -}; - -/* tzapp get mode response.*/ -__packed struct tzapp_get_mode_info_rsp { - uint32_t tzapp_ssm_cmd; - uint8_t enc_mode_info[ENC_MODE_MAX_SIZE]; - uint32_t enc_mode_len; - uint32_t status; -}; - -/* Modem/SSM packet format.*/ -struct ssm_common_msg { - enum ssm_ipc_req ipc_req; - int err_code; - -}; - -#endif diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index abdaed34c7285116ffb573102880d55fafdfa8c1..f13b5b95c00f4e5f2304b99132f4fa38bd37c76d 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -99,6 +99,15 @@ static const struct dmi_system_id asus_quirks[] = { */ .driver_data = &quirk_asus_wapf4, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X302UA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"), + }, + .driver_data = &quirk_asus_wapf4, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. X401U", @@ -356,6 +365,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ + { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ { KE_END, 0}, }; diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index ab7860a21a2258925c9ff4c6b3621dd59bbbcf78..4709206e5eed8e8f644ed29803d2f5c2f4458913 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -551,6 +551,7 @@ static const struct platform_device_id therm_id_table[] = { { "msic_thermal", 1 }, { } }; +MODULE_DEVICE_TABLE(platform, therm_id_table); static struct platform_driver mid_thermal_driver = { .driver = { diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index ab6151f054204c46063ad824b14985c97e3b934c..c0b64e571a5ec06f0fc695db2969d14dd75f7631 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -41,6 +41,7 @@ #define TOSHIBA_ACPI_VERSION "0.20" #define PROC_INTERFACE_VERSION 1 +#include #include #include #include @@ -1233,7 +1234,7 @@ static const struct file_operations keys_proc_fops = { .write = keys_proc_write, }; -static int version_proc_show(struct seq_file *m, void *v) +static int __maybe_unused version_proc_show(struct seq_file *m, void *v) { seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); diff --git a/drivers/power/fg-core.h b/drivers/power/fg-core.h index 1db904ba4713e5c62c1aeb1aa31ef92125fddb1d..604d4bd69db7f98765126aaeb122159a9a7420cc 100644 --- a/drivers/power/fg-core.h +++ b/drivers/power/fg-core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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,8 +24,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -50,6 +52,7 @@ #define SRAM_WRITE "fg_sram_write" #define PROFILE_LOAD "fg_profile_load" #define DELTA_SOC "fg_delta_soc" +#define FG_ESR_VOTER "fg_esr_voter" /* Delta BSOC irq votable reasons */ #define DELTA_BSOC_IRQ_VOTER "fg_delta_bsoc_irq" @@ -94,6 +97,11 @@ enum fg_debug_flag { FG_TTF = BIT(8), /* Show time to full */ }; +enum awake_reasons { + FG_SW_ESR_WAKE = BIT(0), + FG_STATUS_NOTIFY_WAKE = BIT(1), +}; + /* SRAM access */ enum sram_access_flags { FG_IMA_DEFAULT = 0, @@ -165,9 +173,11 @@ enum fg_sram_param_id { FG_SRAM_SYS_TERM_CURR, FG_SRAM_CHG_TERM_CURR, FG_SRAM_CHG_TERM_BASE_CURR, + FG_SRAM_CUTOFF_CURR, FG_SRAM_DELTA_MSOC_THR, FG_SRAM_DELTA_BSOC_THR, FG_SRAM_RECHARGE_SOC_THR, + FG_SRAM_SYNC_SLEEP_THR, FG_SRAM_RECHARGE_VBATT_THR, FG_SRAM_KI_COEFF_MED_DISCHG, FG_SRAM_KI_COEFF_HI_DISCHG, @@ -233,12 +243,16 @@ struct fg_dt_props { bool force_load_profile; bool hold_soc_while_full; bool auto_recharge_soc; + bool use_esr_sw; + bool disable_esr_pull_dn; + bool disable_fg_twm; int cutoff_volt_mv; int empty_volt_mv; int vbatt_low_thr_mv; int chg_term_curr_ma; int chg_term_base_curr_ma; int sys_term_curr_ma; + int cutoff_curr_ma; int delta_soc_thr; int recharge_soc_thr; int recharge_volt_thr_mv; @@ -246,6 +260,7 @@ struct fg_dt_props { int esr_timer_charging[NUM_ESR_TIMERS]; int esr_timer_awake[NUM_ESR_TIMERS]; int esr_timer_asleep[NUM_ESR_TIMERS]; + int esr_timer_shutdown[NUM_ESR_TIMERS]; int rconn_mohms; int esr_clamp_mohms; int cl_start_soc; @@ -265,6 +280,8 @@ struct fg_dt_props { int slope_limit_temp; int esr_pulse_thresh_ma; int esr_meas_curr_ma; + int ki_coeff_full_soc_dischg; + int sync_sleep_threshold_ma; int jeita_thresholds[NUM_JEITA_LEVELS]; int ki_coeff_soc[KI_COEFF_SOC_LEVELS]; int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS]; @@ -374,20 +391,24 @@ struct fg_chip { struct fg_batt_props bp; struct fg_cyc_ctr_data cyc_ctr; struct notifier_block nb; + struct notifier_block twm_nb; struct fg_cap_learning cl; + struct alarm esr_sw_timer; struct mutex bus_lock; struct mutex sram_rw_lock; struct mutex batt_avg_lock; struct mutex charge_full_lock; + spinlock_t awake_lock; u32 batt_soc_base; u32 batt_info_base; u32 mem_if_base; u32 rradc_base; u32 wa_flags; + u32 esr_wakeup_ms; + u32 awake_status; int batt_id_ohms; int ki_coeff_full_soc; int charge_status; - int prev_charge_status; int charge_done; int charge_type; int last_soc; @@ -410,11 +431,14 @@ struct fg_chip { bool esr_flt_cold_temp_en; bool slope_limit_en; bool use_ima_single_mode; + bool usb_present; + bool twm_state; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; struct work_struct status_change_work; struct work_struct cycle_count_work; + struct work_struct esr_sw_work; struct delayed_work batt_avg_work; struct delayed_work sram_dump_work; struct fg_circ_buf ibatt_circ_buf; @@ -477,4 +501,6 @@ extern void fg_circ_buf_add(struct fg_circ_buf *, int); extern void fg_circ_buf_clr(struct fg_circ_buf *); extern int fg_circ_buf_avg(struct fg_circ_buf *, int *); extern int fg_lerp(const struct fg_pt *, size_t, s32, s32 *); +void fg_stay_awake(struct fg_chip *chip, int awake_reason); +void fg_relax(struct fg_chip *chip, int awake_reason); #endif diff --git a/drivers/power/fg-reg.h b/drivers/power/fg-reg.h index cd0b2fb4391f87e64bcf556358d17dd205f368a5..37dff8bc52ec95b4bceedaad876784f6848735f8 100644 --- a/drivers/power/fg-reg.h +++ b/drivers/power/fg-reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -29,6 +29,7 @@ #define BATT_SOC_STS_CLR(chip) (chip->batt_soc_base + 0x4A) #define BATT_SOC_LOW_PWR_CFG(chip) (chip->batt_soc_base + 0x52) #define BATT_SOC_LOW_PWR_STS(chip) (chip->batt_soc_base + 0x56) +#define BATT_SOC_RST_CTRL0(chip) (chip->batt_soc_base + 0xBA) /* BATT_SOC_INT_RT_STS */ #define MSOC_EMPTY_BIT BIT(5) @@ -39,6 +40,11 @@ /* BATT_SOC_RESTART */ #define RESTART_GO_BIT BIT(0) +/* BATT_SOC_RST_CTRL0 */ +#define BCL_RST_BIT BIT(2) +#define MEM_RST_BIT BIT(1) +#define ALG_RST_BIT BIT(0) + /* FG_BATT_INFO register definitions */ #define BATT_INFO_BATT_TEMP_STS(chip) (chip->batt_info_base + 0x06) #define BATT_INFO_SYS_BATT(chip) (chip->batt_info_base + 0x07) diff --git a/drivers/power/fg-util.c b/drivers/power/fg-util.c index a68f49e9bb96977e09ad4b99ca67137f710b5d15..223c1429cef87cf4612983c2cfd598bd0f5ec4f2 100644 --- a/drivers/power/fg-util.c +++ b/drivers/power/fg-util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -230,8 +230,8 @@ static inline bool fg_sram_address_valid(u16 address, int len) int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len, int flags) { - int rc = 0; - bool tried_again = false; + int rc = 0, tries = 0; + bool atomic_access = false; if (!chip) @@ -258,7 +258,7 @@ int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset, } else { flags = FG_IMA_DEFAULT; } -wait: + /* * Atomic access mean waiting upon SOC_UPDATE interrupt from * FG_ALG and do the transaction after that. This is to make @@ -267,16 +267,20 @@ wait: * FG cycle (~1.47 seconds). */ if (atomic_access) { - /* Wait for SOC_UPDATE completion */ - rc = wait_for_completion_interruptible_timeout( - &chip->soc_update, - msecs_to_jiffies(SOC_UPDATE_WAIT_MS)); - - /* If we were interrupted wait again one more time. */ - if (rc == -ERESTARTSYS && !tried_again) { - tried_again = true; - goto wait; - } else if (rc <= 0) { + for (tries = 0; tries < 2; tries++) { + /* Wait for SOC_UPDATE completion */ + rc = wait_for_completion_interruptible_timeout( + &chip->soc_update, + msecs_to_jiffies(SOC_UPDATE_WAIT_MS)); + if (rc > 0) { + rc = 0; + break; + } else if (!rc) { + rc = -ETIMEDOUT; + } + } + + if (rc < 0) { pr_err("wait for soc_update timed out rc=%d\n", rc); goto out; } @@ -432,7 +436,7 @@ int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val) reg &= ~mask; reg |= val & mask; - sec_access = (addr & 0x00FF) > 0xD0; + sec_access = (addr & 0x00FF) > 0xB8; if (sec_access) { rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, (addr & 0xFF00) | 0xD0, &sec_addr_val, 1); @@ -935,3 +939,27 @@ err_remove_fs: debugfs_remove_recursive(chip->dfs_root); return -ENOMEM; } + +void fg_stay_awake(struct fg_chip *chip, int awake_reason) +{ + spin_lock(&chip->awake_lock); + + if (!chip->awake_status) + pm_stay_awake(chip->dev); + + chip->awake_status |= awake_reason; + + spin_unlock(&chip->awake_lock); +} + +void fg_relax(struct fg_chip *chip, int awake_reason) +{ + spin_lock(&chip->awake_lock); + + chip->awake_status &= ~awake_reason; + + if (!chip->awake_status) + pm_relax(chip->dev); + + spin_unlock(&chip->awake_lock); +} diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 0c52e2a0d90cdba166a5cdfda72f70d86f5a2572..3a36774cbdfef5f2efbcb9f90cadf30d00ea8672 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -30,9 +30,9 @@ static inline unsigned int get_irq_flags(struct resource *res) static struct device *dev; static struct pda_power_pdata *pdata; static struct resource *ac_irq, *usb_irq; -static struct timer_list charger_timer; -static struct timer_list supply_timer; -static struct timer_list polling_timer; +static struct delayed_work charger_work; +static struct delayed_work polling_work; +static struct delayed_work supply_work; static int polling; #if IS_ENABLED(CONFIG_USB_PHY) @@ -143,7 +143,7 @@ static void update_charger(void) } } -static void supply_timer_func(unsigned long unused) +static void supply_work_func(struct work_struct *work) { if (ac_status == PDA_PSY_TO_CHANGE) { ac_status = new_ac_status; @@ -164,11 +164,12 @@ static void psy_changed(void) * Okay, charger set. Now wait a bit before notifying supplicants, * charge power should stabilize. */ - mod_timer(&supply_timer, - jiffies + msecs_to_jiffies(pdata->wait_for_charger)); + cancel_delayed_work(&supply_work); + schedule_delayed_work(&supply_work, + msecs_to_jiffies(pdata->wait_for_charger)); } -static void charger_timer_func(unsigned long unused) +static void charger_work_func(struct work_struct *work) { update_status(); psy_changed(); @@ -187,13 +188,14 @@ static irqreturn_t power_changed_isr(int irq, void *power_supply) * Wait a bit before reading ac/usb line status and setting charger, * because ac/usb status readings may lag from irq. */ - mod_timer(&charger_timer, - jiffies + msecs_to_jiffies(pdata->wait_for_status)); + cancel_delayed_work(&charger_work); + schedule_delayed_work(&charger_work, + msecs_to_jiffies(pdata->wait_for_status)); return IRQ_HANDLED; } -static void polling_timer_func(unsigned long unused) +static void polling_work_func(struct work_struct *work) { int changed = 0; @@ -214,8 +216,9 @@ static void polling_timer_func(unsigned long unused) if (changed) psy_changed(); - mod_timer(&polling_timer, - jiffies + msecs_to_jiffies(pdata->polling_interval)); + cancel_delayed_work(&polling_work); + schedule_delayed_work(&polling_work, + msecs_to_jiffies(pdata->polling_interval)); } #if IS_ENABLED(CONFIG_USB_PHY) @@ -253,8 +256,9 @@ static int otg_handle_notification(struct notifier_block *nb, * Wait a bit before reading ac/usb line status and setting charger, * because ac/usb status readings may lag from irq. */ - mod_timer(&charger_timer, - jiffies + msecs_to_jiffies(pdata->wait_for_status)); + cancel_delayed_work(&charger_work); + schedule_delayed_work(&charger_work, + msecs_to_jiffies(pdata->wait_for_status)); return NOTIFY_OK; } @@ -302,8 +306,8 @@ static int pda_power_probe(struct platform_device *pdev) if (!pdata->ac_max_uA) pdata->ac_max_uA = 500000; - setup_timer(&charger_timer, charger_timer_func, 0); - setup_timer(&supply_timer, supply_timer_func, 0); + INIT_DELAYED_WORK(&charger_work, charger_work_func); + INIT_DELAYED_WORK(&supply_work, supply_work_func); ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); @@ -381,9 +385,10 @@ static int pda_power_probe(struct platform_device *pdev) if (polling) { dev_dbg(dev, "will poll for status\n"); - setup_timer(&polling_timer, polling_timer_func, 0); - mod_timer(&polling_timer, - jiffies + msecs_to_jiffies(pdata->polling_interval)); + INIT_DELAYED_WORK(&polling_work, polling_work_func); + cancel_delayed_work(&polling_work); + schedule_delayed_work(&polling_work, + msecs_to_jiffies(pdata->polling_interval)); } if (ac_irq || usb_irq) @@ -429,9 +434,9 @@ static int pda_power_remove(struct platform_device *pdev) free_irq(ac_irq->start, &pda_psy_ac); if (polling) - del_timer_sync(&polling_timer); - del_timer_sync(&charger_timer); - del_timer_sync(&supply_timer); + cancel_delayed_work_sync(&polling_work); + cancel_delayed_work_sync(&charger_work); + cancel_delayed_work_sync(&supply_work); if (pdata->is_usb_online) power_supply_unregister(&pda_psy_usb); diff --git a/drivers/power/qcom/msm-pm.c b/drivers/power/qcom/msm-pm.c index 64228e7743311e885f95792d98c2d0402cc80223..426109953a80e1460fec3e3640f3e9700dd62a1b 100644 --- a/drivers/power/qcom/msm-pm.c +++ b/drivers/power/qcom/msm-pm.c @@ -550,7 +550,7 @@ static int msm_cpu_status_probe(struct platform_device *pdev) u32 cpu; int rc; - if (!pdev | !pdev->dev.of_node) + if (!pdev || !pdev->dev.of_node) return -EFAULT; msm_pm_slp_sts = devm_kzalloc(&pdev->dev, diff --git a/drivers/power/qpnp-fg-gen3.c b/drivers/power/qpnp-fg-gen3.c index 5c00796b17596eae0ea6af1492490ca6ffe82edb..ceb520f8d57f2980c2f2b01d64fa91e712ecf27d 100644 --- a/drivers/power/qpnp-fg-gen3.c +++ b/drivers/power/qpnp-fg-gen3.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -16,9 +16,12 @@ #include #include #include +#include +#include #include #include #include +#include #include "fg-core.h" #include "fg-reg.h" @@ -34,6 +37,8 @@ #define ESR_PULSE_THRESH_OFFSET 3 #define SLOPE_LIMIT_WORD 3 #define SLOPE_LIMIT_OFFSET 0 +#define CUTOFF_CURR_WORD 4 +#define CUTOFF_CURR_OFFSET 0 #define CUTOFF_VOLT_WORD 5 #define CUTOFF_VOLT_OFFSET 0 #define SYS_TERM_CURR_WORD 6 @@ -62,6 +67,8 @@ #define RECHARGE_SOC_THR_OFFSET 0 #define CHG_TERM_CURR_WORD 14 #define CHG_TERM_CURR_OFFSET 1 +#define SYNC_SLEEP_THR_WORD 14 +#define SYNC_SLEEP_THR_OFFSET 3 #define EMPTY_VOLT_WORD 15 #define EMPTY_VOLT_OFFSET 0 #define VBATT_LOW_WORD 15 @@ -74,6 +81,8 @@ #define ESR_TIMER_CHG_MAX_OFFSET 0 #define ESR_TIMER_CHG_INIT_WORD 18 #define ESR_TIMER_CHG_INIT_OFFSET 2 +#define ESR_EXTRACTION_ENABLE_WORD 19 +#define ESR_EXTRACTION_ENABLE_OFFSET 0 #define PROFILE_LOAD_WORD 24 #define PROFILE_LOAD_OFFSET 0 #define ESR_RSLOW_DISCHG_WORD 34 @@ -129,6 +138,8 @@ #define DELTA_MSOC_THR_v2_OFFSET 0 #define RECHARGE_SOC_THR_v2_WORD 14 #define RECHARGE_SOC_THR_v2_OFFSET 1 +#define SYNC_SLEEP_THR_v2_WORD 14 +#define SYNC_SLEEP_THR_v2_OFFSET 2 #define CHG_TERM_CURR_v2_WORD 15 #define CHG_TERM_BASE_CURR_v2_OFFSET 0 #define CHG_TERM_CURR_v2_OFFSET 1 @@ -205,12 +216,16 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = { 1000000, 122070, 0, fg_encode_current, NULL), PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1, 100000, 390625, 0, fg_encode_current, NULL), + PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3, + 1000000, 122070, 0, fg_encode_current, NULL), PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET, 1, 256, 100, 0, fg_encode_default, NULL), + PARAM(SYNC_SLEEP_THR, SYNC_SLEEP_THR_WORD, SYNC_SLEEP_THR_OFFSET, + 1, 100000, 390625, 0, fg_encode_default, NULL), PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD, ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL), @@ -281,6 +296,8 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0, fg_encode_current, NULL), + PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3, + 1000000, 122070, 0, fg_encode_current, NULL), PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET, @@ -288,6 +305,8 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD, RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default, NULL), + PARAM(SYNC_SLEEP_THR, SYNC_SLEEP_THR_v2_WORD, SYNC_SLEEP_THR_v2_OFFSET, + 1, 100000, 390625, 0, fg_encode_default, NULL), PARAM(RECHARGE_VBATT_THR, RECHARGE_VBATT_THR_v2_WORD, RECHARGE_VBATT_THR_v2_OFFSET, 1, 1000, 15625, -2000, fg_encode_voltage, NULL), @@ -555,13 +574,31 @@ static int fg_get_charge_raw(struct fg_chip *chip, int *val) return rc; } - *val = div_s64(cc_soc * chip->cl.nom_cap_uah, CC_SOC_30BIT); + *val = div_s64((int64_t)cc_soc * chip->cl.nom_cap_uah, CC_SOC_30BIT); + return 0; +} + +#define BATT_SOC_32BIT GENMASK(31, 0) +static int fg_get_charge_counter_shadow(struct fg_chip *chip, int *val) +{ + int rc; + unsigned int batt_soc; + + rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc); + if (rc < 0) { + pr_err("Error in getting BATT_SOC, rc=%d\n", rc); + return rc; + } + + *val = div_u64((uint64_t)batt_soc * chip->cl.learned_cc_uah, + BATT_SOC_32BIT); return 0; } static int fg_get_charge_counter(struct fg_chip *chip, int *val) { - int rc, cc_soc; + int rc; + int cc_soc; rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc); if (rc < 0) { @@ -569,7 +606,7 @@ static int fg_get_charge_counter(struct fg_chip *chip, int *val) return rc; } - *val = div_s64(cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT); + *val = div_s64((int64_t)cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT); return 0; } @@ -816,7 +853,7 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) return 0; } - if (chip->battery_missing) { + if (chip->battery_missing || !chip->soc_reporting_ready) { *val = BATT_MISS_SOC; return 0; } @@ -1121,7 +1158,7 @@ static int fg_batt_miss_irq_en_cb(struct votable *votable, void *data, enable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq); } else { disable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq); - disable_irq(chip->irqs[BATT_MISSING_IRQ].irq); + disable_irq_nosync(chip->irqs[BATT_MISSING_IRQ].irq); } return 0; @@ -1140,7 +1177,7 @@ static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data, enable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq); } else { disable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq); - disable_irq(chip->irqs[BSOC_DELTA_IRQ].irq); + disable_irq_nosync(chip->irqs[BSOC_DELTA_IRQ].irq); } return 0; @@ -1175,6 +1212,18 @@ static bool batt_psy_initialized(struct fg_chip *chip) return true; } +static bool usb_psy_initialized(struct fg_chip *chip) +{ + if (chip->usb_psy) + return true; + + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) + return false; + + return true; +} + static bool is_parallel_charger_available(struct fg_chip *chip) { if (!chip->parallel_psy) @@ -1186,6 +1235,21 @@ static bool is_parallel_charger_available(struct fg_chip *chip) return true; } +static int fg_prime_cc_soc_sw(struct fg_chip *chip, unsigned int cc_soc_sw) +{ + int rc; + + rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word, + chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw, + chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC); + if (rc < 0) + pr_err("Error in writing cc_soc_sw, rc=%d\n", rc); + else + fg_dbg(chip, FG_STATUS, "cc_soc_sw: %u\n", cc_soc_sw); + + return rc; +} + static int fg_save_learned_cap_to_sram(struct fg_chip *chip) { int16_t cc_mah; @@ -1335,8 +1399,10 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) static int fg_cap_learning_process_full_data(struct fg_chip *chip) { - int rc, cc_soc_sw, cc_soc_delta_pct; + int rc; + unsigned int cc_soc_sw; int64_t delta_cc_uah; + unsigned int cc_soc_delta_pct; rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw); if (rc < 0) { @@ -1354,43 +1420,40 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip) return -ERANGE; } - delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct, + delta_cc_uah = div64_u64(chip->cl.learned_cc_uah * cc_soc_delta_pct, 100); chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah; - fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n", + fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%u total_cc_uah=%llu\n", cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah); return 0; } -#define BATT_SOC_32BIT GENMASK(31, 0) static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc) { - int rc, cc_soc_sw, batt_soc_msb; + int rc; + unsigned int batt_soc_msb, cc_soc_sw; batt_soc_msb = batt_soc >> 24; if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) > chip->dt.cl_start_soc) { - fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n", + fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %u is high!, not starting\n", batt_soc_msb); return -EINVAL; } - chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb, + chip->cl.init_cc_uah = div64_u64(chip->cl.learned_cc_uah * batt_soc_msb, FULL_SOC_RAW); /* Prime cc_soc_sw with battery SOC when capacity learning begins */ - cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT, + cc_soc_sw = div64_u64((uint64_t)batt_soc * CC_SOC_30BIT, BATT_SOC_32BIT); - rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word, - chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw, - chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC); + rc = fg_prime_cc_soc_sw(chip, cc_soc_sw); if (rc < 0) { pr_err("Error in writing cc_soc_sw, rc=%d\n", rc); goto out; } chip->cl.init_cc_soc_sw = cc_soc_sw; - chip->cl.active = true; fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", batt_soc_msb, chip->cl.init_cc_soc_sw); out: @@ -1399,7 +1462,8 @@ out: static int fg_cap_learning_done(struct fg_chip *chip) { - int rc, cc_soc_sw; + int rc; + unsigned int cc_soc_sw; rc = fg_cap_learning_process_full_data(chip); if (rc < 0) { @@ -1410,9 +1474,7 @@ static int fg_cap_learning_done(struct fg_chip *chip) /* Write a FULL value to cc_soc_sw */ cc_soc_sw = CC_SOC_30BIT; - rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word, - chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw, - chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC); + rc = fg_prime_cc_soc_sw(chip, cc_soc_sw); if (rc < 0) { pr_err("Error in writing cc_soc_sw, rc=%d\n", rc); goto out; @@ -1425,8 +1487,10 @@ out: static void fg_cap_learning_update(struct fg_chip *chip) { - int rc, batt_soc, batt_soc_msb; + int rc; + unsigned int batt_soc, batt_soc_msb, cc_soc_sw; bool input_present = is_input_present(chip); + bool prime_cc = false; mutex_lock(&chip->cl.lock); @@ -1454,8 +1518,12 @@ static void fg_cap_learning_update(struct fg_chip *chip) if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { rc = fg_cap_learning_begin(chip, batt_soc); chip->cl.active = (rc == 0); + } else { + if ((chip->charge_status == + POWER_SUPPLY_STATUS_DISCHARGING) || + chip->charge_done) + prime_cc = true; } - } else { if (chip->charge_done) { rc = fg_cap_learning_done(chip); @@ -1473,6 +1541,7 @@ static void fg_cap_learning_update(struct fg_chip *chip) batt_soc_msb); chip->cl.active = false; chip->cl.init_cc_uah = 0; + prime_cc = true; } } @@ -1489,10 +1558,29 @@ static void fg_cap_learning_update(struct fg_chip *chip) batt_soc_msb); chip->cl.active = false; chip->cl.init_cc_uah = 0; + prime_cc = true; } } } + /* + * Prime CC_SOC_SW when the device is not charging or during charge + * termination when the capacity learning is not active. + */ + + if (prime_cc) { + if (chip->charge_done) + cc_soc_sw = CC_SOC_30BIT; + else + cc_soc_sw = div_u64((uint64_t)batt_soc * + CC_SOC_30BIT, BATT_SOC_32BIT); + + rc = fg_prime_cc_soc_sw(chip, cc_soc_sw); + if (rc < 0) + pr_err("Error in writing cc_soc_sw, rc=%d\n", + rc); + } + out: mutex_unlock(&chip->cl.lock); } @@ -1559,6 +1647,8 @@ static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp) if (batt_temp < 0) ki_coeff_full_soc = 0; + else if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) + ki_coeff_full_soc = chip->dt.ki_coeff_full_soc_dischg; else ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT; @@ -2136,9 +2226,6 @@ static int fg_esr_timer_config(struct fg_chip *chip, bool sleep) static void fg_batt_avg_update(struct fg_chip *chip) { - if (chip->charge_status == chip->prev_charge_status) - return; - cancel_delayed_work_sync(&chip->batt_avg_work); fg_circ_buf_clr(&chip->ibatt_circ_buf); fg_circ_buf_clr(&chip->vbatt_circ_buf); @@ -2149,6 +2236,142 @@ static void fg_batt_avg_update(struct fg_chip *chip) msecs_to_jiffies(2000)); } +#define ESR_SW_FCC_UA 100000 /* 100mA */ +#define ESR_EXTRACTION_ENABLE_MASK BIT(0) +static void fg_esr_sw_work(struct work_struct *work) +{ + struct fg_chip *chip = container_of(work, + struct fg_chip, esr_sw_work); + union power_supply_propval pval = {0, }; + int rc, esr_uohms = 0; + + vote(chip->awake_votable, FG_ESR_VOTER, true, 0); + /* + * Enable ESR extraction just before we reduce the FCC + * to make sure that FG extracts the ESR. Disable ESR + * extraction after FCC reduction is complete to prevent + * any further HW pulses. + */ + rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, + ESR_EXTRACTION_ENABLE_OFFSET, + ESR_EXTRACTION_ENABLE_MASK, 0x1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Failed to enable ESR extraction rc=%d\n", rc); + goto done; + } + + /* delay for 1 FG cycle to complete */ + msleep(1500); + + /* for FCC to 100mA */ + pval.intval = ESR_SW_FCC_UA; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + &pval); + if (rc < 0) { + pr_err("Failed to set FCC to 100mA rc=%d\n", rc); + goto done; + } + + /* delay for ESR readings */ + msleep(3000); + + /* FCC to 0 (removes vote) */ + pval.intval = 0; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + &pval); + if (rc < 0) { + pr_err("Failed to remove FCC vote rc=%d\n", rc); + goto done; + } + + fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms); + fg_dbg(chip, FG_STATUS, "SW ESR done ESR=%d\n", esr_uohms); + + /* restart the alarm timer */ + alarm_start_relative(&chip->esr_sw_timer, + ms_to_ktime(chip->esr_wakeup_ms)); +done: + rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, + ESR_EXTRACTION_ENABLE_OFFSET, + ESR_EXTRACTION_ENABLE_MASK, 0x0, FG_IMA_DEFAULT); + if (rc < 0) + pr_err("Failed to disable ESR extraction rc=%d\n", rc); + + + vote(chip->awake_votable, FG_ESR_VOTER, false, 0); + fg_relax(chip, FG_SW_ESR_WAKE); +} + +static enum alarmtimer_restart + fg_esr_sw_timer(struct alarm *alarm, ktime_t now) +{ + struct fg_chip *chip = container_of(alarm, + struct fg_chip, esr_sw_timer); + + if (!chip->usb_present) + return ALARMTIMER_NORESTART; + + fg_stay_awake(chip, FG_SW_ESR_WAKE); + schedule_work(&chip->esr_sw_work); + + return ALARMTIMER_NORESTART; +} + +static int fg_config_esr_sw(struct fg_chip *chip) +{ + int rc; + union power_supply_propval prop = {0, }; + + if (!chip->dt.use_esr_sw) + return 0; + + if (!usb_psy_initialized(chip)) + return 0; + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &prop); + if (rc < 0) { + pr_err("Error in reading usb-status rc = %d\n", rc); + return rc; + } + + if (chip->usb_present != prop.intval) { + chip->usb_present = prop.intval; + fg_dbg(chip, FG_STATUS, "USB status changed=%d\n", + chip->usb_present); + /* cancel any pending work */ + alarm_cancel(&chip->esr_sw_timer); + cancel_work_sync(&chip->esr_sw_work); + + if (chip->usb_present) { + /* disable ESR extraction across the charging cycle */ + rc = fg_sram_masked_write(chip, + ESR_EXTRACTION_ENABLE_WORD, + ESR_EXTRACTION_ENABLE_OFFSET, + ESR_EXTRACTION_ENABLE_MASK, + 0x0, FG_IMA_DEFAULT); + if (rc < 0) + return rc; + /* wake up early for the first ESR on insertion */ + alarm_start_relative(&chip->esr_sw_timer, + ms_to_ktime(chip->esr_wakeup_ms / 2)); + } else { + /* enable ESR extraction on removal */ + rc = fg_sram_masked_write(chip, + ESR_EXTRACTION_ENABLE_WORD, + ESR_EXTRACTION_ENABLE_OFFSET, + ESR_EXTRACTION_ENABLE_MASK, + 0x1, FG_IMA_DEFAULT); + if (rc < 0) + return rc; + } + } + + return 0; +} + static void status_change_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, @@ -2161,6 +2384,15 @@ static void status_change_work(struct work_struct *work) goto out; } + if (!chip->soc_reporting_ready) { + fg_dbg(chip, FG_STATUS, "Profile load is not complete yet\n"); + goto out; + } + + rc = fg_config_esr_sw(chip); + if (rc < 0) + pr_err("Failed to config SW ESR rc=%d\n", rc); + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &prop); if (rc < 0) { @@ -2168,7 +2400,6 @@ static void status_change_work(struct work_struct *work) goto out; } - chip->prev_charge_status = chip->charge_status; chip->charge_status = prop.intval; rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); @@ -2225,11 +2456,10 @@ static void status_change_work(struct work_struct *work) } fg_batt_avg_update(chip); - out: - fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n", + fg_dbg(chip, FG_STATUS, "charge_status:%d charge_type:%d charge_done:%d\n", chip->charge_status, chip->charge_type, chip->charge_done); - pm_relax(chip->dev); + fg_relax(chip, FG_STATUS_NOTIFY_WAKE); } static void restore_cycle_counter(struct fg_chip *chip) @@ -2623,6 +2853,10 @@ done: out: chip->soc_reporting_ready = true; vote(chip->awake_votable, PROFILE_LOAD, false, 0); + if (!work_pending(&chip->status_change_work)) { + fg_stay_awake(chip, FG_STATUS_NOTIFY_WAKE); + schedule_work(&chip->status_change_work); + } } static void sram_dump_work(struct work_struct *work) @@ -3097,6 +3331,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: rc = fg_get_charge_counter(chip, &pval->intval); break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW: + rc = fg_get_charge_counter_shadow(chip, &pval->intval); + break; case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: rc = fg_get_time_to_full(chip, &pval->intval); break; @@ -3188,13 +3425,29 @@ static int fg_notifier_cb(struct notifier_block *nb, * We cannot vote for awake votable here as that takes * a mutex lock and this is executed in an atomic context. */ - pm_stay_awake(chip->dev); + fg_stay_awake(chip, FG_STATUS_NOTIFY_WAKE); schedule_work(&chip->status_change_work); } return NOTIFY_OK; } +static int twm_notifier_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct fg_chip *chip = container_of(nb, struct fg_chip, twm_nb); + + if (action != PMIC_TWM_CLEAR && + action != PMIC_TWM_ENABLE) { + pr_debug("Unsupported option %lu\n", action); + return NOTIFY_OK; + } + + chip->twm_state = (u8)action; + + return NOTIFY_OK; +} + static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_TEMP, @@ -3212,6 +3465,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, POWER_SUPPLY_PROP_SOC_REPORTING_READY, @@ -3266,6 +3520,16 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } + fg_encode(chip->sp, FG_SRAM_CUTOFF_CURR, chip->dt.cutoff_curr_ma, + buf); + rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_CURR].addr_word, + chip->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf, + chip->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing cutoff_curr, rc=%d\n", rc); + return rc; + } + if (!(chip->wa_flags & PMI8998_V1_REV_WA)) { fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR, chip->dt.chg_term_base_curr_ma, buf); @@ -3481,7 +3745,7 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - if (is_debug_batt_id(chip)) { + if (is_debug_batt_id(chip) || chip->dt.disable_esr_pull_dn) { val = ESR_NO_PULL_DOWN; rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip), ESR_PULL_DOWN_MODE_MASK, val); @@ -3491,6 +3755,33 @@ static int fg_hw_init(struct fg_chip *chip) } } + if (chip->dt.use_esr_sw) { + /* Enable ESR extraction explicitly */ + rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, + ESR_EXTRACTION_ENABLE_OFFSET, + ESR_EXTRACTION_ENABLE_MASK, + 0x1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in enabling ESR extraction rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.sync_sleep_threshold_ma != -EINVAL) { + fg_encode(chip->sp, FG_SRAM_SYNC_SLEEP_THR, + chip->dt.sync_sleep_threshold_ma, buf); + rc = fg_sram_write(chip, + chip->sp[FG_SRAM_SYNC_SLEEP_THR].addr_word, + chip->sp[FG_SRAM_SYNC_SLEEP_THR].addr_byte, buf, + chip->sp[FG_SRAM_SYNC_SLEEP_THR].len, + FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing sync_sleep_threshold=%d\n", + rc); + return rc; + } + } + return 0; } @@ -3951,7 +4242,11 @@ static int fg_parse_slope_limit_coefficients(struct fg_chip *chip) static int fg_parse_ki_coefficients(struct fg_chip *chip) { struct device_node *node = chip->dev->of_node; - int rc, i; + int rc, i, temp; + + rc = of_property_read_u32(node, "qcom,ki-coeff-full-dischg", &temp); + if (!rc) + chip->dt.ki_coeff_full_soc_dischg = temp; rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg", chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS); @@ -3997,6 +4292,7 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip) #define DEFAULT_CHG_TERM_CURR_MA 100 #define DEFAULT_CHG_TERM_BASE_CURR_MA 75 #define DEFAULT_SYS_TERM_CURR_MA -125 +#define DEFAULT_CUTOFF_CURR_MA 500 #define DEFAULT_DELTA_SOC_THR 1 #define DEFAULT_RECHARGE_SOC_THR 95 #define DEFAULT_BATT_TEMP_COLD 0 @@ -4158,6 +4454,12 @@ static int fg_parse_dt(struct fg_chip *chip) else chip->dt.chg_term_base_curr_ma = temp; + rc = of_property_read_u32(node, "qcom,fg-cutoff-current", &temp); + if (rc < 0) + chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA; + else + chip->dt.cutoff_curr_ma = temp; + rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp); if (rc < 0) chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR; @@ -4232,6 +4534,13 @@ static int fg_parse_dt(struct fg_chip *chip) chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL; } + rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-shutdown", + chip->dt.esr_timer_shutdown, NUM_ESR_TIMERS); + if (rc < 0) { + chip->dt.esr_timer_shutdown[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_shutdown[TIMER_MAX] = -EINVAL; + } + chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en"); if (chip->cyc_ctr.en) chip->cyc_ctr.id = 1; @@ -4365,6 +4674,22 @@ static int fg_parse_dt(struct fg_chip *chip) chip->dt.esr_meas_curr_ma = temp; } + chip->dt.sync_sleep_threshold_ma = -EINVAL; + rc = of_property_read_u32(node, + "qcom,fg-sync-sleep-threshold-ma", &temp); + if (!rc) { + if (temp >= 0 && temp < 997) + chip->dt.sync_sleep_threshold_ma = temp; + } + + chip->dt.use_esr_sw = of_property_read_bool(node, "qcom,fg-use-sw-esr"); + + chip->dt.disable_esr_pull_dn = of_property_read_bool(node, + "qcom,fg-disable-esr-pull-dn"); + + chip->dt.disable_fg_twm = of_property_read_bool(node, + "qcom,fg-disable-in-twm"); + return 0; } @@ -4405,7 +4730,6 @@ static int fg_gen3_probe(struct spmi_device *spmi) chip->debug_mask = &fg_gen3_debug_mask; chip->irqs = fg_irqs; chip->charge_status = -EINVAL; - chip->prev_charge_status = -EINVAL; chip->ki_coeff_full_soc = -EINVAL; chip->spmi = spmi; @@ -4473,11 +4797,13 @@ static int fg_gen3_probe(struct spmi_device *spmi) mutex_init(&chip->cl.lock); mutex_init(&chip->batt_avg_lock); mutex_init(&chip->charge_full_lock); + spin_lock_init(&chip->awake_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work); INIT_WORK(&chip->status_change_work, status_change_work); INIT_WORK(&chip->cycle_count_work, cycle_count_work); + INIT_WORK(&chip->esr_sw_work, fg_esr_sw_work); INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work); INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work); dev_set_drvdata(&spmi->dev, chip); @@ -4496,6 +4822,23 @@ static int fg_gen3_probe(struct spmi_device *spmi) goto exit; } + if (chip->dt.use_esr_sw) { + if (alarmtimer_get_rtcdev()) { + alarm_init(&chip->esr_sw_timer, ALARM_BOOTTIME, + fg_esr_sw_timer); + } else { + pr_err("Failed to get esw_sw alarm-timer\n"); + /* RTC always registers, hence defer until it passes */ + rc = -EPROBE_DEFER; + goto exit; + } + if (chip->dt.esr_timer_charging[TIMER_MAX] != -EINVAL) + chip->esr_wakeup_ms = + chip->dt.esr_timer_charging[TIMER_MAX] * 1460; + else + chip->esr_wakeup_ms = 140000; /* 140 seconds */ + } + chip->fg_psy.name = "bms"; chip->fg_psy.type = POWER_SUPPLY_TYPE_BMS; chip->fg_psy.properties = fg_psy_props; @@ -4523,6 +4866,11 @@ static int fg_gen3_probe(struct spmi_device *spmi) goto exit; } + chip->twm_nb.notifier_call = twm_notifier_cb; + rc = qpnp_misc_twm_notifier_register(&chip->twm_nb); + if (rc < 0) + pr_err("Failed to register twm_notifier_cb rc=%d\n", rc); + rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", @@ -4619,6 +4967,34 @@ static int fg_gen3_remove(struct spmi_device *spmi) return 0; } +static void fg_gen3_shutdown(struct spmi_device *spmi) +{ + struct fg_chip *chip = dev_get_drvdata(&spmi->dev); + int rc; + u8 mask; + + rc = fg_set_esr_timer(chip, chip->dt.esr_timer_shutdown[TIMER_RETRY], + chip->dt.esr_timer_shutdown[TIMER_MAX], false, + FG_IMA_NO_WLOCK); + if (rc < 0) + pr_err("Error in setting ESR timer at shutdown, rc=%d\n", rc); + + if (chip->twm_state == PMIC_TWM_ENABLE && chip->dt.disable_fg_twm) { + rc = fg_masked_write(chip, BATT_SOC_EN_CTL(chip), + FG_ALGORITHM_EN_BIT, 0); + if (rc < 0) + pr_err("Error in disabling FG rc=%d\n", rc); + + mask = BCL_RST_BIT | MEM_RST_BIT | ALG_RST_BIT; + rc = fg_masked_write(chip, BATT_SOC_RST_CTRL0(chip), + mask, mask); + if (rc < 0) + pr_err("Error in disabling FG resets rc=%d\n", rc); + } + + fg_cleanup(chip); +} + static const struct of_device_id fg_gen3_match_table[] = { {.compatible = FG_GEN3_DEV_NAME}, {}, @@ -4633,6 +5009,7 @@ static struct spmi_driver fg_gen3_driver = { }, .probe = fg_gen3_probe, .remove = fg_gen3_remove, + .shutdown = fg_gen3_shutdown, }; static int __init fg_gen3_init(void) diff --git a/drivers/power/qpnp-linear-charger.c b/drivers/power/qpnp-linear-charger.c index b7af1dd414c06d70eef8ee9adae82ac1992c4815..21e3199e9affae17e971d0b4a71d999ef1c90c75 100644 --- a/drivers/power/qpnp-linear-charger.c +++ b/drivers/power/qpnp-linear-charger.c @@ -1,5 +1,4 @@ -/* Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights - * reserved. +/* Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights reserved. * * 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 diff --git a/drivers/power/qpnp-smb2.c b/drivers/power/qpnp-smb2.c index d7e31a7a1ff7b2836f2e337234baeed0908d295a..f732f84228c026e6705e7cb6992f9bd655505a61 100644 --- a/drivers/power/qpnp-smb2.c +++ b/drivers/power/qpnp-smb2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * 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 @@ -167,6 +167,7 @@ struct smb_dt_props { bool no_battery; bool hvdcp_disable; bool auto_recharge_soc; + bool no_pd; }; struct smb2 { @@ -202,6 +203,9 @@ static int smb2_parse_dt(struct smb2 *chip) chip->dt.no_battery = of_property_read_bool(node, "qcom,batteryless-platform"); + chip->dt.no_pd = of_property_read_bool(node, + "qcom,pd-not-supported"); + chg->skip_usb_notification = of_property_read_bool(node, "qcom,skip-usb-notification"); @@ -553,6 +557,7 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_QNOVO, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CHARGE_DONE, @@ -561,6 +566,9 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_DIE_HEALTH, POWER_SUPPLY_PROP_RERUN_AICL, POWER_SUPPLY_PROP_DP_DM, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CYCLE_COUNT, }; static int smb2_batt_get_prop(struct power_supply *psy, @@ -610,9 +618,6 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: rc = smblib_get_prop_input_current_limited(chg, val); break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - rc = smblib_get_prop_batt_voltage_now(chg, val); - break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: val->intval = get_client_vote(chg->fv_votable, BATT_PROFILE_VOTER); @@ -624,9 +629,6 @@ static int smb2_batt_get_prop(struct power_supply *psy, val->intval = get_client_vote_locked(chg->fv_votable, QNOVO_VOTER); break; - case POWER_SUPPLY_PROP_CURRENT_NOW: - rc = smblib_get_prop_batt_current_now(chg, val); - break; case POWER_SUPPLY_PROP_CURRENT_QNOVO: val->intval = get_client_vote_locked(chg->fcc_votable, QNOVO_VOTER); @@ -635,8 +637,9 @@ static int smb2_batt_get_prop(struct power_supply *psy, val->intval = get_client_vote(chg->fcc_votable, BATT_PROFILE_VOTER); break; - case POWER_SUPPLY_PROP_TEMP: - rc = smblib_get_prop_batt_temp(chg, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + val->intval = get_client_vote(chg->fcc_votable, + FG_ESR_VOTER); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -661,6 +664,14 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_RERUN_AICL: val->intval = 0; break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_CYCLE_COUNT: + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_TEMP: + rc = smblib_get_prop_from_bms(chg, psp, val); + break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; @@ -728,6 +739,12 @@ static int smb2_batt_set_prop(struct power_supply *psy, chg->batt_profile_fcc_ua = val->intval; vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval); break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + if (val->intval) + vote(chg->fcc_votable, FG_ESR_VOTER, true, val->intval); + else + vote(chg->fcc_votable, FG_ESR_VOTER, false, 0); + break; case POWER_SUPPLY_PROP_SET_SHIP_MODE: /* Not in ship mode as long as the device is active */ if (!val->intval) @@ -1150,6 +1167,8 @@ static int smb2_init_hw(struct smb2 *chip) chg->micro_usb_mode, 0); vote(chg->hvdcp_enable_votable, MICRO_USB_VOTER, chg->micro_usb_mode, 0); + vote(chg->pd_disallowed_votable_indirect, PD_NOT_SUPPORTED_VOTER, + chip->dt.no_pd, 0); /* * AICL configuration: @@ -1262,6 +1281,13 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg); + if (rc < 0) { + dev_err(chg->dev, "Couldn't read float charger options rc=%d\n", + rc); + return rc; + } + switch (chip->dt.chg_inhibit_thr_mv) { case 50: rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG, @@ -1423,6 +1449,7 @@ static int smb2_determine_initial_status(struct smb2 *chip) smblib_handle_usb_source_change(0, &irq_data); smblib_handle_chg_state_change(0, &irq_data); smblib_handle_icl_change(0, &irq_data); + smblib_handle_batt_temp_changed(0, &irq_data); return 0; } @@ -1485,6 +1512,7 @@ static struct smb_irq_info smb2_irqs[] = { .name = "bat-temp", .handler = smblib_handle_batt_temp_changed, .flags = IRQ_TYPE_EDGE_RISING, + .wake = true, }, [BATT_OCP_IRQ] = { .name = "bat-ocp", diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index eb31643ceb2707dc2538993a767ca1ec6c6821ef..7e535dfcedca83d27df9c07cb653791ca235842f 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. * * 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 @@ -4902,26 +4902,10 @@ static int smbchg_restricted_charging(struct smbchg_chip *chip, bool enable) return rc; } -#ifdef CONFIG_MACH_XIAOMI_MIDO -extern void ist30xx_set_ta_mode(bool mode); -extern void tpd_usb_plugin(bool mode); -extern void gtp_usb_plugin(bool mode); -int set_usb_charge_mode_par = 0; -#endif - static void handle_usb_removal(struct smbchg_chip *chip) { struct power_supply *parallel_psy = get_parallel_psy(chip); int rc; -#ifdef CONFIG_MACH_XIAOMI_MIDO - if (set_usb_charge_mode_par == 1) { - ist30xx_set_ta_mode(0); - } else if (set_usb_charge_mode_par == 2) { - tpd_usb_plugin(0); - } else if (set_usb_charge_mode_par == 3) { - gtp_usb_plugin(0); - } -#endif pr_smb(PR_STATUS, "triggered\n"); smbchg_aicl_deglitch_wa_check(chip); @@ -4992,9 +4976,6 @@ static bool is_usbin_uv_high(struct smbchg_chip *chip) return reg &= USBIN_UV_BIT; } -#ifdef CONFIG_MACH_XIAOMI_MIDO -static int rerun_apsd(struct smbchg_chip *chip); -#endif #define HVDCP_NOTIFY_MS 2500 static void handle_usb_insertion(struct smbchg_chip *chip) { @@ -5002,24 +4983,9 @@ static void handle_usb_insertion(struct smbchg_chip *chip) int rc; char *usb_type_name = "null"; -#ifdef CONFIG_MACH_XIAOMI_MIDO - if (set_usb_charge_mode_par == 1) { - ist30xx_set_ta_mode(1); - } else if (set_usb_charge_mode_par == 2) { - tpd_usb_plugin(1); - } else if (set_usb_charge_mode_par == 3) { - gtp_usb_plugin(1); - } -#endif pr_smb(PR_STATUS, "triggered\n"); /* usb inserted */ read_usb_type(chip, &usb_type_name, &usb_supply_type); -#ifdef CONFIG_MACH_XIAOMI_MIDO - if (usb_supply_type == POWER_SUPPLY_TYPE_USB_CDP || usb_supply_type == POWER_SUPPLY_TYPE_USB) { - rc = rerun_apsd(chip); - read_usb_type(chip, &usb_type_name, &usb_supply_type); - } -#endif pr_smb(PR_STATUS, "inserted type = %d (%s)", usb_supply_type, usb_type_name); @@ -6151,10 +6117,8 @@ static void smbchg_external_power_changed(struct power_supply *psy) msecs_to_jiffies(HVDCP_NOTIFY_MS)); } -#ifndef CONFIG_MACH_XIAOMI_MIDO if (usb_supply_type != POWER_SUPPLY_TYPE_USB) goto skip_current_for_non_sdp; -#endif pr_smb(PR_MISC, "usb type = %s current_limit = %d\n", usb_type_name, current_limit); @@ -6164,10 +6128,8 @@ static void smbchg_external_power_changed(struct power_supply *psy) if (rc < 0) pr_err("Couldn't update USB PSY ICL vote rc=%d\n", rc); -#ifndef CONFIG_MACH_XIAOMI_MIDO skip_current_for_non_sdp: smbchg_vfloat_adjust_check(chip); -#endif power_supply_changed(&chip->batt_psy); } @@ -6359,11 +6321,7 @@ static int smbchg_battery_get_property(struct power_supply *psy, val->intval = get_prop_batt_health(chip); break; case POWER_SUPPLY_PROP_TECHNOLOGY: -#ifdef CONFIG_MACH_XIAOMI_MIDO - val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; -#else val->intval = POWER_SUPPLY_TECHNOLOGY_LION; -#endif break; case POWER_SUPPLY_PROP_FLASH_CURRENT_MAX: val->intval = smbchg_calc_max_flash_current(chip); @@ -6389,6 +6347,7 @@ static int smbchg_battery_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = get_prop_batt_current_now(chip); + val->intval *= (-1); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = get_prop_batt_voltage_now(chip); @@ -6575,16 +6534,6 @@ static irqreturn_t batt_warm_handler(int irq, void *_chip) { struct smbchg_chip *chip = _chip; u8 reg = 0; -#ifdef CONFIG_MACH_XIAOMI_MIDO - int rc; - /* set the warm float voltage compensation,set the warm float voltage to 4.1V */ - if (chip->float_voltage_comp != -EINVAL) { - rc = smbchg_float_voltage_comp_set(chip, chip->float_voltage_comp); - if (rc < 0) - dev_err(chip->dev, "Couldn't set float voltage comp rc = %d\n", rc); - pr_smb(PR_STATUS, "set float voltage comp to %d\n", chip->float_voltage_comp); -} -#endif smbchg_read(chip, ®, chip->bat_if_base + RT_STS, 1); chip->batt_warm = !!(reg & HOT_BAT_SOFT_BIT); @@ -6602,15 +6551,6 @@ static irqreturn_t batt_cool_handler(int irq, void *_chip) struct smbchg_chip *chip = _chip; u8 reg = 0; -#ifdef CONFIG_MACH_XIAOMI_MIDO - int rc; - /* set the cool float voltage compensation ,set the cool float voltage to 4.4V*/ - rc = smbchg_float_voltage_comp_set(chip, 0); - if (rc < 0) - dev_err(chip->dev, "Couldn't set float voltage comp rc = %d\n", rc); -#endif - - smbchg_read(chip, ®, chip->bat_if_base + RT_STS, 1); chip->batt_cool = !!(reg & COLD_BAT_SOFT_BIT); pr_smb(PR_INTERRUPT, "triggered: 0x%02x\n", reg); @@ -7675,21 +7615,6 @@ static int smbchg_hw_init(struct smbchg_chip *chip) if (rc < 0) dev_err(chip->dev, "Couldn't set OTG OC config rc = %d\n", rc); -#ifdef CONFIG_MACH_XIAOMI_MIDO - rc = smbchg_sec_masked_write(chip, chip->otg_base + OTG_CFG, 0x0c, 0x8); - if (rc < 0) { - dev_err(chip->dev, "Couldn't set SMBCHGL_OTG_CFG rc=%d\n", - rc); - } - - rc = smbchg_read(chip, ®, chip->otg_base + OTG_CFG, 1); - printk("%s:read OTG_CFG=%2x\n", __func__, reg); - if (rc < 0) { - dev_err(chip->dev, "Couldn't set SMBCHGL_OTG_CFG rc=%d\n", - rc); - } -#endif - } if (chip->otg_pinctrl) { @@ -8680,9 +8605,6 @@ static int smbchg_probe(struct spmi_device *spmi) goto votables_cleanup; } -#ifdef CONFIG_MACH_XIAOMI_MIDO - chip->hvdcp_not_supported = true; -#endif rc = smbchg_check_chg_version(chip); if (rc) { pr_err("Unable to check schg version rc=%d\n", rc); diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 142d4c775cbd9b91ca3df9626c53025574e76f07..35821b6fe5157c09cef50d2b3e5c09b92a888a6b 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * 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 @@ -304,10 +304,6 @@ static void msm_restart_prepare(const char *cmd) strcmp(cmd, "userrequested"))); } -#ifdef CONFIG_MSM_PRESERVE_MEM - need_warm_reset = true; -#endif - /* Hard reset the PMIC unless memory contents must be maintained. */ if (need_warm_reset) { qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET); diff --git a/drivers/power/smb-lib.c b/drivers/power/smb-lib.c index c1e7c2b87c9212bc4bec1b45c4927e96be517d66..bdb4fe19a833502efbad62c131ba959f4dcd720e 100644 --- a/drivers/power/smb-lib.c +++ b/drivers/power/smb-lib.c @@ -537,10 +537,17 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* if PD is active, APSD is disabled so won't have a valid result */ - if (chg->pd_active) + if (chg->pd_active) { chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; - else + } else { + /* + * Update real charger type only if its not FLOAT + * detected as as SDP + */ + if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT && + chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) chg->real_charger_type = apsd_result->pst; + } if (!chg->skip_usb_notification) power_supply_set_supply_type(chg->usb_psy, @@ -796,6 +803,7 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) { int rc; u8 icl_options; + const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* power source is SDP */ switch (icl_ua) { @@ -820,6 +828,21 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return -EINVAL; } + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB && + apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) { + /* + * change the float charger configuration to SDP, if this + * is the case of SDP being detected as FLOAT + */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, + FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't set float ICL options rc=%d\n", + rc); + return rc; + } + } + rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options); if (rc < 0) { @@ -1293,68 +1316,110 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) #define MAX_RETRY 15 #define MIN_DELAY_US 2000 #define MAX_DELAY_US 9000 -static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) +static int otg_current[] = {250000, 500000, 1000000, 1500000}; +static int smblib_enable_otg_wa(struct smb_charger *chg) { - struct smb_charger *chg = rdev_get_drvdata(rdev); - int rc, retry_count = 0, min_delay = MIN_DELAY_US; u8 stat; + int rc, i, retry_count = 0, min_delay = MIN_DELAY_US; - smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); - rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, - ENG_BUCKBOOST_HALT1_8_MODE_BIT, - ENG_BUCKBOOST_HALT1_8_MODE_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", - rc); - return rc; - } + for (i = 0; i < ARRAY_SIZE(otg_current); i++) { + smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n", + otg_current[i]); + rc = smblib_set_charge_param(chg, &chg->param.otg_cl, + otg_current[i]); + if (rc < 0) { + smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc); + return rc; + } - smblib_dbg(chg, PR_OTG, "enabling OTG\n"); - rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc); - return rc; - } + rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc); + return rc; + } - if (chg->wa_flags & OTG_WA) { - /* check for softstart */ + retry_count = 0; + min_delay = MIN_DELAY_US; do { usleep_range(min_delay, min_delay + 100); rc = smblib_read(chg, OTG_STATUS_REG, &stat); if (rc < 0) { - smblib_err(chg, - "Couldn't read OTG status rc=%d\n", - rc); + smblib_err(chg, "Couldn't read OTG status rc=%d\n", + rc); goto out; } if (stat & BOOST_SOFTSTART_DONE_BIT) { rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua); - if (rc < 0) - smblib_err(chg, - "Couldn't set otg limit\n"); + if (rc < 0) { + smblib_err(chg, "Couldn't set otg limit rc=%d\n", + rc); + goto out; + } break; } - /* increase the delay for following iterations */ if (retry_count > 5) min_delay = MAX_DELAY_US; + } while (retry_count++ < MAX_RETRY); if (retry_count >= MAX_RETRY) { - smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n"); - goto out; + smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n", + otg_current[i]); + rc = smblib_write(chg, CMD_OTG_REG, 0); + if (rc < 0) { + smblib_err(chg, "disable OTG rc=%d\n", rc); + goto out; + } + } else { + smblib_dbg(chg, PR_OTG, "OTG enabled\n"); + return 0; } } + if (i == ARRAY_SIZE(otg_current)) { + rc = -EINVAL; + goto out; + } + return 0; out: - /* disable OTG if softstart failed */ smblib_write(chg, CMD_OTG_REG, 0); return rc; } +static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) +{ + struct smb_charger *chg = rdev_get_drvdata(rdev); + int rc; + + smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); + rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, + ENG_BUCKBOOST_HALT1_8_MODE_BIT, + ENG_BUCKBOOST_HALT1_8_MODE_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", + rc); + return rc; + } + + smblib_dbg(chg, PR_OTG, "enabling OTG\n"); + + if (chg->wa_flags & OTG_WA) { + rc = smblib_enable_otg_wa(chg); + if (rc < 0) + smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc); + } else { + rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc); + } + + return rc; +} + int smblib_vbus_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); @@ -1626,7 +1691,8 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, stat); if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { - rc = smblib_get_prop_batt_voltage_now(chg, &pval); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); if (!rc) { /* * If Vbatt is within 40mV above Vfloat, then don't @@ -1684,45 +1750,6 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, return 0; } -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_VOLTAGE_NOW, val); - return rc; -} - -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CURRENT_NOW, val); - return rc; -} - -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_TEMP, val); - return rc; -} - int smblib_get_prop_batt_charge_done(struct smb_charger *chg, union power_supply_propval *val) { @@ -1758,6 +1785,20 @@ int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg, return 0; } +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, psp, val); + + return rc; +} + /*********************** * BATTERY PSY SETTERS * ***********************/ @@ -2091,12 +2132,6 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, union power_supply_propval *val) { - int rc = 0; - - rc = smblib_get_prop_usb_present(chg, val); - if (rc < 0 || !val->intval) - return rc; - if (!chg->iio.usbin_v_chan || PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER) chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v"); @@ -2299,16 +2334,9 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg, int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, union power_supply_propval *val) { - const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); int rc, pulses; - val->intval = MICRO_5V; - if (apsd_result == NULL) { - smblib_err(chg, "APSD result is NULL\n"); - return 0; - } - - switch (apsd_result->pst) { + switch (chg->real_charger_type) { case POWER_SUPPLY_TYPE_USB_HVDCP_3: rc = smblib_get_pulse_cnt(chg, &pulses); if (rc < 0) { @@ -2318,6 +2346,9 @@ int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, } val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses; break; + case POWER_SUPPLY_TYPE_USB_PD: + val->intval = chg->voltage_min_uv; + break; default: val->intval = MICRO_5V; break; @@ -2564,6 +2595,7 @@ int smblib_set_prop_usb_voltage_min(struct smb_charger *chg, } chg->voltage_min_uv = min_uv; + power_supply_changed(&chg->usb_main_psy); return rc; } @@ -2585,17 +2617,13 @@ int smblib_set_prop_usb_voltage_max(struct smb_charger *chg, return rc; } -int smblib_set_prop_pd_active(struct smb_charger *chg, - const union power_supply_propval *val) +static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) { int rc; bool orientation, sink_attached, hvdcp; u8 stat; - if (!get_effective_result(chg->pd_allowed_votable)) - return -EINVAL; - - chg->pd_active = val->intval; + chg->pd_active = pd_active; if (chg->pd_active) { vote(chg->apsd_disable_votable, PD_VOTER, true, 0); vote(chg->pd_allowed_votable, PD_VOTER, true, 0); @@ -2655,8 +2683,8 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, hvdcp = stat & QC_CHARGER_BIT; vote(chg->apsd_disable_votable, PD_VOTER, false, 0); - vote(chg->pd_allowed_votable, PD_VOTER, true, 0); - vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); + vote(chg->pd_allowed_votable, PD_VOTER, false, 0); + vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, false, 0); @@ -2683,6 +2711,15 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, return rc; } +int smblib_set_prop_pd_active(struct smb_charger *chg, + const union power_supply_propval *val) +{ + if (!get_effective_result(chg->pd_allowed_votable)) + return -EINVAL; + + return __smblib_set_prop_pd_active(chg, val->intval); +} + int smblib_set_prop_ship_mode(struct smb_charger *chg, const union power_supply_propval *val) { @@ -2848,6 +2885,51 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, return rc; } +static int smblib_recover_from_soft_jeita(struct smb_charger *chg) +{ + u8 stat_1 = 0, stat_2 = 0; + int rc; + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", + rc); + return rc; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", + rc); + return rc; + } + + if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) && + ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) { + /* + * We are moving from JEITA soft -> Normal and charging + * is terminated + */ + rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable charging rc=%d\n", + rc); + return rc; + } + rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, + CHARGING_ENABLE_CMD_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable charging rc=%d\n", + rc); + return rc; + } + } + + chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK; + + return 0; +} + /*********************** * USB MAIN PSY GETTERS * *************************/ @@ -3040,6 +3122,14 @@ irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + int rc; + + rc = smblib_recover_from_soft_jeita(chg); + if (rc < 0) { + smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n", + rc); + return IRQ_HANDLED; + } rerun_election(chg->fcc_votable); power_supply_changed(&chg->batt_psy); @@ -3374,6 +3464,13 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, /* enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); + + /* + * if pd is not allowed, then set pd_active = false right here, + * so that it starts the hvdcp engine + */ + if (!get_effective_result(chg->pd_allowed_votable)) + __smblib_set_prop_pd_active(chg, 0); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n", @@ -3418,11 +3515,17 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); break; case POWER_SUPPLY_TYPE_USB_DCP: - case POWER_SUPPLY_TYPE_USB_FLOAT: typec_mode = smblib_get_prop_typec_mode(chg); rp_ua = get_rp_based_dcp_current(chg, typec_mode); vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua); break; + case POWER_SUPPLY_TYPE_USB_FLOAT: + /* + * limit ICL to 100mA, the USB driver will enumerate to check + * if this is a SDP and appropriately set the current + */ + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); + break; case POWER_SUPPLY_TYPE_USB_HVDCP: case POWER_SUPPLY_TYPE_USB_HVDCP_3: vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000); @@ -3438,11 +3541,22 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { const struct apsd_result *apsd_result; + union power_supply_propval pval = {0, }; + int rc; if (!rising) return; apsd_result = smblib_update_usb_type(chg); + if (!chg->skip_usb_notification && chg->typec_present) { + smblib_dbg(chg, PR_REGISTER, "Notify USB insertion\n"); + rc = smblib_get_prop_usb_online(chg, &pval); + if (rc < 0) + smblib_err(chg, "Couldn't read USB online status rc=%d\n", + rc); + power_supply_set_online(chg->usb_psy, pval.intval); + power_supply_set_present(chg->usb_psy, true); + } if (!chg->typec_legacy_valid) smblib_force_legacy_icl(chg, apsd_result->pst); @@ -3473,7 +3587,6 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; - union power_supply_propval pval = {0, }; int rc = 0; u8 stat; @@ -3511,16 +3624,6 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) smblib_handle_sdp_enumeration_done(chg, (bool)(stat & ENUMERATION_DONE_BIT)); - if (!chg->skip_usb_notification && chg->typec_present) { - smblib_dbg(chg, PR_REGISTER, "Notify USB insertion\n"); - rc = smblib_get_prop_usb_online(chg, &pval); - if (rc < 0) - smblib_err(chg, "Couldn't read USB online status rc=%d\n", - rc); - power_supply_set_online(chg->usb_psy, pval.intval); - power_supply_set_present(chg->usb_psy, true); - } - smblib_handle_slow_plugin_timeout(chg, (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT)); @@ -3628,6 +3731,13 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) chg->pd_hard_reset = 0; chg->typec_legacy_valid = false; + /* write back the default FLOAT charger configuration */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, + (u8)FLOAT_OPTIONS_MASK, chg->float_cfg); + if (rc < 0) + smblib_err(chg, "Couldn't write float charger options rc=%d\n", + rc); + /* reset back to 120mS tCC debounce */ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0); if (rc < 0) @@ -3713,10 +3823,14 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg) smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", rc); - if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) + if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) { typec_sink_insertion(chg); - else + } else { + /* vote to the USB stack to float DP_DM before APSD */ + power_supply_set_dp_dm(chg->usb_psy, + POWER_SUPPLY_DP_DM_DPF_DMF); typec_sink_removal(chg); + } } static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) @@ -3728,6 +3842,24 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT)) return; + /* + * if APSD indicates FLOAT and the USB stack had detected SDP, + * do not respond to Rp changes as we do not confirm that its + * a legacy cable + */ + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) + return; + /* + * We want the ICL vote @ 100mA for a FLOAT charger + * until the detection by the USB stack is complete. + * Ignore the Rp changes unless there is a + * pre-existing valid vote. + */ + if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT && + get_client_vote(chg->usb_icl_votable, + LEGACY_UNKNOWN_VOTER) <= 100000) + return; + /* * handle Rp change for DCP/FLOAT/OCP. * Update the current only if the Rp is different from @@ -3831,6 +3963,14 @@ irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; chg->is_hdc = true; + /* + * Disable usb IRQs after the flag set and re-enable IRQs after + * the flag cleared in the delayed work queue, to avoid any IRQ + * storming during the delays + */ + if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq) + disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); + schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60)); return IRQ_HANDLED; @@ -4005,6 +4145,8 @@ static void clear_hdc_work(struct work_struct *work) clear_hdc_work.work); chg->is_hdc = 0; + if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq) + enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); } static void rdstd_cc2_detach_work(struct work_struct *work) @@ -4302,7 +4444,9 @@ static void smblib_legacy_detection_work(struct work_struct *work) smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc); /* wait for the adapter to turn off VBUS */ - msleep(500); + msleep(1000); + + smblib_dbg(chg, PR_MISC, "legacy workaround enabling typec\n"); rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, @@ -4311,7 +4455,7 @@ static void smblib_legacy_detection_work(struct work_struct *work) smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc); /* wait for type-c detection to complete */ - msleep(100); + msleep(400); rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat); if (rc < 0) { @@ -4323,6 +4467,8 @@ static void smblib_legacy_detection_work(struct work_struct *work) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH; + smblib_dbg(chg, PR_MISC, "legacy workaround done legacy = %d rp_high = %d\n", + legacy, rp_high); if (!legacy || !rp_high) vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, false, 0); diff --git a/drivers/power/smb-lib.h b/drivers/power/smb-lib.h index cc2b722c4367336094ea292bd25a0c3c88992b83..11cbea66003d646bc23b298ce567574eea7b4854 100644 --- a/drivers/power/smb-lib.h +++ b/drivers/power/smb-lib.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * 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 @@ -64,6 +64,8 @@ enum print_reason { #define OTG_DELAY_VOTER "OTG_DELAY_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER" +#define PD_NOT_SUPPORTED_VOTER "PD_NOT_SUPPORTED_VOTER" +#define FG_ESR_VOTER "FG_ESR_VOTER" #define VCONN_MAX_ATTEMPTS 3 #define OTG_MAX_ATTEMPTS 3 @@ -317,6 +319,8 @@ struct smb_charger { int typec_mode; int usb_icl_change_irq_enabled; bool skip_usb_notification; + u32 jeita_status; + u8 float_cfg; /* workaround flag */ u32 wa_flags; @@ -400,12 +404,6 @@ int smblib_get_prop_system_temp_level(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val); int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, @@ -494,6 +492,9 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua); int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua); int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val); int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index 84419af16f777095687eddb59d74c7ca6762e3bb..fd12ccc11e2625eb04b4b575ea233ae7959342db 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -538,6 +538,7 @@ struct powercap_zone *powercap_register_zone( power_zone->id = result; idr_init(&power_zone->idr); + result = -ENOMEM; power_zone->name = kstrdup(name, GFP_KERNEL); if (!power_zone->name) goto err_name_alloc; diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index f8a76090cbca1e8bbf694a4fbc16a54ef60490d5..52d0235145605814f1c40e61518925a2fe9ebcfd 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -88,6 +88,7 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, case PTP_PF_PHYSYNC: if (chan != 0) return -EINVAL; + break; default: return -EINVAL; } diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index f3c64b38f1d364a58e56119f251b1a90d5ed54b2..540db68933e73668ea879885705ecf12049f4514 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -804,7 +804,7 @@ EXPORT_SYMBOL_GPL(devm_pwm_put); */ bool pwm_can_sleep(struct pwm_device *pwm) { - return pwm->chip->can_sleep; + return true; } EXPORT_SYMBOL_GPL(pwm_can_sleep); diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index cb75133085a8b9b0adaa71a3374645520a0023c6..acc9987475f500592365a3b957b3599ba0e58e99 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -384,6 +384,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) aqcsfrc_mask = AQCSFRC_CSFA_MASK; } + /* Update shadow register first before modifying active register */ + ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); /* * Changes to immediate action on Action Qualifier. This puts * Action Qualifier control on PWM output from next TBCLK diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 5a1d4afa4776231e457f5606e0a53c514477b510..87621db13cb77e4c86cdac669149c34386d9b0e0 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -181,6 +181,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, dev_err(dev, "failed to parse DT for regulator %s\n", child->name); + of_node_put(child); return -EINVAL; } match->of_node = of_node_get(child); diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index c879dff597eeaba773468b66a71526a9ca1fb5e8..eceb75105c08ed07a96bd7929c15caf235271ed2 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -142,6 +142,7 @@ static struct regulator_ops pfuze100_sw_regulator_ops = { static struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index b12f1694ad00d5e594a511fe69b2d0eda7c83031..95d15411a45551d99c9c4b787a16be55a694166f 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -249,6 +249,13 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) missing = year; } + /* Can't proceed if alarm is still invalid after replacing + * missing fields. + */ + err = rtc_valid_tm(&alarm->time); + if (err) + goto done; + /* with luck, no rollover is needed */ rtc_tm_to_time(&now, &t_now); rtc_tm_to_time(&alarm->time, &t_alm); @@ -300,9 +307,9 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) dev_warn(&rtc->dev, "alarm rollover not handled\n"); } -done: err = rtc_valid_tm(&alarm->time); +done: if (err) { dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n", alarm->time.tm_year + 1900, alarm->time.tm_mon + 1, @@ -374,6 +381,11 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; + if (!rtc->ops) + return -ENODEV; + else if (!rtc->ops->set_alarm) + return -EINVAL; + err = rtc_valid_tm(&alarm->time); if (err != 0) return err; diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c index a9a0800d99d7211a9c8c648ffb4311dce9d47be1..e49d87e55678276eb83406ab55bbe3a42dd14e6b 100644 --- a/drivers/rtc/qpnp-rtc.c +++ b/drivers/rtc/qpnp-rtc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015,2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015,2018, The Linux Foundation. All rights reserved. * * 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 @@ -593,7 +593,7 @@ static int qpnp_rtc_probe(struct spmi_device *spmi) qpnp_rtc_ops.set_time = qpnp_rtc_set_time; dev_set_drvdata(&spmi->dev, rtc_dd); - + device_init_wakeup(&spmi->dev, 1); /* Register the RTC device */ rtc_dd->rtc = rtc_device_register("qpnp_rtc", &spmi->dev, &qpnp_rtc_ops, THIS_MODULE); @@ -613,7 +613,6 @@ static int qpnp_rtc_probe(struct spmi_device *spmi) goto fail_req_irq; } - device_init_wakeup(&spmi->dev, 1); enable_irq_wake(rtc_dd->rtc_alarm_irq); dev_dbg(&spmi->dev, "Probe success !!\n"); @@ -623,6 +622,7 @@ static int qpnp_rtc_probe(struct spmi_device *spmi) fail_req_irq: rtc_device_unregister(rtc_dd->rtc); fail_rtc_enable: + device_init_wakeup(&spmi->dev, 0); dev_set_drvdata(&spmi->dev, NULL); return rc; diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index fc0ff87aa5dfe23d39689c64b40c0cff1d84b32c..f53198207e9383d96db390b336310278173ee329 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -164,6 +164,10 @@ static int bq4802_probe(struct platform_device *pdev) } else if (p->r->flags & IORESOURCE_MEM) { p->regs = devm_ioremap(&pdev->dev, p->r->start, resource_size(p->r)); + if (!p->regs){ + err = -ENOMEM; + goto out; + } p->read = bq4802_read_mem; p->write = bq4802_write_mem; } else { diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 2e678c681b1304cb15459d011846fa79ab596d94..5d91852af497f7fae4b932b893282c634dd16529 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -86,7 +86,8 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) for (i = 2; i < 6; i++) buf[i] = __raw_readl(&rtcreg->dat); spin_unlock_irq(&pdata->lock); - sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | + (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, tm); return rtc_valid_tm(tm); } @@ -147,7 +148,8 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; spin_unlock_irq(&pdata->lock); - sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | + (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, &alrm->time); return rtc_valid_tm(&alrm->time); } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 35672b081254cc7e7e51c04f406d61ad277143ac..7c73388f8c1c9c30bb5f5660d0c90dfe0eec6d1e 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1672,8 +1672,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, /* check for for attention message */ if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) { device = dasd_device_from_cdev_locked(cdev); - device->discipline->check_attention(device, irb->esw.esw1.lpum); - dasd_put_device(device); + if (!IS_ERR(device)) { + device->discipline->check_attention(device, + irb->esw.esw1.lpum); + dasd_put_device(device); + } } if (!cqr) diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index d261347136820a76957db8b8c9b9654ead81961b..d05c553eb552abcf475abf42338d39fd2734c20f 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2743,6 +2743,16 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) erp = dasd_3990_erp_handle_match_erp(cqr, erp); } + + /* + * For path verification work we need to stick with the path that was + * originally chosen so that the per path configuration data is + * assigned correctly. + */ + if (test_bit(DASD_CQR_VERIFY_PATH, &erp->flags) && cqr->lpm) { + erp->lpm = cqr->lpm; + } + if (device->features & DASD_FEATURE_ERPLOG) { /* print current erp_chain */ dev_err(&device->cdev->dev, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index d47f5b99623a1e4913f6a8d1b9571e18cf5968f1..ff1ab6da8cff4e432f2575f9535a5f8eb0b51239 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -518,10 +518,12 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, pfxdata->validity.define_extent = 1; /* private uid is kept up to date, conf_data may be outdated */ - if (startpriv->uid.type != UA_BASE_DEVICE) { + if (startpriv->uid.type == UA_BASE_PAV_ALIAS) pfxdata->validity.verify_base = 1; - if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) - pfxdata->validity.hyper_pav = 1; + + if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) { + pfxdata->validity.verify_base = 1; + pfxdata->validity.hyper_pav = 1; } /* define extend data (mostly)*/ @@ -2064,8 +2066,11 @@ static int dasd_eckd_basic_to_ready(struct dasd_device *device) static int dasd_eckd_online_to_ready(struct dasd_device *device) { - cancel_work_sync(&device->reload_device); - cancel_work_sync(&device->kick_validate); + if (cancel_work_sync(&device->reload_device)) + dasd_put_device(device); + if (cancel_work_sync(&device->kick_validate)) + dasd_put_device(device); + return 0; }; @@ -2969,10 +2974,12 @@ static int prepare_itcw(struct itcw *itcw, pfxdata.validity.define_extent = 1; /* private uid is kept up to date, conf_data may be outdated */ - if (startpriv->uid.type != UA_BASE_DEVICE) { + if (startpriv->uid.type == UA_BASE_PAV_ALIAS) + pfxdata.validity.verify_base = 1; + + if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) { pfxdata.validity.verify_base = 1; - if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) - pfxdata.validity.hyper_pav = 1; + pfxdata.validity.hyper_pav = 1; } switch (cmd) { diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 83da53c8e54c5b982d604d1c7f91846404d9072b..8febd61e1e55cc4d1dba6c6dea59adc31a633b2c 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -784,6 +784,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_set_timeout(cdev, 0); cdev->private->iretry = 255; + cdev->private->async_kill_io_rc = -ETIMEDOUT; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -860,7 +861,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) /* OK, i/o is dead now. Call interrupt handler. */ if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-EIO)); + ERR_PTR(cdev->private->async_kill_io_rc)); } static void @@ -877,14 +878,16 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_online_verify(cdev, 0); if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-EIO)); + ERR_PTR(cdev->private->async_kill_io_rc)); } void ccw_device_kill_io(struct ccw_device *cdev) { int ret; + ccw_device_set_timeout(cdev, 0); cdev->private->iretry = 255; + cdev->private->async_kill_io_rc = -EIO; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index b108f4a5c7dd33aef5d20d9e5a5074a31ac8514e..b142c7a389b7e50f103f717b652ae491c05475bf 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -155,6 +155,7 @@ struct ccw_device_private { unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; struct irb irb; /* device status */ + int async_kill_io_rc; struct senseid senseid; /* SenseID info */ struct pgid pgid[8]; /* path group IDs per chpid*/ struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 848e3b64ea6e3004d8c2da9f4ed2868ff25305e0..90f93c2be8cde4b52f1f6619eb12554ef324752e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -126,7 +126,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, int start, int count, int auto_ack) { - int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0; + int rc, tmp_count = count, tmp_start = start, nr = q->nr; unsigned int ccq = 0; qperf_inc(q, eqbs); @@ -149,14 +149,7 @@ again: qperf_inc(q, eqbs_partial); DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x", tmp_count); - /* - * Retry once, if that fails bail out and process the - * extracted buffers before trying again. - */ - if (!retried++) - goto again; - else - return count - tmp_count; + return count - tmp_count; } DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); @@ -212,7 +205,10 @@ again: return 0; } -/* returns number of examined buffers and their common state in *state */ +/* + * Returns number of examined buffers and their common state in *state. + * Requested number of buffers-to-examine must be > 0. + */ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, unsigned char *state, unsigned int count, int auto_ack, int merge_pending) @@ -223,17 +219,23 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, if (is_qebsm(q)) return qdio_do_eqbs(q, state, bufnr, count, auto_ack); - for (i = 0; i < count; i++) { - if (!__state) { - __state = q->slsb.val[bufnr]; - if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) - __state = SLSB_P_OUTPUT_EMPTY; - } else if (merge_pending) { - if ((q->slsb.val[bufnr] & __state) != __state) - break; - } else if (q->slsb.val[bufnr] != __state) - break; + /* get initial state: */ + __state = q->slsb.val[bufnr]; + if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) + __state = SLSB_P_OUTPUT_EMPTY; + + for (i = 1; i < count; i++) { bufnr = next_buf(bufnr); + + /* merge PENDING into EMPTY: */ + if (merge_pending && + q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING && + __state == SLSB_P_OUTPUT_EMPTY) + continue; + + /* stop if next state differs from initial state: */ + if (q->slsb.val[bufnr] != __state) + break; } *state = __state; return i; @@ -638,21 +640,20 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q, unsigned long phys_aob = 0; if (!q->use_cq) - goto out; + return 0; if (!q->aobs[bufnr]) { struct qaob *aob = qdio_allocate_aob(); q->aobs[bufnr] = aob; } if (q->aobs[bufnr]) { - q->sbal_state[bufnr].flags = QDIO_OUTBUF_STATE_FLAG_NONE; q->sbal_state[bufnr].aob = q->aobs[bufnr]; q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user; phys_aob = virt_to_phys(q->aobs[bufnr]); WARN_ON_ONCE(phys_aob & 0xFF); } -out: + q->sbal_state[bufnr].flags = 0; return phys_aob; } diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 841fe58fb0b5ec554edd4368ad95ca25855add5b..862f7f358cc4a764d4aad2b21a99c8a35f089049 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -593,6 +593,11 @@ struct qeth_cmd_buffer { void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *); }; +static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob) +{ + return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE); +} + /** * definition of a qeth channel, used for read and write */ diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 2acac8c2ca49cafa3487ddf616b3967d01d43e59..595c140cc79c99787cbf6d9e8551e17a9842aca8 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -517,8 +517,7 @@ static inline int qeth_is_cq(struct qeth_card *card, unsigned int queue) queue == card->qdio.no_in_queues - 1; } - -static int qeth_issue_next_read(struct qeth_card *card) +static int __qeth_issue_next_read(struct qeth_card *card) { int rc; struct qeth_cmd_buffer *iob; @@ -549,6 +548,17 @@ static int qeth_issue_next_read(struct qeth_card *card) return rc; } +static int qeth_issue_next_read(struct qeth_card *card) +{ + int ret; + + spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card))); + ret = __qeth_issue_next_read(card); + spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card))); + + return ret; +} + static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) { struct qeth_reply *reply; @@ -944,7 +954,7 @@ void qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread) spin_lock_irqsave(&card->thread_mask_lock, flags); card->thread_running_mask &= ~thread; spin_unlock_irqrestore(&card->thread_mask_lock, flags); - wake_up(&card->wait_q); + wake_up_all(&card->wait_q); } EXPORT_SYMBOL_GPL(qeth_clear_thread_running_bit); @@ -1148,6 +1158,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, } rc = qeth_get_problem(cdev, irb); if (rc) { + card->read_or_write_problem = 1; qeth_clear_ipacmd_list(card); qeth_schedule_recovery(card); goto out; @@ -1166,7 +1177,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, return; if (channel == &card->read && channel->state == CH_STATE_UP) - qeth_issue_next_read(card); + __qeth_issue_next_read(card); iob = channel->iob; index = channel->buf_no; @@ -2023,7 +2034,7 @@ int qeth_send_control_data(struct qeth_card *card, int len, unsigned long flags; struct qeth_reply *reply = NULL; unsigned long timeout, event_timeout; - struct qeth_ipa_cmd *cmd; + struct qeth_ipa_cmd *cmd = NULL; QETH_CARD_TEXT(card, 2, "sendctl"); @@ -2037,23 +2048,27 @@ int qeth_send_control_data(struct qeth_card *card, int len, } reply->callback = reply_cb; reply->param = reply_param; - if (card->state == CARD_STATE_DOWN) - reply->seqno = QETH_IDX_COMMAND_SEQNO; - else - reply->seqno = card->seqno.ipa++; + init_waitqueue_head(&reply->wait_q); - spin_lock_irqsave(&card->lock, flags); - list_add_tail(&reply->list, &card->cmd_waiter_list); - spin_unlock_irqrestore(&card->lock, flags); QETH_DBF_HEX(CTRL, 2, iob->data, QETH_DBF_CTRL_LEN); while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; - qeth_prepare_control_data(card, len, iob); - if (IS_IPA(iob->data)) + if (IS_IPA(iob->data)) { + cmd = __ipa_cmd(iob); + cmd->hdr.seqno = card->seqno.ipa++; + reply->seqno = cmd->hdr.seqno; event_timeout = QETH_IPA_TIMEOUT; - else + } else { + reply->seqno = QETH_IDX_COMMAND_SEQNO; event_timeout = QETH_TIMEOUT; + } + qeth_prepare_control_data(card, len, iob); + + spin_lock_irqsave(&card->lock, flags); + list_add_tail(&reply->list, &card->cmd_waiter_list); + spin_unlock_irqrestore(&card->lock, flags); + timeout = jiffies + event_timeout; QETH_CARD_TEXT(card, 6, "noirqpnd"); @@ -2078,9 +2093,8 @@ int qeth_send_control_data(struct qeth_card *card, int len, /* we have only one long running ipassist, since we can ensure process context of this command we can sleep */ - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - if ((cmd->hdr.command == IPA_CMD_SETIP) && - (cmd->hdr.prot_version == QETH_PROT_IPV4)) { + if (cmd && cmd->hdr.command == IPA_CMD_SETIP && + cmd->hdr.prot_version == QETH_PROT_IPV4) { if (!wait_event_timeout(reply->wait_q, atomic_read(&reply->received), event_timeout)) goto time_err; @@ -2887,7 +2901,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, memset(cmd, 0, sizeof(struct qeth_ipa_cmd)); cmd->hdr.command = command; cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST; - cmd->hdr.seqno = card->seqno.ipa; + /* cmd->hdr.seqno is set by qeth_send_control_data() */ cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); cmd->hdr.rel_adapter_no = (__u8) card->info.portno; if (card->options.layer2) @@ -3475,13 +3489,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (atomic_read(&queue->set_pci_flags_count)) qdio_flags |= QDIO_FLAG_PCI_OUT; + atomic_add(count, &queue->used_buffers); + rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, queue->queue_no, index, count); if (queue->card->options.performance_stats) queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; - atomic_add(count, &queue->used_buffers); if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ @@ -4934,8 +4949,6 @@ static void qeth_core_free_card(struct qeth_card *card) QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); qeth_clean_channel(&card->read); qeth_clean_channel(&card->write); - if (card->dev) - free_netdev(card->dev); kfree(card->ip_tbd_list); qeth_free_qdio_buffers(card); unregister_service_level(&card->qeth_service_level); diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 9d5f746faf72c190b6f04b55098f4c424fda1916..9eeabfe30747fae63c879ae9e09958fb2224074e 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -456,6 +456,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, if (card->discipline) { card->discipline->remove(card->gdev); qeth_core_free_discipline(card); + card->options.layer2 = -1; } rc = qeth_core_load_discipline(card, newdis); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index e0c3d5850af7733c3c81a72a9e2f27059acd6f80..da8d94b27ec90c7d7c584a69178e817cecbb6c1e 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -452,7 +452,7 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card, default: dev_kfree_skb_any(skb); QETH_CARD_TEXT(card, 3, "inbunkno"); - QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); + QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr)); continue; } work_done++; @@ -922,8 +922,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) qeth_l2_set_offline(cgdev); if (card->dev) { - netif_napi_del(&card->napi); unregister_netdev(card->dev); + free_netdev(card->dev); card->dev = NULL; } return; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index e5f8031ba317e2cc640922d27cdac0e283310812..f3a765655072919a210520173029a44313f1b465 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1993,7 +1993,7 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, default: dev_kfree_skb_any(skb); QETH_CARD_TEXT(card, 3, "inbunkno"); - QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); + QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr)); continue; } work_done++; @@ -2769,17 +2769,13 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, char daddr[16]; struct af_iucv_trans_hdr *iucv_hdr; - skb_pull(skb, 14); - card->dev->header_ops->create(skb, card->dev, 0, - card->dev->dev_addr, card->dev->dev_addr, - card->dev->addr_len); - skb_pull(skb, 14); - iucv_hdr = (struct af_iucv_trans_hdr *)skb->data; memset(hdr, 0, sizeof(struct qeth_hdr)); hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.ext_flags = 0; - hdr->hdr.l3.length = skb->len; + hdr->hdr.l3.length = skb->len - ETH_HLEN; hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; + + iucv_hdr = (struct af_iucv_trans_hdr *) (skb->data + ETH_HLEN); memset(daddr, 0, sizeof(daddr)); daddr[0] = 0xfe; daddr[1] = 0x80; @@ -2962,10 +2958,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && (skb_shinfo(skb)->nr_frags == 0)) { new_skb = skb; - if (new_skb->protocol == ETH_P_AF_IUCV) - data_offset = 0; - else - data_offset = ETH_HLEN; + data_offset = ETH_HLEN; hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); if (!hdr) goto tx_drop; @@ -3340,8 +3333,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) qeth_l3_set_offline(cgdev); if (card->dev) { - netif_napi_del(&card->napi); unregister_netdev(card->dev); + free_netdev(card->dev); card->dev = NULL; } diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index d8f990b6b332c62f41c90b747347c71f56ef1709..333dcb7a0e331a058e94efae52dd5382c61095ca 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -190,7 +190,7 @@ static struct device_driver smsg_driver = { static void __exit smsg_exit(void) { - cpcmd("SET SMSG IUCV", NULL, 0, NULL); + cpcmd("SET SMSG OFF", NULL, 0, NULL); device_unregister(smsg_dev); iucv_unregister(&smsg_handler, 1); driver_unregister(&smsg_driver); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8004b071a9f2e59f5cb9bbe90993ff7b108f973c..a7a0b3e4f5ea92efb9ec3c532234027107eec299 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -356,6 +356,8 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update); + adapter->erp_action.adapter = adapter; + if (zfcp_qdio_setup(adapter)) goto failed; @@ -512,6 +514,9 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, port->dev.groups = zfcp_port_attr_groups; port->dev.release = zfcp_port_release; + port->erp_action.adapter = adapter; + port->erp_action.port = port; + if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) { kfree(port); goto err_out; diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 5d7fbe4e907e37e464c63e8f3278c78edcb838cf..296889dc193f598ee316e6e5288013f2862846d0 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -418,8 +418,8 @@ void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf) rec->scsi_retries = sc->retries; rec->scsi_allowed = sc->allowed; rec->scsi_id = sc->device->id; - /* struct zfcp_dbf_scsi needs to be updated to handle 64bit LUNs */ rec->scsi_lun = (u32)sc->device->lun; + rec->scsi_lun_64_hi = (u32)(sc->device->lun >> 32); rec->host_scribble = (unsigned long)sc->host_scribble; memcpy(rec->scsi_opcode, sc->cmnd, @@ -427,19 +427,32 @@ void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf) if (fsf) { rec->fsf_req_id = fsf->req_id; + rec->pl_len = FCP_RESP_WITH_EXT; fcp_rsp = (struct fcp_resp_with_ext *) &(fsf->qtcb->bottom.io.fcp_rsp); + /* mandatory parts of FCP_RSP IU in this SCSI record */ memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT); if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) { fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; rec->fcp_rsp_info = fcp_rsp_info->rsp_code; + rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_rsp_len); } if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) { - rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE, - (u16)ZFCP_DBF_PAY_MAX_REC); - zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len, - "fcp_sns", fsf->req_id); + rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_sns_len); } + /* complete FCP_RSP IU in associated PAYload record + * but only if there are optional parts + */ + if (fcp_rsp->resp.fr_flags != 0) + zfcp_dbf_pl_write( + dbf, fcp_rsp, + /* at least one full PAY record + * but not beyond hardware response field + */ + min_t(u16, max_t(u16, rec->pl_len, + ZFCP_DBF_PAY_MAX_REC), + FSF_FCP_RSP_SIZE), + "fcp_riu", fsf->req_id); } debug_event(dbf->scsi, 1, rec, sizeof(*rec)); diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 0be3d48681aead94466a71ab7b34c6ae7ca098ff..2039e7510a3045b73987c28327f88e82c0fccec4 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -196,7 +196,7 @@ enum zfcp_dbf_scsi_id { * @id: unique number of recovery record type * @tag: identifier string specifying the location of initiation * @scsi_id: scsi device id - * @scsi_lun: scsi device logical unit number + * @scsi_lun: scsi device logical unit number, low part of 64 bit, old 32 bit * @scsi_result: scsi result * @scsi_retries: current retry number of scsi request * @scsi_allowed: allowed retries @@ -206,6 +206,7 @@ enum zfcp_dbf_scsi_id { * @host_scribble: LLD specific data attached to SCSI request * @pl_len: length of paload stored as zfcp_dbf_pay * @fsf_rsp: response for fsf request + * @scsi_lun_64_hi: scsi device logical unit number, high part of 64 bit */ struct zfcp_dbf_scsi { u8 id; @@ -222,6 +223,7 @@ struct zfcp_dbf_scsi { u64 host_scribble; u16 pl_len; struct fcp_resp_with_ext fcp_rsp; + u32 scsi_lun_64_hi; } __packed; /** @@ -291,7 +293,11 @@ void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) { struct fsf_qtcb *qtcb = req->qtcb; - if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) && + if (unlikely(req->status & (ZFCP_STATUS_FSFREQ_DISMISSED | + ZFCP_STATUS_FSFREQ_ERROR))) { + zfcp_dbf_hba_fsf_resp("fs_rerr", 3, req); + + } else if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) && (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { zfcp_dbf_hba_fsf_resp("fs_perr", 1, req); diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index f263e8c8b64179b35b33b8523b789c582d35372f..a6e62bcc88ac074228b87a556942e468e4e66fd7 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -193,9 +193,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &zfcp_sdev->status); erp_action = &zfcp_sdev->erp_action; - memset(erp_action, 0, sizeof(struct zfcp_erp_action)); - erp_action->port = port; - erp_action->sdev = sdev; + WARN_ON_ONCE(erp_action->port != port); + WARN_ON_ONCE(erp_action->sdev != sdev); if (!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -208,8 +207,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, zfcp_erp_action_dismiss_port(port); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; - memset(erp_action, 0, sizeof(struct zfcp_erp_action)); - erp_action->port = port; + WARN_ON_ONCE(erp_action->port != port); + WARN_ON_ONCE(erp_action->sdev != NULL); if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; @@ -219,7 +218,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, zfcp_erp_action_dismiss_adapter(adapter); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); erp_action = &adapter->erp_action; - memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + WARN_ON_ONCE(erp_action->port != NULL); + WARN_ON_ONCE(erp_action->sdev != NULL); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -229,7 +229,11 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, return NULL; } - erp_action->adapter = adapter; + WARN_ON_ONCE(erp_action->adapter != adapter); + memset(&erp_action->list, 0, sizeof(erp_action->list)); + memset(&erp_action->timer, 0, sizeof(erp_action->timer)); + erp_action->step = ZFCP_ERP_STEP_UNINITIALIZED; + erp_action->fsf_req_id = 0; erp_action->action = need; erp_action->status = act_status; diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index b1d2024ed51367ef4c892a62ed00ecab267ed74b..c2e40e10b293f6fe36d64729f84899f680ca423d 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -4,7 +4,7 @@ * Fibre Channel related definitions and inline functions for the zfcp * device driver * - * Copyright IBM Corp. 2009 + * Copyright IBM Corp. 2009, 2017 */ #ifndef ZFCP_FC_H @@ -291,6 +291,10 @@ void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp, !(rsp_flags & FCP_SNS_LEN_VAL) && fcp_rsp->resp.fr_status == SAM_STAT_GOOD) set_host_byte(scsi, DID_ERROR); + } else if (unlikely(rsp_flags & FCP_RESID_OVER)) { + /* FCP_DL was not sufficient for SCSI data length */ + if (fcp_rsp->resp.fr_status == SAM_STAT_GOOD) + set_host_byte(scsi, DID_ERROR); } } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 0fe8d5d951196425871d958c4003f773f8c4a3e2..5dc56db8a8933d00faf91847d071016ecffd4bbb 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2247,7 +2247,8 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0); - if (scsi_prot_sg_count(scsi_cmnd)) { + if ((scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) && + scsi_prot_sg_count(scsi_cmnd)) { zfcp_qdio_set_data_div(qdio, &req->qdio_req, scsi_prot_sg_count(scsi_cmnd)); retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 7b353647cb9087894ded09ec8b51234023adce85..be9c7d2524e77a066fb4368e565aad8b3df1b38f 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -138,10 +138,15 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) struct zfcp_unit *unit; int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE; + zfcp_sdev->erp_action.adapter = adapter; + zfcp_sdev->erp_action.sdev = sdev; + port = zfcp_get_port_by_wwpn(adapter, rport->port_name); if (!port) return -ENXIO; + zfcp_sdev->erp_action.port = port; + unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev)); if (unit) put_device(&unit->dev); @@ -245,8 +250,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); - if (ret) + if (ret) { + zfcp_dbf_scsi_devreset("fiof", scpnt, tm_flags); return ret; + } if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { @@ -254,8 +261,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) return SUCCESS; } } - if (!fsf_req) + if (!fsf_req) { + zfcp_dbf_scsi_devreset("reqf", scpnt, tm_flags); return FAILED; + } wait_for_completion(&fsf_req->completion); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 6adf9abdf955ed67a3f62ea8ae657e4215bfbe9f..944c44cc2cb98be41024961412aa97f4ac60dc8f 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -901,6 +901,11 @@ static int twa_chrdev_open(struct inode *inode, struct file *file) unsigned int minor_number; int retval = TW_IOCTL_ERROR_OS_ENODEV; + if (!capable(CAP_SYS_ADMIN)) { + retval = -EACCES; + goto out; + } + minor_number = iminor(inode); if (minor_number >= twa_device_extension_count) goto out; @@ -2052,6 +2057,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (twa_initialize_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension"); + retval = -ENOMEM; goto out_free_device_extension; } @@ -2074,6 +2080,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = ioremap(mem_addr, mem_len); if (!tw_dev->base_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); + retval = -ENOMEM; goto out_release_mem_region; } @@ -2081,8 +2088,10 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) TW_DISABLE_INTERRUPTS(tw_dev); /* Initialize the card */ - if (twa_reset_sequence(tw_dev, 0)) + if (twa_reset_sequence(tw_dev, 0)) { + retval = -ENOMEM; goto out_iounmap; + } /* Set host specific parameters */ if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) || diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 2ee2e543ab738627699fee8484b864987ee5f51e..e853e5c3608eaee132562566f4603c2abe85ceb7 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1613,6 +1613,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (twl_initialize_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension"); + retval = -ENOMEM; goto out_free_device_extension; } @@ -1627,6 +1628,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = pci_iomap(pdev, 1, 0); if (!tw_dev->base_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap"); + retval = -ENOMEM; goto out_release_mem_region; } @@ -1636,6 +1638,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) /* Initialize the card */ if (twl_reset_sequence(tw_dev, 0)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe"); + retval = -ENOMEM; goto out_iounmap; } diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index b327742b95ef82e31ecd09a5193f48772b235970..f09db8f428c2069c37bf9370f74acd85483537c4 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1047,6 +1047,9 @@ static int tw_chrdev_open(struct inode *inode, struct file *file) dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + minor_number = iminor(inode); if (minor_number >= tw_device_extension_count) return -ENODEV; @@ -2288,6 +2291,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (tw_initialize_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension."); + retval = -ENOMEM; goto out_free_device_extension; } @@ -2302,6 +2306,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = pci_resource_start(pdev, 0); if (!tw_dev->base_addr) { printk(KERN_WARNING "3w-xxxx: Failed to get io address."); + retval = -ENOMEM; goto out_release_mem_region; } diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index ce177a50ec0515e1f6be0ac4e4db1de34597b28e..e51fc393e1ad1a09ff600db9c5d3b3c7c30a6ef7 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1270,9 +1270,10 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) host = aac->scsi_host_ptr; scsi_block_requests(host); aac_adapter_disable_int(aac); - if (aac->thread->pid != current->pid) { + if (aac->thread && aac->thread->pid != current->pid) { spin_unlock_irq(host->host_lock); kthread_stop(aac->thread); + aac->thread = NULL; jafo = 1; } @@ -1343,6 +1344,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) aac->name); if (IS_ERR(aac->thread)) { retval = PTR_ERR(aac->thread); + aac->thread = NULL; goto out; } } diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index a759cb2d4b15e65868b578a8c3110a7bd6f647b9..3902bf072b5ef16402839720360ced13334cd9e1 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1096,6 +1096,7 @@ static void __aac_shutdown(struct aac_dev * aac) up(&fib->event_wait); } kthread_stop(aac->thread); + aac->thread = NULL; } aac_send_shutdown(aac); aac_adapter_disable_int(aac); @@ -1172,8 +1173,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) * Map in the registers from the adapter. */ aac->base_size = AAC_MIN_FOOTPRINT_SIZE; - if ((*aac_drivers[index].init)(aac)) + if ((*aac_drivers[index].init)(aac)) { + error = -ENODEV; goto out_unmap; + } if (aac->sync_mode) { if (aac_sync_mode) diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index c56741fc4b994ad38138261b63444d28f22c3fc8..f2d5dc164c00cea8bfd8508064a8cf3c667e30ec 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -1047,8 +1047,10 @@ static int __init aic94xx_init(void) aic94xx_transport_template = sas_domain_attach_transport(&aic94xx_transport_functions); - if (!aic94xx_transport_template) + if (!aic94xx_transport_template) { + err = -ENOMEM; goto out_destroy_caches; + } err = pci_register_driver(&aic94xx_pci_driver); if (err) diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 71cfb1e504c4648a0a412b99cd09d51e969414a0..80aa67df41fd7dd071fd0a215b8ec5fdd1e6b23a 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2010,7 +2010,7 @@ static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, * have valid data in the sense buffer that could * confuse the higher levels. */ - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); //printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id); //{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); } /* diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index 8e83d0474fe7c57560714dd488d4db1fcc1f4d15..996f3170a7ab839e376b03627f8602e284a5bdc3 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -254,7 +254,8 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf, struct bfad_s *bfad = port->bfad; struct bfa_s *bfa = &bfad->bfa; struct bfa_ioc_s *ioc = &bfa->ioc; - int addr, len, rc, i; + int addr, rc, i; + u32 len; u32 *regbuf; void __iomem *rb, *reg_addr; unsigned long flags; @@ -274,7 +275,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf, } rc = sscanf(kern_buf, "%x:%x", &addr, &len); - if (rc < 2) { + if (rc < 2 || len > (UINT_MAX >> 2)) { printk(KERN_INFO "bfad[%d]: %s failed to read user buf\n", bfad->inst_no, __func__); diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 1346e052e03cc1311792b8a4c9bf3c85565748a6..8009158a66391c224e6f727c23e7342476a91502 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -191,6 +191,7 @@ struct bnx2fc_hba { struct bnx2fc_cmd_mgr *cmd_mgr; spinlock_t hba_lock; struct mutex hba_mutex; + struct mutex hba_stats_mutex; unsigned long adapter_state; #define ADAPTER_STATE_UP 0 #define ADAPTER_STATE_GOING_DOWN 1 diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 72533c58c1f3bc0d6a18412a197651399abbf6a2..2577f8e86be3c5b97414032dab464fd4d9bc4bae 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -641,15 +641,17 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost) if (!fw_stats) return NULL; + mutex_lock(&hba->hba_stats_mutex); + bnx2fc_stats = fc_get_host_stats(shost); init_completion(&hba->stat_req_done); if (bnx2fc_send_stat_req(hba)) - return bnx2fc_stats; + goto unlock_stats_mutex; rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ)); if (!rc) { BNX2FC_HBA_DBG(lport, "FW stat req timed out\n"); - return bnx2fc_stats; + goto unlock_stats_mutex; } BNX2FC_STATS(hba, rx_stat2, fc_crc_cnt); bnx2fc_stats->invalid_crc_count += hba->bfw_stats.fc_crc_cnt; @@ -671,6 +673,9 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost) memcpy(&hba->prev_stats, hba->stats_buffer, sizeof(struct fcoe_statistics_params)); + +unlock_stats_mutex: + mutex_unlock(&hba->hba_stats_mutex); return bnx2fc_stats; } @@ -1303,6 +1308,7 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) } spin_lock_init(&hba->hba_lock); mutex_init(&hba->hba_mutex); + mutex_init(&hba->hba_stats_mutex); hba->cnic = cnic; diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 5b99844ef6bf73209518c8e586825bbc1486866e..82adbf53eaad2de7f3401d15fd19351c81ed4f15 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1932,6 +1932,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, /* we will not receive ABTS response for this IO */ BNX2FC_IO_DBG(io_req, "Timer context finished processing " "this scsi cmd\n"); + return; } /* Cancel the timeout_work, as we received IO completion */ diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index fb072cc5e9fdb53f92f318d265313095cd8979e1..dada9ce4e70221f4f002c3e655386cb21231433e 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -2742,6 +2742,8 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep) BNX2X_DOORBELL_PCI_BAR); reg_off = (1 << BNX2X_DB_SHIFT) * (cid_num & 0x1FFFF); ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4); + if (!ep->qp.ctx_base) + return -ENOMEM; goto arm_cq; } diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 15081257cfc881d71e0638159dea1e58006f2769..1cfb05bea4c4c997ebfa52812c07eb7319da9642 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1262,6 +1262,7 @@ static void release_offload_resources(struct cxgbi_sock *csk) csk, csk->state, csk->flags, csk->tid); cxgbi_sock_free_cpl_skbs(csk); + cxgbi_sock_purge_write_queue(csk); if (csk->wr_cred != csk->wr_max_cred) { cxgbi_sock_purge_wr_queue(csk); cxgbi_sock_reset_wr_list(csk); diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 84765384c47ca4486caf3a7e4366521af193be3f..d03f0568bfda8930626e3b9e17058f46ccd49717 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -464,7 +464,7 @@ static int clariion_prep_fn(struct scsi_device *sdev, struct request *req) static int clariion_std_inquiry(struct scsi_device *sdev, struct clariion_dh_data *csdev) { - int err; + int err = SCSI_DH_OK; char *sp_model; err = send_inquiry_cmd(sdev, 0, csdev); diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 34a1b1f333b4c16881ea3f6a610f29a73fc18a56..d5184aa1ace4e147e82860e41945d6d23b14bd18 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -752,9 +752,9 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, case ELS_LOGO: if (fip->mode == FIP_MODE_VN2VN) { if (fip->state != FIP_ST_VNMP_UP) - return -EINVAL; + goto drop; if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI) - return -EINVAL; + goto drop; } else { if (fip->state != FIP_ST_ENABLED) return 0; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 8fae03215a85d2d26920146617cbfc68c8a845ed..543c1026698484a4589df18c08dbea68939b1c2c 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -366,7 +366,7 @@ enum ibmvfc_fcp_rsp_info_codes { }; struct ibmvfc_fcp_rsp_info { - __be16 reserved; + u8 reserved[3]; u8 rsp_code; u8 reserved2[4]; }__attribute__((packed, aligned (2))); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 7b23f21f22f1717ad77094c21874661f4f535e88..e9331cf5478d96b52718a4ad1993e88a1828df97 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -93,7 +93,7 @@ static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2; static int fast_fail = 1; static int client_reserve = 1; -static char partition_name[97] = "UNKNOWN"; +static char partition_name[96] = "UNKNOWN"; static unsigned int partition_number = -1; static struct scsi_transport_template *ibmvscsi_transport_template; @@ -261,7 +261,7 @@ static void gather_partition_info(void) ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL); if (ppartition_name) - strncpy(partition_name, ppartition_name, + strlcpy(partition_name, ppartition_name, sizeof(partition_name)); p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL); if (p_number_ptr) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 105adb4cf6a8c154d3cf58c32e7cb8321435063c..54dfae5c8ee3b00c692bb9258c13d68b4e0ccc9f 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -828,8 +828,10 @@ static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) qc->err_mask |= AC_ERR_OTHER; sata_port->ioasa.status |= ATA_BUSY; - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); ata_qc_complete(qc); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -5830,8 +5832,10 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) res->in_erp = 0; } scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -6214,8 +6218,10 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, } scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -6241,8 +6247,10 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) scsi_dma_unmap(scsi_cmd); spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags); } else { spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index ac879745ef8007ab2a4973aff26e3c950e8f1dba..18a409bb9e0ca4955eee05c2ef07eb7020427707 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -291,7 +291,7 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, * Note: We have not moved the current phy_index so we will actually * compare the startting phy with itself. * This is expected and required to add the phy to the port. */ - while (phy_index < SCI_MAX_PHYS) { + for (; phy_index < SCI_MAX_PHYS; phy_index++) { if ((phy_mask & (1 << phy_index)) == 0) continue; sci_phy_get_sas_address(&ihost->phys[phy_index], @@ -311,7 +311,6 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, &ihost->phys[phy_index]); assigned_phy_mask |= (1 << phy_index); - phy_index++; } } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 4c74cf9ffe167ae950b1554956b1d539848d0bd1..857bf9417817fa40e0baf4b2e03d5f4c6b50b031 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -283,11 +283,11 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) */ if (opcode != ISCSI_OP_SCSI_DATA_OUT) { iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " + "task [op %x itt " "0x%x/0x%x] " "rejected.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); + opcode, task->itt, + task->hdr_itt); return -EACCES; } /* @@ -296,10 +296,10 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) */ if (conn->session->fast_abort) { iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " + "task [op %x itt " "0x%x/0x%x] fast abort.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); + opcode, task->itt, + task->hdr_itt); return -EACCES; } break; @@ -1695,6 +1695,15 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) */ switch (session->state) { case ISCSI_STATE_FAILED: + /* + * cmds should fail during shutdown, if the session + * state is bad, allowing completion to happen + */ + if (unlikely(system_state != SYSTEM_RUNNING)) { + reason = FAILURE_SESSION_FAILED; + sc->result = DID_NO_CONNECT << 16; + break; + } case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; sc->result = DID_IMM_RETRY << 16; @@ -1727,7 +1736,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) { reason = FAILURE_SESSION_IN_RECOVERY; - sc->result = DID_REQUEUE; + sc->result = DID_REQUEUE << 16; goto fault; } @@ -1998,6 +2007,19 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) } if (session->state != ISCSI_STATE_LOGGED_IN) { + /* + * During shutdown, if session is prematurely disconnected, + * recovery won't happen and there will be hung cmds. Not + * handling cmds would trigger EH, also bad in this case. + * Instead, handle cmd, allow completion to happen and let + * upper layer to deal with the result. + */ + if (unlikely(system_state != SYSTEM_RUNNING)) { + sc->result = DID_NO_CONNECT << 16; + ISCSI_DBG_EH(session, "sc on shutdown, handled\n"); + rc = BLK_EH_HANDLED; + goto done; + } /* * We are probably in the middle of iscsi recovery so let * that complete and handle the error. @@ -2102,7 +2124,7 @@ done: task->last_timeout = jiffies; spin_unlock(&session->frwd_lock); ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? - "timer reset" : "nh"); + "timer reset" : "shutdown or nh"); return rc; } diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 0cac7d8fd0f7cac75b0ecc2d63662d18eeda4a56..36664c2aad0c5726131e60f884c77c3afd9ca845 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -47,17 +47,16 @@ static void smp_task_timedout(unsigned long _task) unsigned long flags; spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { task->task_state_flags |= SAS_TASK_STATE_ABORTED; + complete(&task->slow_task->completion); + } spin_unlock_irqrestore(&task->task_state_lock, flags); - - complete(&task->slow_task->completion); } static void smp_task_done(struct sas_task *task) { - if (!del_timer(&task->slow_task->timer)) - return; + del_timer(&task->slow_task->timer); complete(&task->slow_task->completion); } @@ -282,6 +281,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) phy->phy->minimum_linkrate = dr->pmin_linkrate; phy->phy->maximum_linkrate = dr->pmax_linkrate; phy->phy->negotiated_linkrate = phy->linkrate; + phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED); skip: if (new_phy) @@ -675,7 +675,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) res = smp_execute_task(dev, req, RPEL_REQ_SIZE, resp, RPEL_RESP_SIZE); - if (!res) + if (res) goto out; phy->invalid_dword_count = scsi_to_u32(&resp[12]); @@ -684,6 +684,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); out: + kfree(req); kfree(resp); return res; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 24e477d2ea701d97a9afe69bf48831cbb8c8cf66..7e3e0fe0ebe97c9e4a202e9cf0ab5d1db96a68fd 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -250,6 +250,7 @@ out_done: static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) { struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); + struct domain_device *dev = cmd_to_domain_dev(cmd); struct sas_task *task = TO_SAS_TASK(cmd); /* At this point, we only get called following an actual abort @@ -258,6 +259,14 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) */ sas_end_task(cmd, task); + if (dev_is_sata(dev)) { + /* defer commands to libata so that libata EH can + * handle ata qcs correctly + */ + list_move_tail(&cmd->eh_entry, &sas_ha->eh_ata_q); + return; + } + /* now finish the command and move it on to the error * handler done list, this also takes it off the * error handler pending list. @@ -265,22 +274,6 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); } -static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) -{ - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_ha_struct *ha = dev->port->ha; - struct sas_task *task = TO_SAS_TASK(cmd); - - if (!dev_is_sata(dev)) { - sas_eh_finish_cmd(cmd); - return; - } - - /* report the timeout to libata */ - sas_end_task(cmd, task); - list_move_tail(&cmd->eh_entry, &ha->eh_ata_q); -} - static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) { struct scsi_cmnd *cmd, *n; @@ -288,7 +281,7 @@ static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd list_for_each_entry_safe(cmd, n, error_q, eh_entry) { if (cmd->device->sdev_target == my_cmd->device->sdev_target && cmd->device->lun == my_cmd->device->lun) - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); } } @@ -678,12 +671,12 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * case TASK_IS_DONE: SAS_DPRINTK("%s: task 0x%p is done\n", __func__, task); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", __func__, task); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); @@ -694,7 +687,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * "recovered\n", SAS_ADDR(task->dev), cmd->device->lun); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); sas_scsi_clear_queue_lu(work_q, cmd); goto Again; } diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 2f9b96826ac0d4b69c66a1a005a24d7c17d30bfb..aa347c3ed33a7f63df739e2b6d7a29ac99307657 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -629,7 +629,12 @@ lpfc_issue_lip(struct Scsi_Host *shost) LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; + /* + * If the link is offline, disabled or BLOCK_MGMT_IO + * it doesn't make any sense to allow issue_lip + */ if ((vport->fc_flag & FC_OFFLINE_MODE) || + (phba->hba_flag & LINK_DISABLED) || (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM; @@ -5136,6 +5141,19 @@ lpfc_free_sysfs_attr(struct lpfc_vport *vport) * Dynamic FC Host Attributes Support */ +/** + * lpfc_get_host_symbolic_name - Copy symbolic name into the scsi host + * @shost: kernel scsi host pointer. + **/ +static void +lpfc_get_host_symbolic_name(struct Scsi_Host *shost) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + + lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost), + sizeof fc_host_symbolic_name(shost)); +} + /** * lpfc_get_host_port_id - Copy the vport DID into the scsi host port id * @shost: kernel scsi host pointer. @@ -5670,6 +5688,8 @@ struct fc_function_template lpfc_transport_functions = { .show_host_supported_fc4s = 1, .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, + + .get_host_symbolic_name = lpfc_get_host_symbolic_name, .show_host_symbolic_name = 1, /* dynamic attributes the driver supports */ @@ -5737,6 +5757,8 @@ struct fc_function_template lpfc_vport_transport_functions = { .show_host_supported_fc4s = 1, .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, + + .get_host_symbolic_name = lpfc_get_host_symbolic_name, .show_host_symbolic_name = 1, /* dynamic attributes the driver supports */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4c25485aa934973742efe76fa34dd8aa00af17db..b55bc56c0e783164a4bc3348f36199df03df1dd1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -6870,7 +6870,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvPRLI++; - if (vport->port_state < LPFC_DISC_AUTH) { + if ((vport->port_state < LPFC_DISC_AUTH) && + (vport->fc_flag & FC_FABRIC)) { rjt_err = LSRJT_UNABLE_TPC; rjt_exp = LSEXP_NOTHING_MORE; break; @@ -7265,11 +7266,17 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); - if (vport->port_type == LPFC_PHYSICAL_PORT - && !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) - lpfc_issue_init_vfi(vport); - else + if (mb->mbxStatus == MBX_NOT_FINISHED) + break; + if ((vport->port_type == LPFC_PHYSICAL_PORT) && + !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) { + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_issue_init_vfi(vport); + else + lpfc_initial_flogi(vport); + } else { lpfc_initial_fdisc(vport); + } break; } } else { diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 5452f1f4220ec50bb55f50ba1872a33302a29579..efb100a3bca43f23a844eec7a69b3d636a426600 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -716,8 +716,9 @@ lpfc_work_done(struct lpfc_hba *phba) (phba->hba_flag & HBA_SP_QUEUE_EVT)) { if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); + /* Preserve legacy behavior. */ + if (!(phba->hba_flag & HBA_SP_QUEUE_EVT)) + set_bit(LPFC_DATA_READY, &phba->data_flags); } else { if (phba->link_state >= LPFC_LINK_UP) { pring->flag &= ~LPFC_DEFERRED_RING_EVENT; @@ -4737,7 +4738,8 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_cancel_retry_delay_tmo(vport, ndlp); if ((ndlp->nlp_flag & NLP_DEFER_RM) && !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) && - !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) { + !(ndlp->nlp_flag & NLP_RPI_REGISTERED) && + phba->sli_rev != LPFC_SLI_REV4) { /* For this case we need to cleanup the default rpi * allocated by the firmware. */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index f432ec180cf819d3c05ed70f121733362c001ed1..37b14a1278be474ca80bdb698d3fdf0e18e6ba1d 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -2951,7 +2951,7 @@ struct lpfc_mbx_get_port_name { #define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 #define MB_CQE_STATUS_DMA_FAILED 0x5 -#define LPFC_MBX_WR_CONFIG_MAX_BDE 8 +#define LPFC_MBX_WR_CONFIG_MAX_BDE 1 struct lpfc_mbx_wr_object { struct mbox_header header; union { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 207a43d952fa47e290894c2ade6dc19df3b1f026..cdade5828a5d609a810689c5d3faa3c3b6328a27 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -115,9 +115,13 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) /* set consumption flag every once in a while */ if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); + else + bf_set(wqe_wqec, &wqe->generic.wqe_com, 0); if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); + /* ensure WQE bcopy flushed before doorbell write */ + wmb(); /* Update the host index before invoking device */ host_index = q->host_index; @@ -9772,6 +9776,7 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->ulpCommand = CMD_CLOSE_XRI_CN; abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + abtsiocbp->vport = vport; lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, "0339 Abort xri x%x, original iotag x%x, " @@ -13466,6 +13471,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, case LPFC_Q_CREATE_VERSION_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, wq->entry_count); + bf_set(lpfc_mbox_hdr_version, &shdr->request, + LPFC_Q_CREATE_VERSION_1); + switch (wq->entry_size) { default: case 64: diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index a87ee33f4f2a6619b9b2f92a35c6e571a7a8d37e..1ea4702da5bb7ca964bed86478baac968180a14b 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -528,6 +528,12 @@ enable_vport(struct fc_vport *fc_vport) spin_lock_irq(shost->host_lock); vport->load_flag |= FC_LOADING; + if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { + spin_unlock_irq(shost->host_lock); + lpfc_issue_init_vpi(vport); + goto out; + } + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); @@ -548,6 +554,8 @@ enable_vport(struct fc_vport *fc_vport) } else { lpfc_vport_set_state(vport, FC_VPORT_FAILED); } + +out: lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, "1827 Vport Enabled.\n"); return VPORT_OK; diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 994fc5caf036c89434f1231425696ec6ecd398ba..79fb6a4f661f8461e2508874252c37c9c71066ae 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -55,6 +55,7 @@ struct mac_esp_priv { int error; }; static struct esp *esp_chips[2]; +static DEFINE_SPINLOCK(esp_chips_lock); #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ platform_get_drvdata((struct platform_device *) \ @@ -562,15 +563,18 @@ static int esp_mac_probe(struct platform_device *dev) } host->irq = IRQ_MAC_SCSI; - esp_chips[dev->id] = esp; - mb(); - if (esp_chips[!dev->id] == NULL) { - err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); - if (err < 0) { - esp_chips[dev->id] = NULL; - goto fail_free_priv; - } + + /* The request_irq() call is intended to succeed for the first device + * and fail for the second device. + */ + err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); + spin_lock(&esp_chips_lock); + if (err < 0 && esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); + goto fail_free_priv; } + esp_chips[dev->id] = esp; + spin_unlock(&esp_chips_lock); err = scsi_esp_register(esp, &dev->dev); if (err) @@ -579,8 +583,13 @@ static int esp_mac_probe(struct platform_device *dev) return 0; fail_free_irq: - if (esp_chips[!dev->id] == NULL) + spin_lock(&esp_chips_lock); + esp_chips[dev->id] = NULL; + if (esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); free_irq(host->irq, esp); + } else + spin_unlock(&esp_chips_lock); fail_free_priv: kfree(mep); fail_free_command_block: @@ -599,9 +608,13 @@ static int esp_mac_remove(struct platform_device *dev) scsi_esp_unregister(esp); + spin_lock(&esp_chips_lock); esp_chips[dev->id] = NULL; - if (!(esp_chips[0] || esp_chips[1])) + if (esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); free_irq(irq, NULL); + } else + spin_unlock(&esp_chips_lock); kfree(mep); diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 2485255f341499a686914c15d1bff2efb59c81c5..a8e6e32639aee869d7ecd9004e187c715e455522 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4200,6 +4200,9 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) int irq, i, j; int error = -ENODEV; + if (hba_count >= MAX_CONTROLLERS) + goto out; + if (pci_enable_device(pdev)) goto out; pci_set_master(pdev); diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 1ff0ece876441b810cde5255a01d102b41231872..24cc8786ff069d896af7ed7b4c1ff30b24b8bcc7 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3743,6 +3743,7 @@ int megasas_alloc_cmds(struct megasas_instance *instance) if (megasas_create_frame_pool(instance)) { printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n"); megasas_free_cmds(instance); + return -ENOMEM; } return 0; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index c1b2e86839ae5403e910a81f6ac7d8b5a15769ee..e9cd3013dcd0047a8983f4e17d4056f18ef788c7 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -404,6 +404,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, return -EINVAL; if (start > ha->optrom_size) return -EINVAL; + if (size > ha->optrom_size - start) + size = ha->optrom_size - start; mutex_lock(&ha->optrom_mutex); switch (val) { @@ -429,8 +431,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, } ha->optrom_region_start = start; - ha->optrom_region_size = start + size > ha->optrom_size ? - ha->optrom_size - start : size; + ha->optrom_region_size = start + size; ha->optrom_state = QLA_SREADING; ha->optrom_buffer = vmalloc(ha->optrom_region_size); @@ -503,8 +504,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, } ha->optrom_region_start = start; - ha->optrom_region_size = start + size > ha->optrom_size ? - ha->optrom_size - start : size; + ha->optrom_region_size = start + size; ha->optrom_state = QLA_SWRITING; ha->optrom_buffer = vmalloc(ha->optrom_region_size); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c919ac042593fff265b60297900966662b9ef2ee..6191c300faff968bc09d4e9163e5c344d731842d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -325,11 +325,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, wait_for_completion(&tm_iocb->u.tmf.comp); - rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ? - QLA_SUCCESS : QLA_FUNCTION_FAILED; + rval = tm_iocb->u.tmf.data; - if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) { - ql_dbg(ql_dbg_taskm, vha, 0x8030, + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x8030, "TM IOCB failed (%x).\n", rval); } @@ -365,6 +364,7 @@ qla24xx_abort_sp_done(void *data, void *ptr, int res) srb_t *sp = (srb_t *)ptr; struct srb_iocb *abt = &sp->u.iocb_cmd; + del_timer(&sp->u.iocb_cmd.timer); complete(&abt->u.abt.comp); } @@ -3211,7 +3211,8 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) return; if (fcport->fp_speed == PORT_SPEED_UNKNOWN || - fcport->fp_speed > ha->link_data_rate) + fcport->fp_speed > ha->link_data_rate || + !ha->flags.gpsc_supported) return; rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed, diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e1911776636928c5f987491f51a1f552ccfc2340..3f613ef474aa2f1370949d71028bebdd7a01d422 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -268,7 +268,8 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n"); else @@ -2454,7 +2455,8 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n"); else diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 26223ff51e661a22995b809b8150bfbc216d4679..7bc28c8d28320837fd371c94550aab8f50dbe8fc 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -5000,8 +5000,9 @@ qla2x00_do_dpc(void *data) } } - if (test_and_clear_bit(ISP_ABORT_NEEDED, - &base_vha->dpc_flags)) { + if (test_and_clear_bit + (ISP_ABORT_NEEDED, &base_vha->dpc_flags) && + !test_bit(UNLOADING, &base_vha->dpc_flags)) { ql_dbg(ql_dbg_dpc, base_vha, 0x4007, "ISP abort scheduled.\n"); diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 8f6d0fb2cd807255a66e962c3cb7c4c8633d4d77..f3c7c5b6bde38b2ad65991bfa09482baa11af9ac 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -167,6 +167,8 @@ #define DEV_DB_NON_PERSISTENT 0 #define DEV_DB_PERSISTENT 1 +#define QL4_ISP_REG_DISCONNECT 0xffffffffU + #define COPY_ISID(dst_isid, src_isid) { \ int i, j; \ for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 199fcf79a051870c654429c4a9bc92d6baa8b4e5..d0cad6fc598e18023d1a63ea82d83b51a2ed87d3 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -268,6 +268,24 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { static struct scsi_transport_template *qla4xxx_scsi_transport; +static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha) +{ + u32 reg_val = 0; + int rval = QLA_SUCCESS; + + if (is_qla8022(ha)) + reg_val = readl(&ha->qla4_82xx_reg->host_status); + else if (is_qla8032(ha) || is_qla8042(ha)) + reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER); + else + reg_val = readw(&ha->reg->ctrl_status); + + if (reg_val == QL4_ISP_REG_DISCONNECT) + rval = QLA_ERROR; + + return rval; +} + static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, uint32_t iface_type, uint32_t payload_size, uint32_t pid, struct sockaddr *dst_addr) @@ -9230,10 +9248,17 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) struct srb *srb = NULL; int ret = SUCCESS; int wait = 0; + int rval; ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n", ha->host_no, id, lun, cmd, cmd->cmnd[0]); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + spin_lock_irqsave(&ha->hardware_lock, flags); srb = (struct srb *) CMD_SP(cmd); if (!srb) { @@ -9285,6 +9310,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int ret = FAILED, stat; + int rval; if (!ddb_entry) return ret; @@ -9304,6 +9330,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + /* FIXME: wait for hba to go online */ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); if (stat != QLA_SUCCESS) { @@ -9347,6 +9379,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int stat, ret; + int rval; if (!ddb_entry) return FAILED; @@ -9364,6 +9397,12 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + stat = qla4xxx_reset_target(ha, ddb_entry); if (stat != QLA_SUCCESS) { starget_printk(KERN_INFO, scsi_target(cmd->device), @@ -9418,9 +9457,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) { int return_status = FAILED; struct scsi_qla_host *ha; + int rval; ha = to_qla_host(cmd->device->host); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba) qla4_83xx_set_idc_dontreset(ha); diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 7439304f01d04c40adbed1a58c22ca8f270b722a..90abf7f5289d69829940175ed5d49805ae15413f 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -160,7 +160,7 @@ static struct { {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, + {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_REPORTLUN2}, {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, {"easyRAID", "16P", NULL, BLIST_NOREPORTLUN}, {"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN}, @@ -180,7 +180,7 @@ static struct { {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ - {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ + {"HP", "OPEN-", "*", BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 46b9f39afe63e0406c13d32ed5cd42e8325a6333..b0aa970fb9997b46253d5d884462066ea63e1bc1 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -676,8 +676,24 @@ static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (device_remove_file_self(dev, attr)) - scsi_remove_device(to_scsi_device(dev)); + struct kernfs_node *kn; + + kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); + WARN_ON_ONCE(!kn); + /* + * Concurrent writes into the "delete" sysfs attribute may trigger + * concurrent calls to device_remove_file() and scsi_remove_device(). + * device_remove_file() handles concurrent removal calls by + * serializing these and by ignoring the second and later removal + * attempts. Concurrent calls of scsi_remove_device() are + * serialized. The second and later calls of scsi_remove_device() are + * ignored because the first call of that function changes the device + * state into SDEV_DEL. + */ + device_remove_file(dev, attr); + scsi_remove_device(to_scsi_device(dev)); + if (kn) + sysfs_unbreak_active_protection(kn); return count; }; static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 67d43e35693df9e9e119bb6a4c2faac56f1bc260..c36c65ccc0b2fcf7687efdc6d8ce408d2d4ba113 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2343,6 +2343,12 @@ iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp) return nlmsg_multicast(nls, skb, 0, group, gfp); } +static int +iscsi_unicast_skb(struct sk_buff *skb, u32 portid) +{ + return nlmsg_unicast(nls, skb, portid); +} + int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size) { @@ -2545,14 +2551,11 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport, EXPORT_SYMBOL_GPL(iscsi_ping_comp_event); static int -iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi, - void *payload, int size) +iscsi_if_send_reply(u32 portid, int type, void *payload, int size) { struct sk_buff *skb; struct nlmsghdr *nlh; int len = nlmsg_total_size(size); - int flags = multi ? NLM_F_MULTI : 0; - int t = done ? NLMSG_DONE : type; skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { @@ -2560,10 +2563,9 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi, return -ENOMEM; } - nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0); - nlh->nlmsg_flags = flags; + nlh = __nlmsg_put(skb, 0, 0, type, (len - sizeof(*nlh)), 0); memcpy(nlmsg_data(nlh), payload, size); - return iscsi_multicast_skb(skb, group, GFP_ATOMIC); + return iscsi_unicast_skb(skb, portid); } static int @@ -3490,6 +3492,7 @@ static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) { int err = 0; + u32 portid; struct iscsi_uevent *ev = nlmsg_data(nlh); struct iscsi_transport *transport = NULL; struct iscsi_internal *priv; @@ -3510,10 +3513,12 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) if (!try_module_get(transport->owner)) return -EINVAL; + portid = NETLINK_CB(skb).portid; + switch (nlh->nlmsg_type) { case ISCSI_UEVENT_CREATE_SESSION: err = iscsi_if_create_session(priv, ep, ev, - NETLINK_CB(skb).portid, + portid, ev->u.c_session.initial_cmdsn, ev->u.c_session.cmds_max, ev->u.c_session.queue_depth); @@ -3526,7 +3531,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) } err = iscsi_if_create_session(priv, ep, ev, - NETLINK_CB(skb).portid, + portid, ev->u.c_bound_session.initial_cmdsn, ev->u.c_bound_session.cmds_max, ev->u.c_bound_session.queue_depth); @@ -3684,6 +3689,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) static void iscsi_if_rx(struct sk_buff *skb) { + u32 portid = NETLINK_CB(skb).portid; + mutex_lock(&rx_queue_mutex); while (skb->len >= NLMSG_HDRLEN) { int err; @@ -3693,7 +3700,7 @@ iscsi_if_rx(struct sk_buff *skb) uint32_t group; nlh = nlmsg_hdr(skb); - if (nlh->nlmsg_len < sizeof(*nlh) || + if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) || skb->len < nlh->nlmsg_len) { break; } @@ -3719,8 +3726,8 @@ iscsi_if_rx(struct sk_buff *skb) break; if (ev->type == ISCSI_UEVENT_GET_CHAP && !err) break; - err = iscsi_if_send_reply(group, nlh->nlmsg_seq, - nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); + err = iscsi_if_send_reply(portid, nlh->nlmsg_type, + ev, sizeof(*ev)); } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH); skb_pull(skb, rlen); } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8192b7af62a44a726144f19e052bef2349f4bd87..4b7ed4e82551f1b94a32fc773c32dd8b8f0ac018 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1795,6 +1795,8 @@ sd_spinup_disk(struct scsi_disk *sdkp) break; /* standby */ if (sshdr.asc == 4 && sshdr.ascq == 0xc) break; /* unavailable */ + if (sshdr.asc == 4 && sshdr.ascq == 0x1b) + break; /* sanitize in progress */ /* * Issue command to spin up drive when not ready */ diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index c1abb35c896a5217b45c5ef9b86a3193995d8ab3..9848a9c8944d293e1deaf3c8152d7b2d095a846a 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -51,6 +51,8 @@ static int sg_version_num = 30536; /* 2 digits for each component */ #include #include #include +#include +#include /* for sg_check_file_access() */ #include "scsi.h" #include @@ -133,7 +135,7 @@ struct sg_device; /* forward declarations */ struct sg_fd; typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ - struct sg_request *nextrp; /* NULL -> tail request (slist) */ + struct list_head entry; /* list entry */ struct sg_fd *parentfp; /* NULL -> not in use */ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ sg_io_hdr_t header; /* scsi command+info, see */ @@ -157,11 +159,9 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ - unsigned save_scat_len; /* original length of trunc. scat. element */ - Sg_request *headrp; /* head of request slist, NULL->empty */ + struct list_head rq_list; /* head of request list */ struct fasync_struct *async_qp; /* used by asynchronous notification */ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ - char low_dma; /* as in parent but possibly overridden to 1 */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */ @@ -223,6 +223,33 @@ static void sg_device_destroy(struct kref *kref); sdev_printk(prefix, (sdp)->device, "[%s] " fmt, \ (sdp)->disk->disk_name, ##a) +/* + * The SCSI interfaces that use read() and write() as an asynchronous variant of + * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways + * to trigger read() and write() calls from various contexts with elevated + * privileges. This can lead to kernel memory corruption (e.g. if these + * interfaces are called through splice()) and privilege escalation inside + * userspace (e.g. if a process with access to such a device passes a file + * descriptor to a SUID binary as stdin/stdout/stderr). + * + * This function provides protection for the legacy API by restricting the + * calling context. + */ +static int sg_check_file_access(struct file *filp, const char *caller) +{ + if (filp->f_cred != current_real_cred()) { + pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", + caller, task_tgid_vnr(current), current->comm); + return -EPERM; + } + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + pr_err_once("%s: process %d (%s) called from kernel context, this is not allowed.\n", + caller, task_tgid_vnr(current), current->comm); + return -EACCES; + } + return 0; +} + static int sg_allow_access(struct file *filp, unsigned char *cmd) { struct sg_fd *sfp = filp->private_data; @@ -407,6 +434,14 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) struct sg_header *old_hdr = NULL; int retval = 0; + /* + * This could cause a response to be stranded. Close the associated + * file descriptor to free up any resources being held. + */ + retval = sg_check_file_access(filp, __func__); + if (retval) + return retval; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, @@ -537,6 +572,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) } else count = (old_hdr->result == 0) ? 0 : -EIO; sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); retval = count; free_old_hdr: kfree(old_hdr); @@ -577,6 +613,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) } err_out: err2 = sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return err ? : err2 ? : count; } @@ -592,9 +629,11 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) struct sg_header old_hdr; sg_io_hdr_t *hp; unsigned char cmnd[SG_MAX_CDB_SIZE]; + int retval; - if (unlikely(segment_eq(get_fs(), KERNEL_DS))) - return -EINVAL; + retval = sg_check_file_access(filp, __func__); + if (retval) + return retval; if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; @@ -676,18 +715,14 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) * is a non-zero input_size, so emit a warning. */ if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - static char cmd[TASK_COMM_LEN]; - if (strcmp(current->comm, cmd)) { - printk_ratelimited(KERN_WARNING - "sg_write: data in/out %d/%d bytes " - "for SCSI command 0x%x-- guessing " - "data in;\n program %s not setting " - "count and/or reply_len properly\n", - old_hdr.reply_len - (int)SZ_SG_HEADER, - input_size, (unsigned int) cmnd[0], - current->comm); - strcpy(cmd, current->comm); - } + printk_ratelimited(KERN_WARNING + "sg_write: data in/out %d/%d bytes " + "for SCSI command 0x%x-- guessing " + "data in;\n program %s not setting " + "count and/or reply_len properly\n", + old_hdr.reply_len - (int)SZ_SG_HEADER, + input_size, (unsigned int) cmnd[0], + current->comm); } k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); return (k < 0) ? k : count; @@ -786,11 +821,15 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, "sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) cmnd[0], (int) hp->cmd_len)); + if (hp->dxfer_len >= SZ_256M) + return -EINVAL; + k = sg_start_req(srp, cmnd); if (k) { SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, "sg_common_write: start_req err=%d\n", k)); sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return k; /* probably out of space --> ENOMEM */ } if (atomic_read(&sdp->detaching)) { @@ -803,6 +842,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, } sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return -ENODEV; } @@ -855,6 +895,39 @@ static int max_sectors_bytes(struct request_queue *q) return max_sectors << 9; } +static void +sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo) +{ + Sg_request *srp; + int val; + unsigned int ms; + + val = 0; + list_for_each_entry(srp, &sfp->rq_list, entry) { + if (val >= SG_MAX_QUEUE) + break; + rinfo[val].req_state = srp->done + 1; + rinfo[val].problem = + srp->header.masked_status & + srp->header.host_status & + srp->header.driver_status; + if (srp->done) + rinfo[val].duration = + srp->header.duration; + else { + ms = jiffies_to_msecs(jiffies); + rinfo[val].duration = + (ms > srp->header.duration) ? + (ms - srp->header.duration) : 0; + } + rinfo[val].orphan = srp->orphan; + rinfo[val].sg_io_owned = srp->sg_io_owned; + rinfo[val].pack_id = srp->header.pack_id; + rinfo[val].usr_ptr = srp->header.usr_ptr; + val++; + } +} + static long sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) { @@ -917,25 +990,14 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) /* strange ..., for backward compatibility */ return sfp->timeout_user; case SG_SET_FORCE_LOW_DMA: - result = get_user(val, ip); - if (result) - return result; - if (val) { - sfp->low_dma = 1; - if ((0 == sfp->low_dma) && !sfp->res_in_use) { - val = (int) sfp->reserve.bufflen; - sg_remove_scat(sfp, &sfp->reserve); - sg_build_reserve(sfp, val); - mutex_unlock(&sfp->parentdp->open_rel_lock); - } - } else { - if (atomic_read(&sdp->detaching)) - return -ENODEV; - sfp->low_dma = sdp->device->host->unchecked_isa_dma; - } + /* + * N.B. This ioctl never worked properly, but failed to + * return an error value. So returning '0' to keep compability + * with legacy applications. + */ return 0; case SG_GET_LOW_DMA: - return put_user((int) sfp->low_dma, ip); + return put_user((int) sdp->device->host->unchecked_isa_dma, ip); case SG_GET_SCSI_ID: if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t))) return -EFAULT; @@ -969,7 +1031,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) if (!access_ok(VERIFY_WRITE, ip, sizeof (int))) return -EFAULT; read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) { + list_for_each_entry(srp, &sfp->rq_list, entry) { if ((1 == srp->done) && (!srp->sg_io_owned)) { read_unlock_irqrestore(&sfp->rq_list_lock, iflags); @@ -982,7 +1044,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return 0; case SG_GET_NUM_WAITING: read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) { + val = 0; + list_for_each_entry(srp, &sfp->rq_list, entry) { if ((1 == srp->done) && (!srp->sg_io_owned)) ++val; } @@ -1051,40 +1114,13 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return -EFAULT; else { sg_req_info_t *rinfo; - unsigned int ms; - rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE, - GFP_KERNEL); + rinfo = kzalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE, + GFP_KERNEL); if (!rinfo) return -ENOMEM; read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; - ++val, srp = srp ? srp->nextrp : srp) { - memset(&rinfo[val], 0, SZ_SG_REQ_INFO); - if (srp) { - rinfo[val].req_state = srp->done + 1; - rinfo[val].problem = - srp->header.masked_status & - srp->header.host_status & - srp->header.driver_status; - if (srp->done) - rinfo[val].duration = - srp->header.duration; - else { - ms = jiffies_to_msecs(jiffies); - rinfo[val].duration = - (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; - } - rinfo[val].orphan = srp->orphan; - rinfo[val].sg_io_owned = - srp->sg_io_owned; - rinfo[val].pack_id = - srp->header.pack_id; - rinfo[val].usr_ptr = - srp->header.usr_ptr; - } - } + sg_fill_request_table(sfp, rinfo); read_unlock_irqrestore(&sfp->rq_list_lock, iflags); result = __copy_to_user(p, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE); @@ -1218,7 +1254,7 @@ sg_poll(struct file *filp, poll_table * wait) return POLLERR; poll_wait(filp, &sfp->read_wait, wait); read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) { + list_for_each_entry(srp, &sfp->rq_list, entry) { /* if any read waiting, flag it */ if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned)) res = POLLIN | POLLRDNORM; @@ -1340,6 +1376,7 @@ sg_rq_end_io_usercontext(struct work_struct *work) struct sg_fd *sfp = srp->parentfp; sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); kref_put(&sfp->f_ref, sg_remove_sfp); } @@ -1886,8 +1923,6 @@ sg_finish_rem_req(Sg_request *srp) else sg_remove_scat(sfp, req_schp); - sg_remove_request(sfp, srp); - return ret; } @@ -1911,6 +1946,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) int sg_tablesize = sfp->parentdp->sg_tablesize; int blk_size = buff_size, order; gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN; + struct sg_device *sdp = sfp->parentdp; if (blk_size < 0) return -EFAULT; @@ -1936,7 +1972,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) scatter_elem_sz_prev = num; } - if (sfp->low_dma) + if (sdp->device->host->unchecked_isa_dma) gfp_mask |= GFP_DMA; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) @@ -1952,7 +1988,7 @@ retry: num = (rem_sz > scatter_elem_sz_prev) ? scatter_elem_sz_prev : rem_sz; - schp->pages[k] = alloc_pages(gfp_mask, order); + schp->pages[k] = alloc_pages(gfp_mask | __GFP_ZERO, order); if (!schp->pages[k]) goto out; @@ -2106,7 +2142,6 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp) req_schp->pages = NULL; req_schp->page_order = 0; req_schp->sglist_len = 0; - sfp->save_scat_len = 0; srp->res_used = 0; /* Called without mutex lock to avoid deadlock */ sfp->res_in_use = 0; @@ -2119,7 +2154,7 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id) unsigned long iflags; write_lock_irqsave(&sfp->rq_list_lock, iflags); - for (resp = sfp->headrp; resp; resp = resp->nextrp) { + list_for_each_entry(resp, &sfp->rq_list, entry) { /* look for requests that are ready + not SG_IO owned */ if ((1 == resp->done) && (!resp->sg_io_owned) && ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { @@ -2138,70 +2173,45 @@ sg_add_request(Sg_fd * sfp) { int k; unsigned long iflags; - Sg_request *resp; Sg_request *rp = sfp->req_arr; write_lock_irqsave(&sfp->rq_list_lock, iflags); - resp = sfp->headrp; - if (!resp) { - memset(rp, 0, sizeof (Sg_request)); - rp->parentfp = sfp; - resp = rp; - sfp->headrp = resp; - } else { - if (0 == sfp->cmd_q) - resp = NULL; /* command queuing disallowed */ - else { - for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { - if (!rp->parentfp) - break; - } - if (k < SG_MAX_QUEUE) { - memset(rp, 0, sizeof (Sg_request)); - rp->parentfp = sfp; - while (resp->nextrp) - resp = resp->nextrp; - resp->nextrp = rp; - resp = rp; - } else - resp = NULL; + if (!list_empty(&sfp->rq_list)) { + if (!sfp->cmd_q) + goto out_unlock; + + for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { + if (!rp->parentfp) + break; } + if (k >= SG_MAX_QUEUE) + goto out_unlock; } - if (resp) { - resp->nextrp = NULL; - resp->header.duration = jiffies_to_msecs(jiffies); - } + memset(rp, 0, sizeof (Sg_request)); + rp->parentfp = sfp; + rp->header.duration = jiffies_to_msecs(jiffies); + list_add_tail(&rp->entry, &sfp->rq_list); write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return resp; + return rp; +out_unlock: + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return NULL; } /* Return of 1 for found; 0 for not found */ static int sg_remove_request(Sg_fd * sfp, Sg_request * srp) { - Sg_request *prev_rp; - Sg_request *rp; unsigned long iflags; int res = 0; - if ((!sfp) || (!srp) || (!sfp->headrp)) + if (!sfp || !srp || list_empty(&sfp->rq_list)) return res; write_lock_irqsave(&sfp->rq_list_lock, iflags); - prev_rp = sfp->headrp; - if (srp == prev_rp) { - sfp->headrp = prev_rp->nextrp; - prev_rp->parentfp = NULL; + if (!list_empty(&srp->entry)) { + list_del(&srp->entry); + srp->parentfp = NULL; res = 1; - } else { - while ((rp = prev_rp->nextrp)) { - if (srp == rp) { - prev_rp->nextrp = rp->nextrp; - rp->parentfp = NULL; - res = 1; - break; - } - prev_rp = rp; - } } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return res; @@ -2220,20 +2230,19 @@ sg_add_sfp(Sg_device * sdp) init_waitqueue_head(&sfp->read_wait); rwlock_init(&sfp->rq_list_lock); - + INIT_LIST_HEAD(&sfp->rq_list); kref_init(&sfp->f_ref); mutex_init(&sfp->f_mutex); sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER; sfp->force_packid = SG_DEF_FORCE_PACK_ID; - sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? - sdp->device->host->unchecked_isa_dma : 1; sfp->cmd_q = SG_DEF_COMMAND_Q; sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; write_lock_irqsave(&sdp->sfd_lock, iflags); if (atomic_read(&sdp->detaching)) { write_unlock_irqrestore(&sdp->sfd_lock, iflags); + kfree(sfp); return ERR_PTR(-ENODEV); } list_add_tail(&sfp->sfd_siblings, &sdp->sfds); @@ -2261,10 +2270,18 @@ sg_remove_sfp_usercontext(struct work_struct *work) { struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work); struct sg_device *sdp = sfp->parentdp; + Sg_request *srp; + unsigned long iflags; /* Cleanup any responses which were never read(). */ - while (sfp->headrp) - sg_finish_rem_req(sfp->headrp); + write_lock_irqsave(&sfp->rq_list_lock, iflags); + while (!list_empty(&sfp->rq_list)) { + srp = list_first_entry(&sfp->rq_list, Sg_request, entry); + sg_finish_rem_req(srp); + list_del(&srp->entry); + srp->parentfp = NULL; + } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp, @@ -2667,7 +2684,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) /* must be called while holding sg_index_lock */ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) { - int k, m, new_interface, blen, usg; + int k, new_interface, blen, usg; Sg_request *srp; Sg_fd *fp; const sg_io_hdr_t *hp; @@ -2683,13 +2700,11 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) jiffies_to_msecs(fp->timeout), fp->reserve.bufflen, (int) fp->reserve.k_use_sg, - (int) fp->low_dma); + (int) sdp->device->host->unchecked_isa_dma); seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n", (int) fp->cmd_q, (int) fp->force_packid, (int) fp->keep_orphan); - for (m = 0, srp = fp->headrp; - srp != NULL; - ++m, srp = srp->nextrp) { + list_for_each_entry(srp, &fp->rq_list, entry) { hp = &srp->header; new_interface = (hp->interface_id == '\0') ? 0 : 1; if (srp->res_used) { @@ -2727,7 +2742,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); } - if (0 == m) + if (list_empty(&fp->rq_list)) seq_puts(s, " No requests active\n"); read_unlock(&fp->rq_list_lock); } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 288bd5f7dc03eda96014c5c225b1535134701874..ff243f88d87814dc4a635ffb67b79c2d62741ad9 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -522,6 +522,8 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode) struct scsi_cd *cd; int ret = -ENXIO; + check_disk_change(bdev); + mutex_lock(&sr_mutex); cd = scsi_cd_get(bdev->bd_disk); if (cd) { @@ -587,18 +589,28 @@ out: static unsigned int sr_block_check_events(struct gendisk *disk, unsigned int clearing) { - struct scsi_cd *cd = scsi_cd(disk); + unsigned int ret = 0; + struct scsi_cd *cd; - if (atomic_read(&cd->device->disk_events_disable_depth)) + cd = scsi_cd_get(disk); + if (!cd) return 0; - return cdrom_check_events(&cd->cdi, clearing); + if (!atomic_read(&cd->device->disk_events_disable_depth)) + ret = cdrom_check_events(&cd->cdi, clearing); + + scsi_cd_put(cd); + return ret; } static int sr_block_revalidate_disk(struct gendisk *disk) { - struct scsi_cd *cd = scsi_cd(disk); struct scsi_sense_hdr sshdr; + struct scsi_cd *cd; + + cd = scsi_cd_get(disk); + if (!cd) + return -ENXIO; /* if the unit is not ready, nothing more to do */ if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) @@ -607,6 +619,7 @@ static int sr_block_revalidate_disk(struct gendisk *disk) sr_cd_check(&cd->cdi); get_sectorsize(cd); out: + scsi_cd_put(cd); return 0; } diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index e511e3406cfa88377540d5cee11bfc87668f05b8..96c6e75bbfe62b3e1a91b915de712ed5343ac3e5 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1029,10 +1029,11 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, case TEST_UNIT_READY: break; default: - set_host_byte(scmnd, DID_TARGET_FAILURE); + set_host_byte(scmnd, DID_ERROR); } break; case SRB_STATUS_INVALID_LUN: + set_host_byte(scmnd, DID_NO_CONNECT); do_work = true; process_err_fn = storvsc_remove_lun; break; diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 6b349e3018692435b3523f8d0cef4e4daaf6f3ef..c6425e3df5a04958dca96430eb507ad13684b76b 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -536,7 +536,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa * Look for the greatest clock divisor that allows an * input speed faster than the period. */ - while (div-- > 0) + while (--div > 0) if (kpc >= (div_10M[div] << 2)) break; /* diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 36edd2baac5867bdbd06243403add4f409e12d5b..699e5b706211bb1e9693cec8a8140a3c3abc81e6 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5138,10 +5138,10 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, completion = ktime_get(); delta_us = ktime_us_delta(completion, req->lat_hist_io_start); - /* rq_data_dir() => true if WRITE */ - blk_update_latency_hist(&hba->io_lat_s, - (rq_data_dir(req) == READ), - delta_us); + blk_update_latency_hist( + (rq_data_dir(req) == READ) ? + &hba->io_lat_read : + &hba->io_lat_write, delta_us); } } /* Do not touch lrbp after scsi done */ @@ -5473,7 +5473,11 @@ static void ufshcd_exception_event_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, eeh_work); pm_runtime_get_sync(hba->dev); + ufshcd_scsi_block_requests(hba); + + + err = ufshcd_get_ee_status(hba, &status); if (err) { dev_err(hba->dev, "%s: failed to get exception status %d\n", @@ -5487,7 +5491,11 @@ static void ufshcd_exception_event_handler(struct work_struct *work) ufshcd_bkops_exception_event_handler(hba); out: + ufshcd_scsi_unblock_requests(hba); + + + pm_runtime_put_sync(hba->dev); return; } @@ -7331,12 +7339,15 @@ static int ufshcd_config_vreg(struct device *dev, struct ufs_vreg *vreg, bool on) { int ret = 0; - struct regulator *reg = vreg->reg; - const char *name = vreg->name; + struct regulator *reg; + const char *name; int min_uV, uA_load; BUG_ON(!vreg); + reg = vreg->reg; + name = vreg->name; + if (regulator_count_voltages(reg) > 0) { min_uV = on ? vreg->min_uV : 0; ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); @@ -8580,9 +8591,10 @@ latency_hist_store(struct device *dev, struct device_attribute *attr, if (kstrtol(buf, 0, &value)) return -EINVAL; - if (value == BLK_IO_LAT_HIST_ZERO) - blk_zero_latency_hist(&hba->io_lat_s); - else if (value == BLK_IO_LAT_HIST_ENABLE || + if (value == BLK_IO_LAT_HIST_ZERO) { + memset(&hba->io_lat_read, 0, sizeof(hba->io_lat_read)); + memset(&hba->io_lat_write, 0, sizeof(hba->io_lat_write)); + } else if (value == BLK_IO_LAT_HIST_ENABLE || value == BLK_IO_LAT_HIST_DISABLE) hba->latency_hist_enabled = value; return count; @@ -8593,8 +8605,14 @@ latency_hist_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); + size_t written_bytes; + + written_bytes = blk_latency_hist_show("Read", &hba->io_lat_read, + buf, PAGE_SIZE); + written_bytes += blk_latency_hist_show("Write", &hba->io_lat_write, + buf + written_bytes, PAGE_SIZE - written_bytes); - return blk_latency_hist_show(&hba->io_lat_s, buf); + return written_bytes; } static DEVICE_ATTR(latency_hist, S_IRUGO | S_IWUSR, diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 465012a0362dc2cd59ac3a1e2d63b95b75533851..97f50f7a4d4d9a0f0d96dd822bdd9beacdf53359 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -890,7 +890,8 @@ struct ufs_hba { int scsi_block_reqs_cnt; int latency_hist_enabled; - struct io_latency_state io_lat_s; + struct io_latency_state io_lat_read; + struct io_latency_state io_lat_write; }; /* Returns true if clocks can be gated. Otherwise false */ diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index b83846fc785964a93b9885e690b6de2f72175b4f..4b179030fb9234dc8a48eb38adf0455bbca646fb 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #define VIRTIO_SCSI_MEMPOOL_SZ 64 @@ -664,6 +665,28 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc) return virtscsi_tmf(vscsi, cmd); } +static int virtscsi_device_alloc(struct scsi_device *sdevice) +{ + /* + * Passed through SCSI targets (e.g. with qemu's 'scsi-block') + * may have transfer limits which come from the host SCSI + * controller or something on the host side other than the + * target itself. + * + * To make this work properly, the hypervisor can adjust the + * target's VPD information to advertise these limits. But + * for that to work, the guest has to look at the VPD pages, + * which we won't do by default if it is an SPC-2 device, even + * if it does actually support it. + * + * So, set the blist to always try to read the VPD pages. + */ + sdevice->sdev_bflags = BLIST_TRY_VPD_PAGES; + + return 0; +} + + /** * virtscsi_change_queue_depth() - Change a virtscsi target's queue depth * @sdev: Virtscsi target whose queue depth to change @@ -752,6 +775,7 @@ static struct scsi_host_template virtscsi_host_template_single = { .change_queue_depth = virtscsi_change_queue_depth, .eh_abort_handler = virtscsi_abort, .eh_device_reset_handler = virtscsi_device_reset, + .slave_alloc = virtscsi_device_alloc, .can_queue = 1024, .dma_boundary = UINT_MAX, @@ -770,6 +794,7 @@ static struct scsi_host_template virtscsi_host_template_multi = { .change_queue_depth = virtscsi_change_queue_depth, .eh_abort_handler = virtscsi_abort, .eh_device_reset_handler = virtscsi_device_reset, + .slave_alloc = virtscsi_device_alloc, .can_queue = 1024, .dma_boundary = UINT_MAX, diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 598f65efaaec0e725851301959d138deda7cfaa1..d5dd70049f8140c91afb21417e62cf98a41b7a89 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -567,9 +567,14 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, (btstat == BTSTAT_SUCCESS || btstat == BTSTAT_LINKED_COMMAND_COMPLETED || btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { - cmd->result = (DID_OK << 16) | sdstat; - if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer) - cmd->result |= (DRIVER_SENSE << 24); + if (sdstat == SAM_STAT_COMMAND_TERMINATED) { + cmd->result = (DID_RESET << 16); + } else { + cmd->result = (DID_OK << 16) | sdstat; + if (sdstat == SAM_STAT_CHECK_CONDITION && + cmd->sense_buffer) + cmd->result |= (DRIVER_SENSE << 24); + } } else switch (btstat) { case BTSTAT_SUCCESS: @@ -615,7 +620,7 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, break; case BTSTAT_ABORTQUEUE: - cmd->result = (DID_ABORT << 16); + cmd->result = (DID_BUS_BUSY << 16); break; case BTSTAT_SCSIPARITY: diff --git a/drivers/sensors/sensors_ssc.c b/drivers/sensors/sensors_ssc.c index c8287be3f40a43de39023e303f7c4b51729b4b00..ad630b67a83edc40a8d5ecd25c0c6e164ca68a58 100644 --- a/drivers/sensors/sensors_ssc.c +++ b/drivers/sensors/sensors_ssc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 19ed167c7bc2e5bd70f0a29bbc8b6b7e6dd2fdc0..7c237999bcf03155ec2f5b51228cb3f9cdda0b0e 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -41,6 +41,15 @@ config MSM_QDSP6_APRV2 used by audio driver to configure QDSP6's ASM, ADM and AFE. +config MSM_QDSP6_APRV2_VM + bool "Audio QDSP6 APRv2 virtualization support" + depends on MSM_HAB + help + Enable APRv2 IPC protocol support over + HAB between application processor and + QDSP6. APR is used by audio driver to + configure QDSP6's ASM, ADM and AFE. + config MSM_GLADIATOR_ERP tristate "GLADIATOR coherency interconnect error reporting driver" help @@ -663,6 +672,15 @@ config MSM_GLINK_PKT This enable the usersapce clients to read and write to some glink packets channel. +config MSM_BGRSB + bool "Provide support for rsb events on Blackghost chipset" + depends on MSM_GLINK + help + BGRSB communicates to BG over Glink for RSB configuration and + enable/disable on device power state change. It enables/disables + the regulator specific to RSB. Sends the side band events generated + by BG to input framework. + config MSM_TZ_SMMU bool "Helper functions for SMMU configuration through TZ" depends on ARCH_MSMTHULIUM || ARCH_MSM8953 @@ -751,15 +769,6 @@ config MSM_SECURE_BUFFER use this memory and no unauthorized access is made to the buffer -config ICNSS - tristate "Platform driver for Q6 integrated connectivity" - select CNSS_UTILS - ---help--- - This module adds support for Q6 integrated WLAN connectivity - subsystem. This module is responsible for communicating WLAN on/off - control messages to FW over QMI channel. It is also responsible for - handling WLAN PD restart notifications. - config MSM_BAM_DMUX bool "BAM Data Mux Driver" depends on SPS @@ -884,10 +893,29 @@ config QCOM_EARLY_RANDOM may not be truly random. Select this option to make an early call to get some random data to put in the pool. If unsure, say N. +config QCOM_QDSS_BRIDGE + bool "Configure bridge driver for Qualcomm Technologies, Inc. MDM" + depends on MSM_MHI + help + The driver will help route diag traffic over the QDSS sub-system to + USB on APPS side. The driver acts as a bridge between the PCIE MHI + and USB interface. The amount of buffer memory allocated at runtime + can be modified via module params. If unsure, say N. + +config MSM_BG_GLINK + tristate "WCD DSP GLINK Driver" + depends on MSM_GLINK + default y if MSM_BGCOM=y + help + This option enables driver which provides communication interface + between MSM and BG over glink transport protocol. This driver + provides read and write interface via char device.This driver is + used by the audio codec driver to interface with BG. + config WCD_DSP_GLINK tristate "WCD DSP GLINK Driver" depends on MSM_GLINK - default y if SND_SOC_WCD934X=y + default y if (SND_SOC_WCD934X=y || MSM_BG_GLINK=y) help This option enables driver which provides communication interface between MSM and WCD DSP over glink transport protocol. This driver diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 81f85c9faf8d41887c010d97233eac95b3118797..d2e186bfc205f4d42d584022eaff7818c570b570 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -46,8 +46,8 @@ obj-$(CONFIG_MSM_GLINK_SMD_XPRT) += glink_smd_xprt.o obj-$(CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT) += glink_smem_native_xprt.o obj-$(CONFIG_MSM_GLINK_BGCOM_XPRT) += glink_bgcom_xprt.o obj-$(CONFIG_MSM_SMEM_LOGGING) += smem_log.o -obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_sleepstate.o -obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_spinlock_test.o +obj-$(CONFIG_MSM_BG_GLINK) += bg_glink.o +obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_loopback.o smp2p_debug.o smp2p_sleepstate.o obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o obj-$(CONFIG_MSM_IPC_ROUTER_USB_XPRT) += ipc_router_usb_xprt.o @@ -92,12 +92,12 @@ ifdef CONFIG_MSM_SUBSYSTEM_RESTART obj-y += ramdump.o endif +obj-$(CONFIG_MSM_BGRSB) += bg_rsb.o obj-$(CONFIG_MSM_BGCOM_INTERFACE) += bgcom_interface.o obj-$(CONFIG_MSM_SERVICE_NOTIFIER) += service-notifier.o obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o sysmon-qmi.o obj-$(CONFIG_MSM_SECURE_BUFFER) += secure_buffer.o obj-$(CONFIG_TRACER_PKT) += tracer_pkt.o -obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o obj-$(CONFIG_MSM_SERVICE_LOCATOR) += service-locator.o obj-$(CONFIG_MSM_QBT1000) += qbt1000.o @@ -110,3 +110,4 @@ obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o obj-$(CONFIG_MSM_HAB) += hab/ obj-$(CONFIG_SERIAL_NUM) += serial_num.o obj-$(CONFIG_SECBOOT_FUSE) += secboot_fuse.o +obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o diff --git a/drivers/soc/qcom/bam_dmux.c b/drivers/soc/qcom/bam_dmux.c index a52feefad1d4bec04ae61af26f7bd2da27714d77..8cec5bc0434987d37c2a7aab7682c3671243ecaf 100644 --- a/drivers/soc/qcom/bam_dmux.c +++ b/drivers/soc/qcom/bam_dmux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -2305,7 +2305,9 @@ static int bam_init(void) a2_props.virt_addr = a2_virt_addr; a2_props.virt_size = a2_phys_size; a2_props.irq = a2_bam_irq; - a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP | SPS_BAM_HOLD_MEM; + a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP + | SPS_BAM_HOLD_MEM + | SPS_BAM_OPT_IRQ_NO_SUSPEND; a2_props.num_pipes = A2_NUM_PIPES; a2_props.summing_threshold = A2_SUMMING_THRESHOLD; a2_props.constrained_logging = true; diff --git a/drivers/soc/qcom/bg_glink.c b/drivers/soc/qcom/bg_glink.c new file mode 100644 index 0000000000000000000000000000000000000000..4a23f7e95bca21803f2963e6b6195ea568c793bc --- /dev/null +++ b/drivers/soc/qcom/bg_glink.c @@ -0,0 +1,484 @@ +/* Copyright (c) 2017 The Linux Foundation.All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GLINK_LINK_STATE_UP_WAIT_TIMEOUT 5000 +#define APR_MAXIMUM_NUM_OF_RETRIES 2 +#define BG_RX_INTENT_REQ_TIMEOUT_MS 3000 +#define BG_GLINK_NAME "bg-cdc-glink" +#define BG_GLINK_EDGE "bg" +#define BG_MAX_NO_OF_INTENTS 20 + +struct bg_cdc_glink_drvdata { + struct device *dev; + struct platform_device *pdev; + struct bg_cdc_glink_ch_info *ch_info; + void *handle; + wait_queue_head_t wait; + u8 num_channels; + u8 active_channel; + enum glink_link_state link_state; +}; + +struct bg_cdc_glink_ch_info { + void *handle; + struct mutex w_lock; + struct mutex r_lock; + struct mutex m_lock; + bg_glink_cb_fn func; + wait_queue_head_t wait; + unsigned channel_state; + bool if_remote_intent_ready; +}; +static int __bg_cdc_glink_write(struct bg_cdc_glink_ch_info *ch_info, + void *data, char *tx_buf, int len) +{ + int rc = 0; + + if (!ch_info) + return -EINVAL; + mutex_lock(&ch_info->w_lock); + rc = glink_tx(ch_info->handle, tx_buf, data, len, GLINK_TX_REQ_INTENT); + mutex_unlock(&ch_info->w_lock); + + if (rc) + pr_err("%s: glink_tx failed, rc[%d]\n", __func__, rc); + else + rc = len; + + return rc; +} + +int bg_cdc_glink_write(void *ch_info, void *data, + int len) +{ + int rc = 0; + char *tx_buf = NULL; + + if (!((struct bg_cdc_glink_ch_info *)ch_info)->handle || !data) + return -EINVAL; + + /* check if channel is connected before proceeding */ + if (((struct bg_cdc_glink_ch_info *)ch_info)->channel_state + != GLINK_CONNECTED) { + pr_err("channel is not connected\n"); + return -EINVAL; + } + + tx_buf = kzalloc((sizeof(char) * len), GFP_KERNEL); + if (IS_ERR_OR_NULL(tx_buf)) { + rc = -EINVAL; + goto exit; + } + memcpy(tx_buf, data, len); + + rc = __bg_cdc_glink_write((struct bg_cdc_glink_ch_info *)ch_info, + tx_buf, tx_buf, len); + + if (rc < 0) { + pr_err("%s: Unable to send the packet, rc:%d\n", __func__, rc); + kfree(tx_buf); + } +exit: + return rc; +} +EXPORT_SYMBOL(bg_cdc_glink_write); + +static void bg_cdc_glink_notify_rx(void *handle, const void *priv, + const void *pkt_priv, const void *ptr, + size_t size) +{ + struct bg_cdc_glink_ch_info *ch_info = + (struct bg_cdc_glink_ch_info *)priv; + + if (!ch_info || !ptr) { + pr_err("%s: Invalid ch_info or ptr\n", __func__); + return; + } + + pr_debug("%s: Rx packet received\n", __func__); + + mutex_lock(&ch_info->r_lock); + if (ch_info->func) + ch_info->func((void *)ptr, size); + mutex_unlock(&ch_info->r_lock); + glink_rx_done(ch_info->handle, ptr, true); +} + +static void bg_cdc_glink_notify_tx_abort(void *handle, const void *priv, + const void *pkt_priv) +{ + pr_debug("%s: tx_abort received for pkt_priv:%pK\n", + __func__, pkt_priv); + kfree(pkt_priv); +} + +static void bg_cdc_glink_notify_tx_done(void *handle, const void *priv, + const void *pkt_priv, const void *ptr) +{ + pr_debug("%s: tx_done received for pkt_priv:%pK\n", + __func__, pkt_priv); + kfree(pkt_priv); +} + +static bool bg_cdc_glink_notify_rx_intent_req(void *handle, const void *priv, + size_t req_size) +{ + struct bg_cdc_glink_ch_info *ch_info = + (struct bg_cdc_glink_ch_info *)priv; + + if (!ch_info) { + pr_err("%s: Invalid ch_info\n", __func__); + return false; + } + + pr_debug("%s: No rx intents queued, unable to receive\n", __func__); + return false; +} + +static void bg_cdc_glink_notify_remote_rx_intent(void *handle, const void *priv, + size_t size) +{ + struct bg_cdc_glink_ch_info *ch_info = + (struct bg_cdc_glink_ch_info *)priv; + + if (!ch_info) { + pr_err("%s: Invalid ch_info\n", __func__); + return; + } + /* + * This is to make sure that the far end has queued at least one intent + * before we attempt any IPC. + */ + pr_debug("%s: remote queued an intent\n", __func__); + ch_info->if_remote_intent_ready = true; + wake_up(&ch_info->wait); +} + +static void bg_cdc_glink_notify_state(void *handle, const void *priv, + unsigned event) +{ + struct bg_cdc_glink_ch_info *ch_info = + (struct bg_cdc_glink_ch_info *)priv; + + if (!ch_info) { + pr_err("%s: Invalid ch_info\n", __func__); + return; + } + + ch_info->channel_state = event; + pr_debug("%s: Channel state[%d]\n", __func__, event); + + if (event == GLINK_CONNECTED) + wake_up(&ch_info->wait); +} + +static int bg_cdc_glink_rx_intents_config(struct bg_cdc_glink_ch_info *ch_info, + int num_of_intents, uint32_t *size) +{ + int i; + int rc = 0; + + if (!ch_info || !num_of_intents || !size) { + pr_err("%s: Invalid parameter\n", __func__); + return -EINVAL; + } + if (num_of_intents > BG_MAX_NO_OF_INTENTS) { + pr_err("%s: Invalid no_of_intents = %d\n", + __func__, num_of_intents); + return -EINVAL; + } + + for (i = 0; i < num_of_intents; i++) { + rc = glink_queue_rx_intent(ch_info->handle, ch_info, *(size+i)); + if (rc) { + pr_err("%s: Failed to queue rx intent, iteration[%d]\n", + __func__, i); + break; + } + } + + return rc; +} +/* + * bg_cdc_channel_open - API to open Glink channel. + * ch_cfg: glink channel configuration + * func: callback function to notify client. + */ +void *bg_cdc_channel_open(struct platform_device *pdev, + struct bg_glink_ch_cfg *ch_cfg, + bg_glink_cb_fn func) +{ + int rc; + struct bg_cdc_glink_drvdata *bg_cdc_glink; + struct glink_open_config open_cfg; + struct bg_cdc_glink_ch_info *ch_info; + + if (!pdev) { + pr_err("%s: invalid platform device\n", __func__); + return NULL; + } + bg_cdc_glink = platform_get_drvdata(pdev); + + if (!bg_cdc_glink) { + dev_err(&pdev->dev, "%s: driver data not found\n", + __func__); + return NULL; + } + if (bg_cdc_glink->active_channel > bg_cdc_glink->num_channels) { + dev_err(bg_cdc_glink->dev, "%s: invalid channel number\n", + __func__); + return NULL; + } + + ch_info = &bg_cdc_glink->ch_info[bg_cdc_glink->active_channel]; + mutex_lock(&ch_info->m_lock); + if (ch_info->handle) { + dev_err(&pdev->dev, "%s: This channel is already opened\n", + __func__); + rc = -EBUSY; + goto unlock; + } + + if (bg_cdc_glink->link_state != GLINK_LINK_STATE_UP) { + rc = wait_event_timeout(bg_cdc_glink->wait, + bg_cdc_glink->link_state == GLINK_LINK_STATE_UP, + msecs_to_jiffies(GLINK_LINK_STATE_UP_WAIT_TIMEOUT)); + if (rc == 0) { + dev_err(bg_cdc_glink->dev, "%s: Open timeout\n", + __func__); + rc = -ETIMEDOUT; + goto unlock; + } + dev_dbg(bg_cdc_glink->dev, "%s: Wakeup done\n", __func__); + } + + memset(&open_cfg, 0, sizeof(struct glink_open_config)); + open_cfg.options = GLINK_OPT_INITIAL_XPORT; + open_cfg.edge = BG_GLINK_EDGE; + open_cfg.name = ch_cfg->ch_name; + open_cfg.notify_rx = bg_cdc_glink_notify_rx; + open_cfg.notify_tx_done = bg_cdc_glink_notify_tx_done; + open_cfg.notify_state = bg_cdc_glink_notify_state; + open_cfg.notify_rx_intent_req = bg_cdc_glink_notify_rx_intent_req; + open_cfg.notify_remote_rx_intent = bg_cdc_glink_notify_remote_rx_intent; + open_cfg.notify_tx_abort = bg_cdc_glink_notify_tx_abort; + open_cfg.rx_intent_req_timeout_ms = BG_RX_INTENT_REQ_TIMEOUT_MS; + open_cfg.priv = ch_info; + + ch_info->channel_state = GLINK_REMOTE_DISCONNECTED; + ch_info->handle = glink_open(&open_cfg); + if (IS_ERR_OR_NULL(ch_info->handle)) { + dev_err(bg_cdc_glink->dev, "%s: glink_open failed %s\n", + __func__, ch_cfg->ch_name); + ch_info->handle = NULL; + rc = -EINVAL; + goto unlock; + } + bg_cdc_glink->active_channel++; + rc = wait_event_timeout(ch_info->wait, + (ch_info->channel_state == GLINK_CONNECTED), 5 * HZ); + if (rc == 0) { + dev_err(bg_cdc_glink->dev, "%s: TIMEOUT for OPEN event\n", + __func__); + rc = -ETIMEDOUT; + goto close_link; + } + rc = bg_cdc_glink_rx_intents_config(ch_info, + ch_cfg->num_of_intents, ch_cfg->intents_size); + if (rc) { + dev_err(bg_cdc_glink->dev, "%s: Unable to queue intents\n", + __func__); + goto close_link; + } + + ch_info->func = func; + +close_link: + if (rc) { + if (bg_cdc_glink->active_channel > 0) + bg_cdc_glink->active_channel--; + glink_close(ch_info->handle); + ch_info->handle = NULL; + } +unlock: + mutex_unlock(&ch_info->m_lock); + + return rc ? NULL : (void *)ch_info; +} +EXPORT_SYMBOL(bg_cdc_channel_open); + + +int bg_cdc_channel_close(struct platform_device *pdev, + void *ch_info) +{ + struct bg_cdc_glink_drvdata *bg_cdc_glink; + int rc; + struct bg_cdc_glink_ch_info *channel_info + = (struct bg_cdc_glink_ch_info *)ch_info; + bg_cdc_glink = platform_get_drvdata(pdev); + if (!channel_info || !channel_info->handle) { + rc = -EINVAL; + goto exit; + } + + mutex_lock(&channel_info->m_lock); + if (bg_cdc_glink->active_channel > 0) + bg_cdc_glink->active_channel--; + rc = glink_close(channel_info->handle); + channel_info->handle = NULL; + channel_info->func = NULL; + channel_info->if_remote_intent_ready = false; + mutex_unlock(&channel_info->m_lock); +exit: + return rc; +} +EXPORT_SYMBOL(bg_cdc_channel_close); + +static void bg_cdc_glink_link_state_cb(struct glink_link_state_cb_info *cb_info, + void *priv) +{ + struct bg_cdc_glink_drvdata *bg_cdc_glink = + (struct bg_cdc_glink_drvdata *) priv; + + if (!cb_info) { + pr_err("%s: Invalid cb_info\n", __func__); + return; + } + + dev_dbg(bg_cdc_glink->dev, "%s: edge[%s] link state[%d]\n", __func__, + cb_info->edge, cb_info->link_state); + + bg_cdc_glink->link_state = cb_info->link_state; + if (bg_cdc_glink->link_state == GLINK_LINK_STATE_UP) + wake_up(&bg_cdc_glink->wait); +} + +static int bg_cdc_glink_probe(struct platform_device *pdev) +{ + struct bg_cdc_glink_drvdata *bg_cdc_glink; + struct glink_link_info link_info; + u32 num_channels; + int ret = 0; + int i; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,msm-glink-channels", + &num_channels); + + if (ret) { + dev_err(&pdev->dev, "%s: glink channels from DT file %s\n", + __func__, "qcom,msm-glink-channels"); + return -EINVAL; + } + + /* Allocate BG codec Glink structure */ + bg_cdc_glink = kzalloc(sizeof(struct bg_cdc_glink_drvdata), GFP_KERNEL); + if (!bg_cdc_glink) + return -ENOMEM; + + bg_cdc_glink->ch_info = kzalloc((sizeof(struct bg_cdc_glink_ch_info) * + num_channels), GFP_KERNEL); + if (!bg_cdc_glink->ch_info) { + ret = -ENOMEM; + goto err_memory_fail; + } + bg_cdc_glink->dev = &pdev->dev; + bg_cdc_glink->pdev = pdev; + bg_cdc_glink->num_channels = num_channels; + platform_set_drvdata(pdev, bg_cdc_glink); + + init_waitqueue_head(&bg_cdc_glink->wait); + + /* Register glink link_state notification */ + link_info.glink_link_state_notif_cb = bg_cdc_glink_link_state_cb; + link_info.transport = NULL; + link_info.edge = BG_GLINK_EDGE; + bg_cdc_glink->link_state = GLINK_LINK_STATE_DOWN; + bg_cdc_glink->handle = + glink_register_link_state_cb(&link_info, bg_cdc_glink); + if (!bg_cdc_glink->handle) { + dev_err(&pdev->dev, "%s: Unable to register link state\n", + __func__); + ret = -EINVAL; + goto err_glink_register_fail; + } + + for (i = 0; i < num_channels; i++) { + mutex_init(&bg_cdc_glink->ch_info[i].w_lock); + mutex_init(&bg_cdc_glink->ch_info[i].r_lock); + mutex_init(&bg_cdc_glink->ch_info[i].m_lock); + init_waitqueue_head(&bg_cdc_glink->ch_info[i].wait); + } + return ret; +err_glink_register_fail: + kfree(bg_cdc_glink->ch_info); + +err_memory_fail: + kfree(bg_cdc_glink); + + return ret; +} + +static const struct of_device_id bg_cdc_glink_of_match[] = { + { .compatible = "qcom,bg-cdc-glink", }, + {}, +}; + +static int bg_cdc_glink_remove(struct platform_device *pdev) +{ + struct bg_cdc_glink_drvdata *bg_cdc_glink = platform_get_drvdata(pdev); + int i; + + if (!bg_cdc_glink) { + dev_err(&pdev->dev, "%s: invalid data\n", + __func__); + return -EINVAL; + } + if (bg_cdc_glink->handle) + glink_unregister_link_state_cb(bg_cdc_glink->handle); + + for (i = 0; i < bg_cdc_glink->num_channels; i++) { + mutex_destroy(&bg_cdc_glink->ch_info[i].w_lock); + mutex_destroy(&bg_cdc_glink->ch_info[i].r_lock); + mutex_destroy(&bg_cdc_glink->ch_info[i].m_lock); + } + kfree(bg_cdc_glink->ch_info); + kfree(bg_cdc_glink); + return 0; +} + +static struct platform_driver msm_bg_cdc_glink_driver = { + .driver = { + .owner = THIS_MODULE, + .name = BG_GLINK_NAME, + .of_match_table = bg_cdc_glink_of_match, + }, + .probe = bg_cdc_glink_probe, + .remove = bg_cdc_glink_remove, +}; +module_platform_driver(msm_bg_cdc_glink_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BG Glink driver"); diff --git a/drivers/soc/qcom/bg_rsb.c b/drivers/soc/qcom/bg_rsb.c new file mode 100644 index 0000000000000000000000000000000000000000..694de695ddc371b3b67b16a194184fb64420edcc --- /dev/null +++ b/drivers/soc/qcom/bg_rsb.c @@ -0,0 +1,1063 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * 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. + * + */ + +#define pr_fmt(msg) "bgrsb: %s: " msg, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bgrsb.h" + +#define BGRSB_GLINK_INTENT_SIZE 0x04 +#define BGRSB_MSG_SIZE 0x08 +#define TIMEOUT_MS 2000 + +#define BGRSB_LDO15_VTG_MIN_UV 3300000 +#define BGRSB_LDO15_VTG_MAX_UV 3300000 + +#define BGRSB_LDO11_VTG_MIN_UV 1800000 +#define BGRSB_LDO11_VTG_MAX_UV 1800000 + +#define BGRSB_BGWEAR_SUBSYS "bg-wear" + +#define BGRSB_BTTN_CONFIGURE 5 +#define BGRSB_POWER_CALIBRATION 2 +#define BGRSB_POWER_ENABLE 1 +#define BGRSB_POWER_DISABLE 0 +#define BGRSB_GLINK_POWER_ENABLE 6 +#define BGRSB_GLINK_POWER_DISABLE 7 + + +struct bgrsb_regulator { + struct regulator *regldo11; + struct regulator *regldo15; +}; + +enum ldo_task { + BGRSB_ENABLE_LDO11, + BGRSB_ENABLE_LDO15, + BGRSB_DISABLE_LDO11, + BGRSB_DISABLE_LDO15, + BGRSB_NO_ACTION +}; + +enum bgrsb_state { + BGRSB_STATE_UNKNOWN, + BGRSB_STATE_INIT, + BGRSB_STATE_LDO11_ENABLED, + BGRSB_STATE_RSB_CONFIGURED, + BGRSB_STATE_LDO15_ENABLED, + BGRSB_STATE_RSB_ENABLED +}; + +struct bgrsb_msg { + uint32_t cmd_id; + uint32_t data; +}; + +struct bgrsb_priv { + void *handle; + struct input_dev *input; + struct mutex glink_mutex; + + struct mutex rsb_state_mutex; + + enum bgrsb_state bgrsb_current_state; + enum glink_link_state link_state; + + bool chnl_state; + void *lhndl; + + struct work_struct bg_up_work; + struct work_struct bg_down_work; + + struct work_struct rsb_up_work; + struct work_struct rsb_down_work; + + struct work_struct rsb_glink_up_work; + struct work_struct rsb_glink_down_work; + + struct work_struct rsb_calibration_work; + struct work_struct bttn_configr_work; + + struct work_struct glink_work; + + struct workqueue_struct *bgrsb_event_wq; + struct workqueue_struct *bgrsb_wq; + + struct bg_glink_chnl chnl; + char rx_buf[BGRSB_GLINK_INTENT_SIZE]; + + struct bgrsb_regulator rgltr; + + enum ldo_task ldo_action; + + void *bgwear_subsys_handle; + + struct completion bg_resp_cmplt; + struct completion wrk_cmplt; + struct completion bg_lnikup_cmplt; + struct completion tx_done; + + struct device *ldev; + + struct wakeup_source bgrsb_ws; + + wait_queue_head_t link_state_wait; + + uint32_t calbrtion_intrvl; + uint32_t calbrtion_cpi; + + uint8_t bttn_configs; + + bool calibration_needed; + bool is_calibrd; +}; + +static void *bgrsb_drv; +static int bgrsb_enable(struct bgrsb_priv *dev, bool enable); + +int bgrsb_send_input(struct event *evnt) +{ + uint8_t press_code; + uint8_t value; + + struct bgrsb_priv *dev = + container_of(bgrsb_drv, struct bgrsb_priv, lhndl); + + if (!evnt) + return -EINVAL; + + if (evnt->sub_id == 1) { + input_report_rel(dev->input, REL_WHEEL, evnt->evnt_data); + input_sync(dev->input); + } else if (evnt->sub_id == 2) { + + press_code = (uint8_t) evnt->evnt_data; + value = (uint8_t) (evnt->evnt_data >> 8); + + switch (press_code) { + case 0x1: + if (value == 0) { + input_report_key(dev->input, KEY_VOLUMEDOWN, 1); + input_sync(dev->input); + } else { + input_report_key(dev->input, KEY_VOLUMEDOWN, 0); + input_sync(dev->input); + } + break; + case 0x2: + if (value == 0) { + input_report_key(dev->input, KEY_VOLUMEUP, 1); + input_sync(dev->input); + } else { + input_report_key(dev->input, KEY_VOLUMEUP, 0); + input_sync(dev->input); + } + break; + case 0x3: + if (value == 0) { + input_report_key(dev->input, KEY_POWER, 1); + input_sync(dev->input); + } else { + input_report_key(dev->input, KEY_POWER, 0); + input_sync(dev->input); + } + break; + default: + pr_info("event: type[%d] , data: %d\n", + evnt->sub_id, evnt->evnt_data); + } + } + return 0; +} +EXPORT_SYMBOL(bgrsb_send_input); + +static void bgrsb_glink_notify_rx(void *handle, const void *priv, + const void *pkt_priv, const void *ptr, size_t size) +{ + struct bgrsb_priv *dev = (struct bgrsb_priv *)priv; + + memcpy(dev->rx_buf, ptr, size); + glink_rx_done(dev->handle, ptr, false); + complete(&dev->bg_resp_cmplt); +} + +static void bgrsb_glink_notify_state(void *handle, const void *priv, + unsigned event) +{ + struct bgrsb_priv *dev = (struct bgrsb_priv *)priv; + + switch (event) { + case GLINK_CONNECTED: + complete(&dev->bg_lnikup_cmplt); + break; + case GLINK_REMOTE_DISCONNECTED: + case GLINK_LOCAL_DISCONNECTED: + dev->chnl_state = false; + break; + } +} + +static void bgrsb_glink_notify_tx_done(void *handle, const void *priv, + const void *pkt_priv, const void *ptr) +{ + struct bgrsb_priv *dev = (struct bgrsb_priv *)priv; + + complete(&dev->tx_done); +} + +static void bgrsb_glink_close_work(struct work_struct *work) +{ + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, glink_work); + + if (dev->handle) + glink_close(dev->handle); + dev->handle = NULL; +} + +static void bgrsb_glink_open_work(struct work_struct *work) +{ + struct glink_open_config open_cfg; + void *hndl = NULL; + int rc = 0; + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, glink_work); + + if (dev->handle) + return; + + memset(&open_cfg, 0, sizeof(struct glink_open_config)); + open_cfg.priv = (void *)dev; + open_cfg.edge = dev->chnl.chnl_edge; + open_cfg.transport = dev->chnl.chnl_trnsprt; + open_cfg.name = dev->chnl.chnl_name; + open_cfg.notify_tx_done = bgrsb_glink_notify_tx_done; + open_cfg.notify_state = bgrsb_glink_notify_state; + open_cfg.notify_rx = bgrsb_glink_notify_rx; + + init_completion(&dev->bg_lnikup_cmplt); + hndl = glink_open(&open_cfg); + + if (IS_ERR_OR_NULL(hndl)) { + pr_err("Glink open failed[%s]\n", + dev->chnl.chnl_name); + dev->handle = NULL; + return; + } + + rc = wait_for_completion_timeout(&dev->bg_lnikup_cmplt, + msecs_to_jiffies(TIMEOUT_MS)); + if (!rc) { + pr_err("Channel open failed. Time out\n"); + return; + } + dev->chnl_state = true; + dev->handle = hndl; +} + +static void bgrsb_glink_state_cb(struct glink_link_state_cb_info *cb_info, + void *data) +{ + struct bgrsb_priv *dev = (struct bgrsb_priv *)data; + + dev->link_state = cb_info->link_state; + switch (dev->link_state) { + case GLINK_LINK_STATE_UP: + INIT_WORK(&dev->glink_work, bgrsb_glink_open_work); + queue_work(dev->bgrsb_event_wq, &dev->glink_work); + break; + case GLINK_LINK_STATE_DOWN: + INIT_WORK(&dev->glink_work, bgrsb_glink_close_work); + queue_work(dev->bgrsb_event_wq, &dev->glink_work); + break; + } +} + +static int bgrsb_init_link_inf(struct bgrsb_priv *dev) +{ + struct glink_link_info link_info; + void *hndl; + + link_info.glink_link_state_notif_cb = bgrsb_glink_state_cb; + link_info.transport = dev->chnl.chnl_trnsprt; + link_info.edge = dev->chnl.chnl_edge; + + hndl = glink_register_link_state_cb(&link_info, (void *)dev); + if (IS_ERR_OR_NULL(hndl)) { + pr_err("Unable to register link[%s]\n", + dev->chnl.chnl_name); + return -EFAULT; + } + return 0; +} + +static int bgrsb_init_regulators(struct device *pdev) +{ + struct regulator *reg11; + struct regulator *reg15; + struct bgrsb_priv *dev = dev_get_drvdata(pdev); + + reg11 = regulator_get(pdev, "vdd-ldo1"); + if (IS_ERR_OR_NULL(reg11)) { + pr_err("Unable to get regulator for LDO-11\n"); + return PTR_ERR(reg11); + } + + reg15 = regulator_get(pdev, "vdd-ldo2"); + if (IS_ERR_OR_NULL(reg15)) { + pr_err("Unable to get regulator for LDO-15\n"); + return PTR_ERR(reg15); + } + + dev->rgltr.regldo11 = reg11; + dev->rgltr.regldo15 = reg15; + + return 0; +} + +static int bgrsb_ldo_work(struct bgrsb_priv *dev, enum ldo_task ldo_action) +{ + int ret = 0; + + switch (ldo_action) { + case BGRSB_ENABLE_LDO11: + ret = regulator_set_voltage(dev->rgltr.regldo11, + BGRSB_LDO11_VTG_MIN_UV, BGRSB_LDO11_VTG_MAX_UV); + if (ret) { + pr_err("Failed to request LDO-11 voltage.\n"); + goto err_ret; + } + ret = regulator_enable(dev->rgltr.regldo11); + if (ret) { + pr_err("Failed to enable LDO-11 %d\n", ret); + goto err_ret; + } + break; + + case BGRSB_ENABLE_LDO15: + ret = regulator_set_voltage(dev->rgltr.regldo15, + BGRSB_LDO15_VTG_MIN_UV, BGRSB_LDO15_VTG_MAX_UV); + if (ret) { + pr_err("Failed to request LDO-15 voltage.\n"); + goto err_ret; + } + ret = regulator_enable(dev->rgltr.regldo15); + if (ret) { + pr_err("Failed to enable LDO-15 %d\n", ret); + goto err_ret; + } + break; + case BGRSB_DISABLE_LDO11: + ret = regulator_disable(dev->rgltr.regldo11); + if (ret) { + pr_err("Failed to disable LDO-11 %d\n", ret); + goto err_ret; + } + break; + + case BGRSB_DISABLE_LDO15: + ret = regulator_disable(dev->rgltr.regldo15); + if (ret) { + pr_err("Failed to disable LDO-15 %d\n", ret); + goto err_ret; + } + regulator_set_optimum_mode(dev->rgltr.regldo15, 0); + break; + default: + ret = -EINVAL; + } + +err_ret: + return ret; +} + +static void bgrsb_bgdown_work(struct work_struct *work) +{ + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + bg_down_work); + + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO15) == 0) + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + else + pr_err("Failed to unvote LDO-15 on BG down\n"); + } + + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_CONFIGURED) { + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11) == 0) + dev->bgrsb_current_state = BGRSB_STATE_INIT; + else + pr_err("Failed to unvote LDO-11 on BG down\n"); + } + + pr_info("RSB current state is : %d\n", dev->bgrsb_current_state); + + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) { + if (dev->is_calibrd) + dev->calibration_needed = true; + } +} + +static void bgrsb_glink_bgdown_work(struct work_struct *work) +{ + int rc; + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + rsb_glink_down_work); + + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + + rc = bgrsb_enable(dev, false); + if (rc != 0) { + pr_err("Failed to send disable command to BG\n"); + return; + } + + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO15) != 0) { + pr_err("Failed to un-vote LDO-15\n"); + return; + } + + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_info("RSB Disabled\n"); + } + + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_CONFIGURED) { + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11) == 0) + dev->bgrsb_current_state = BGRSB_STATE_INIT; + else + pr_err("Failed to unvote LDO-11 on BG Glink down\n"); + } + if (dev->handle) + glink_close(dev->handle); + dev->handle = NULL; + pr_debug("BG Glink Close connection\n"); +} + +static int bgrsb_tx_msg(struct bgrsb_priv *dev, void *msg, size_t len) +{ + int rc = 0; + uint8_t resp = 0; + + if (!dev->chnl_state) + return -ENODEV; + + __pm_stay_awake(&dev->bgrsb_ws); + mutex_lock(&dev->glink_mutex); + init_completion(&dev->tx_done); + init_completion(&dev->bg_resp_cmplt); + + rc = glink_queue_rx_intent(dev->handle, + (void *)dev, BGRSB_GLINK_INTENT_SIZE); + + if (rc) { + pr_err("Failed to queue intent\n"); + goto err_ret; + } + + rc = glink_tx(dev->handle, (void *)dev, msg, + len, GLINK_TX_REQ_INTENT); + if (rc) { + pr_err("Failed to send command\n"); + goto err_ret; + } + + rc = wait_for_completion_timeout(&dev->tx_done, + msecs_to_jiffies(TIMEOUT_MS)); + if (!rc) { + pr_err("Timed out waiting for Command to send\n"); + rc = -ETIMEDOUT; + goto err_ret; + } + + rc = wait_for_completion_timeout(&dev->bg_resp_cmplt, + msecs_to_jiffies(TIMEOUT_MS)); + if (!rc) { + pr_err("Timed out waiting for response\n"); + rc = -ETIMEDOUT; + goto err_ret; + } + + resp = *(uint8_t *)dev->rx_buf; + if (!(resp == 0x01)) { + pr_err("Bad RSB response\n"); + rc = -EINVAL; + goto err_ret; + } + rc = 0; + +err_ret: + mutex_unlock(&dev->glink_mutex); + __pm_relax(&dev->bgrsb_ws); + return rc; +} + +static int bgrsb_enable(struct bgrsb_priv *dev, bool enable) +{ + int rc = 0; + struct bgrsb_msg req = {0}; + + req.cmd_id = 0x02; + req.data = enable ? 0x01 : 0x00; + + rc = bgrsb_tx_msg(dev, &req, BGRSB_MSG_SIZE); + return rc; +} + +static int bgrsb_configr_rsb(struct bgrsb_priv *dev, bool enable) +{ + int rc = 0; + struct bgrsb_msg req = {0}; + + req.cmd_id = 0x01; + req.data = enable ? 0x01 : 0x00; + + rc = bgrsb_tx_msg(dev, &req, BGRSB_MSG_SIZE); + return rc; +} + +static void bgrsb_bgup_work(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + bg_up_work); + + if (bgrsb_ldo_work(dev, BGRSB_ENABLE_LDO11) == 0) { + + rc = wait_event_timeout(dev->link_state_wait, + (dev->chnl_state == true), + msecs_to_jiffies(TIMEOUT_MS)); + if (rc == 0) { + pr_err("Glink channel connection time out\n"); + return; + } + rc = bgrsb_configr_rsb(dev, true); + if (rc != 0) { + pr_err("BG failed to configure RSB %d\n", rc); + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11) == 0) + dev->bgrsb_current_state = BGRSB_STATE_INIT; + return; + } + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_debug("RSB Cofigured\n"); + } +} + +static void bgrsb_glink_bgup_work(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + rsb_glink_up_work); + + if (bgrsb_ldo_work(dev, BGRSB_ENABLE_LDO11) == 0) { + + INIT_WORK(&dev->glink_work, bgrsb_glink_open_work); + queue_work(dev->bgrsb_event_wq, &dev->glink_work); + + rc = wait_event_timeout(dev->link_state_wait, + (dev->chnl_state == true), + msecs_to_jiffies(TIMEOUT_MS)); + if (rc == 0) { + pr_err("Glink channel connection time out\n"); + return; + } + rc = bgrsb_configr_rsb(dev, true); + if (rc != 0) { + pr_err("BG Glink failed to configure RSB %d\n", rc); + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11) == 0) + dev->bgrsb_current_state = BGRSB_STATE_INIT; + return; + } + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_debug("Glink RSB Cofigured\n"); + } +} + +/** + *ssr_bg_cb(): callback function is called + *by ssr framework when BG goes down, up and during ramdump + *collection. It handles BG shutdown and power up events. + */ +static int ssr_bgrsb_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bgrsb_priv *dev = container_of(bgrsb_drv, + struct bgrsb_priv, lhndl); + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + queue_work(dev->bgrsb_wq, &dev->bg_down_work); + break; + case SUBSYS_AFTER_POWERUP: + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) + queue_work(dev->bgrsb_wq, &dev->bg_up_work); + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block ssr_bg_nb = { + .notifier_call = ssr_bgrsb_cb, + .priority = 0, +}; + +/** + * ssr_register checks that domain id should be in range and register + * SSR framework for value at domain id. + */ +static int bgrsb_ssr_register(struct bgrsb_priv *dev) +{ + struct notifier_block *nb; + + if (!dev) + return -ENODEV; + + nb = &ssr_bg_nb; + dev->bgwear_subsys_handle = + subsys_notif_register_notifier(BGRSB_BGWEAR_SUBSYS, nb); + + if (!dev->bgwear_subsys_handle) { + dev->bgwear_subsys_handle = NULL; + return -EFAULT; + } + return 0; +} + +static void bgrsb_enable_rsb(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + rsb_up_work); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state != BGRSB_STATE_RSB_CONFIGURED) { + pr_err("BG is not yet configured for RSB\n"); + goto unlock; + } + + if (bgrsb_ldo_work(dev, BGRSB_ENABLE_LDO15) == 0) { + + rc = bgrsb_enable(dev, true); + if (rc != 0) { + pr_err("Failed to send enable command to BG\n"); + bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO15); + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + goto unlock; + } + } + dev->bgrsb_current_state = BGRSB_STATE_RSB_ENABLED; + pr_debug("RSB Enabled\n"); + + if (dev->calibration_needed) { + dev->calibration_needed = false; + queue_work(dev->bgrsb_wq, &dev->rsb_calibration_work); + } +unlock: + mutex_unlock(&dev->rsb_state_mutex); + +} + +static void bgrsb_disable_rsb(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + rsb_down_work); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + + rc = bgrsb_enable(dev, false); + if (rc != 0) { + pr_err("Failed to send disable command to BG\n"); + goto unlock; + } + + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO15) != 0) + goto unlock; + + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_debug("RSB Disabled\n"); + } + +unlock: + mutex_unlock(&dev->rsb_state_mutex); +} + +static void bgrsb_calibration(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_msg req = {0}; + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, + rsb_calibration_work); + + req.cmd_id = 0x03; + req.data = dev->calbrtion_cpi; + + rc = bgrsb_tx_msg(dev, &req, 5); + if (rc != 0) { + pr_err("Failed to send resolution value to BG\n"); + return; + } + + req.cmd_id = 0x04; + req.data = dev->calbrtion_intrvl; + + rc = bgrsb_tx_msg(dev, &req, 5); + if (rc != 0) { + pr_err("Failed to send interval value to BG\n"); + return; + } + dev->is_calibrd = true; + pr_debug("RSB Calibbered\n"); +} + +static void bgrsb_buttn_configration(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_msg req = {0}; + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, + bttn_configr_work); + + req.cmd_id = 0x05; + req.data = dev->bttn_configs; + + rc = bgrsb_tx_msg(dev, &req, 5); + if (rc != 0) { + pr_err("Failed to send button configuration cmnd to BG\n"); + return; + } + + dev->bttn_configs = 0; + pr_debug("Button configured\n"); +} + +static int split_bg_work(struct bgrsb_priv *dev, char *str) +{ + long val; + int ret; + char *tmp; + + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + switch (val) { + case BGRSB_POWER_DISABLE: + queue_work(dev->bgrsb_wq, &dev->rsb_down_work); + break; + case BGRSB_POWER_ENABLE: + queue_work(dev->bgrsb_wq, &dev->rsb_up_work); + break; + case BGRSB_POWER_CALIBRATION: + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + dev->calbrtion_intrvl = (uint32_t)val; + + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + dev->calbrtion_cpi = (uint32_t)val; + + queue_work(dev->bgrsb_wq, &dev->rsb_calibration_work); + break; + case BGRSB_BTTN_CONFIGURE: + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + dev->bttn_configs = (uint8_t)val; + queue_work(dev->bgrsb_wq, &dev->bttn_configr_work); + break; + case BGRSB_GLINK_POWER_DISABLE: + queue_work(dev->bgrsb_wq, &dev->rsb_glink_down_work); + break; + case BGRSB_GLINK_POWER_ENABLE: + queue_work(dev->bgrsb_wq, &dev->rsb_glink_up_work); + break; + } + return 0; +} + +static int store_enable(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t count) +{ + int rc; + struct bgrsb_priv *dev = dev_get_drvdata(pdev); + char *arr = kstrdup(buff, GFP_KERNEL); + + if (!arr) + goto err_ret; + + rc = split_bg_work(dev, arr); + if (rc != 0) + pr_err("Not able to process request\n"); + +err_ret: + return count; +} + +static int show_enable(struct device *dev, struct device_attribute *attr, + char *buff) +{ + return 0; +} + +static struct device_attribute dev_attr_rsb = { + .attr = { + .name = "enable", + .mode = 00660, + }, + .show = show_enable, + .store = store_enable, +}; + +static int bgrsb_init(struct bgrsb_priv *dev) +{ + bgrsb_drv = &dev->lhndl; + dev->chnl.chnl_name = "RSB_CTRL"; + dev->chnl.chnl_edge = "bg"; + dev->chnl.chnl_trnsprt = "bgcom"; + mutex_init(&dev->glink_mutex); + mutex_init(&dev->rsb_state_mutex); + dev->link_state = GLINK_LINK_STATE_DOWN; + + dev->ldo_action = BGRSB_NO_ACTION; + + dev->bgrsb_event_wq = + create_singlethread_workqueue(dev->chnl.chnl_name); + if (!dev->bgrsb_event_wq) { + pr_err("Failed to init Glink work-queue\n"); + goto err_ret; + } + + dev->bgrsb_wq = + create_singlethread_workqueue("bg-work-queue"); + if (!dev->bgrsb_wq) { + pr_err("Failed to init BG-RSB work-queue\n"); + goto free_rsb_wq; + } + + init_waitqueue_head(&dev->link_state_wait); + + /* set default bgrsb state */ + dev->bgrsb_current_state = BGRSB_STATE_INIT; + + /* Init all works */ + INIT_WORK(&dev->bg_up_work, bgrsb_bgup_work); + INIT_WORK(&dev->bg_down_work, bgrsb_bgdown_work); + INIT_WORK(&dev->rsb_up_work, bgrsb_enable_rsb); + INIT_WORK(&dev->rsb_down_work, bgrsb_disable_rsb); + INIT_WORK(&dev->rsb_calibration_work, bgrsb_calibration); + INIT_WORK(&dev->bttn_configr_work, bgrsb_buttn_configration); + INIT_WORK(&dev->rsb_glink_down_work, bgrsb_glink_bgdown_work); + INIT_WORK(&dev->rsb_glink_up_work, bgrsb_glink_bgup_work); + + return 0; + +free_rsb_wq: + destroy_workqueue(dev->bgrsb_event_wq); +err_ret: + return -EFAULT; +} + +static int bg_rsb_probe(struct platform_device *pdev) +{ + struct bgrsb_priv *dev; + struct input_dev *input; + int rc; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + /* Add wake lock for PM suspend */ + wakeup_source_init(&dev->bgrsb_ws, "BGRSB_wake_lock"); + + dev->bgrsb_current_state = BGRSB_STATE_UNKNOWN; + rc = bgrsb_init(dev); + if (rc) + goto err_ret_dev; + + rc = bgrsb_init_link_inf(dev); + if (rc) + goto err_ret_dev; + + /* Set up input device */ + input = input_allocate_device(); + if (!input) + goto err_ret_dev; + + input_set_capability(input, EV_REL, REL_WHEEL); + input_set_capability(input, EV_KEY, KEY_VOLUMEUP); + input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN); + input->name = "bg-spi"; + + rc = input_register_device(input); + if (rc) { + pr_err("Input device registration failed\n"); + goto err_ret_inp; + } + dev->input = input; + + /* register device for bg-wear ssr */ + rc = bgrsb_ssr_register(dev); + if (rc) { + pr_err("Failed to register for bg ssr\n"); + goto err_ret_inp; + } + rc = device_create_file(&pdev->dev, &dev_attr_rsb); + if (rc) { + pr_err("Not able to create the file bg-rsb/enable\n"); + goto err_ret_inp; + } + dev_set_drvdata(&pdev->dev, dev); + rc = bgrsb_init_regulators(&pdev->dev); + if (rc) { + pr_err("Failed to set regulators\n"); + goto err_ret_inp; + } + return 0; + +err_ret_inp: + input_free_device(input); + +err_ret_dev: + devm_kfree(&pdev->dev, dev); + return -ENODEV; +} + +static int bg_rsb_remove(struct platform_device *pdev) +{ + struct bgrsb_priv *dev = platform_get_drvdata(pdev); + + destroy_workqueue(dev->bgrsb_event_wq); + destroy_workqueue(dev->bgrsb_wq); + input_free_device(dev->input); + wakeup_source_trash(&dev->bgrsb_ws); + + return 0; +} + +static int bg_rsb_resume(struct device *pldev) +{ + struct platform_device *pdev = to_platform_device(pldev); + struct bgrsb_priv *dev = platform_get_drvdata(pdev); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_CONFIGURED) + goto ret_success; + + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) { + if (bgrsb_ldo_work(dev, BGRSB_ENABLE_LDO11) == 0) { + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_debug("RSB Cofigured\n"); + goto ret_success; + } + pr_err("RSB failed to resume\n"); + } + mutex_unlock(&dev->rsb_state_mutex); + return -EINVAL; + +ret_success: + mutex_unlock(&dev->rsb_state_mutex); + return 0; +} + +static int bg_rsb_suspend(struct device *pldev) +{ + struct platform_device *pdev = to_platform_device(pldev); + struct bgrsb_priv *dev = platform_get_drvdata(pdev); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) + goto ret_success; + + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO15) != 0) + goto ret_err; + } + + if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11) == 0) { + dev->bgrsb_current_state = BGRSB_STATE_INIT; + pr_debug("RSB Init\n"); + goto ret_success; + } + +ret_err: + pr_err("RSB failed to suspend\n"); + mutex_unlock(&dev->rsb_state_mutex); + return -EINVAL; + +ret_success: + mutex_unlock(&dev->rsb_state_mutex); + return 0; +} + +static const struct of_device_id bg_rsb_of_match[] = { + { .compatible = "qcom,bg-rsb", }, + { } +}; + +static const struct dev_pm_ops pm_rsb = { + .resume = bg_rsb_resume, + .suspend = bg_rsb_suspend, +}; + +static struct platform_driver bg_rsb_driver = { + .driver = { + .name = "bg-rsb", + .of_match_table = bg_rsb_of_match, + .pm = &pm_rsb, + }, + .probe = bg_rsb_probe, + .remove = bg_rsb_remove, +}; + +module_platform_driver(bg_rsb_driver); +MODULE_DESCRIPTION("SoC BG RSB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/bgcom.h b/drivers/soc/qcom/bgcom.h index 8e1dcceb45946452073fea70f796d31971d3b62d..674a2cf5f5aada0936c9750a0b1b9c9aac569f53 100644 --- a/drivers/soc/qcom/bgcom.h +++ b/drivers/soc/qcom/bgcom.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -208,4 +208,6 @@ int bgcom_resume(void *handle); int bgcom_set_spi_state(enum bgcom_spi_state state); +void bgcom_bgdown_handler(void); + #endif /* BGCOM_H */ diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c index 29dee0313077761e572211009b5a5e401c97e50b..44c39b9231df19bb3a832c0459976e2c7e6d8403 100644 --- a/drivers/soc/qcom/bgcom_interface.c +++ b/drivers/soc/qcom/bgcom_interface.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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,15 +27,48 @@ #include #include "bgcom.h" #include "linux/bgcom_interface.h" +#include "bgcom_interface.h" +#include +#include +#include +#include +#include +#include #define BGCOM "bg_com_dev" +#define BGDAEMON_LDO09_LPM_VTG 0 +#define BGDAEMON_LDO09_NPM_VTG 10000 + +#define BGDAEMON_LDO03_LPM_VTG 0 +#define BGDAEMON_LDO03_NPM_VTG 10000 + +#define MPPS_DOWN_EVENT_TO_BG_TIMEOUT 3000 +#define SLEEP_FOR_SPI_BUS 2000 + enum { SSR_DOMAIN_BG, SSR_DOMAIN_MODEM, SSR_DOMAIN_MAX, }; +enum ldo_task { + ENABLE_LDO03, + ENABLE_LDO09, + DISABLE_LDO03, + DISABLE_LDO09 +}; + +struct bgdaemon_regulator { + struct regulator *regldo03; + struct regulator *regldo09; +}; + +struct bgdaemon_priv { + struct bgdaemon_regulator rgltr; + enum ldo_task ldo_action; +}; + struct bg_event { enum bg_event_type e_type; }; @@ -52,6 +85,8 @@ static char *ssr_domains[] = { "modem", }; +static struct bgdaemon_priv *dev; +static unsigned bgreset_gpio; static DEFINE_MUTEX(bg_char_mutex); static struct cdev bg_cdev; static struct class *bg_class; @@ -59,7 +94,9 @@ struct device *dev_ret; static dev_t bg_dev; static int device_open; static void *handle; +static bool twm_exit; static struct bgcom_open_config_type config_type; +static DECLARE_COMPLETION(bg_modem_down_wait); /** * send_uevent(): send events to user space @@ -78,6 +115,104 @@ static int send_uevent(struct bg_event *pce) return kobject_uevent_env(&dev_ret->kobj, KOBJ_CHANGE, envp); } +static int bgdaemon_configure_regulators(bool state) +{ + int retval; + + if (state == true) { + retval = regulator_enable(dev->rgltr.regldo03); + if (retval) + pr_err("Failed to enable LDO-03 regulator:%d\n", + retval); + retval = regulator_enable(dev->rgltr.regldo09); + if (retval) + pr_err("Failed to enable LDO-09 regulator:%d\n", + retval); + } + if (state == false) { + retval = regulator_disable(dev->rgltr.regldo03); + if (retval) + pr_err("Failed to disable LDO-03 regulator:%d\n", + retval); + retval = regulator_disable(dev->rgltr.regldo09); + if (retval) + pr_err("Failed to disable LDO-09 regulator:%d\n", + retval); + } + return retval; +} +static int bgdaemon_init_regulators(struct device *pdev) +{ + int rc; + struct regulator *reg03; + struct regulator *reg09; + + reg03 = regulator_get(pdev, "ssr-reg1"); + if (IS_ERR_OR_NULL(reg03)) { + rc = PTR_ERR(reg03); + pr_err("Unable to get regulator for LDO-03\n"); + goto err_ret; + } + reg09 = regulator_get(pdev, "ssr-reg2"); + if (IS_ERR_OR_NULL(reg09)) { + rc = PTR_ERR(reg09); + pr_err("Unable to get regulator for LDO-09\n"); + goto err_ret; + } + dev->rgltr.regldo03 = reg03; + dev->rgltr.regldo09 = reg09; + return 0; +err_ret: + return rc; +} + +static int bgdaemon_ldowork(enum ldo_task do_action) +{ + int ret; + + switch (do_action) { + case ENABLE_LDO03: + ret = regulator_set_optimum_mode(dev->rgltr.regldo03, + BGDAEMON_LDO03_NPM_VTG); + if (ret < 0) { + pr_err("Failed to request LDO-03 voltage:%d\n", + ret); + goto err_ret; + } + break; + case ENABLE_LDO09: + ret = regulator_set_optimum_mode(dev->rgltr.regldo09, + BGDAEMON_LDO09_NPM_VTG); + if (ret < 0) { + pr_err("Failed to request LDO-09 voltage:%d\n", + ret); + goto err_ret; + } + break; + case DISABLE_LDO03: + ret = regulator_set_optimum_mode(dev->rgltr.regldo03, + BGDAEMON_LDO03_LPM_VTG); + if (ret < 0) { + pr_err("Failed to disable LDO-03:%d\n", ret); + goto err_ret; + } + break; + case DISABLE_LDO09: + ret = regulator_set_optimum_mode(dev->rgltr.regldo09, + BGDAEMON_LDO09_LPM_VTG); + if (ret < 0) { + pr_err("Failed to disable LDO-09:%d\n", ret); + goto err_ret; + } + break; + default: + ret = -EINVAL; + } + +err_ret: + return ret; +} + static int bgcom_char_open(struct inode *inode, struct file *file) { int ret; @@ -169,6 +304,22 @@ static int bgchar_write_cmd(struct bg_ui_data *fui_obj_msg, int type) return ret; } +int bg_soft_reset(void) +{ + /*pull down reset gpio */ + gpio_direction_output(bgreset_gpio, 0); + msleep(50); + gpio_set_value(bgreset_gpio, 1); + return 0; +} +EXPORT_SYMBOL(bg_soft_reset); + +static int modem_down2_bg(void) +{ + complete(&bg_modem_down_wait); + return 0; +} + static long bg_com_ioctl(struct file *filp, unsigned int ui_bgcom_cmd, unsigned long arg) { @@ -204,6 +355,18 @@ static long bg_com_ioctl(struct file *filp, break; case SET_SPI_BUSY: ret = bgcom_set_spi_state(BGCOM_SPI_BUSY); + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); + break; + case BG_SOFT_RESET: + ret = bg_soft_reset(); + break; + case BG_MODEM_DOWN2_BG_DONE: + ret = modem_down2_bg(); + break; + case BG_TWM_EXIT: + twm_exit = true; + ret = 0; break; default: ret = -ENOIOCTLCMD; @@ -222,6 +385,69 @@ static int bgcom_char_close(struct inode *inode, struct file *file) return ret; } +static int bg_daemon_probe(struct platform_device *pdev) +{ + struct device_node *node; + unsigned reset_gpio; + int ret; + + node = pdev->dev.of_node; + + dev = kzalloc(sizeof(struct bgdaemon_priv), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + reset_gpio = of_get_named_gpio(node, "qcom,bg-reset-gpio", 0); + if (!gpio_is_valid(reset_gpio)) { + pr_err("gpio %d found is not valid\n", reset_gpio); + goto err_ret; + } + + if (gpio_request(reset_gpio, "bg_reset_gpio")) { + pr_err("gpio %d request failed\n", reset_gpio); + goto err_ret; + } + + if (gpio_direction_output(reset_gpio, 1)) { + pr_err("gpio %d direction not set\n", reset_gpio); + goto err_ret; + } + + pr_info("bg-soft-reset gpio successfully requested\n"); + bgreset_gpio = reset_gpio; + + ret = bgdaemon_init_regulators(&pdev->dev); + if (ret != 0) { + pr_err("Failed to init regulators:%d\n", ret); + goto err_device; + } + ret = bgdaemon_configure_regulators(true); + if (ret) { + pr_err("Failed to confifigure regulators:%d\n", ret); + bgdaemon_configure_regulators(false); + goto err_ret; + } + +err_device: + return -ENODEV; +err_ret: + return 0; +} + +static const struct of_device_id bg_daemon_of_match[] = { + { .compatible = "qcom,bg-daemon", }, + { } +}; +MODULE_DEVICE_TABLE(of, bg_daemon_of_match); + +static struct platform_driver bg_daemon_driver = { + .probe = bg_daemon_probe, + .driver = { + .name = "bg-daemon", + .of_match_table = bg_daemon_of_match, + }, +}; + static const struct file_operations fops = { .owner = THIS_MODULE, .open = bgcom_char_open, @@ -261,6 +487,10 @@ static int __init init_bg_com_dev(void) pr_err("device create failed\n"); return PTR_ERR(dev_ret); } + + if (platform_driver_register(&bg_daemon_driver)) + pr_err("%s: failed to register bg-daemon register\n", __func__); + return 0; } @@ -270,6 +500,8 @@ static void __exit exit_bg_com_dev(void) class_destroy(bg_class); cdev_del(&bg_cdev); unregister_chrdev_region(bg_dev, 1); + bgdaemon_configure_regulators(false); + platform_driver_unregister(&bg_daemon_driver); } /** @@ -285,10 +517,21 @@ static int ssr_bg_cb(struct notifier_block *this, switch (opcode) { case SUBSYS_BEFORE_SHUTDOWN: bge.e_type = BG_BEFORE_POWER_DOWN; + bgdaemon_ldowork(ENABLE_LDO03); + bgdaemon_ldowork(ENABLE_LDO09); + bgcom_bgdown_handler(); + bgcom_set_spi_state(BGCOM_SPI_BUSY); send_uevent(&bge); break; + case SUBSYS_AFTER_SHUTDOWN: + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); + break; case SUBSYS_AFTER_POWERUP: bge.e_type = BG_AFTER_POWER_UP; + bgdaemon_ldowork(DISABLE_LDO03); + bgdaemon_ldowork(DISABLE_LDO09); + bgcom_set_spi_state(BGCOM_SPI_FREE); send_uevent(&bge); break; } @@ -304,11 +547,17 @@ static int ssr_modem_cb(struct notifier_block *this, unsigned long opcode, void *data) { struct bg_event modeme; + int ret; switch (opcode) { case SUBSYS_BEFORE_SHUTDOWN: modeme.e_type = MODEM_BEFORE_POWER_DOWN; + reinit_completion(&bg_modem_down_wait); send_uevent(&modeme); + ret = wait_for_completion_timeout(&bg_modem_down_wait, + msecs_to_jiffies(MPPS_DOWN_EVENT_TO_BG_TIMEOUT)); + if (!ret) + pr_err("Time out on modem down event\n"); break; case SUBSYS_AFTER_POWERUP: modeme.e_type = MODEM_AFTER_POWER_UP; @@ -318,6 +567,16 @@ static int ssr_modem_cb(struct notifier_block *this, return NOTIFY_DONE; } +bool is_twm_exit(void) +{ + if (twm_exit) { + twm_exit = false; + return true; + } + return false; +} +EXPORT_SYMBOL(is_twm_exit); + static struct notifier_block ssr_modem_nb = { .notifier_call = ssr_modem_cb, .priority = 0, diff --git a/drivers/soc/qcom/bgcom_interface.h b/drivers/soc/qcom/bgcom_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..ab1f5143f6e38182ce681e1ef6bc04ed55c2a92f --- /dev/null +++ b/drivers/soc/qcom/bgcom_interface.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * 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. + * + */ +#ifndef BGCOM_INTERFACE_H +#define BGCOM_INTERFACE_H + +/** + * bg_soft_reset() - soft reset Blackghost + * Return 0 on success or -Ve on error +*/ +int bg_soft_reset(void); + +/** + * is_twm_exit() + * Return true if device is booting up on TWM exit. + * value is auto cleared once read. +*/ +bool is_twm_exit(void); + +#endif /* BGCOM_INTERFACE_H */ diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index 13658bf0eeb3ab3dbe3a9f6eb8425786e3058d03..2ce11076847a8fe1861697dc65b15fbfaf951a52 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -25,7 +25,10 @@ #include #include #include +#include #include "bgcom.h" +#include "bgrsb.h" +#include "bgcom_interface.h" #define BG_SPI_WORD_SIZE (0x04) #define BG_SPI_READ_LEN (0x04) @@ -37,14 +40,23 @@ #define BG_SPI_AHB_CMD_LEN (0x05) #define BG_SPI_AHB_READ_CMD_LEN (0x08) #define BG_STATUS_REG (0x05) +#define BG_CMND_REG (0x14) #define BG_SPI_MAX_WORDS (0x3FFFFFFD) #define BG_SPI_MAX_REGS (0x0A) +#define HED_EVENT_ID_LEN (0x02) +#define HED_EVENT_SIZE_LEN (0x02) +#define HED_EVENT_DATA_STRT_LEN (0x05) +#define CMA_BFFR_POOL_SIZE (128*1024) + +#define MAX_RETRY 500 enum bgcom_state { /*BGCOM Staus ready*/ BGCOM_PROB_SUCCESS = 0, BGCOM_PROB_WAIT = 1, + BGCOM_STATE_SUSPEND = 2, + BGCOM_STATE_ACTIVE = 3 }; enum bgcom_req_type { @@ -52,6 +64,7 @@ enum bgcom_req_type { BGCOM_READ_REG = 0, BGCOM_READ_FIFO = 1, BGCOM_READ_AHB = 2, + BGCOM_WRITE_REG = 3, }; struct bg_spi_priv { @@ -63,6 +76,8 @@ struct bg_spi_priv { struct spi_message msg1; struct spi_transfer xfer1; int irq_lock; + + enum bgcom_state bg_state; }; struct cb_data { @@ -80,19 +95,77 @@ struct bg_context { struct cb_data *cb; }; +struct event_list { + struct event *evnt; + struct list_head list; +}; static void *bg_com_drv; static uint32_t g_slav_status_reg; /* BGCOM client callbacks set-up */ +static void send_input_events(struct work_struct *work); static struct list_head cb_head = LIST_HEAD_INIT(cb_head); - +static struct list_head pr_lst_hd = LIST_HEAD_INIT(pr_lst_hd); static enum bgcom_spi_state spi_state; + +static struct workqueue_struct *wq; +static DECLARE_WORK(input_work , send_input_events); + +static struct mutex bg_resume_mutex; + +static atomic_t bg_is_spi_active; +static int bg_irq; + +static uint8_t *fxd_mem_buffer; +static struct mutex cma_buffer_lock; + +static struct spi_device *get_spi_device(void) +{ + struct bg_spi_priv *bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + struct spi_device *spi = bg_spi->spi; + return spi; +} + +static void augmnt_fifo(uint8_t *data, int pos) +{ + data[pos] = '\0'; +} + +static void send_input_events(struct work_struct *work) +{ + struct list_head *temp; + struct list_head *pos; + struct event_list *node; + struct event *evnt; + + if (list_empty(&pr_lst_hd)) + return; + + list_for_each_safe(pos, temp, &pr_lst_hd) { + node = list_entry(pos, struct event_list, list); + evnt = node->evnt; + bgrsb_send_input(evnt); + kfree(evnt); + list_del(&node->list); + kfree(node); + } +} + int bgcom_set_spi_state(enum bgcom_spi_state state) { + struct bg_spi_priv *bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); if (state < 0 || state > 1) return -EINVAL; + + if (state == spi_state) + return 0; + + mutex_lock(&bg_spi->xfer_mutex); spi_state = state; + mutex_unlock(&bg_spi->xfer_mutex); return 0; } EXPORT_SYMBOL(bgcom_set_spi_state); @@ -105,7 +178,7 @@ void add_to_irq_list(struct cb_data *data) static bool is_bgcom_ready(void) { - return bg_com_drv ? true : false; + return (bg_com_drv != NULL ? true : false); } static void bg_spi_reinit_xfer(struct spi_transfer *xfer) @@ -138,6 +211,10 @@ static int read_bg_locl(enum bgcom_req_type req_type, case BGCOM_READ_FIFO: ret = bgcom_fifo_read(&clnt_handle, no_of_words, buf); break; + case BGCOM_WRITE_REG: + ret = bgcom_reg_write(&clnt_handle, BG_CMND_REG, + no_of_words, buf); + break; case BGCOM_READ_AHB: break; } @@ -159,6 +236,8 @@ static int bgcom_transfer(void *handle, uint8_t *tx_buf, cntx = (struct bg_context *)handle; if (cntx->state == BGCOM_PROB_WAIT) { + if (!is_bgcom_ready()) + return -ENODEV; cntx->bg_spi = container_of(bg_com_drv, struct bg_spi_priv, lhandle); cntx->state = BGCOM_PROB_SUCCESS; @@ -171,6 +250,9 @@ static int bgcom_transfer(void *handle, uint8_t *tx_buf, tx_xfer = &bg_spi->xfer1; spi = bg_spi->spi; + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + mutex_lock(&bg_spi->xfer_mutex); bg_spi_reinit_xfer(tx_xfer); tx_xfer->tx_buf = tx_buf; @@ -203,6 +285,62 @@ void send_event(enum bgcom_event_type event, } } +void bgcom_bgdown_handler(void) +{ + send_event(BGCOM_EVENT_RESET_OCCURRED, NULL); + g_slav_status_reg = 0; +} +EXPORT_SYMBOL(bgcom_bgdown_handler); + +static void parse_fifo(uint8_t *data, union bgcom_event_data_type *event_data) +{ + uint16_t p_len; + uint8_t sub_id; + uint32_t evnt_tm; + uint16_t event_id; + void *evnt_data; + struct event *evnt; + struct event_list *data_list; + + while (*data != '\0') { + + event_id = *((uint16_t *) data); + data = data + HED_EVENT_ID_LEN; + p_len = *((uint16_t *) data); + data = data + HED_EVENT_SIZE_LEN; + + if (event_id == 0xFFFE) { + + sub_id = *data; + evnt_tm = *((uint32_t *)(data+1)); + + evnt = kmalloc(sizeof(*evnt), GFP_KERNEL); + evnt->sub_id = sub_id; + evnt->evnt_tm = evnt_tm; + evnt->evnt_data = + *(int16_t *)(data + HED_EVENT_DATA_STRT_LEN); + + data_list = kmalloc(sizeof(*data_list), GFP_KERNEL); + data_list->evnt = evnt; + list_add_tail(&data_list->list, &pr_lst_hd); + + } else if (event_id == 0x0001) { + evnt_data = kmalloc(p_len, GFP_KERNEL); + if (evnt_data != NULL) { + memcpy(evnt_data, data, p_len); + event_data->fifo_data.to_master_fifo_used = + p_len/BG_SPI_WORD_SIZE; + event_data->fifo_data.data = evnt_data; + send_event(BGCOM_EVENT_TO_MASTER_FIFO_USED, + event_data); + } + } + data = data + p_len; + } + if (!list_empty(&pr_lst_hd)) + queue_work(wq, &input_work); +} + static void send_back_notification(uint32_t slav_status_reg, uint32_t slav_status_auto_clear_reg, uint32_t fifo_fill_reg, uint32_t fifo_size_reg) @@ -277,25 +415,22 @@ static void send_back_notification(uint32_t slav_status_reg, } if (master_fifo_used > 0) { - ptr = kzalloc(master_fifo_used*BG_SPI_WORD_SIZE, + ptr = kzalloc(master_fifo_used*BG_SPI_WORD_SIZE + 1, GFP_KERNEL | GFP_ATOMIC); if (ptr != NULL) { ret = read_bg_locl(BGCOM_READ_FIFO, master_fifo_used, ptr); if (!ret) { - event_data.fifo_data.to_master_fifo_used = - master_fifo_used; - event_data.fifo_data.data = ptr; - send_event(BGCOM_EVENT_TO_MASTER_FIFO_USED, - &event_data); + augmnt_fifo((uint8_t *)ptr, + master_fifo_used*BG_SPI_WORD_SIZE); + parse_fifo((uint8_t *)ptr, &event_data); } + kfree(ptr); } } - if (slave_fifo_free > 0) { - event_data.to_slave_fifo_free = slave_fifo_free; - send_event(BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data); - } + event_data.to_slave_fifo_free = slave_fifo_free; + send_event(BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data); } static void bg_irq_tasklet_hndlr_l(void) @@ -328,6 +463,7 @@ static void bg_irq_tasklet_hndlr_l(void) int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, uint32_t num_words, void *read_buf) { + dma_addr_t dma_hndl_tx, dma_hndl_rx; uint32_t txn_len; uint8_t *tx_buf; uint8_t *rx_buf; @@ -335,6 +471,7 @@ int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, int ret; uint8_t cmnd = 0; uint32_t ahb_addr = 0; + struct spi_device *spi = get_spi_device(); if (!handle || !read_buf || num_words == 0 || num_words > BG_SPI_MAX_WORDS) { @@ -349,18 +486,24 @@ int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, return -EBUSY; } + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_AHB_READ_CMD_LEN + size; - tx_buf = kzalloc(txn_len, GFP_KERNEL); + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl_tx, GFP_KERNEL); if (!tx_buf) return -ENOMEM; - rx_buf = kzalloc(txn_len, GFP_KERNEL); - + rx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl_rx, GFP_KERNEL); if (!rx_buf) { - kfree(tx_buf); + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl_tx); return -ENOMEM; } @@ -375,8 +518,8 @@ int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, if (!ret) memcpy(read_buf, rx_buf+BG_SPI_AHB_READ_CMD_LEN, size); - kfree(tx_buf); - kfree(rx_buf); + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl_tx); + dma_free_coherent(&spi->dev, txn_len, rx_buf, dma_hndl_rx); return ret; } EXPORT_SYMBOL(bgcom_ahb_read); @@ -384,12 +527,15 @@ EXPORT_SYMBOL(bgcom_ahb_read); int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, uint32_t num_words, void *write_buf) { + dma_addr_t dma_hndl; uint32_t txn_len; uint8_t *tx_buf; uint32_t size; int ret; + bool is_cma_used = false; uint8_t cmnd = 0; uint32_t ahb_addr = 0; + struct spi_device *spi = get_spi_device(); if (!handle || !write_buf || num_words == 0 || num_words > BG_SPI_MAX_WORDS) { @@ -405,13 +551,29 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, return -EBUSY; } + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + + mutex_lock(&cma_buffer_lock); size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_AHB_CMD_LEN + size; + if (fxd_mem_buffer != NULL && txn_len <= CMA_BFFR_POOL_SIZE) { + memset(fxd_mem_buffer, 0, txn_len); + tx_buf = fxd_mem_buffer; + is_cma_used = true; + } else { + pr_info("DMA memory used for size[%d]\n", txn_len); + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl, GFP_KERNEL); + } - tx_buf = kzalloc(txn_len, GFP_KERNEL); - - if (!tx_buf) + if (!tx_buf) { + mutex_unlock(&cma_buffer_lock); return -ENOMEM; + } cmnd |= BG_SPI_AHB_WRITE_CMD; ahb_addr |= ahb_start_addr; @@ -421,7 +583,9 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size); ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); - kfree(tx_buf); + if (!is_cma_used) + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); + mutex_unlock(&cma_buffer_lock); return ret; } EXPORT_SYMBOL(bgcom_ahb_write); @@ -449,6 +613,11 @@ int bgcom_fifo_write(void *handle, uint32_t num_words, return -EBUSY; } + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_WRITE_CMND_LEN + size; @@ -491,6 +660,11 @@ int bgcom_fifo_read(void *handle, uint32_t num_words, return -EBUSY; } + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_READ_LEN + size; tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); @@ -541,6 +715,11 @@ int bgcom_reg_write(void *handle, uint8_t reg_start_addr, return -EBUSY; } + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + size = num_regs*BG_SPI_WORD_SIZE; txn_len = BG_SPI_WRITE_CMND_LEN + size; @@ -611,16 +790,73 @@ int bgcom_reg_read(void *handle, uint8_t reg_start_addr, } EXPORT_SYMBOL(bgcom_reg_read); +static int is_bg_resume(void *handle) +{ + uint32_t txn_len; + int ret; + uint8_t tx_buf[8] = {0}; + uint8_t rx_buf[8] = {0}; + uint32_t cmnd_reg = 0; + + if (spi_state == BGCOM_SPI_BUSY) { + printk_ratelimited("SPI is held by TZ\n"); + goto ret_err; + } + + txn_len = 0x08; + tx_buf[0] = 0x05; + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + if (!ret) + memcpy(&cmnd_reg, rx_buf+BG_SPI_READ_LEN, 0x04); + +ret_err: + return cmnd_reg & BIT(31); +} + int bgcom_resume(void *handle) { - return handle ? 0 : -EINVAL; + struct bg_spi_priv *bg_spi; + struct bg_context *cntx; + int retry = 0; + + if (handle == NULL) + return -EINVAL; + + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + + cntx = (struct bg_context *)handle; + bg_spi = cntx->bg_spi; + + mutex_lock(&bg_resume_mutex); + if (bg_spi->bg_state == BGCOM_STATE_ACTIVE) + goto unlock; + do { + if (is_bg_resume(handle)) { + bg_spi->bg_state = BGCOM_STATE_ACTIVE; + break; + } + udelay(10); + ++retry; + } while (retry < MAX_RETRY); + +unlock: + mutex_unlock(&bg_resume_mutex); + if (retry == MAX_RETRY) { + /* BG failed to resume. Trigger BG soft reset. */ + pr_err("BG failed to resume\n"); + bg_soft_reset(); + return -ETIMEDOUT; + } + return 0; } EXPORT_SYMBOL(bgcom_resume); int bgcom_suspend(void *handle) { - return handle ? 0 : -EINVAL; - + if (!handle) + return -EINVAL; + return 0; } EXPORT_SYMBOL(bgcom_suspend); @@ -688,11 +924,17 @@ EXPORT_SYMBOL(bgcom_close); static irqreturn_t bg_irq_tasklet_hndlr(int irq, void *device) { struct bg_spi_priv *bg_spi = device; + /* check if call-back exists */ - if (list_empty(&cb_head)) { - pr_debug("No callback registered\n"); + if (!atomic_read(&bg_is_spi_active)) { + printk_ratelimited("Interrupt received in suspend state\n"); + return IRQ_HANDLED; + } else if (list_empty(&cb_head)) { + pr_err("No callback registered\n"); return IRQ_HANDLED; } else if (spi_state == BGCOM_SPI_BUSY) { + /* delay for spi to be freed */ + msleep(50); return IRQ_HANDLED; } else if (!bg_spi->irq_lock) { bg_spi->irq_lock = 1; @@ -715,10 +957,21 @@ static void bg_spi_init(struct bg_spi_priv *bg_spi) spi_message_add_tail(&bg_spi->xfer1, &bg_spi->msg1); /* BGCOM IRQ set-up */ - bg_com_drv = &bg_spi->lhandle; bg_spi->irq_lock = 0; spi_state = BGCOM_SPI_FREE; + + wq = create_singlethread_workqueue("input_wq"); + + bg_spi->bg_state = BGCOM_STATE_ACTIVE; + + bg_com_drv = &bg_spi->lhandle; + + mutex_init(&bg_resume_mutex); + + fxd_mem_buffer = kmalloc(CMA_BFFR_POOL_SIZE, GFP_KERNEL | GFP_ATOMIC); + + mutex_init(&cma_buffer_lock); } static int bg_spi_probe(struct spi_device *spi) @@ -726,7 +979,6 @@ static int bg_spi_probe(struct spi_device *spi) struct bg_spi_priv *bg_spi; struct device_node *node; int irq_gpio = 0; - int bg_irq = 0; int ret; bg_spi = devm_kzalloc(&spi->dev, sizeof(*bg_spi), @@ -763,6 +1015,10 @@ static int bg_spi_probe(struct spi_device *spi) if (ret) goto err_ret; + + atomic_set(&bg_is_spi_active, 1); + dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(64)); + pr_info("Bgcom Probed successfully\n"); return ret; err_ret: @@ -779,10 +1035,59 @@ static int bg_spi_remove(struct spi_device *spi) mutex_destroy(&bg_spi->xfer_mutex); devm_kfree(&spi->dev, bg_spi); spi_set_drvdata(spi, NULL); - + if (fxd_mem_buffer != NULL) + kfree(fxd_mem_buffer); + mutex_destroy(&cma_buffer_lock); return 0; } +static void bg_spi_shutdown(struct spi_device *spi) +{ + bg_spi_remove(spi); +} + +static int bgcom_pm_suspend(struct device *dev) +{ + uint32_t cmnd_reg = 0; + struct spi_device *s_dev = to_spi_device(dev); + struct bg_spi_priv *bg_spi = spi_get_drvdata(s_dev); + int ret = 0; + + if (bg_spi->bg_state == BGCOM_STATE_SUSPEND) + return 0; + + cmnd_reg |= BIT(31); + ret = read_bg_locl(BGCOM_WRITE_REG, 1, &cmnd_reg); + if (ret == 0) { + bg_spi->bg_state = BGCOM_STATE_SUSPEND; + atomic_set(&bg_is_spi_active, 0); + disable_irq(bg_irq); + } + pr_info("suspended with : %d\n", ret); + return ret; +} + +static int bgcom_pm_resume(struct device *dev) +{ + struct bg_context clnt_handle; + int ret; + struct bg_spi_priv *spi = + container_of(bg_com_drv, struct bg_spi_priv, lhandle); + + clnt_handle.bg_spi = spi; + atomic_set(&bg_is_spi_active, 1); + ret = bgcom_resume(&clnt_handle); + if (ret == 0) + enable_irq(bg_irq); + pr_info("Bgcom resumed with : %d\n", ret); + return ret; +} + +static const struct dev_pm_ops bgcom_pm = { + .suspend = bgcom_pm_suspend, + .resume = bgcom_pm_resume, +}; + static const struct of_device_id bg_spi_of_match[] = { { .compatible = "qcom,bg-spi", }, { } @@ -793,9 +1098,11 @@ static struct spi_driver bg_spi_driver = { .driver = { .name = "bg-spi", .of_match_table = bg_spi_of_match, + .pm = &bgcom_pm, }, .probe = bg_spi_probe, .remove = bg_spi_remove, + .shutdown = bg_spi_shutdown, }; module_spi_driver(bg_spi_driver); diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h b/drivers/soc/qcom/bgrsb.h similarity index 51% rename from drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h rename to drivers/soc/qcom/bgrsb.h index 618926fa8341c3677c6a16d4caa5a5a4e6771ca5..1ac75d9821f8129b370c55772ad417a49f7cb211 100644 --- a/drivers/media/platform/msm/ais/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h +++ b/drivers/soc/qcom/bgrsb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * 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 @@ -8,39 +8,29 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + * */ -#ifndef MSM_CSIPHY_2_0_HWREG_H -#define MSM_CSIPHY_2_0_HWREG_H +#ifndef BGRSB_H +#define BGRSB_H + +struct event { + uint8_t sub_id; + int16_t evnt_data; + uint32_t evnt_tm; +}; -#include -struct csiphy_reg_parms_t csiphy_v2_0 = { - /* MIPI CSI PHY registers */ - 0x17C, - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x180, - 0x1A0, - 0x6F, - 0x1A4, - 0x1C0, - 0x1C4, - 0x4, - 0x1E0, - 0x1E8, - 0x0, +struct bg_glink_chnl { + char *chnl_name; + char *chnl_edge; + char *chnl_trnsprt; }; -#endif + +/** + * bgrsb_send_input() - send the recived input to input framework + * @evnt: pointer to the event structure + */ +int bgrsb_send_input(struct event *evnt); + +#endif /* BGCOM_H */ diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index 41dccd0c29ce66a93ce6eb2c410edfa0a3fb702f..14d3a77ce0ee92674dd23719d9406095d7f53c47 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * 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 @@ -37,6 +37,7 @@ #define GLINK_QOS_DEF_NUM_PRIORITY 1 #define GLINK_QOS_DEF_MTU 2048 +#define GLINK_CH_XPRT_NAME_SIZE ((3 * GLINK_NAME_SIZE) + 4) #define GLINK_KTHREAD_PRIO 1 /** @@ -369,7 +370,7 @@ static void tx_func(struct kthread_work *work); static struct channel_ctx *ch_name_to_ch_ctx_create( struct glink_core_xprt_ctx *xprt_ctx, - const char *name); + const char *name, bool local); static void ch_push_remote_rx_intent(struct channel_ctx *ctx, size_t size, uint32_t riid, void *cookie); @@ -1820,13 +1821,14 @@ static void glink_ch_ctx_release(struct rwref_lock *ch_st_lock) * it is not found. * @xprt_ctx: Transport to search for a matching channel. * @name: Name of the desired channel. + * @local: If called from local open or not * * Return: The channel corresponding to @name, NULL if a matching channel was * not found AND a new channel could not be created. */ static struct channel_ctx *ch_name_to_ch_ctx_create( struct glink_core_xprt_ctx *xprt_ctx, - const char *name) + const char *name, bool local) { struct channel_ctx *entry; struct channel_ctx *ctx; @@ -1870,6 +1872,20 @@ check_ctx: list_for_each_entry_safe(entry, temp, &xprt_ctx->channels, port_list_node) if (!strcmp(entry->name, name) && !entry->pending_delete) { + rwref_get(&entry->ch_state_lhb2); + /* port already exists */ + if (entry->local_open_state != GLINK_CHANNEL_CLOSED + && local) { + /* not ready to be re-opened */ + GLINK_INFO_CH_XPRT(entry, xprt_ctx, + "%s: Ch not ready. State: %u\n", + __func__, entry->local_open_state); + rwref_put(&entry->ch_state_lhb2); + entry = NULL; + } else if (local) { + entry->local_open_state = + GLINK_CHANNEL_OPENING; + } spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1, flags); kfree(ctx); @@ -1901,6 +1917,10 @@ check_ctx: kfree(flcid); } + ctx->transport_ptr = xprt_ctx; + rwref_get(&ctx->ch_state_lhb2); + if (local) + ctx->local_open_state = GLINK_CHANNEL_OPENING; list_add_tail(&ctx->port_list_node, &xprt_ctx->channels); GLINK_INFO_PERF_CH_XPRT(ctx, xprt_ctx, @@ -2567,22 +2587,13 @@ void *glink_open(const struct glink_open_config *cfg) * look for an existing port structure which can occur in * reopen and remote-open-first cases */ - ctx = ch_name_to_ch_ctx_create(transport_ptr, cfg->name); + ctx = ch_name_to_ch_ctx_create(transport_ptr, cfg->name, true); if (ctx == NULL) { GLINK_ERR("%s:%s %s: Error - unable to allocate new channel\n", cfg->transport, cfg->edge, __func__); return ERR_PTR(-ENOMEM); } - /* port already exists */ - if (ctx->local_open_state != GLINK_CHANNEL_CLOSED) { - /* not ready to be re-opened */ - GLINK_INFO_CH_XPRT(ctx, transport_ptr, - "%s: Channel not ready to be re-opened. State: %u\n", - __func__, ctx->local_open_state); - return ERR_PTR(-EBUSY); - } - /* initialize port structure */ ctx->user_priv = cfg->priv; ctx->rx_intent_req_timeout_jiffies = @@ -2613,8 +2624,6 @@ void *glink_open(const struct glink_open_config *cfg) ctx->local_xprt_req = best_id; ctx->no_migrate = cfg->transport && !(cfg->options & GLINK_OPT_INITIAL_XPORT); - ctx->transport_ptr = transport_ptr; - ctx->local_open_state = GLINK_CHANNEL_OPENING; GLINK_INFO_PERF_CH(ctx, "%s: local:GLINK_CHANNEL_CLOSED->GLINK_CHANNEL_OPENING\n", __func__); @@ -2859,6 +2868,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, size_t intent_size; bool is_atomic = tx_flags & (GLINK_TX_SINGLE_THREADED | GLINK_TX_ATOMIC); + char glink_name[GLINK_CH_XPRT_NAME_SIZE]; unsigned long flags; void *cookie = NULL; @@ -2893,21 +2903,22 @@ static int glink_tx_common(void *handle, void *pkt_priv, tracer_pkt_log_event(data, GLINK_CORE_TX); } - /* find matching rx intent (best-fit algorithm for now) */ + scnprintf(glink_name, GLINK_CH_XPRT_NAME_SIZE, "%s_%s_%s", ctx->name, + ctx->transport_ptr->edge, ctx->transport_ptr->name); + /* find matching rx intent (first-fit algorithm for now) */ if (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size, &cookie)) { if (!(tx_flags & GLINK_TX_REQ_INTENT)) { /* no rx intent available */ - GLINK_ERR_CH(ctx, - "%s: R[%u]:%zu Intent not present for lcid\n", - __func__, riid, size); + GLINK_ERR( + "%s: %s: R[%u]:%zu Intent not present\n", + glink_name, __func__, riid, size); ret = -EAGAIN; goto glink_tx_common_err; } if (is_atomic && !(ctx->transport_ptr->capabilities & GCAP_AUTO_QUEUE_RX_INT)) { - GLINK_ERR_CH(ctx, - "%s: Cannot request intent in atomic context\n", - __func__); + GLINK_ERR("%s: %s: %s\n", glink_name, __func__, + "Cannot request intent in atomic context"); ret = -EINVAL; goto glink_tx_common_err; } @@ -2917,8 +2928,8 @@ static int glink_tx_common(void *handle, void *pkt_priv, ret = ctx->transport_ptr->ops->tx_cmd_rx_intent_req( ctx->transport_ptr->ops, ctx->lcid, size); if (ret) { - GLINK_ERR_CH(ctx, "%s: Request intent failed %d\n", - __func__, ret); + GLINK_ERR("%s: %s: Request intent failed %d\n", + glink_name, __func__, ret); goto glink_tx_common_err; } @@ -2926,18 +2937,18 @@ static int glink_tx_common(void *handle, void *pkt_priv, &intent_size, &cookie)) { rwref_read_put(&ctx->ch_state_lhb2); if (is_atomic) { - GLINK_ERR_CH(ctx, - "%s Intent of size %zu not ready\n", - __func__, size); + GLINK_ERR("%s: %s: Intent of size %zu %s\n", + glink_name, __func__, size, + "not ready"); ret = -EAGAIN; goto glink_tx_common_err_2; } if (ctx->transport_ptr->local_state == GLINK_XPRT_DOWN || !ch_is_fully_opened(ctx)) { - GLINK_ERR_CH(ctx, - "%s: Channel closed while waiting for intent\n", - __func__); + GLINK_ERR("%s: %s: %s %s\n", glink_name, + __func__, "Channel closed while", + "waiting for intent"); ret = -EBUSY; goto glink_tx_common_err_2; } @@ -2946,18 +2957,18 @@ static int glink_tx_common(void *handle, void *pkt_priv, if (!wait_for_completion_timeout( &ctx->int_req_ack_complete, ctx->rx_intent_req_timeout_jiffies)) { - GLINK_ERR_CH(ctx, - "%s: Intent request ack with size: %zu not granted for lcid\n", - __func__, size); + GLINK_ERR( + "%s: %s: %s %zu not granted for lcid\n", + glink_name, __func__, + "Intent request ack with size:", size); ret = -ETIMEDOUT; goto glink_tx_common_err_2; } if (!ctx->int_req_ack) { - GLINK_ERR_CH(ctx, - "%s: Intent Request with size: %zu %s", - __func__, size, - "not granted for lcid\n"); + GLINK_ERR("%s: %s: %s %zu %s\n", glink_name, + __func__, "Intent Request with size:", + size, "not granted for lcid"); ret = -EAGAIN; goto glink_tx_common_err_2; } @@ -2966,9 +2977,9 @@ static int glink_tx_common(void *handle, void *pkt_priv, if (!wait_for_completion_timeout( &ctx->int_req_complete, ctx->rx_intent_req_timeout_jiffies)) { - GLINK_ERR_CH(ctx, - "%s: Intent request with size: %zu not granted for lcid\n", - __func__, size); + GLINK_ERR("%s: %s: %s %zu %s\n", glink_name, + __func__, "Intent request with size: ", + size, "not granted for lcid"); ret = -ETIMEDOUT; goto glink_tx_common_err_2; } @@ -4800,7 +4811,7 @@ static void glink_core_rx_cmd_ch_remote_open(struct glink_transport_if *if_ptr, bool do_migrate; glink_core_migration_edge_lock(if_ptr->glink_core_priv); - ctx = ch_name_to_ch_ctx_create(if_ptr->glink_core_priv, name); + ctx = ch_name_to_ch_ctx_create(if_ptr->glink_core_priv, name, false); if (ctx == NULL) { GLINK_ERR_XPRT(if_ptr->glink_core_priv, "%s: invalid rcid %u received, name '%s'\n", @@ -4900,6 +4911,7 @@ static void glink_core_rx_cmd_ch_remote_close( struct channel_ctx *ctx; bool is_ch_fully_closed; struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv; + unsigned long flags; ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid); if (!ctx) { @@ -4917,11 +4929,13 @@ static void glink_core_rx_cmd_ch_remote_close( rwref_put(&ctx->ch_state_lhb2); return; } + spin_lock_irqsave(&ctx->transport_ptr->xprt_ctx_lock_lhb1, flags); + ctx->pending_delete = true; + spin_unlock_irqrestore(&ctx->transport_ptr->xprt_ctx_lock_lhb1, flags); GLINK_INFO_CH(ctx, "%s: remote: OPENED->CLOSED\n", __func__); is_ch_fully_closed = glink_core_remote_close_common(ctx, false); - ctx->pending_delete = true; if_ptr->tx_cmd_ch_remote_close_ack(if_ptr, rcid); if (is_ch_fully_closed) { diff --git a/drivers/soc/qcom/glink_bgcom_xprt.c b/drivers/soc/qcom/glink_bgcom_xprt.c index c38c3de5f5c381f317e00ec5e2569d9646eba6b3..9cba9d8cce679deaee49131f286210cfbd15c49a 100644 --- a/drivers/soc/qcom/glink_bgcom_xprt.c +++ b/drivers/soc/qcom/glink_bgcom_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. * * 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 @@ -50,6 +50,8 @@ #define BGCOM_TO_MASTER_FIFO_READY 0x00000004 #define BGCOM_AHB_READY 0x00000008 #define WORD_SIZE 4 +#define TX_BLOCKED_CMD_RESERVE 16 +#define FIFO_FULL_RESERVE (TX_BLOCKED_CMD_RESERVE/WORD_SIZE) #define BGCOM_LINKUP (BGCOM_APPLICATION_RUNNING \ | BGCOM_TO_SLAVE_FIFO_READY \ | BGCOM_TO_MASTER_FIFO_READY \ @@ -216,6 +218,11 @@ static int glink_bgcom_get_tx_avail(struct edge_info *einfo) mutex_lock(&einfo->tx_avail_lock); tx_avail = einfo->fifo_fill.tx_avail; + if (tx_avail < FIFO_FULL_RESERVE) + tx_avail = 0; + else + tx_avail -= FIFO_FULL_RESERVE; + mutex_unlock(&einfo->tx_avail_lock); return tx_avail; } @@ -286,13 +293,19 @@ static void send_tx_blocked_signal(struct edge_info *einfo) uint64_t reserved3; }; struct read_notif_request read_notif_req = {0}; + int size_in_word = sizeof(read_notif_req)/WORD_SIZE; + void *src = &read_notif_req; + int ret; read_notif_req.cmd = READ_NOTIF_CMD; - if (!einfo->tx_blocked_signal_sent) { einfo->tx_blocked_signal_sent = true; - glink_bgcom_xprt_tx_cmd_safe(einfo, &read_notif_req, - sizeof(read_notif_req)); + ret = bgcom_fifo_write(einfo->bgcom_handle, size_in_word, src); + if (ret < 0) { + GLINK_ERR("%s: Err %d send blocked\n", __func__, ret); + return; + } + glink_bgcom_update_tx_avail(einfo, size_in_word); } } @@ -555,13 +568,11 @@ static void process_rx_cmd(struct edge_info *einfo, * tx_wakeup_worker() - worker function to wakeup tx blocked thread * @work: kwork associated with the edge to process commands on. */ -static void tx_wakeup_worker(struct work_struct *work) +static void tx_wakeup_worker(struct edge_info *einfo) { - struct edge_info *einfo; int rcu_id; struct bgcom_fifo_fill fifo_fill; - einfo = container_of(work, struct edge_info, wakeup_work); mutex_lock(&einfo->tx_avail_lock); bgcom_reg_read(einfo->bgcom_handle, BGCOM_REG_FIFO_FILL, 1, &fifo_fill); @@ -1266,8 +1277,10 @@ static int tx_data(struct glink_transport_if *if_ptr, uint16_t cmd_id, /* Need enough space to write the command */ if (glink_bgcom_get_tx_avail(einfo) <= sizeof(cmd)/WORD_SIZE) { einfo->tx_resume_needed = true; + send_tx_blocked_signal(einfo); mutex_unlock(&einfo->write_lock); srcu_read_unlock(&einfo->use_ref, rcu_id); + GLINK_ERR("%s: No Space in Fifo\n", __func__); return -EAGAIN; } cmd.addr = 0; @@ -1277,7 +1290,7 @@ static int tx_data(struct glink_transport_if *if_ptr, uint16_t cmd_id, if (cmd.id == TRACER_PKT_CMD) tracer_pkt_log_event((void *)(pctx->data), GLINK_XPRT_TX); - bgcom_resume(&einfo->bgcom_handle); + bgcom_resume(einfo->bgcom_handle); bgcom_ahb_write(einfo->bgcom_handle, (uint32_t)(size_t)dst, ALIGN(tx_size, WORD_SIZE)/WORD_SIZE, data_start); @@ -1440,7 +1453,7 @@ static void glink_bgcom_event_handler(void *handle, break; case BGCOM_EVENT_TO_SLAVE_FIFO_FREE: if (einfo->water_mark_reached) - queue_work(system_unbound_wq, &einfo->wakeup_work); + tx_wakeup_worker(einfo); break; case BGCOM_EVENT_RESET_OCCURRED: einfo->bgcom_status = BGCOM_RESET; @@ -1592,7 +1605,6 @@ static int glink_bgcom_probe(struct platform_device *pdev) init_xprt_cfg(einfo, subsys_name); init_xprt_if(einfo); - INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker); init_kthread_worker(&einfo->kworker); init_srcu_struct(&einfo->use_ref); mutex_init(&einfo->write_lock); @@ -1646,7 +1658,6 @@ bgcom_open_fail: glink_core_unregister_transport(&einfo->xprt_if); reg_xprt_fail: flush_kthread_worker(&einfo->kworker); - flush_work(&einfo->wakeup_work); kthread_stop(einfo->task); einfo->task = NULL; kthread_fail: @@ -1690,14 +1701,14 @@ static int glink_bgcom_suspend(struct platform_device *pdev, int rc = -EBUSY; einfo = (struct edge_info *)dev_get_drvdata(&pdev->dev); - if (strcmp(einfo->xprt_cfg.edge, "bgcom")) + if (strcmp(einfo->xprt_cfg.edge, "bg")) return 0; spin_lock_irqsave(&einfo->activity_lock, flags); suspend = !(einfo->activity_flag); spin_unlock_irqrestore(&einfo->activity_lock, flags); if (suspend) - rc = bgcom_suspend(&einfo->bgcom_handle); + rc = bgcom_suspend(einfo->bgcom_handle); if (rc < 0) GLINK_ERR("%s: Could not suspend activity_flag %d, rc %d\n", __func__, einfo->activity_flag, rc); diff --git a/drivers/soc/qcom/glink_smd_xprt.c b/drivers/soc/qcom/glink_smd_xprt.c index 6abe943069d0535cb11cd1e5fffb4ece1bb06027..6107aa56de1c12deaa947f0f56afb788e8e727d9 100644 --- a/drivers/soc/qcom/glink_smd_xprt.c +++ b/drivers/soc/qcom/glink_smd_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016,2019 The Linux Foundation. All rights reserved. * * 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 @@ -812,15 +812,16 @@ static void process_data_event(unsigned long param) &einfo->xprt_if, ch->rcid, liid); - if (!intent->data && einfo->intentless) { + if (!intent) + continue; + if (!intent->data && einfo->intentless) intent->data = kmalloc(pkt_remaining, GFP_ATOMIC); - if (!intent->data) { - SMDXPRT_DBG(einfo, - "%s kmalloc failed '%s' %u:%u\n", - __func__, ch->name, - ch->lcid, ch->rcid); - continue; - } + if (!intent->data) { + SMDXPRT_DBG(einfo, + "%s kmalloc failed '%s' %u:%u\n", + __func__, ch->name, + ch->lcid, ch->rcid); + continue; } smd_read(ch->smd_ch, intent->data + intent->write_offset, read_avail); diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 25afa0bcb0f934cf1c15e3bf9dbda0abfaa4cf50..0fba1e2d183b75e125c17fb710f6b3fb3d5647d5 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -441,6 +441,8 @@ static int fifo_read(struct edge_info *einfo, void *_data, int len) uint32_t fifo_size = einfo->rx_fifo_size; uint32_t n; + if (read_index >= fifo_size || write_index >= fifo_size) + return 0; while (len) { ptr = einfo->rx_fifo + read_index; if (read_index <= write_index) @@ -484,6 +486,8 @@ static uint32_t fifo_write_body(struct edge_info *einfo, const void *_data, uint32_t fifo_size = einfo->tx_fifo_size; uint32_t n; + if (read_index >= fifo_size || *write_index >= fifo_size) + return 0; while (len) { ptr = einfo->tx_fifo + *write_index; if (*write_index < read_index) { @@ -893,6 +897,7 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) cmd_data = d_cmd->data; kfree(d_cmd); } else { + memset(&cmd, 0, sizeof(cmd)); fifo_read(einfo, &cmd, sizeof(cmd)); cmd_data = NULL; } @@ -995,6 +1000,7 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) cmd_data)->size; kfree(cmd_data); } else { + memset(&intent, 0, sizeof(intent)); fifo_read(einfo, &intent, sizeof(intent)); } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c deleted file mode 100644 index caa4328124f256d80bc78e8009da882de4c8f6c5..0000000000000000000000000000000000000000 --- a/drivers/soc/qcom/icnss.c +++ /dev/null @@ -1,1555 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wlan_firmware_service_v01.h" - -enum icnss_qmi_event_type { - ICNSS_QMI_EVENT_SERVER_ARRIVE, - ICNSS_QMI_EVENT_SERVER_EXIT, - ICNSS_QMI_EVENT_FW_READY_IND, -}; - -struct icnss_qmi_event { - struct list_head list; - enum icnss_qmi_event_type type; - void *data; -}; - -#define ICNSS_PANIC 1 -#define WLFW_TIMEOUT_MS 3000 -#define WLFW_SERVICE_INS_ID_V01 0 -#define ICNSS_WLFW_QMI_CONNECTED BIT(0) -#define ICNSS_FW_READY BIT(1) -#define MAX_PROP_SIZE 32 -#define MAX_VOLTAGE_LEVEL 2 -#define VREG_ON 1 -#define VREG_OFF 0 - -#define ICNSS_IS_WLFW_QMI_CONNECTED(_state) \ - ((_state) & ICNSS_WLFW_QMI_CONNECTED) -#define ICNSS_IS_FW_READY(_state) ((_state) & ICNSS_FW_READY) -#ifdef ICNSS_PANIC -#define ICNSS_ASSERT(_condition) do { \ - if (!(_condition)) { \ - pr_err("ICNSS ASSERT in %s Line %d\n", \ - __func__, __LINE__); \ - BUG_ON(1); \ - } \ - } while (0) -#else -#define ICNSS_ASSERT(_condition) do { \ - if (!(_condition)) { \ - pr_err("ICNSS ASSERT in %s Line %d\n", \ - __func__, __LINE__); \ - WARN_ON(1); \ - } \ - } while (0) -#endif - -struct ce_irq_list { - int irq; - irqreturn_t (*handler)(int, void *); -}; - -struct icnss_vreg_info { - struct regulator *reg; - const char *name; - u32 nominal_min; - u32 max_voltage; - bool state; -}; - -static struct { - struct platform_device *pdev; - struct icnss_driver_ops *ops; - struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS]; - struct icnss_vreg_info vreg_info; - u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS]; - phys_addr_t mem_base_pa; - void __iomem *mem_base_va; - struct qmi_handle *wlfw_clnt; - struct list_head qmi_event_list; - spinlock_t qmi_event_lock; - struct work_struct qmi_event_work; - struct work_struct qmi_recv_msg_work; - struct workqueue_struct *qmi_event_wq; - phys_addr_t msa_pa; - uint32_t msa_mem_size; - void *msa_va; - uint32_t state; - struct wlfw_rf_chip_info_s_v01 chip_info; - struct wlfw_rf_board_info_s_v01 board_info; - struct wlfw_soc_info_s_v01 soc_info; - struct wlfw_fw_version_info_s_v01 fw_version_info; - u32 pwr_pin_result; - u32 phy_io_pin_result; - u32 rf_pin_result; - struct icnss_mem_region_info - icnss_mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01]; - bool skip_qmi; -} *penv; - -static int icnss_qmi_event_post(enum icnss_qmi_event_type type, void *data) -{ - struct icnss_qmi_event *event = NULL; - unsigned long flags; - int gfp = GFP_KERNEL; - - if (in_interrupt() || irqs_disabled()) - gfp = GFP_ATOMIC; - - event = kzalloc(sizeof(*event), gfp); - if (event == NULL) - return -ENOMEM; - - event->type = type; - event->data = data; - spin_lock_irqsave(&penv->qmi_event_lock, flags); - list_add_tail(&event->list, &penv->qmi_event_list); - spin_unlock_irqrestore(&penv->qmi_event_lock, flags); - - queue_work(penv->qmi_event_wq, &penv->qmi_event_work); - - return 0; -} - -static int icnss_qmi_pin_connect_result_ind(void *msg, unsigned int msg_len) -{ - struct msg_desc ind_desc; - struct wlfw_pin_connect_result_ind_msg_v01 ind_msg; - int ret = 0; - - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } - - ind_desc.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01; - ind_desc.max_msg_len = WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN; - ind_desc.ei_array = wlfw_pin_connect_result_ind_msg_v01_ei; - - ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len); - if (ret < 0) { - pr_err("%s: Failed to decode message!\n", __func__); - goto out; - } - - /* store pin result locally */ - if (ind_msg.pwr_pin_result_valid) - penv->pwr_pin_result = ind_msg.pwr_pin_result; - if (ind_msg.phy_io_pin_result_valid) - penv->phy_io_pin_result = ind_msg.phy_io_pin_result; - if (ind_msg.rf_pin_result_valid) - penv->rf_pin_result = ind_msg.rf_pin_result; - - pr_debug("%s: Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n", - __func__, ind_msg.pwr_pin_result, ind_msg.phy_io_pin_result, - ind_msg.rf_pin_result); -out: - return ret; -} - -static int icnss_vreg_on(struct icnss_vreg_info *vreg_info) -{ - int ret = 0; - - if (!vreg_info->reg) { - pr_err("%s: regulator is not initialized\n", __func__); - return -ENOENT; - } - - if (!vreg_info->max_voltage || !vreg_info->nominal_min) { - pr_err("%s: %s invalid constraints specified\n", - __func__, vreg_info->name); - return -EINVAL; - } - - ret = regulator_set_voltage(vreg_info->reg, - vreg_info->nominal_min, vreg_info->max_voltage); - if (ret < 0) { - pr_err("%s: regulator_set_voltage failed for (%s). min_uV=%d,max_uV=%d,ret=%d\n", - __func__, vreg_info->name, - vreg_info->nominal_min, - vreg_info->max_voltage, ret); - return ret; - } - - ret = regulator_enable(vreg_info->reg); - if (ret < 0) { - pr_err("%s: Fail to enable regulator (%s) ret=%d\n", - __func__, vreg_info->name, ret); - } - return ret; -} - -static int icnss_vreg_off(struct icnss_vreg_info *vreg_info) -{ - int ret = 0; - int min_uV = 0; - - if (!vreg_info->reg) { - pr_err("%s: regulator is not initialized\n", __func__); - return -ENOENT; - } - - ret = regulator_disable(vreg_info->reg); - if (ret < 0) { - pr_err("%s: Fail to disable regulator (%s) ret=%d\n", - __func__, vreg_info->name, ret); - return ret; - } - - ret = regulator_set_voltage(vreg_info->reg, - min_uV, vreg_info->max_voltage); - if (ret < 0) { - pr_err("%s: regulator_set_voltage failed for (%s). min_uV=%d,max_uV=%d,ret=%d\n", - __func__, vreg_info->name, min_uV, - vreg_info->max_voltage, ret); - } - return ret; -} - -static int icnss_vreg_set(bool state) -{ - int ret = 0; - struct icnss_vreg_info *vreg_info = &penv->vreg_info; - - if (vreg_info->state == state) { - pr_debug("Already %s state is %s\n", vreg_info->name, - state ? "enabled" : "disabled"); - return ret; - } - - if (state) - ret = icnss_vreg_on(vreg_info); - else - ret = icnss_vreg_off(vreg_info); - - if (ret < 0) - goto out; - - pr_debug("%s: %s is now %s\n", __func__, vreg_info->name, - state ? "enabled" : "disabled"); - - vreg_info->state = state; -out: - return ret; -} - -static int icnss_adrastea_power_on(void) -{ - int ret = 0; - - ret = icnss_vreg_set(VREG_ON); - if (ret < 0) { - pr_err("%s: Failed to turn on voltagre regulator: %d\n", - __func__, ret); - goto out; - } - /* TZ API of power on adrastea */ -out: - return ret; -} - -static int icnss_adrastea_power_off(void) -{ - int ret = 0; - - ret = icnss_vreg_set(VREG_OFF); - if (ret < 0) { - pr_err("%s: Failed to turn off voltagre regulator: %d\n", - __func__, ret); - goto out; - } - /* TZ API of power off adrastea */ -out: - return ret; -} - -static int wlfw_msa_mem_info_send_sync_msg(void) -{ - int ret = 0; - int i; - struct wlfw_msa_info_req_msg_v01 req; - struct wlfw_msa_info_resp_msg_v01 resp; - struct msg_desc req_desc, resp_desc; - - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } - - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - - req.msa_addr = penv->msa_pa; - req.size = penv->msa_mem_size; - - req_desc.max_msg_len = WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN; - req_desc.msg_id = QMI_WLFW_MSA_INFO_REQ_V01; - req_desc.ei_array = wlfw_msa_info_req_msg_v01_ei; - - resp_desc.max_msg_len = WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN; - resp_desc.msg_id = QMI_WLFW_MSA_INFO_RESP_V01; - resp_desc.ei_array = wlfw_msa_info_resp_msg_v01_ei; - - ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), - &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); - if (ret < 0) { - pr_err("%s: send req failed %d\n", __func__, ret); - goto out; - } - - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - pr_err("%s: QMI request failed %d %d\n", - __func__, resp.resp.result, resp.resp.error); - ret = resp.resp.result; - goto out; - } - - pr_debug("%s: Receive mem_region_info_len: %d\n", - __func__, resp.mem_region_info_len); - - if (resp.mem_region_info_len > 2) { - pr_err("%s : Invalid memory region length received\n", - __func__); - ret = -EINVAL; - goto out; - } - - for (i = 0; i < resp.mem_region_info_len; i++) { - penv->icnss_mem_region[i].reg_addr = - resp.mem_region_info[i].region_addr; - penv->icnss_mem_region[i].size = - resp.mem_region_info[i].size; - penv->icnss_mem_region[i].secure_flag = - resp.mem_region_info[i].secure_flag; - pr_debug("%s : Memory Region: %d Addr:0x%x Size : %d Flag: %d\n", - __func__, - i, - (unsigned int)penv->icnss_mem_region[i].reg_addr, - penv->icnss_mem_region[i].size, - penv->icnss_mem_region[i].secure_flag); - } - -out: - return ret; -} - -static int wlfw_msa_ready_send_sync_msg(void) -{ - int ret; - struct wlfw_msa_ready_req_msg_v01 req; - struct wlfw_msa_ready_resp_msg_v01 resp; - struct msg_desc req_desc, resp_desc; - - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } - - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - - req_desc.max_msg_len = WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN; - req_desc.msg_id = QMI_WLFW_MSA_READY_REQ_V01; - req_desc.ei_array = wlfw_msa_ready_req_msg_v01_ei; - - resp_desc.max_msg_len = WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN; - resp_desc.msg_id = QMI_WLFW_MSA_READY_RESP_V01; - resp_desc.ei_array = wlfw_msa_ready_resp_msg_v01_ei; - - ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), - &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); - if (ret < 0) { - pr_err("%s: send req failed %d\n", __func__, ret); - goto out; - } - - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - pr_err("%s: QMI request failed %d %d\n", - __func__, resp.resp.result, resp.resp.error); - ret = resp.resp.result; - goto out; - } -out: - return ret; -} - -static int wlfw_ind_register_send_sync_msg(void) -{ - int ret; - struct wlfw_ind_register_req_msg_v01 req; - struct wlfw_ind_register_resp_msg_v01 resp; - struct msg_desc req_desc, resp_desc; - - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } - - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - - req.fw_ready_enable_valid = 1; - req.fw_ready_enable = 1; - req.msa_ready_enable_valid = 1; - req.msa_ready_enable = 1; - req.pin_connect_result_enable_valid = 1; - req.pin_connect_result_enable = 1; - - req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN; - req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01; - req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei; - - resp_desc.max_msg_len = WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN; - resp_desc.msg_id = QMI_WLFW_IND_REGISTER_RESP_V01; - resp_desc.ei_array = wlfw_ind_register_resp_msg_v01_ei; - - ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), - &resp_desc, &resp, sizeof(resp), - WLFW_TIMEOUT_MS); - if (ret < 0) { - pr_err("%s: send req failed %d\n", __func__, ret); - goto out; - } - - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - pr_err("%s: QMI request failed %d %d\n", - __func__, resp.resp.result, resp.resp.error); - ret = resp.resp.result; - goto out; - } -out: - return ret; -} - -static int wlfw_cap_send_sync_msg(void) -{ - int ret; - struct wlfw_cap_req_msg_v01 req; - struct wlfw_cap_resp_msg_v01 resp; - struct msg_desc req_desc, resp_desc; - - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } - - memset(&resp, 0, sizeof(resp)); - - req_desc.max_msg_len = WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN; - req_desc.msg_id = QMI_WLFW_CAP_REQ_V01; - req_desc.ei_array = wlfw_cap_req_msg_v01_ei; - - resp_desc.max_msg_len = WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN; - resp_desc.msg_id = QMI_WLFW_CAP_RESP_V01; - resp_desc.ei_array = wlfw_cap_resp_msg_v01_ei; - - ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), - &resp_desc, &resp, sizeof(resp), - WLFW_TIMEOUT_MS); - if (ret < 0) { - pr_err("%s: send req failed %d\n", __func__, ret); - goto out; - } - - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - pr_err("%s: QMI request failed %d %d\n", - __func__, resp.resp.result, resp.resp.error); - ret = resp.resp.result; - goto out; - } - - /* store cap locally */ - if (resp.chip_info_valid) - penv->chip_info = resp.chip_info; - if (resp.board_info_valid) - penv->board_info = resp.board_info; - else - penv->board_info.board_id = 0xFF; - if (resp.soc_info_valid) - penv->soc_info = resp.soc_info; - if (resp.fw_version_info_valid) - penv->fw_version_info = resp.fw_version_info; - - pr_debug("%s: chip_id: 0x%0x, chip_family: 0x%0x, board_id: 0x%0x, soc_id: 0x%0x, fw_version: 0x%0x, fw_build_timestamp: %s", - __func__, - penv->chip_info.chip_id, - penv->chip_info.chip_family, - penv->board_info.board_id, - penv->soc_info.soc_id, - penv->fw_version_info.fw_version, - penv->fw_version_info.fw_build_timestamp); -out: - return ret; -} - -static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) -{ - int ret; - struct wlfw_wlan_mode_req_msg_v01 req; - struct wlfw_wlan_mode_resp_msg_v01 resp; - struct msg_desc req_desc, resp_desc; - - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } - - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - - req.mode = mode; - - req_desc.max_msg_len = WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN; - req_desc.msg_id = QMI_WLFW_WLAN_MODE_REQ_V01; - req_desc.ei_array = wlfw_wlan_mode_req_msg_v01_ei; - - resp_desc.max_msg_len = WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN; - resp_desc.msg_id = QMI_WLFW_WLAN_MODE_RESP_V01; - resp_desc.ei_array = wlfw_wlan_mode_resp_msg_v01_ei; - - ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), - &resp_desc, &resp, sizeof(resp), - WLFW_TIMEOUT_MS); - if (ret < 0) { - pr_err("%s: send req failed %d\n", __func__, ret); - goto out; - } - - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - pr_err("%s: QMI request failed %d %d\n", - __func__, resp.resp.result, resp.resp.error); - ret = resp.resp.result; - goto out; - } -out: - return ret; -} - -static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data) -{ - int ret; - struct wlfw_wlan_cfg_req_msg_v01 req; - struct wlfw_wlan_cfg_resp_msg_v01 resp; - struct msg_desc req_desc, resp_desc; - - if (!penv || !penv->wlfw_clnt) { - return -ENODEV; - goto out; - } - - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - - memcpy(&req, data, sizeof(req)); - - req_desc.max_msg_len = WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN; - req_desc.msg_id = QMI_WLFW_WLAN_CFG_REQ_V01; - req_desc.ei_array = wlfw_wlan_cfg_req_msg_v01_ei; - - resp_desc.max_msg_len = WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN; - resp_desc.msg_id = QMI_WLFW_WLAN_CFG_RESP_V01; - resp_desc.ei_array = wlfw_wlan_cfg_resp_msg_v01_ei; - - ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), - &resp_desc, &resp, sizeof(resp), - WLFW_TIMEOUT_MS); - if (ret < 0) { - pr_err("%s: send req failed %d\n", __func__, ret); - goto out; - } - - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - pr_err("%s: QMI request failed %d %d\n", - __func__, resp.resp.result, resp.resp.error); - ret = resp.resp.result; - goto out; - } -out: - return ret; -} - -static int wlfw_ini_send_sync_msg(bool enablefwlog) -{ - int ret; - struct wlfw_ini_req_msg_v01 req; - struct wlfw_ini_resp_msg_v01 resp; - struct msg_desc req_desc, resp_desc; - - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } - - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - - req.enablefwlog_valid = 1; - req.enablefwlog = enablefwlog; - - req_desc.max_msg_len = WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN; - req_desc.msg_id = QMI_WLFW_INI_REQ_V01; - req_desc.ei_array = wlfw_ini_req_msg_v01_ei; - - resp_desc.max_msg_len = WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN; - resp_desc.msg_id = QMI_WLFW_INI_RESP_V01; - resp_desc.ei_array = wlfw_ini_resp_msg_v01_ei; - - ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), - &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); - if (ret < 0) { - pr_err("%s: send req failed %d\n", __func__, ret); - goto out; - } - - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - pr_err("%s: QMI request failed %d %d\n", - __func__, resp.resp.result, resp.resp.error); - ret = resp.resp.result; - goto out; - } -out: - return ret; -} - -static void icnss_qmi_wlfw_clnt_notify_work(struct work_struct *work) -{ - int ret; - - if (!penv || !penv->wlfw_clnt) - return; - - do { - pr_debug("%s: Received Event\n", __func__); - } while ((ret = qmi_recv_msg(penv->wlfw_clnt)) == 0); - - if (ret != -ENOMSG) - pr_err("%s: Error receiving message\n", __func__); -} - -static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle, - enum qmi_event_type event, void *notify_priv) -{ - if (!penv || !penv->wlfw_clnt) - return; - - switch (event) { - case QMI_RECV_MSG: - schedule_work(&penv->qmi_recv_msg_work); - break; - default: - pr_debug("%s: Received Event: %d\n", __func__, event); - break; - } -} - -static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, - unsigned int msg_id, void *msg, - unsigned int msg_len, void *ind_cb_priv) -{ - if (!penv) - return; - - pr_debug("%s: Received Ind 0x%x\n", __func__, msg_id); - - switch (msg_id) { - case QMI_WLFW_FW_READY_IND_V01: - icnss_qmi_event_post(ICNSS_QMI_EVENT_FW_READY_IND, NULL); - break; - case QMI_WLFW_MSA_READY_IND_V01: - pr_debug("%s: Received MSA Ready Indication msg_id 0x%x\n", - __func__, msg_id); - break; - case QMI_WLFW_PIN_CONNECT_RESULT_IND_V01: - pr_debug("%s: Received Pin Connect Test Result msg_id 0x%x\n", - __func__, msg_id); - icnss_qmi_pin_connect_result_ind(msg, msg_len); - break; - default: - pr_err("%s: Invalid msg_id 0x%x\n", __func__, msg_id); - break; - } -} - -static int icnss_qmi_event_server_arrive(void *data) -{ - int ret = 0; - - if (!penv) - return -ENODEV; - - penv->wlfw_clnt = qmi_handle_create(icnss_qmi_wlfw_clnt_notify, penv); - if (!penv->wlfw_clnt) { - pr_err("%s: QMI client handle alloc failed\n", __func__); - ret = -ENOMEM; - goto out; - } - - ret = qmi_connect_to_service(penv->wlfw_clnt, - WLFW_SERVICE_ID_V01, - WLFW_SERVICE_VERS_V01, - WLFW_SERVICE_INS_ID_V01); - if (ret < 0) { - pr_err("%s: Server not found : %d\n", __func__, ret); - goto fail; - } - - ret = qmi_register_ind_cb(penv->wlfw_clnt, - icnss_qmi_wlfw_clnt_ind, penv); - if (ret < 0) { - pr_err("%s: Failed to register indication callback: %d\n", - __func__, ret); - goto fail; - } - - penv->state |= ICNSS_WLFW_QMI_CONNECTED; - - pr_info("%s: QMI Server Connected\n", __func__); - - ret = icnss_adrastea_power_on(); - if (ret < 0) { - pr_err("%s: Failed to power on hardware: %d\n", - __func__, ret); - goto fail; - } - - ret = wlfw_ind_register_send_sync_msg(); - if (ret < 0) { - pr_err("%s: Failed to send indication message: %d\n", - __func__, ret); - goto err_power_on; - } - - if (penv->msa_va) { - ret = wlfw_msa_mem_info_send_sync_msg(); - if (ret < 0) { - pr_err("%s: Failed to send MSA info: %d\n", - __func__, ret); - goto err_power_on; - } - ret = wlfw_msa_ready_send_sync_msg(); - if (ret < 0) { - pr_err("%s: Failed to send MSA ready : %d\n", - __func__, ret); - goto err_power_on; - } - } else { - pr_err("%s: Invalid MSA address\n", __func__); - ret = -EINVAL; - goto err_power_on; - } - - ret = wlfw_cap_send_sync_msg(); - if (ret < 0) { - pr_err("%s: Failed to get capability: %d\n", - __func__, ret); - goto err_power_on; - } - return ret; - -err_power_on: - ret = icnss_vreg_set(VREG_OFF); - if (ret < 0) { - pr_err("%s: Failed to turn off voltagre regulator: %d\n", - __func__, ret); - } -fail: - qmi_handle_destroy(penv->wlfw_clnt); - penv->wlfw_clnt = NULL; -out: - ICNSS_ASSERT(0); - return ret; -} - -static int icnss_qmi_event_server_exit(void *data) -{ - if (!penv || !penv->wlfw_clnt) - return -ENODEV; - - pr_info("%s: QMI Service Disconnected\n", __func__); - - qmi_handle_destroy(penv->wlfw_clnt); - - penv->state = 0; - penv->wlfw_clnt = NULL; - - return 0; -} - -static int icnss_qmi_event_fw_ready_ind(void *data) -{ - int ret = 0; - - if (!penv) - return -ENODEV; - - penv->state |= ICNSS_FW_READY; - - if (!penv->pdev) { - pr_err("%s: Device is not ready\n", __func__); - ret = -ENODEV; - goto out; - } - - ret = icnss_adrastea_power_off(); - if (ret < 0) { - pr_err("%s: Failed to power off hardware: %d\n", - __func__, ret); - goto out; - } - - if (!penv->ops || !penv->ops->probe) { - pr_err("%s: WLAN driver is not registed yet\n", __func__); - ret = -ENOENT; - goto out; - } - - ret = penv->ops->probe(&penv->pdev->dev); - if (ret < 0) - pr_err("%s: Driver probe failed: %d\n", __func__, ret); -out: - return ret; -} - -static int icnss_qmi_wlfw_clnt_svc_event_notify(struct notifier_block *this, - unsigned long code, - void *_cmd) -{ - int ret = 0; - - if (!penv) - return -ENODEV; - - pr_debug("%s: Event Notify: code: %ld", __func__, code); - - switch (code) { - case QMI_SERVER_ARRIVE: - ret = icnss_qmi_event_post(ICNSS_QMI_EVENT_SERVER_ARRIVE, NULL); - break; - - case QMI_SERVER_EXIT: - ret = icnss_qmi_event_post(ICNSS_QMI_EVENT_SERVER_EXIT, NULL); - break; - default: - pr_debug("%s: Invalid code: %ld", __func__, code); - break; - } - return ret; -} - -static void icnss_qmi_wlfw_event_work(struct work_struct *work) -{ - struct icnss_qmi_event *event; - unsigned long flags; - - spin_lock_irqsave(&penv->qmi_event_lock, flags); - - while (!list_empty(&penv->qmi_event_list)) { - event = list_first_entry(&penv->qmi_event_list, - struct icnss_qmi_event, list); - list_del(&event->list); - spin_unlock_irqrestore(&penv->qmi_event_lock, flags); - - switch (event->type) { - case ICNSS_QMI_EVENT_SERVER_ARRIVE: - icnss_qmi_event_server_arrive(event->data); - break; - case ICNSS_QMI_EVENT_SERVER_EXIT: - icnss_qmi_event_server_exit(event->data); - break; - case ICNSS_QMI_EVENT_FW_READY_IND: - icnss_qmi_event_fw_ready_ind(event->data); - break; - default: - pr_debug("%s: Invalid Event type: %d", - __func__, event->type); - break; - } - kfree(event); - spin_lock_irqsave(&penv->qmi_event_lock, flags); - } - spin_unlock_irqrestore(&penv->qmi_event_lock, flags); -} - -static struct notifier_block wlfw_clnt_nb = { - .notifier_call = icnss_qmi_wlfw_clnt_svc_event_notify, -}; - -int icnss_register_driver(struct icnss_driver_ops *ops) -{ - struct platform_device *pdev; - int ret = 0; - - if (!penv || !penv->pdev) { - ret = -ENODEV; - goto out; - } - - pdev = penv->pdev; - if (!pdev) { - ret = -ENODEV; - goto out; - } - - if (penv->ops) { - pr_err("icnss: driver already registered\n"); - ret = -EEXIST; - goto out; - } - penv->ops = ops; - - if (penv->skip_qmi) - penv->state |= ICNSS_FW_READY; - - /* check for all conditions before invoking probe */ - if (ICNSS_IS_FW_READY(penv->state) && penv->ops->probe) { - ret = icnss_vreg_set(VREG_ON); - if (ret < 0) { - pr_err("%s: Failed to turn on voltagre regulator: %d\n", - __func__, ret); - goto out; - } - ret = penv->ops->probe(&pdev->dev); - } else { - pr_err("icnss: FW is not ready\n"); - ret = -ENOENT; - } -out: - return ret; -} -EXPORT_SYMBOL(icnss_register_driver); - -int icnss_unregister_driver(struct icnss_driver_ops *ops) -{ - int ret = 0; - struct platform_device *pdev; - - if (!penv || !penv->pdev) { - ret = -ENODEV; - goto out; - } - - pdev = penv->pdev; - if (!pdev) { - ret = -ENODEV; - goto out; - } - if (!penv->ops) { - pr_err("icnss: driver not registered\n"); - ret = -ENOENT; - goto out; - } - if (penv->ops->remove) - penv->ops->remove(&pdev->dev); - - penv->ops = NULL; - - ret = icnss_vreg_set(VREG_OFF); - if (ret < 0) - pr_err("%s: Failed to turn off voltagre regulator: %d\n", - __func__, ret); -out: - return ret; -} -EXPORT_SYMBOL(icnss_unregister_driver); - -int icnss_register_ce_irq(unsigned int ce_id, - irqreturn_t (*handler)(int, void *), - unsigned long flags, const char *name) -{ - int ret = 0; - unsigned int irq; - struct ce_irq_list *irq_entry; - - if (!penv || !penv->pdev) { - ret = -ENODEV; - goto out; - } - if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) { - pr_err("icnss: Invalid CE ID %d\n", ce_id); - ret = -EINVAL; - goto out; - } - irq = penv->ce_irqs[ce_id]; - irq_entry = &penv->ce_irq_list[ce_id]; - - if (irq_entry->handler || irq_entry->irq) { - pr_err("icnss: handler already registered %d\n", irq); - ret = -EEXIST; - goto out; - } - - ret = request_irq(irq, handler, IRQF_SHARED, name, &penv->pdev->dev); - if (ret) { - pr_err("icnss: IRQ not registered %d\n", irq); - ret = -EINVAL; - goto out; - } - irq_entry->irq = irq; - irq_entry->handler = handler; - pr_debug("icnss: IRQ registered %d\n", irq); -out: - return ret; - -} -EXPORT_SYMBOL(icnss_register_ce_irq); - -int icnss_unregister_ce_irq(unsigned int ce_id) -{ - int ret = 0; - unsigned int irq; - struct ce_irq_list *irq_entry; - - if (!penv || !penv->pdev) { - ret = -ENODEV; - goto out; - } - irq = penv->ce_irqs[ce_id]; - irq_entry = &penv->ce_irq_list[ce_id]; - if (!irq_entry->handler || !irq_entry->irq) { - pr_err("icnss: handler not registered %d\n", irq); - ret = -EEXIST; - goto out; - } - free_irq(irq, &penv->pdev->dev); - irq_entry->irq = 0; - irq_entry->handler = NULL; -out: - return ret; -} -EXPORT_SYMBOL(icnss_unregister_ce_irq); - -int icnss_ce_request_irq(unsigned int ce_id, - irqreturn_t (*handler)(int, void *), - unsigned long flags, const char *name, void *ctx) -{ - int ret = 0; - unsigned int irq; - struct ce_irq_list *irq_entry; - - if (!penv || !penv->pdev) { - ret = -ENODEV; - goto out; - } - if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) { - pr_err("icnss: Invalid CE ID %d\n", ce_id); - ret = -EINVAL; - goto out; - } - irq = penv->ce_irqs[ce_id]; - irq_entry = &penv->ce_irq_list[ce_id]; - - if (irq_entry->handler || irq_entry->irq) { - pr_err("icnss: handler already registered %d\n", irq); - ret = -EEXIST; - goto out; - } - - ret = request_irq(irq, handler, flags, name, ctx); - if (ret) { - pr_err("icnss: IRQ not registered %d\n", irq); - ret = -EINVAL; - goto out; - } - irq_entry->irq = irq; - irq_entry->handler = handler; - pr_debug("icnss: IRQ registered %d\n", irq); -out: - return ret; -} -EXPORT_SYMBOL(icnss_ce_request_irq); - -int icnss_ce_free_irq(unsigned int ce_id, void *ctx) -{ - int ret = 0; - unsigned int irq; - struct ce_irq_list *irq_entry; - - if (!penv || !penv->pdev) { - ret = -ENODEV; - goto out; - } - irq = penv->ce_irqs[ce_id]; - irq_entry = &penv->ce_irq_list[ce_id]; - if (!irq_entry->handler || !irq_entry->irq) { - pr_err("icnss: handler not registered %d\n", irq); - ret = -EEXIST; - goto out; - } - free_irq(irq, ctx); - irq_entry->irq = 0; - irq_entry->handler = NULL; -out: - return ret; -} -EXPORT_SYMBOL(icnss_ce_free_irq); - -void icnss_enable_irq(unsigned int ce_id) -{ - unsigned int irq; - - if (!penv || !penv->pdev) { - pr_err("icnss: platform driver not initialized\n"); - return; - } - irq = penv->ce_irqs[ce_id]; - enable_irq(irq); -} -EXPORT_SYMBOL(icnss_enable_irq); - -void icnss_disable_irq(unsigned int ce_id) -{ - unsigned int irq; - - if (!penv || !penv->pdev) { - pr_err("icnss: platform driver not initialized\n"); - return; - } - irq = penv->ce_irqs[ce_id]; - disable_irq(irq); -} -EXPORT_SYMBOL(icnss_disable_irq); - -int icnss_get_soc_info(struct icnss_soc_info *info) -{ - if (!penv) { - pr_err("icnss: platform driver not initialized\n"); - return -EINVAL; - } - - info->v_addr = penv->mem_base_va; - info->p_addr = penv->mem_base_pa; - - return 0; -} -EXPORT_SYMBOL(icnss_get_soc_info); - -int icnss_set_fw_debug_mode(bool enablefwlog) -{ - int ret; - - ret = wlfw_ini_send_sync_msg(enablefwlog); - if (ret) - pr_err("icnss: Fail to send ini, ret = %d\n", ret); - - return ret; -} -EXPORT_SYMBOL(icnss_set_fw_debug_mode); - -int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, - enum icnss_driver_mode mode, - const char *host_version) -{ - struct wlfw_wlan_cfg_req_msg_v01 req; - u32 i; - int ret; - - memset(&req, 0, sizeof(req)); - - if (mode == ICNSS_WALTEST || mode == ICNSS_CCPM) - goto skip; - else if (!config || !host_version) { - pr_err("%s: Invalid cfg pointer\n", __func__); - ret = -EINVAL; - goto out; - } - - req.host_version_valid = 1; - strlcpy(req.host_version, host_version, - QMI_WLFW_MAX_STR_LEN_V01 + 1); - - req.tgt_cfg_valid = 1; - if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01) - req.tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; - else - req.tgt_cfg_len = config->num_ce_tgt_cfg; - for (i = 0; i < req.tgt_cfg_len; i++) { - req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num; - req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir; - req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries; - req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max; - req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags; - } - - req.svc_cfg_valid = 1; - if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01) - req.svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01; - else - req.svc_cfg_len = config->num_ce_svc_pipe_cfg; - for (i = 0; i < req.svc_cfg_len; i++) { - req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id; - req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; - req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; - } - - req.shadow_reg_valid = 1; - if (config->num_shadow_reg_cfg > - QMI_WLFW_MAX_NUM_SHADOW_REG_V01) - req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; - else - req.shadow_reg_len = config->num_shadow_reg_cfg; - - memcpy(req.shadow_reg, config->shadow_reg_cfg, - sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req.shadow_reg_len); - - ret = wlfw_wlan_cfg_send_sync_msg(&req); - if (ret) { - pr_err("%s: Failed to send cfg, ret = %d\n", __func__, ret); - goto out; - } -skip: - ret = wlfw_wlan_mode_send_sync_msg(mode); - if (ret) - pr_err("%s: Failed to send mode, ret = %d\n", __func__, ret); -out: - if (penv->skip_qmi) - ret = 0; - - return ret; -} -EXPORT_SYMBOL(icnss_wlan_enable); - -int icnss_wlan_disable(enum icnss_driver_mode mode) -{ - return wlfw_wlan_mode_send_sync_msg(QMI_WLFW_OFF_V01); -} -EXPORT_SYMBOL(icnss_wlan_disable); - -int icnss_get_ce_id(int irq) -{ - int i; - - for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++) { - if (penv->ce_irqs[i] == irq) - return i; - } - pr_err("icnss: No matching CE id for irq %d\n", irq); - return -EINVAL; -} -EXPORT_SYMBOL(icnss_get_ce_id); - -static ssize_t icnss_wlan_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - int val; - int ret; - - if (!penv) - return -ENODEV; - - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; - - if (val == ICNSS_WALTEST || val == ICNSS_CCPM) { - pr_debug("%s: WLAN Test Mode -> %d\n", __func__, val); - ret = icnss_wlan_enable(NULL, val, NULL); - if (ret) - pr_err("%s: WLAN Test Mode %d failed with %d\n", - __func__, val, ret); - } else { - pr_err("%s: Mode %d is not supported from command line\n", - __func__, val); - ret = -EINVAL; - } - - return ret; -} - -static DEVICE_ATTR(icnss_wlan_mode, S_IWUSR, NULL, icnss_wlan_mode_store); - -static int icnss_dt_parse_vreg_info(struct device *dev, - struct icnss_vreg_info *vreg_info, - const char *vreg_name) -{ - int ret = 0; - u32 voltage_levels[MAX_VOLTAGE_LEVEL]; - char prop_name[MAX_PROP_SIZE]; - struct device_node *np = dev->of_node; - - snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name); - if (!of_parse_phandle(np, prop_name, 0)) { - pr_err("%s: No vreg data found for %s\n", __func__, vreg_name); - ret = -EINVAL; - return ret; - } - - vreg_info->name = vreg_name; - - snprintf(prop_name, MAX_PROP_SIZE, - "qcom,%s-voltage-level", vreg_name); - ret = of_property_read_u32_array(np, prop_name, voltage_levels, - ARRAY_SIZE(voltage_levels)); - if (ret) { - pr_err("%s: error reading %s property\n", __func__, prop_name); - return ret; - } - - vreg_info->nominal_min = voltage_levels[0]; - vreg_info->max_voltage = voltage_levels[1]; - - return ret; -} - -static int icnss_get_resources(struct device *dev) -{ - int ret = 0; - struct icnss_vreg_info *vreg_info; - - vreg_info = &penv->vreg_info; - if (vreg_info->reg) { - pr_err("%s: %s regulator is already initialized\n", __func__, - vreg_info->name); - return ret; - } - - vreg_info->reg = devm_regulator_get(dev, vreg_info->name); - if (IS_ERR(vreg_info->reg)) { - ret = PTR_ERR(vreg_info->reg); - if (ret == -EPROBE_DEFER) { - pr_err("%s: %s probe deferred!\n", __func__, - vreg_info->name); - } else { - pr_err("%s: Get %s failed!\n", __func__, - vreg_info->name); - } - } - return ret; -} - -static int icnss_release_resources(void) -{ - int ret = 0; - struct icnss_vreg_info *vreg_info = &penv->vreg_info; - - if (!vreg_info->reg) { - pr_err("%s: regulator is not initialized\n", __func__); - return -ENOENT; - } - - devm_regulator_put(vreg_info->reg); - return ret; -} - -static int icnss_probe(struct platform_device *pdev) -{ - int ret = 0; - struct resource *res; - int i; - struct device *dev = &pdev->dev; - - if (penv) { - pr_err("%s: penv is already initialized\n", __func__); - return -EEXIST; - } - - penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL); - if (!penv) - return -ENOMEM; - - penv->pdev = pdev; - - ret = icnss_dt_parse_vreg_info(dev, &penv->vreg_info, "vdd-io"); - if (ret < 0) { - pr_err("%s: failed parsing vdd io data\n", __func__); - goto out; - } - - ret = icnss_get_resources(dev); - if (ret < 0) { - pr_err("%s: Regulator setup failed (%d)\n", __func__, ret); - goto out; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase"); - if (!res) { - pr_err("%s: Memory base not found\n", __func__); - ret = -EINVAL; - goto release_regulator; - } - penv->mem_base_pa = res->start; - penv->mem_base_va = ioremap(penv->mem_base_pa, resource_size(res)); - if (!penv->mem_base_va) { - pr_err("%s: ioremap failed\n", __func__); - ret = -EINVAL; - goto release_regulator; - } - - for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, i); - if (!res) { - pr_err("%s: Fail to get IRQ-%d\n", __func__, i); - ret = -ENODEV; - goto release_regulator; - } else { - penv->ce_irqs[i] = res->start; - } - } - - if (of_property_read_u32(dev->of_node, "qcom,wlan-msa-memory", - &penv->msa_mem_size) == 0) { - if (penv->msa_mem_size) { - penv->msa_va = dma_alloc_coherent(&pdev->dev, - penv->msa_mem_size, - &penv->msa_pa, - GFP_KERNEL); - if (!penv->msa_va) { - pr_err("%s: DMA alloc failed\n", __func__); - ret = -EINVAL; - goto release_regulator; - } - pr_debug("%s: MAS va: %p, MSA pa: %pa\n", - __func__, penv->msa_va, &penv->msa_pa); - } - } else { - pr_err("%s: Fail to get MSA Memory Size\n", __func__); - ret = -ENODEV; - goto release_regulator; - } - - penv->skip_qmi = of_property_read_bool(dev->of_node, - "qcom,skip-qmi"); - - ret = device_create_file(dev, &dev_attr_icnss_wlan_mode); - if (ret) { - pr_err("%s: wlan_mode sys file creation failed\n", - __func__); - goto err_wlan_mode; - } - - spin_lock_init(&penv->qmi_event_lock); - - penv->qmi_event_wq = alloc_workqueue("icnss_qmi_event", 0, 0); - if (!penv->qmi_event_wq) { - pr_err("%s: workqueue creation failed\n", __func__); - ret = -EFAULT; - goto err_workqueue; - } - - INIT_WORK(&penv->qmi_event_work, icnss_qmi_wlfw_event_work); - INIT_WORK(&penv->qmi_recv_msg_work, icnss_qmi_wlfw_clnt_notify_work); - INIT_LIST_HEAD(&penv->qmi_event_list); - - ret = qmi_svc_event_notifier_register(WLFW_SERVICE_ID_V01, - WLFW_SERVICE_VERS_V01, - WLFW_SERVICE_INS_ID_V01, - &wlfw_clnt_nb); - if (ret < 0) { - pr_err("%s: notifier register failed\n", __func__); - goto err_qmi; - } - - pr_debug("icnss: Platform driver probed successfully\n"); - - return ret; - -err_qmi: - if (penv->qmi_event_wq) - destroy_workqueue(penv->qmi_event_wq); -err_workqueue: - device_remove_file(&pdev->dev, &dev_attr_icnss_wlan_mode); -err_wlan_mode: - if (penv->msa_va) - dma_free_coherent(&pdev->dev, penv->msa_mem_size, - penv->msa_va, penv->msa_pa); -release_regulator: - ret = icnss_release_resources(); - if (ret < 0) - pr_err("%s: fail to release the platform resource\n", - __func__); -out: - devm_kfree(&pdev->dev, penv); - penv = NULL; - return ret; -} - -static int icnss_remove(struct platform_device *pdev) -{ - int ret = 0; - - qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01, - WLFW_SERVICE_VERS_V01, - WLFW_SERVICE_INS_ID_V01, - &wlfw_clnt_nb); - if (penv->qmi_event_wq) - destroy_workqueue(penv->qmi_event_wq); - device_remove_file(&pdev->dev, &dev_attr_icnss_wlan_mode); - if (penv->msa_va) - dma_free_coherent(&pdev->dev, penv->msa_mem_size, - penv->msa_va, penv->msa_pa); - - ret = icnss_vreg_set(VREG_OFF); - if (ret < 0) - pr_err("%s: Failed to turn off voltagre regulator: %d\n", - __func__, ret); - - ret = icnss_release_resources(); - if (ret < 0) - pr_err("%s: fail to release the platform resource\n", - __func__); - return ret; -} - - -static const struct of_device_id icnss_dt_match[] = { - {.compatible = "qcom,icnss"}, - {} -}; - -MODULE_DEVICE_TABLE(of, icnss_dt_match); - -static struct platform_driver icnss_driver = { - .probe = icnss_probe, - .remove = icnss_remove, - .driver = { - .name = "icnss", - .owner = THIS_MODULE, - .of_match_table = icnss_dt_match, - }, -}; - -static int __init icnss_initialize(void) -{ - return platform_driver_register(&icnss_driver); -} - -static void __exit icnss_exit(void) -{ - platform_driver_unregister(&icnss_driver); -} - - -module_init(icnss_initialize); -module_exit(icnss_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION(DEVICE "iCNSS CORE platform driver"); diff --git a/drivers/soc/qcom/ipc_router_mhi_dev_xprt.c b/drivers/soc/qcom/ipc_router_mhi_dev_xprt.c index 22afb008974659adb623055c963479fda6fba750..96dac705646d3722f0ed9b5f95f2202d51abf39f 100644 --- a/drivers/soc/qcom/ipc_router_mhi_dev_xprt.c +++ b/drivers/soc/qcom/ipc_router_mhi_dev_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * 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 @@ -29,7 +29,9 @@ if (ipc_router_mhi_dev_xprt_debug_mask) \ #define MODULE_NAME "ipc_router_mhi_dev_xprt" #define XPRT_NAME_LEN 32 -#define IPC_ROUTER_MHI_XPRT_MAX_PKT_SIZE 0x1000 +#define IPC_ROUTER_MHI_XPRT_MAX_PKT_SIZE 8192 +#define MHI_IPCR_ASYNC_TIMEOUT msecs_to_jiffies(1000) +#define MAX_IPCR_WR_REQ 128 /** * ipc_router_mhi_dev_channel - MHI Channel related information @@ -40,8 +42,6 @@ if (ipc_router_mhi_dev_xprt_debug_mask) \ * @state_lock: Lock to protect access to the state information. * @out_chan_enabled: State of the outgoing channel. * @in_chan_enabled: State of the incoming channel. - * @bytes_to_rx: Remaining bytes to be received in a packet. - * @in_skbq: Queue containing the input buffers. * @max_packet_size: Possible maximum packet size. * @mhi_xprtp: Pointer to IPC Router MHI XPRT. */ @@ -53,8 +53,6 @@ struct ipc_router_mhi_dev_channel { struct mutex state_lock; bool out_chan_enabled; bool in_chan_enabled; - int bytes_to_rx; - struct sk_buff_head in_skbq; size_t max_packet_size; void *mhi_xprtp; }; @@ -67,10 +65,13 @@ struct ipc_router_mhi_dev_channel { * @xprt: IPC Router XPRT structure to contain MHI XPRT specific info. * @wq: Workqueue to queue read & other XPRT related works. * @read_work: Read Work to perform read operation from MHI Driver. - * @in_pkt: Pointer to any partially read packet. * @write_wait_q: Wait Queue to handle the write events. * @xprt_version: IPC Router header version supported by this XPRT. * @xprt_option: XPRT specific options to be handled by IPC Router. + * @wr_req_lock: Lock for write request list + * @wreqs: List of write requests + * @wr_req_list: Head of the list of available write requests + * @read_done: Completion for async read. */ struct ipc_router_mhi_dev_xprt { struct list_head list; @@ -79,11 +80,13 @@ struct ipc_router_mhi_dev_xprt { struct msm_ipc_router_xprt xprt; struct workqueue_struct *wq; struct work_struct read_work; - struct rr_packet *in_pkt; - size_t bytes_to_rx; wait_queue_head_t write_wait_q; unsigned xprt_version; unsigned xprt_option; + spinlock_t wr_req_lock; + struct mhi_req *wreqs; + struct list_head wr_req_list; + struct completion read_done; }; /** @@ -168,6 +171,29 @@ static int ipc_router_mhi_dev_get_xprt_option(struct msm_ipc_router_xprt *xprt) return (int)mhi_xprtp->xprt_option; } +static void mhi_xprt_write_completion_cb(void *req) +{ + struct mhi_req *ureq = req; + struct rr_packet *pkt = ureq->context; + unsigned long flags; + + if (pkt) + kref_put(&pkt->ref, ipc_router_mhi_dev_release_pkt); + + spin_lock_irqsave(&mhi_xprtp->wr_req_lock, flags); + list_add_tail(&ureq->list, &mhi_xprtp->wr_req_list); + spin_unlock_irqrestore(&mhi_xprtp->wr_req_lock, flags); +} + +static void mhi_xprt_read_completion_cb(void *req) +{ + struct mhi_req *ureq = req; + struct ipc_router_mhi_dev_xprt *mhi_xprtp; + + mhi_xprtp = (struct ipc_router_mhi_dev_xprt *)ureq->context; + complete(&mhi_xprtp->read_done); +} + static void mhi_xprt_event_notifier(struct mhi_dev_client_cb_reason *reason) { if (reason->reason == MHI_DEV_TRE_AVAILABLE) { @@ -184,74 +210,91 @@ static void mhi_xprt_event_notifier(struct mhi_dev_client_cb_reason *reason) static void mhi_xprt_read_data(struct work_struct *work) { struct sk_buff *skb; - uint32_t buf_size = mhi_xprtp->ch_hndl.max_packet_size; + struct rr_packet *in_pkt; struct mhi_req mreq = {0}; - size_t data_sz; + int data_sz; struct ipc_router_mhi_dev_xprt *mhi_xprtp = container_of(work, struct ipc_router_mhi_dev_xprt, read_work); + unsigned long compl_ret; - while (1) { - /* Create a new rr_packet, if first fragment */ - if (!mhi_xprtp->bytes_to_rx) { - mhi_xprtp->in_pkt = create_pkt(NULL); - if (!mhi_xprtp->in_pkt) { - IPC_RTR_ERR("%s: Couldn't alloc rr_packet\n", - __func__); - return; - } - D("%s: Allocated rr_packet\n", __func__); + while (!mhi_dev_channel_isempty(mhi_xprtp->ch_hndl.out_handle)) { + in_pkt = create_pkt(NULL); + if (!in_pkt) { + IPC_RTR_ERR("%s: Couldn't alloc rr_packet\n", + __func__); + return; } + D("%s: Allocated rr_packet\n", __func__); - skb = alloc_skb(buf_size, GFP_KERNEL); + skb = alloc_skb(mhi_xprtp->ch_hndl.max_packet_size, GFP_KERNEL); if (!skb) { IPC_RTR_ERR("%s: Could not allocate SKB\n", __func__); - return; + goto exit_free_pkt; } mreq.client = mhi_xprtp->ch_hndl.out_handle; + mreq.context = mhi_xprtp; mreq.buf = skb->data; - mreq.len = buf_size; + mreq.len = mhi_xprtp->ch_hndl.max_packet_size; mreq.chan = mhi_xprtp->ch_hndl.out_chan_id; - mreq.mode = IPA_DMA_SYNC; + mreq.mode = IPA_DMA_ASYNC; + mreq.client_cb = mhi_xprt_read_completion_cb; + + reinit_completion(&mhi_xprtp->read_done); + data_sz = mhi_dev_read_channel(&mreq); if (data_sz < 0) { IPC_RTR_ERR("%s: Failed to queue TRB into MHI\n", __func__); - kfree_skb(skb); - release_pkt(mhi_xprtp->in_pkt); - return; + goto exit_free_skb; } else if (!data_sz) { - kfree_skb(skb); - break; + D("%s: No data available\n", __func__); + goto exit_free_skb; } - if (!mhi_xprtp->bytes_to_rx) { - mhi_xprtp->bytes_to_rx = - ipc_router_peek_pkt_size(skb->data) - data_sz; - } else { - mhi_xprtp->bytes_to_rx -= data_sz; + compl_ret = + wait_for_completion_interruptible_timeout( + &mhi_xprtp->read_done, + MHI_IPCR_ASYNC_TIMEOUT); + + if (compl_ret == -ERESTARTSYS) { + IPC_RTR_ERR("%s: Exit signal caught\n", __func__); + goto exit_free_skb; + } else if (compl_ret == 0) { + IPC_RTR_ERR("%s: Read timed out\n", __func__); + goto exit_free_skb; } - skb_put(skb, data_sz); - mhi_xprtp->in_pkt->length += data_sz; - skb_queue_tail(mhi_xprtp->in_pkt->pkt_fragment_q, skb); - - if (!mhi_xprtp->bytes_to_rx) { - D("%s: Packet size read %d\n", - __func__, mhi_xprtp->in_pkt->length); - msm_ipc_router_xprt_notify(&mhi_xprtp->xprt, - IPC_ROUTER_XPRT_EVENT_DATA, - (void *)mhi_xprtp->in_pkt); - release_pkt(mhi_xprtp->in_pkt); - mhi_xprtp->in_pkt = NULL; + if (mreq.transfer_len != ipc_router_peek_pkt_size(skb->data)) { + IPC_RTR_ERR("%s: Incomplete packet, drop it\n", + __func__); + goto exit_free_skb; } + + skb_put(skb, mreq.transfer_len); + in_pkt->length = mreq.transfer_len; + skb_queue_tail(in_pkt->pkt_fragment_q, skb); + + D("%s: Packet size read %d\n", __func__, in_pkt->length); + msm_ipc_router_xprt_notify(&mhi_xprtp->xprt, + IPC_ROUTER_XPRT_EVENT_DATA, + (void *)in_pkt); + release_pkt(in_pkt); } + + return; + +exit_free_skb: + kfree_skb(skb); +exit_free_pkt: + release_pkt(in_pkt); } /** * ipc_router_mhi_dev_write_skb() - Write a single SKB onto the XPRT * @mhi_xprtp: XPRT in which the SKB has to be written. * @skb: SKB to be written. + * @pkt: IPC packet, for reference count purposes * * @return: return number of bytes written on success, * standard Linux error codes on failure. @@ -260,41 +303,58 @@ static int ipc_router_mhi_dev_write_skb( struct ipc_router_mhi_dev_xprt *mhi_xprtp, struct sk_buff *skb, struct rr_packet *pkt) { - size_t sz_to_write = 0; - size_t offset = 0; - int rc; - struct mhi_req wreq = {0}; - - while (offset < skb->len) { - wait_event(mhi_xprtp->write_wait_q, - !mhi_dev_channel_isempty( - mhi_xprtp->ch_hndl.in_handle) || - !mhi_xprtp->ch_hndl.in_chan_enabled); - mutex_lock(&mhi_xprtp->ch_hndl.state_lock); - if (!mhi_xprtp->ch_hndl.in_chan_enabled) { - mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); - IPC_RTR_ERR("%s: %s chnl reset\n", - __func__, mhi_xprtp->xprt_name); - return -ENETRESET; - } - sz_to_write = min((size_t)(skb->len - offset), - (size_t)IPC_ROUTER_MHI_XPRT_MAX_PKT_SIZE); - - wreq.client = mhi_xprtp->ch_hndl.in_handle; - wreq.buf = skb->data + offset; - wreq.len = sz_to_write; - wreq.chan = mhi_xprtp->ch_hndl.in_chan_id; - wreq.mode = IPA_DMA_SYNC; - rc = mhi_dev_write_channel(&wreq); - if (rc <= 0) { - mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); - IPC_RTR_ERR("%s: Error queueing mhi_xfer 0x%zx\n", - __func__, sz_to_write); - return -EFAULT; - } - offset += sz_to_write; + struct mhi_req *wreq; + + if (skb->len > mhi_xprtp->ch_hndl.max_packet_size) { + IPC_RTR_ERR("%s: Packet size is above the limit\n", __func__); + return -EINVAL; + } + + wait_event_interruptible(mhi_xprtp->write_wait_q, + !mhi_dev_channel_isempty(mhi_xprtp->ch_hndl.in_handle) || + !mhi_xprtp->ch_hndl.in_chan_enabled); + mutex_lock(&mhi_xprtp->ch_hndl.state_lock); + if (!mhi_xprtp->ch_hndl.in_chan_enabled) { + mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); + IPC_RTR_ERR("%s: %s chnl reset\n", + __func__, mhi_xprtp->xprt_name); + return -ENETRESET; + } + + spin_lock_irq(&mhi_xprtp->wr_req_lock); + if (list_empty(&mhi_xprtp->wr_req_list)) { + IPC_RTR_ERR("%s: Write request pool empty\n", __func__); + spin_unlock_irq(&mhi_xprtp->wr_req_lock); mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); + return -ENOMEM; } + wreq = container_of(mhi_xprtp->wr_req_list.next, + struct mhi_req, list); + list_del_init(&wreq->list); + + kref_get(&pkt->ref); + + wreq->client = mhi_xprtp->ch_hndl.in_handle; + wreq->context = pkt; + wreq->buf = skb->data; + wreq->len = skb->len; + if (list_empty(&wreq->list)) + wreq->snd_cmpl = 1; + else + wreq->snd_cmpl = 0; + spin_unlock_irq(&mhi_xprtp->wr_req_lock); + + if (mhi_dev_write_channel(wreq) < 0) { + spin_lock_irq(&mhi_xprtp->wr_req_lock); + list_add_tail(&wreq->list, &mhi_xprtp->wr_req_list); + spin_unlock_irq(&mhi_xprtp->wr_req_lock); + kref_put(&pkt->ref, ipc_router_mhi_dev_release_pkt); + mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); + IPC_RTR_ERR("%s: Error queueing mhi_xfer\n", __func__); + return -EFAULT; + } + + mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); return skb->len; } @@ -369,6 +429,32 @@ static int ipc_router_mhi_dev_close(struct msm_ipc_router_xprt *xprt) return 0; } +static int mhi_dev_xprt_alloc_write_reqs( + struct ipc_router_mhi_dev_xprt *mhi_xprtp) +{ + int i; + + mhi_xprtp->wreqs = kcalloc(MAX_IPCR_WR_REQ, + sizeof(struct mhi_req), + GFP_KERNEL); + if (!mhi_xprtp->wreqs) { + IPC_RTR_ERR("%s: Write reqs alloc failed\n", __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&mhi_xprtp->wr_req_list); + for (i = 0; i < MAX_IPCR_WR_REQ; ++i) { + mhi_xprtp->wreqs[i].chan = mhi_xprtp->ch_hndl.in_chan_id; + mhi_xprtp->wreqs[i].mode = IPA_DMA_ASYNC; + mhi_xprtp->wreqs[i].client_cb = mhi_xprt_write_completion_cb; + list_add_tail(&mhi_xprtp->wreqs[i].list, + &mhi_xprtp->wr_req_list); + } + + D("%s: write reqs allocation successful\n", __func__); + return 0; +} + /** * ipc_router_mhi_dev_driver_register() - register for MHI channels * @@ -406,6 +492,10 @@ static int ipc_router_mhi_dev_driver_register( mhi_xprtp->ch_hndl.in_chan_enabled = true; mutex_unlock(&mhi_xprtp->ch_hndl.state_lock); + rc = mhi_dev_xprt_alloc_write_reqs(mhi_xprtp); + if (rc) + goto exit; + /* Register the XPRT before receiving any data */ msm_ipc_router_xprt_notify(&mhi_xprtp->xprt, IPC_ROUTER_XPRT_EVENT_OPEN, NULL); @@ -495,9 +585,10 @@ static int ipc_router_mhi_dev_config_init( mhi_xprtp->ch_hndl.out_chan_id = mhi_xprt_config->out_chan_id; mhi_xprtp->ch_hndl.in_chan_id = mhi_xprt_config->in_chan_id; mutex_init(&mhi_xprtp->ch_hndl.state_lock); - skb_queue_head_init(&mhi_xprtp->ch_hndl.in_skbq); mhi_xprtp->ch_hndl.max_packet_size = IPC_ROUTER_MHI_XPRT_MAX_PKT_SIZE; mhi_xprtp->ch_hndl.mhi_xprtp = mhi_xprtp; + init_completion(&mhi_xprtp->read_done); + spin_lock_init(&mhi_xprtp->wr_req_lock); /* Register callback to mhi_dev */ rc = mhi_register_state_cb(mhi_dev_xprt_state_cb, mhi_xprtp, diff --git a/drivers/soc/qcom/kernel_protect.c b/drivers/soc/qcom/kernel_protect.c index b48cd0bfc423cdf07adc76c38411fc1a1f4bd1d1..458c73b656016da72c153fa8c20731f8db0411ef 100644 --- a/drivers/soc/qcom/kernel_protect.c +++ b/drivers/soc/qcom/kernel_protect.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015,2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015,2016,2019 The Linux Foundation. All rights reserved. * * 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 @@ -73,9 +73,7 @@ static void msm_protect_kernel_test(void) static int __init msm_protect_kernel(void) { - int ret; - u32 vmid_hlos = VMID_HLOS; - int dest_perms = PERM_READ | PERM_EXEC; + int ret = 0; /* * Although the kernel image is mapped with section mappings, the * start and end of the .text segment are on a PAGE_SIZE @@ -112,17 +110,7 @@ static int __init msm_protect_kernel(void) &kernel_x_start_rounded, &kernel_x_end); } - } else { - ret = hyp_assign_phys(kernel_x_start_rounded, - kernel_x_end - kernel_x_start_rounded, - &vmid_hlos, 1, &vmid_hlos, &dest_perms, 1); } - if (ret) - /* - * We want to fail relatively silently since not all - * platforms support the hyp_assign_phys call. - */ - pr_debug("Couldn't protect the kernel region: %d\n", ret); msm_protect_kernel_test(); diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index 7122e220e5b48d9249a533f7c3a6f7250c08be7e..e8443ed93286d259eed8b65abfbd6def39591adf 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * 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 @@ -343,6 +343,7 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, if (memblock[i].peripheral == DHMS_MEM_PROC_MPSS_V01 && !memblock[i].guarantee && + !memblock[i].client_request && memblock[i].alloted) { pr_debug("memshare: Freeing memory for client id: %d\n", memblock[i].client_id); @@ -592,12 +593,10 @@ static int handle_free_generic_req(void *req_h, void *req, void *conn_h) __func__); flag = 1; } else if (!memblock[client_id].guarantee && + memblock[client_id].client_request && memblock[client_id].alloted) { - pr_debug("In %s: pblk->virtual_addr :%lx, pblk->phy_addr: %lx\n,size: %d", - __func__, - (unsigned long int) - memblock[client_id].virtual_addr, - (unsigned long int)memblock[client_id].phy_addr, + pr_debug("memshare: %s: client_id:%d, size: %d", + __func__, client_id, memblock[client_id].size); dma_free_attrs(memsh_drv->dev, memblock[client_id].size, memblock[client_id].virtual_addr, @@ -605,8 +604,8 @@ static int handle_free_generic_req(void *req_h, void *req, void *conn_h) &attrs); free_client(client_id); } else { - pr_err("In %s, Request came for a guaranteed client cannot free up the memory\n", - __func__); + pr_err("In %s, Request came for a guaranteed client(client_id: %d) cannot free up the memory\n", + __func__, client_id); } if (flag) { @@ -909,6 +908,10 @@ static int memshare_child_probe(struct platform_device *pdev) pdev->dev.of_node, "qcom,allocate-boot-time"); + memblock[num_clients].client_request = of_property_read_bool( + pdev->dev.of_node, + "qcom,allocate-on-request"); + rc = of_property_read_string(pdev->dev.of_node, "label", &name); if (rc) { diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h index 3989075329776631f068ace4c0dc72c859b441d4..711e15b33cf2180b431becb75f014f364af02d38 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.h +++ b/drivers/soc/qcom/memshare/msm_memshare.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved. * * 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 @@ -38,6 +38,8 @@ struct mem_blocks { uint32_t guarantee; /* Memory alloted or not */ uint32_t alloted; + /* Allocation on request from a client*/ + uint32_t client_request; /* Size required for client */ uint32_t size; /* diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index e3bb4bc598ca1574bc4badaa86bde0a183beffe4..3ad927f1c9f94470edd2da1024ea61496b1c5c05 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * 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 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -66,9 +67,9 @@ #define map_from_smd_trans_signal(sigs) \ do { \ if (sigs & SMD_DTR_SIG) \ - sigs |= TIOCM_DTR; \ + sigs |= TIOCM_DSR; \ if (sigs & SMD_CTS_SIG) \ - sigs |= TIOCM_RTS; \ + sigs |= TIOCM_CTS; \ if (sigs & SMD_CD_SIG) \ sigs |= TIOCM_CD; \ if (sigs & SMD_RI_SIG) \ @@ -398,8 +399,8 @@ void glink_pkt_notify_tx_done(void *handle, const void *priv, { GLINK_PKT_INFO("%s(): priv[%p] pkt_priv[%p] ptr[%p]\n", __func__, priv, pkt_priv, ptr); -/* Free Tx buffer allocated in glink_pkt_write */ - kfree(ptr); + /* Free Tx buffer allocated in glink_pkt_write */ + kvfree(ptr); } /** @@ -774,8 +775,10 @@ ssize_t glink_pkt_write(struct file *file, __func__, devp->i, count); data = kzalloc(count, GFP_KERNEL); if (!data) { - GLINK_PKT_ERR("%s buffer allocation failed\n", __func__); - return -ENOMEM; + if (!strcmp(devp->open_cfg.edge, "bg")) + data = vzalloc(count); + if (!data) + return -ENOMEM; } ret = copy_from_user(data, buf, count); @@ -783,14 +786,14 @@ ssize_t glink_pkt_write(struct file *file, GLINK_PKT_ERR( "%s copy_from_user failed ret[%d] on dev id:%d size %zu\n", __func__, ret, devp->i, count); - kfree(data); + kvfree(data); return -EFAULT; } ret = glink_tx(devp->handle, data, data, count, GLINK_TX_REQ_INTENT); if (ret) { GLINK_PKT_ERR("%s glink_tx failed ret[%d]\n", __func__, ret); - kfree(data); + kvfree(data); return ret; } diff --git a/drivers/soc/qcom/pil_bg_intf.h b/drivers/soc/qcom/pil_bg_intf.h index ba25af8f5a8ecca25ad3d2c0e335a05ca73a6a99..777ccaaed112d98788491466ccbd46e9f88d222e 100644 --- a/drivers/soc/qcom/pil_bg_intf.h +++ b/drivers/soc/qcom/pil_bg_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * 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 @@ -23,6 +23,7 @@ enum bg_tz_commands { BGPIL_IMAGE_LOAD, BGPIL_AUTH_MDT, BGPIL_DLOAD_CONT, + BGPIL_GET_BG_VERSION, }; /* tzapp bg request.*/ @@ -36,7 +37,7 @@ __packed struct tzapp_bg_req { __packed struct tzapp_bg_rsp { uint32_t tzapp_bg_cmd; uint32_t bg_info_len; - uint32_t status; + int32_t status; uint32_t bg_info[100]; }; diff --git a/drivers/soc/qcom/qdsp6v2/Makefile b/drivers/soc/qcom/qdsp6v2/Makefile index d78328191bfeee59d62d99febc5a91906777ec53..cec80511cd0624bb07e5e94629583d7421176152 100644 --- a/drivers/soc/qcom/qdsp6v2/Makefile +++ b/drivers/soc/qcom/qdsp6v2/Makefile @@ -2,5 +2,7 @@ obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o voice_svc.o obj-$(CONFIG_MSM_QDSP6_APRV3) += apr.o apr_v3.o apr_tal.o voice_svc.o obj-$(CONFIG_MSM_QDSP6_APRV2_GLINK) += apr.o apr_v2.o apr_tal_glink.o voice_svc.o obj-$(CONFIG_MSM_QDSP6_APRV3_GLINK) += apr.o apr_v3.o apr_tal_glink.o voice_svc.o +obj-$(CONFIG_MSM_QDSP6_APRV2_VM) += apr_vm.o apr_v2.o voice_svc.o obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += msm_audio_ion.o +obj-$(CONFIG_SND_SOC_QDSP6V2_VM) += msm_audio_ion_vm.o obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index 6549febcf4a7645734d09f65c47c7353075ce21c..fb083190134bea1b0dc875cfb895877cc1bd2687 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2014, 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2014, 2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -284,17 +284,17 @@ int apr_send_pkt(void *handle, uint32_t *buf) return -EINVAL; } if (svc->need_reset) { - pr_err("apr: send_pkt service need reset\n"); + pr_err_ratelimited("apr: send_pkt service need reset\n"); return -ENETRESET; } if ((svc->dest_id == APR_DEST_QDSP6) && (apr_get_q6_state() != APR_SUBSYS_LOADED)) { - pr_err("%s: Still dsp is not Up\n", __func__); + pr_err_ratelimited("%s: Still dsp is not Up\n", __func__); return -ENETRESET; } else if ((svc->dest_id == APR_DEST_MODEM) && (apr_get_modem_state() == APR_SUBSYS_DOWN)) { - pr_err("apr: Still Modem is not Up\n"); + pr_err_ratelimited("apr: Still Modem is not Up\n"); return -ENETRESET; } @@ -304,7 +304,7 @@ int apr_send_pkt(void *handle, uint32_t *buf) clnt = &client[dest_id][client_id]; if (!client[dest_id][client_id].handle) { - pr_err("APR: Still service is not yet opened\n"); + pr_err_ratelimited("APR: Still service is not yet opened\n"); spin_unlock_irqrestore(&svc->w_lock, flags); return -EINVAL; } @@ -398,14 +398,14 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn, if (dest_id == APR_DEST_QDSP6) { if (apr_get_q6_state() != APR_SUBSYS_LOADED) { - pr_err("%s: adsp not up\n", __func__); + pr_err_ratelimited("%s: adsp not up\n", __func__); return NULL; } pr_debug("%s: adsp Up\n", __func__); } else if (dest_id == APR_DEST_MODEM) { if (apr_get_modem_state() == APR_SUBSYS_DOWN) { if (is_modem_up) { - pr_err("%s: modem shutdown due to SSR, ret", + pr_err_ratelimited("%s: modem shutdown due to SSR, ret", __func__); return NULL; } @@ -420,7 +420,7 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn, } if (apr_get_svc(svc_name, domain_id, &client_id, &svc_idx, &svc_id)) { - pr_err("%s: apr_get_svc failed\n", __func__); + pr_err_ratelimited("%s: apr_get_svc failed\n", __func__); goto done; } @@ -431,7 +431,7 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn, APR_DL_SMD, apr_cb_func, NULL); if (!clnt->handle) { svc = NULL; - pr_err("APR: Unable to open handle\n"); + pr_err_ratelimited("APR: Unable to open handle\n"); mutex_unlock(&clnt->m_lock); goto done; } @@ -442,7 +442,7 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn, clnt->id = client_id; if (svc->need_reset) { mutex_unlock(&svc->m_lock); - pr_err("APR: Service needs reset\n"); + pr_err_ratelimited("APR: Service needs reset\n"); goto done; } svc->id = svc_id; @@ -531,6 +531,12 @@ void apr_cb_func(void *buf, int len, void *priv) pr_err("APR: Wrong paket size\n"); return; } + + if (hdr->pkt_size < hdr_size) { + pr_err("APR: Packet size less than header size\n"); + return; + } + msg_type = hdr->hdr_field; msg_type = (msg_type >> 0x08) & 0x0003; if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) { diff --git a/drivers/soc/qcom/qdsp6v2/apr_v2.c b/drivers/soc/qcom/qdsp6v2/apr_v2.c index 2d6ea825c811b141535cae2a4703e843ce6c63e1..631eaa15b25712887f5afa9ca5383757cc2d8413 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_v2.c +++ b/drivers/soc/qcom/qdsp6v2/apr_v2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -25,6 +25,7 @@ enum apr_subsys_state apr_get_subsys_state(void) { return apr_get_q6_state(); } +EXPORT_SYMBOL(apr_get_subsys_state); void apr_set_subsys_state(void) { diff --git a/drivers/soc/qcom/qdsp6v2/apr_v3.c b/drivers/soc/qcom/qdsp6v2/apr_v3.c index 6bb913edf3ec9193c52beb6ab5420039bdab5317..085d01def05049874c17293cacc219168d3dcced 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_v3.c +++ b/drivers/soc/qcom/qdsp6v2/apr_v3.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 2018 The Linux Foundation. All rights reserved. * * 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 @@ -25,6 +25,7 @@ enum apr_subsys_state apr_get_subsys_state(void) { return apr_get_modem_state(); } +EXPORT_SYMBOL(apr_get_subsys_state); void apr_set_subsys_state(void) { diff --git a/drivers/soc/qcom/qdsp6v2/apr_vm.c b/drivers/soc/qcom/qdsp6v2/apr_vm.c new file mode 100644 index 0000000000000000000000000000000000000000..b994a86758383b1552ce17d99803a646f8bdea09 --- /dev/null +++ b/drivers/soc/qcom/qdsp6v2/apr_vm.c @@ -0,0 +1,1253 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCM_Q6_NMI_CMD 0x1 +#define APR_PKT_IPC_LOG_PAGE_CNT 2 +#define APR_VM_CB_THREAD_NAME "apr_vm_cb_thread" +#define APR_TX_BUF_SIZE 4096 +#define APR_RX_BUF_SIZE 4096 + +static struct apr_q6 q6; +static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX]; +#ifdef CONFIG_IPC_LOGGING +static void *apr_pkt_ctx; +#define APR_PKT_INFO(x...) \ +do { \ + if (apr_pkt_ctx) \ + ipc_log_string(apr_pkt_ctx, ": "x); \ +} while (0) +#endif +static wait_queue_head_t dsp_wait; +static wait_queue_head_t modem_wait; +static bool is_modem_up; +/* Subsystem restart: QDSP6 data, functions */ +static struct workqueue_struct *apr_reset_workqueue; +static void apr_reset_deregister(struct work_struct *work); +struct apr_reset_work { + void *handle; + struct work_struct work; +}; + +/* hab handle */ +static uint32_t hab_handle_tx; +static uint32_t hab_handle_rx; +static char apr_tx_buf[APR_TX_BUF_SIZE]; +static char apr_rx_buf[APR_RX_BUF_SIZE]; + +/* apr callback thread task */ +static struct task_struct *apr_vm_cb_thread_task; +static int pid; + + +struct apr_svc_table { + char name[64]; + int idx; + int id; + int dest_svc; + int client_id; + int handle; +}; + +/* + * src svc should be assigned dynamically through apr registration: + * 1. replace with a proper string name for registration. + * e.g. "qcom.apps.lnx." + name + * 2. register apr BE, retrieve dynamic src svc address, + * apr handle and store in svc tbl. + */ + +static struct mutex m_lock_tbl_qdsp6; + +static struct apr_svc_table svc_tbl_qdsp6[] = { + { + .name = "AFE", + .idx = 0, + .id = 0, + .dest_svc = APR_SVC_AFE, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "ASM", + .idx = 1, + .id = 0, + .dest_svc = APR_SVC_ASM, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "ADM", + .idx = 2, + .id = 0, + .dest_svc = APR_SVC_ADM, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "CORE", + .idx = 3, + .id = 0, + .dest_svc = APR_SVC_ADSP_CORE, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "TEST", + .idx = 4, + .id = 0, + .dest_svc = APR_SVC_TEST_CLIENT, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "MVM", + .idx = 5, + .id = 0, + .dest_svc = APR_SVC_ADSP_MVM, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "CVS", + .idx = 6, + .id = 0, + .dest_svc = APR_SVC_ADSP_CVS, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "CVP", + .idx = 7, + .id = 0, + .dest_svc = APR_SVC_ADSP_CVP, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "USM", + .idx = 8, + .id = 0, + .dest_svc = APR_SVC_USM, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, + { + .name = "VIDC", + .idx = 9, + .id = 0, + .dest_svc = APR_SVC_VIDC, + .handle = 0, + }, + { + .name = "LSM", + .idx = 10, + .id = 0, + .dest_svc = APR_SVC_LSM, + .client_id = APR_CLIENT_AUDIO, + .handle = 0, + }, +}; + +static struct mutex m_lock_tbl_voice; + +static struct apr_svc_table svc_tbl_voice[] = { + { + .name = "VSM", + .idx = 0, + .id = 0, + .dest_svc = APR_SVC_VSM, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, + { + .name = "VPM", + .idx = 1, + .id = 0, + .dest_svc = APR_SVC_VPM, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, + { + .name = "MVS", + .idx = 2, + .id = 0, + .dest_svc = APR_SVC_MVS, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, + { + .name = "MVM", + .idx = 3, + .id = 0, + .dest_svc = APR_SVC_MVM, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, + { + .name = "CVS", + .idx = 4, + .id = 0, + .dest_svc = APR_SVC_CVS, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, + { + .name = "CVP", + .idx = 5, + .id = 0, + .dest_svc = APR_SVC_CVP, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, + { + .name = "SRD", + .idx = 6, + .id = 0, + .dest_svc = APR_SVC_SRD, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, + { + .name = "TEST", + .idx = 7, + .id = 0, + .dest_svc = APR_SVC_TEST_CLIENT, + .client_id = APR_CLIENT_VOICE, + .handle = 0, + }, +}; + +enum apr_subsys_state apr_get_modem_state(void) +{ + return atomic_read(&q6.modem_state); +} + +void apr_set_modem_state(enum apr_subsys_state state) +{ + atomic_set(&q6.modem_state, state); +} + +enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev, + enum apr_subsys_state new) +{ + return atomic_cmpxchg(&q6.modem_state, prev, new); +} + +enum apr_subsys_state apr_get_q6_state(void) +{ + return atomic_read(&q6.q6_state); +} +EXPORT_SYMBOL(apr_get_q6_state); + +int apr_set_q6_state(enum apr_subsys_state state) +{ + pr_debug("%s: setting adsp state %d\n", __func__, state); + if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED) + return -EINVAL; + atomic_set(&q6.q6_state, state); + return 0; +} +EXPORT_SYMBOL(apr_set_q6_state); + +enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev, + enum apr_subsys_state new) +{ + return atomic_cmpxchg(&q6.q6_state, prev, new); +} + +int apr_wait_for_device_up(int dest_id) +{ + int rc = -1; + + if (dest_id == APR_DEST_MODEM) + rc = wait_event_interruptible_timeout(modem_wait, + (apr_get_modem_state() == APR_SUBSYS_UP), + (1 * HZ)); + else if (dest_id == APR_DEST_QDSP6) + rc = wait_event_interruptible_timeout(dsp_wait, + (apr_get_q6_state() == APR_SUBSYS_UP), + (1 * HZ)); + else + pr_err("%s: unknown dest_id %d\n", __func__, dest_id); + /* returns left time */ + return rc; +} + +static int apr_vm_nb_receive(int32_t handle, void *dest_buff, + uint32_t *size_bytes, uint32_t timeout) +{ + int rc; + uint32_t dest_buff_bytes = *size_bytes; + unsigned long delay = jiffies + (HZ / 2); + + do { + *size_bytes = dest_buff_bytes; + rc = habmm_socket_recv(handle, + dest_buff, + size_bytes, + timeout, + HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING); + } while (time_before(jiffies, delay) && (rc == HAB_AGAIN) && + (*size_bytes == 0)); + + return rc; +} + +static int apr_vm_cb_process_evt(char *buf, int len) +{ + struct apr_client_data data; + struct apr_client *apr_client; + struct apr_svc *c_svc; + struct apr_hdr *hdr; + uint16_t hdr_size; + uint16_t msg_type; + uint16_t ver; + uint16_t src; + uint16_t svc; + uint16_t clnt; + int i; + int temp_port = 0; + uint32_t *ptr; + uint32_t evt_id; + + pr_debug("APR: len = %d\n", len); + ptr = (uint32_t *)buf; + pr_debug("\n*****************\n"); + for (i = 0; i < len/4; i++) + pr_debug("%x ", ptr[i]); + pr_debug("\n"); + pr_debug("\n*****************\n"); + + if (!buf || len <= APR_HDR_SIZE + sizeof(uint32_t)) { + pr_err("APR: Improper apr pkt received: %p %d\n", buf, len); + return -EINVAL; + } + + evt_id = *((int32_t *)buf); + if (evt_id != APRV2_VM_EVT_RX_PKT_AVAILABLE) { + pr_err("APR: Wrong evt id: %d\n", evt_id); + return -EINVAL; + } + hdr = (struct apr_hdr *)(buf + sizeof(uint32_t)); +#ifdef CONFIG_IPC_LOGGING + APR_PKT_INFO("Rx: dest_svc[%d], opcode[0x%X], size[%d]", + hdr->dest_svc, hdr->opcode, hdr->pkt_size); +#endif + ver = hdr->hdr_field; + ver = (ver & 0x000F); + if (ver > APR_PKT_VER + 1) { + pr_err("APR: Wrong version: %d\n", ver); + return -EINVAL; + } + + hdr_size = hdr->hdr_field; + hdr_size = ((hdr_size & 0x00F0) >> 0x4) * 4; + if (hdr_size < APR_HDR_SIZE) { + pr_err("APR: Wrong hdr size:%d\n", hdr_size); + return -EINVAL; + } + + if (hdr->pkt_size < APR_HDR_SIZE) { + pr_err("APR: Wrong paket size\n"); + return -EINVAL; + } + + msg_type = hdr->hdr_field; + msg_type = (msg_type >> 0x08) & 0x0003; + if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) { + pr_err("APR: Wrong message type: %d\n", msg_type); + return -EINVAL; + } + + /* + * dest_svc is dynamic created by apr service + * no need to check the range of dest_svc + */ + if (hdr->src_domain >= APR_DOMAIN_MAX || + hdr->dest_domain >= APR_DOMAIN_MAX || + hdr->src_svc >= APR_SVC_MAX) { + pr_err("APR: Wrong APR header\n"); + return -EINVAL; + } + + svc = hdr->dest_svc; + if (hdr->src_domain == APR_DOMAIN_MODEM) + clnt = APR_CLIENT_VOICE; + else if (hdr->src_domain == APR_DOMAIN_ADSP) + clnt = APR_CLIENT_AUDIO; + else { + pr_err("APR: Pkt from wrong source: %d\n", hdr->src_domain); + return -EINVAL; + } + + src = apr_get_data_src(hdr); + if (src == APR_DEST_MAX) + return -EINVAL; + + pr_debug("src =%d clnt = %d\n", src, clnt); + apr_client = &client[src][clnt]; + for (i = 0; i < APR_SVC_MAX; i++) + if (apr_client->svc[i].id == svc) { + pr_debug("svc_id = %d\n", apr_client->svc[i].id); + c_svc = &apr_client->svc[i]; + break; + } + + if (i == APR_SVC_MAX) { + pr_err("APR: service is not registered\n"); + return -ENXIO; + } + + pr_debug("svc_idx = %d\n", i); + pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id, + c_svc->client_id, c_svc->fn, c_svc->priv); + + data.payload_size = hdr->pkt_size - hdr_size; + data.opcode = hdr->opcode; + data.src = src; + data.src_port = hdr->src_port; + data.dest_port = hdr->dest_port; + data.token = hdr->token; + data.msg_type = msg_type; + if (data.payload_size > 0) + data.payload = (char *)hdr + hdr_size; + + temp_port = ((data.dest_port >> 8) * 8) + (data.dest_port & 0xFF); + pr_debug("port = %d t_port = %d\n", data.src_port, temp_port); + if (c_svc->port_cnt && c_svc->port_fn[temp_port]) + c_svc->port_fn[temp_port](&data, c_svc->port_priv[temp_port]); + else if (c_svc->fn) + c_svc->fn(&data, c_svc->priv); + else + pr_err("APR: Rxed a packet for NULL callback\n"); + + return 0; +} + +static int apr_vm_cb_thread(void *data) +{ + uint32_t apr_rx_buf_len; + struct aprv2_vm_ack_rx_pkt_available_t apr_ack; + int status = 0; + int ret = 0; + + while (1) { + apr_rx_buf_len = sizeof(apr_rx_buf); + ret = habmm_socket_recv(hab_handle_rx, + (void *)&apr_rx_buf, + &apr_rx_buf_len, + 0xFFFFFFFF, + 0); + if (ret) { + pr_err("%s: habmm_socket_recv failed %d\n", + __func__, ret); + /* + * TODO: depends on the HAB error code, + * may need to implement + * a retry mechanism. + * break if recv failed ? + */ + break; + } + + status = apr_vm_cb_process_evt(apr_rx_buf, apr_rx_buf_len); + + apr_ack.status = status; + ret = habmm_socket_send(hab_handle_rx, + (void *)&apr_ack, + sizeof(apr_ack), + 0); + if (ret) { + pr_err("%s: habmm_socket_send failed %d\n", + __func__, ret); + /* TODO: break if send failed ? */ + break; + } + } + + return ret; +} + +static int apr_vm_get_svc(const char *svc_name, int domain_id, int *client_id, + int *svc_idx, int *svc_id, int *dest_svc, int *handle) +{ + int i; + int size; + struct apr_svc_table *tbl; + struct mutex *lock; + struct aprv2_vm_cmd_register_rsp_t apr_rsp; + uint32_t apr_len; + int ret = 0; + struct { + uint32_t cmd_id; + struct aprv2_vm_cmd_register_t reg_cmd; + } tx_data; + + if (domain_id == APR_DOMAIN_ADSP) { + tbl = svc_tbl_qdsp6; + size = ARRAY_SIZE(svc_tbl_qdsp6); + lock = &m_lock_tbl_qdsp6; + } else { + tbl = svc_tbl_voice; + size = ARRAY_SIZE(svc_tbl_voice); + lock = &m_lock_tbl_voice; + } + + mutex_lock(lock); + for (i = 0; i < size; i++) { + if (!strcmp(svc_name, tbl[i].name)) { + *client_id = tbl[i].client_id; + *svc_idx = tbl[i].idx; + if (!tbl[i].id && !tbl[i].handle) { + /* need to register a new service */ + memset((void *) &tx_data, 0, sizeof(tx_data)); + + apr_len = sizeof(tx_data); + tx_data.cmd_id = APRV2_VM_CMDID_REGISTER; + tx_data.reg_cmd.name_size = snprintf( + tx_data.reg_cmd.name, + APRV2_VM_MAX_DNS_SIZE, + "qcom.apps.lnx.%s", + svc_name); + tx_data.reg_cmd.addr = 0; + ret = habmm_socket_send(hab_handle_tx, + (void *) &tx_data, + apr_len, + 0); + if (ret) { + pr_err("%s: habmm_socket_send failed %d\n", + __func__, ret); + mutex_unlock(lock); + return ret; + } + /* wait for response */ + apr_len = sizeof(apr_rsp); + ret = apr_vm_nb_receive(hab_handle_tx, + (void *)&apr_rsp, + &apr_len, + 0xFFFFFFFF); + if (ret) { + pr_err("%s: apr_vm_nb_receive failed %d\n", + __func__, ret); + mutex_unlock(lock); + return ret; + } + if (apr_rsp.status) { + pr_err("%s: apr_vm_nb_receive status %d\n", + __func__, apr_rsp.status); + ret = apr_rsp.status; + mutex_unlock(lock); + return ret; + } + /* update svc table */ + tbl[i].handle = apr_rsp.handle; + tbl[i].id = apr_rsp.addr & + APRV2_VM_PKT_SERVICE_ID_MASK; + } + *svc_id = tbl[i].id; + *dest_svc = tbl[i].dest_svc; + *handle = tbl[i].handle; + break; + } + } + mutex_unlock(lock); + + pr_debug("%s: svc_name = %s client_id = %d domain_id = %d\n", + __func__, svc_name, *client_id, domain_id); + pr_debug("%s: src_svc = %d dest_svc = %d handle = %d\n", + __func__, *svc_id, *dest_svc, *handle); + + if (i == size) { + pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name); + ret = -EINVAL; + } + + return ret; +} + +static int apr_vm_rel_svc(int domain_id, int svc_id, int handle) +{ + int i; + int size; + struct apr_svc_table *tbl; + struct mutex *lock; + struct aprv2_vm_cmd_deregister_rsp_t apr_rsp; + uint32_t apr_len; + int ret = 0; + struct { + uint32_t cmd_id; + struct aprv2_vm_cmd_deregister_t dereg_cmd; + } tx_data; + + if (domain_id == APR_DOMAIN_ADSP) { + tbl = svc_tbl_qdsp6; + size = ARRAY_SIZE(svc_tbl_qdsp6); + lock = &m_lock_tbl_qdsp6; + } else { + tbl = svc_tbl_voice; + size = ARRAY_SIZE(svc_tbl_voice); + lock = &m_lock_tbl_voice; + } + + mutex_lock(lock); + for (i = 0; i < size; i++) { + if (tbl[i].id == svc_id && tbl[i].handle == handle) { + /* need to deregister a service */ + memset((void *) &tx_data, 0, sizeof(tx_data)); + + apr_len = sizeof(tx_data); + tx_data.cmd_id = APRV2_VM_CMDID_DEREGISTER; + tx_data.dereg_cmd.handle = handle; + ret = habmm_socket_send(hab_handle_tx, + (void *) &tx_data, + apr_len, + 0); + if (ret) + pr_err("%s: habmm_socket_send failed %d\n", + __func__, ret); + /* + * TODO: if send failed, should not wait for recv. + * should clear regardless? + */ + /* wait for response */ + apr_len = sizeof(apr_rsp); + ret = apr_vm_nb_receive(hab_handle_tx, + (void *)&apr_rsp, + &apr_len, + 0xFFFFFFFF); + if (ret) + pr_err("%s: apr_vm_nb_receive failed %d\n", + __func__, ret); + if (apr_rsp.status) { + pr_err("%s: apr_vm_nb_receive status %d\n", + __func__, apr_rsp.status); + ret = apr_rsp.status; + } + /* clear svc table */ + tbl[i].handle = 0; + tbl[i].id = 0; + break; + } + } + mutex_unlock(lock); + + if (i == size) { + pr_err("%s: APR: Wrong svc id %d handle %d\n", + __func__, svc_id, handle); + ret = -EINVAL; + } + + return ret; +} + +int apr_send_pkt(void *handle, uint32_t *buf) +{ + struct apr_svc *svc = handle; + struct apr_hdr *hdr; + unsigned long flags; + uint32_t *cmd_id = (uint32_t *)apr_tx_buf; + struct aprv2_vm_cmd_async_send_t *apr_send = + (struct aprv2_vm_cmd_async_send_t *)(apr_tx_buf + + sizeof(uint32_t)); + uint32_t apr_send_len; + struct aprv2_vm_cmd_async_send_rsp_t apr_rsp; + uint32_t apr_rsp_len; + int ret = 0; + + if (!handle || !buf) { + pr_err("APR: Wrong parameters\n"); + return -EINVAL; + } + if (svc->need_reset) { + pr_err("APR: send_pkt service need reset\n"); + return -ENETRESET; + } + + if ((svc->dest_id == APR_DEST_QDSP6) && + (apr_get_q6_state() != APR_SUBSYS_LOADED)) { + pr_err("%s: Still dsp is not Up\n", __func__); + return -ENETRESET; + } else if ((svc->dest_id == APR_DEST_MODEM) && + (apr_get_modem_state() == APR_SUBSYS_DOWN)) { + pr_err("%s: Still Modem is not Up\n", __func__); + return -ENETRESET; + } + + spin_lock_irqsave(&svc->w_lock, flags); + if (!svc->id || !svc->vm_handle) { + pr_err("APR: Still service is not yet opened\n"); + ret = -EINVAL; + goto done; + } + hdr = (struct apr_hdr *)buf; + + hdr->src_domain = APR_DOMAIN_APPS; + hdr->src_svc = svc->id; + hdr->dest_domain = svc->dest_domain; + hdr->dest_svc = svc->vm_dest_svc; +#ifdef CONFIG_IPC_LOGGING + APR_PKT_INFO("Tx: dest_svc[%d], opcode[0x%X], size[%d]", + hdr->dest_svc, hdr->opcode, hdr->pkt_size); +#endif + memset((void *)&apr_tx_buf, 0, sizeof(apr_tx_buf)); + /* pkt_size + cmd_id + handle */ + apr_send_len = hdr->pkt_size + sizeof(uint32_t) * 2; + *cmd_id = APRV2_VM_CMDID_ASYNC_SEND; + apr_send->handle = svc->vm_handle; + + /* safe check */ + if (hdr->pkt_size > APR_TX_BUF_SIZE - (sizeof(uint32_t) * 2)) { + pr_err("APR: Wrong pkt size %d\n", hdr->pkt_size); + ret = -ENOMEM; + goto done; + } + memcpy(&apr_send->pkt_header, buf, hdr->pkt_size); + + ret = habmm_socket_send(hab_handle_tx, + (void *)&apr_tx_buf, + apr_send_len, + 0); + if (ret) { + pr_err("%s: habmm_socket_send failed %d\n", + __func__, ret); + goto done; + } + /* wait for response */ + apr_rsp_len = sizeof(apr_rsp); + ret = apr_vm_nb_receive(hab_handle_tx, + (void *)&apr_rsp, + &apr_rsp_len, + 0xFFFFFFFF); + if (ret) { + pr_err("%s: apr_vm_nb_receive failed %d\n", + __func__, ret); + goto done; + } + if (apr_rsp.status) { + pr_err("%s: apr_vm_nb_receive status %d\n", + __func__, apr_rsp.status); + /* should translate status properly */ + ret = -ECOMM; + goto done; + } + + /* upon successful send, return packet size */ + ret = hdr->pkt_size; + +done: + spin_unlock_irqrestore(&svc->w_lock, flags); + return ret; +} + +struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn, + uint32_t src_port, void *priv) +{ + struct apr_client *clnt; + int client_id = 0; + int svc_idx = 0; + int svc_id = 0; + int dest_id = 0; + int domain_id = 0; + int temp_port = 0; + struct apr_svc *svc = NULL; + int rc = 0; + bool can_open_channel = true; + int dest_svc = 0; + int handle = 0; + + if (!dest || !svc_name || !svc_fn) + return NULL; + + if (!strcmp(dest, "ADSP")) + domain_id = APR_DOMAIN_ADSP; + else if (!strcmp(dest, "MODEM")) { + /* Don't request for SMD channels if destination is MODEM, + * as these channels are no longer used and these clients + * are to listen only for MODEM SSR events + */ + can_open_channel = false; + domain_id = APR_DOMAIN_MODEM; + } else { + pr_err("APR: wrong destination\n"); + goto done; + } + + dest_id = apr_get_dest_id(dest); + + if (dest_id == APR_DEST_QDSP6) { + if (apr_get_q6_state() != APR_SUBSYS_LOADED) { + pr_err("%s: adsp not up\n", __func__); + return NULL; + } + pr_debug("%s: adsp Up\n", __func__); + } else if (dest_id == APR_DEST_MODEM) { + if (apr_get_modem_state() == APR_SUBSYS_DOWN) { + if (is_modem_up) { + pr_err("%s: modem shutdown due to SSR, ret", + __func__); + return NULL; + } + pr_debug("%s: Wait for modem to bootup\n", __func__); + rc = apr_wait_for_device_up(APR_DEST_MODEM); + if (rc == 0) { + pr_err("%s: Modem is not Up\n", __func__); + return NULL; + } + } + pr_debug("%s: modem Up\n", __func__); + } + + if (apr_vm_get_svc(svc_name, domain_id, &client_id, &svc_idx, &svc_id, + &dest_svc, &handle)) { + pr_err("%s: apr_vm_get_svc failed\n", __func__); + goto done; + } + + clnt = &client[dest_id][client_id]; + svc = &clnt->svc[svc_idx]; + mutex_lock(&svc->m_lock); + clnt->id = client_id; + if (svc->need_reset) { + mutex_unlock(&svc->m_lock); + pr_err("APR: Service needs reset\n"); + goto done; + } + svc->id = svc_id; + svc->vm_dest_svc = dest_svc; + svc->dest_id = dest_id; + svc->client_id = client_id; + svc->dest_domain = domain_id; + svc->pkt_owner = APR_PKT_OWNER_DRIVER; + svc->vm_handle = handle; + + if (src_port != 0xFFFFFFFF) { + temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF); + pr_debug("port = %d t_port = %d\n", src_port, temp_port); + if (temp_port >= APR_MAX_PORTS || temp_port < 0) { + pr_err("APR: temp_port out of bounds\n"); + mutex_unlock(&svc->m_lock); + return NULL; + } + if (!svc->port_cnt && !svc->svc_cnt) + clnt->svc_cnt++; + svc->port_cnt++; + svc->port_fn[temp_port] = svc_fn; + svc->port_priv[temp_port] = priv; + } else { + if (!svc->fn) { + if (!svc->port_cnt && !svc->svc_cnt) + clnt->svc_cnt++; + svc->fn = svc_fn; + if (svc->port_cnt) + svc->svc_cnt++; + svc->priv = priv; + } + } + + mutex_unlock(&svc->m_lock); +done: + return svc; +} + +static void apr_reset_deregister(struct work_struct *work) +{ + struct apr_svc *handle = NULL; + struct apr_reset_work *apr_reset = + container_of(work, struct apr_reset_work, work); + + handle = apr_reset->handle; + pr_debug("%s:handle[%p]\n", __func__, handle); + apr_deregister(handle); + kfree(apr_reset); +} + +int apr_deregister(void *handle) +{ + struct apr_svc *svc = handle; + struct apr_client *clnt; + uint16_t dest_id; + uint16_t client_id; + + if (!handle) + return -EINVAL; + + mutex_lock(&svc->m_lock); + dest_id = svc->dest_id; + client_id = svc->client_id; + clnt = &client[dest_id][client_id]; + + if (svc->port_cnt > 0 || svc->svc_cnt > 0) { + if (svc->port_cnt) + svc->port_cnt--; + else if (svc->svc_cnt) + svc->svc_cnt--; + if (!svc->port_cnt && !svc->svc_cnt) { + client[dest_id][client_id].svc_cnt--; + svc->need_reset = 0x0; + } + } else if (client[dest_id][client_id].svc_cnt > 0) { + client[dest_id][client_id].svc_cnt--; + if (!client[dest_id][client_id].svc_cnt) { + svc->need_reset = 0x0; + pr_debug("%s: service is reset %p\n", __func__, svc); + } + } + + if (!svc->port_cnt && !svc->svc_cnt) { + if (apr_vm_rel_svc(svc->dest_domain, svc->id, svc->vm_handle)) + pr_err("%s: apr_vm_rel_svc failed\n", __func__); + svc->priv = NULL; + svc->id = 0; + svc->vm_dest_svc = 0; + svc->fn = NULL; + svc->dest_id = 0; + svc->client_id = 0; + svc->need_reset = 0x0; + svc->vm_handle = 0; + } + mutex_unlock(&svc->m_lock); + + return 0; +} + +void apr_reset(void *handle) +{ + struct apr_reset_work *apr_reset_worker = NULL; + + if (!handle) + return; + pr_debug("%s: handle[%p]\n", __func__, handle); + + if (apr_reset_workqueue == NULL) { + pr_err("%s: apr_reset_workqueue is NULL\n", __func__); + return; + } + + apr_reset_worker = kzalloc(sizeof(struct apr_reset_work), + GFP_ATOMIC); + + if (apr_reset_worker == NULL) { + pr_err("%s: mem failure\n", __func__); + return; + } + + apr_reset_worker->handle = handle; + INIT_WORK(&apr_reset_worker->work, apr_reset_deregister); + queue_work(apr_reset_workqueue, &apr_reset_worker->work); +} + +/* Dispatch the Reset events to Modem and audio clients */ +void dispatch_event(unsigned long code, uint16_t proc) +{ + struct apr_client *apr_client; + struct apr_client_data data; + struct apr_svc *svc; + uint16_t clnt; + int i, j; + + memset(&data, 0, sizeof(data)); + data.opcode = RESET_EVENTS; + data.reset_event = code; + + /* Service domain can be different from the processor */ + data.reset_proc = apr_get_reset_domain(proc); + + clnt = APR_CLIENT_AUDIO; + apr_client = &client[proc][clnt]; + for (i = 0; i < APR_SVC_MAX; i++) { + mutex_lock(&apr_client->svc[i].m_lock); + if (apr_client->svc[i].fn) { + apr_client->svc[i].need_reset = 0x1; + apr_client->svc[i].fn(&data, apr_client->svc[i].priv); + } + if (apr_client->svc[i].port_cnt) { + svc = &(apr_client->svc[i]); + svc->need_reset = 0x1; + for (j = 0; j < APR_MAX_PORTS; j++) + if (svc->port_fn[j]) + svc->port_fn[j](&data, + svc->port_priv[j]); + } + mutex_unlock(&apr_client->svc[i].m_lock); + } + + clnt = APR_CLIENT_VOICE; + apr_client = &client[proc][clnt]; + for (i = 0; i < APR_SVC_MAX; i++) { + mutex_lock(&apr_client->svc[i].m_lock); + if (apr_client->svc[i].fn) { + apr_client->svc[i].need_reset = 0x1; + apr_client->svc[i].fn(&data, apr_client->svc[i].priv); + } + if (apr_client->svc[i].port_cnt) { + svc = &(apr_client->svc[i]); + svc->need_reset = 0x1; + for (j = 0; j < APR_MAX_PORTS; j++) + if (svc->port_fn[j]) + svc->port_fn[j](&data, + svc->port_priv[j]); + } + mutex_unlock(&apr_client->svc[i].m_lock); + } +} + +static int modem_notifier_cb(struct notifier_block *this, unsigned long code, + void *_cmd) +{ + static int boot_count = 2; + + if (boot_count) { + boot_count--; + return NOTIFY_OK; + } + + switch (code) { + case SUBSYS_BEFORE_SHUTDOWN: + pr_debug("M-Notify: Shutdown started\n"); + apr_set_modem_state(APR_SUBSYS_DOWN); + dispatch_event(code, APR_DEST_MODEM); + break; + case SUBSYS_AFTER_SHUTDOWN: + pr_debug("M-Notify: Shutdown Completed\n"); + break; + case SUBSYS_BEFORE_POWERUP: + pr_debug("M-notify: Bootup started\n"); + break; + case SUBSYS_AFTER_POWERUP: + if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) == + APR_SUBSYS_DOWN) + wake_up(&modem_wait); + is_modem_up = 1; + pr_debug("M-Notify: Bootup Completed\n"); + break; + default: + pr_err("M-Notify: General: %lu\n", code); + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block mnb = { + .notifier_call = modem_notifier_cb, +}; + +static bool powered_on; + +static int lpass_notifier_cb(struct notifier_block *this, unsigned long code, + void *_cmd) +{ + static int boot_count = 2; + struct notif_data *data = (struct notif_data *)_cmd; + struct scm_desc desc; + + if (boot_count) { + boot_count--; + return NOTIFY_OK; + } + + switch (code) { + case SUBSYS_BEFORE_SHUTDOWN: + pr_debug("L-Notify: Shutdown started\n"); + apr_set_q6_state(APR_SUBSYS_DOWN); + dispatch_event(code, APR_DEST_QDSP6); + if (data && data->crashed) { + /* Send NMI to QDSP6 via an SCM call. */ + if (!is_scm_armv8()) { + scm_call_atomic1(SCM_SVC_UTIL, + SCM_Q6_NMI_CMD, 0x1); + } else { + desc.args[0] = 0x1; + desc.arginfo = SCM_ARGS(1); + scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_UTIL, + SCM_Q6_NMI_CMD), &desc); + } + /* The write should go through before q6 is shutdown */ + mb(); + pr_debug("L-Notify: Q6 NMI was sent.\n"); + } + break; + case SUBSYS_AFTER_SHUTDOWN: + powered_on = false; + pr_debug("L-Notify: Shutdown Completed\n"); + break; + case SUBSYS_BEFORE_POWERUP: + pr_debug("L-notify: Bootup started\n"); + break; + case SUBSYS_AFTER_POWERUP: + if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, + APR_SUBSYS_LOADED) == APR_SUBSYS_DOWN) + wake_up(&dsp_wait); + powered_on = true; + pr_debug("L-Notify: Bootup Completed\n"); + break; + default: + pr_err("L-Notify: Generel: %lu\n", code); + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block lnb = { + .notifier_call = lpass_notifier_cb, +}; + +static int panic_handler(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct scm_desc desc; + + if (powered_on) { + /* Send NMI to QDSP6 via an SCM call. */ + if (!is_scm_armv8()) { + scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1); + } else { + desc.args[0] = 0x1; + desc.arginfo = SCM_ARGS(1); + scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_UTIL, + SCM_Q6_NMI_CMD), &desc); + } + } + return NOTIFY_DONE; +} + +static struct notifier_block panic_nb = { + .notifier_call = panic_handler, +}; + +static void apr_vm_set_subsys_state(void) +{ + /* set default subsys state in vm env. + Both q6 and modem should be in LOADED state, + since vm boots up at late stage after pm. */ + apr_set_q6_state(APR_SUBSYS_LOADED); + apr_set_modem_state(APR_SUBSYS_LOADED); +} + +static int __init apr_init(void) +{ + int i, j, k; + int ret; + + /* open apr channel tx and rx, store as global */ + ret = habmm_socket_open(&hab_handle_tx, + MM_AUD_1, + 0xFFFFFFFF, + HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_FE); + if (ret) { + pr_err("%s: habmm_socket_open tx failed %d\n", __func__, ret); + return ret; + } + + ret = habmm_socket_open(&hab_handle_rx, + MM_AUD_2, + 0xFFFFFFFF, + HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_FE); + if (ret) { + pr_err("%s: habmm_socket_open rx failed %d\n", __func__, ret); + habmm_socket_close(hab_handle_tx); + return ret; + } + pr_info("%s: hab_handle_tx %x hab_handle_rx %x\n", + __func__, hab_handle_tx, hab_handle_rx); + + /* create apr ch rx cb thread */ + apr_vm_cb_thread_task = kthread_run(apr_vm_cb_thread, + NULL, + APR_VM_CB_THREAD_NAME); + if (IS_ERR(apr_vm_cb_thread_task)) { + ret = PTR_ERR(apr_vm_cb_thread_task); + pr_err("%s: kthread_run failed %d\n", __func__, ret); + habmm_socket_close(hab_handle_tx); + habmm_socket_close(hab_handle_rx); + return ret; + } + pid = apr_vm_cb_thread_task->pid; + pr_info("%s: apr_vm_cb_thread started pid %d\n", + __func__, pid); + + mutex_init(&m_lock_tbl_qdsp6); + mutex_init(&m_lock_tbl_voice); + + for (i = 0; i < APR_DEST_MAX; i++) + for (j = 0; j < APR_CLIENT_MAX; j++) { + mutex_init(&client[i][j].m_lock); + for (k = 0; k < APR_SVC_MAX; k++) { + mutex_init(&client[i][j].svc[k].m_lock); + spin_lock_init(&client[i][j].svc[k].w_lock); + } + } + + apr_vm_set_subsys_state(); + mutex_init(&q6.lock); + apr_reset_workqueue = create_singlethread_workqueue("apr_driver"); + if (!apr_reset_workqueue) { + habmm_socket_close(hab_handle_tx); + habmm_socket_close(hab_handle_rx); + kthread_stop(apr_vm_cb_thread_task); + return -ENOMEM; + } + atomic_notifier_chain_register(&panic_notifier_list, &panic_nb); +#ifdef CONFIG_IPC_LOGGING + apr_pkt_ctx = ipc_log_context_create(APR_PKT_IPC_LOG_PAGE_CNT, + "apr", 0); + if (!apr_pkt_ctx) + pr_err("%s: Unable to create ipc log context\n", __func__); +#endif + return 0; +} +device_initcall(apr_init); + +static int __init apr_late_init(void) +{ + int ret = 0; + + init_waitqueue_head(&dsp_wait); + init_waitqueue_head(&modem_wait); + subsys_notif_register(&mnb, &lnb); + return ret; +} +late_initcall(apr_late_init); + +static void __exit apr_exit(void) +{ + habmm_socket_close(hab_handle_tx); + habmm_socket_close(hab_handle_rx); + kthread_stop(apr_vm_cb_thread_task); +} +__exitcall(apr_exit); diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c index 81b38023f70f96e3359e14bc07eceac991e4161c..9f6610667a44b6ea138050ef381534525ec9601f 100644 --- a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c +++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c @@ -756,13 +756,15 @@ fail_attach: static int msm_audio_smmu_init(struct device *dev) { struct dma_iommu_mapping *mapping; - int ret; + int ret = 0; int disable_htw = 1; mapping = arm_iommu_create_mapping( msm_iommu_get_bus(dev), MSM_AUDIO_ION_VA_START, MSM_AUDIO_ION_VA_LEN); + if (mapping == NULL) + goto fail_attach; if (IS_ERR(mapping)) return PTR_ERR(mapping); diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion_vm.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion_vm.c new file mode 100644 index 0000000000000000000000000000000000000000..fef303853958d1b932ea1f1539cfc4e38462ad11 --- /dev/null +++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion_vm.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../staging/android/ion/ion_priv.h" +#include "../../../staging/android/ion/ion_hvenv_driver.h" + +#define MSM_AUDIO_ION_PROBED (1 << 0) + +#define MSM_AUDIO_SMMU_VM_CMD_MAP 0x00000001 +#define MSM_AUDIO_SMMU_VM_CMD_UNMAP 0x00000002 +#define MSM_AUDIO_SMMU_VM_HAB_MINOR_ID 1 + +struct msm_audio_ion_private { + bool smmu_enabled; + bool audioheap_enabled; + u8 device_status; + struct list_head smmu_map_list; + struct mutex smmu_map_mutex; +}; + +struct msm_audio_smmu_map_data { + struct ion_client *client; + struct ion_handle *handle; + u32 export_id; + struct list_head list; +}; + +struct msm_audio_smmu_vm_map_cmd { + int cmd_id; + u32 export_id; + u32 buf_size; +}; + +struct msm_audio_smmu_vm_map_cmd_rsp { + int status; + u64 addr; +}; + +struct msm_audio_smmu_vm_unmap_cmd { + int cmd_id; + u32 export_id; +}; + +struct msm_audio_smmu_vm_unmap_cmd_rsp { + int status; +}; + +static struct msm_audio_ion_private msm_audio_ion_data = {0,}; +static u32 msm_audio_ion_hab_handle; + +static int msm_audio_ion_get_phys(struct ion_client *client, + struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len, + void *vaddr); + +static int msm_audio_ion_smmu_map(struct ion_client *client, + struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len, void *vaddr) +{ + int rc; + u32 export_id; + u32 cmd_rsp_size; + bool exported = false; + struct msm_audio_smmu_vm_map_cmd_rsp cmd_rsp; + struct msm_audio_smmu_map_data *map_data = NULL; + struct msm_audio_smmu_vm_map_cmd smmu_map_cmd; + + rc = ion_handle_get_size(client, handle, len); + if (rc) { + pr_err("%s: ion_handle_get_size failed, client = %pK, handle = %pK, rc = %d\n", + __func__, client, handle, rc); + goto err; + } + + /* Data required to track per buffer mapping */ + map_data = kzalloc(sizeof(*map_data), GFP_KERNEL); + if (!map_data) { + rc = -ENOMEM; + goto err; + } + + /* Export the buffer to physical VM */ + rc = habmm_export(msm_audio_ion_hab_handle, vaddr, *len, + &export_id, 0); + if (rc) { + pr_err("%s: habmm_export failed vaddr = %pK, len = %zd, rc = %d\n", + __func__, vaddr, *len, rc); + goto err; + } + + exported = true; + smmu_map_cmd.cmd_id = MSM_AUDIO_SMMU_VM_CMD_MAP; + smmu_map_cmd.export_id = export_id; + smmu_map_cmd.buf_size = *len; + + mutex_lock(&(msm_audio_ion_data.smmu_map_mutex)); + rc = habmm_socket_send(msm_audio_ion_hab_handle, + (void *)&smmu_map_cmd, sizeof(smmu_map_cmd), 0); + if (rc) { + pr_err("%s: habmm_socket_send failed %d\n", + __func__, rc); + mutex_unlock(&(msm_audio_ion_data.smmu_map_mutex)); + goto err; + } + + cmd_rsp_size = sizeof(cmd_rsp); + rc = habmm_socket_recv(msm_audio_ion_hab_handle, + (void *)&cmd_rsp, + &cmd_rsp_size, + 0xFFFFFFFF, + 0); + if (rc) { + pr_err("%s: habmm_socket_recv failed %d\n", + __func__, rc); + mutex_unlock(&(msm_audio_ion_data.smmu_map_mutex)); + goto err; + } + mutex_unlock(&(msm_audio_ion_data.smmu_map_mutex)); + + if (cmd_rsp_size != sizeof(cmd_rsp)) { + pr_err("%s: invalid size for cmd rsp %lu, expected %lu\n", + __func__, cmd_rsp_size, sizeof(cmd_rsp)); + rc = -EIO; + goto err; + } + + if (cmd_rsp.status) { + pr_err("%s: SMMU map command failed %d\n", + __func__, cmd_rsp.status); + rc = cmd_rsp.status; + goto err; + } + + *addr = (ion_phys_addr_t)cmd_rsp.addr; + + map_data->client = client; + map_data->handle = handle; + map_data->export_id = export_id; + + mutex_lock(&(msm_audio_ion_data.smmu_map_mutex)); + list_add_tail(&(map_data->list), + &(msm_audio_ion_data.smmu_map_list)); + mutex_unlock(&(msm_audio_ion_data.smmu_map_mutex)); + + return 0; + +err: + if (exported) + (void)habmm_unexport(msm_audio_ion_hab_handle, export_id, 0); + + kfree(map_data); + + return rc; +} + +static int msm_audio_ion_smmu_unmap(struct ion_client *client, + struct ion_handle *handle) +{ + int rc; + bool found = false; + u32 cmd_rsp_size; + struct msm_audio_smmu_vm_unmap_cmd_rsp cmd_rsp; + struct msm_audio_smmu_map_data *map_data, *next; + struct msm_audio_smmu_vm_unmap_cmd smmu_unmap_cmd; + + /* + * Though list_for_each_entry_safe is delete safe, lock + * should be explicitly acquired to avoid race condition + * on adding elements to the list. + */ + mutex_lock(&(msm_audio_ion_data.smmu_map_mutex)); + list_for_each_entry_safe(map_data, next, + &(msm_audio_ion_data.smmu_map_list), list) { + + if (map_data->handle == handle && map_data->client == client) { + found = true; + smmu_unmap_cmd.cmd_id = MSM_AUDIO_SMMU_VM_CMD_UNMAP; + smmu_unmap_cmd.export_id = map_data->export_id; + + rc = habmm_socket_send(msm_audio_ion_hab_handle, + (void *)&smmu_unmap_cmd, + sizeof(smmu_unmap_cmd), 0); + if (rc) { + pr_err("%s: habmm_socket_send failed %d\n", + __func__, rc); + goto err; + } + + cmd_rsp_size = sizeof(cmd_rsp); + rc = habmm_socket_recv(msm_audio_ion_hab_handle, + (void *)&cmd_rsp, + &cmd_rsp_size, + 0xFFFFFFFF, + 0); + if (rc) { + pr_err("%s: habmm_socket_recv failed %d\n", + __func__, rc); + goto err; + } + + if (cmd_rsp_size != sizeof(cmd_rsp)) { + pr_err("%s: invalid size for cmd rsp %lu\n", + __func__, cmd_rsp_size); + rc = -EIO; + goto err; + } + + if (cmd_rsp.status) { + pr_err("%s: SMMU unmap command failed %d\n", + __func__, cmd_rsp.status); + rc = cmd_rsp.status; + goto err; + } + + rc = habmm_unexport(msm_audio_ion_hab_handle, + map_data->export_id, 0xFFFFFFFF); + if (rc) { + pr_err("%s: habmm_unexport failed export_id = %d, rc = %d\n", + __func__, map_data->export_id, rc); + } + + list_del(&(map_data->list)); + kfree(map_data); + break; + } + } + mutex_unlock(&(msm_audio_ion_data.smmu_map_mutex)); + + if (!found) { + pr_err("%s: cannot find map_data ion_handle %pK, ion_client %pK\n", + __func__, handle, client); + rc = -EINVAL; + } + + return rc; + +err: + if (found) { + (void)habmm_unexport(msm_audio_ion_hab_handle, + map_data->export_id, 0xFFFFFFFF); + list_del(&(map_data->list)); + kfree(map_data); + } + + mutex_unlock(&(msm_audio_ion_data.smmu_map_mutex)); + return rc; +} + +int msm_audio_ion_alloc(const char *name, struct ion_client **client, + struct ion_handle **handle, size_t bufsz, + ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr) +{ + int rc = -EINVAL; + unsigned long err_ion_ptr = 0; + + if ((msm_audio_ion_data.smmu_enabled == true) && + !(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) { + pr_debug("%s:probe is not done, deferred\n", __func__); + return -EPROBE_DEFER; + } + if (!name || !client || !handle || !paddr || !vaddr + || !bufsz || !pa_len) { + pr_err("%s: Invalid params\n", __func__); + return -EINVAL; + } + *client = msm_audio_ion_client_create(name); + if (IS_ERR_OR_NULL((void *)(*client))) { + pr_err("%s: ION create client for AUDIO failed\n", __func__); + goto err; + } + + *handle = ion_alloc(*client, bufsz, SZ_4K, + ION_HEAP(ION_AUDIO_HEAP_ID), 0); + if (IS_ERR_OR_NULL((void *) (*handle))) { + if (msm_audio_ion_data.smmu_enabled == true) { + pr_debug("system heap is used"); + msm_audio_ion_data.audioheap_enabled = 0; + *handle = ion_alloc(*client, bufsz, SZ_4K, + ION_HEAP(ION_SYSTEM_HEAP_ID), 0); + } + if (IS_ERR_OR_NULL((void *) (*handle))) { + if (IS_ERR((void *)(*handle))) + err_ion_ptr = PTR_ERR((int *)(*handle)); + pr_err("%s:ION alloc fail err ptr=%ld, smmu_enabled=%d\n", + __func__, err_ion_ptr, msm_audio_ion_data.smmu_enabled); + rc = -ENOMEM; + goto err_ion_client; + } + } else { + pr_debug("audio heap is used"); + msm_audio_ion_data.audioheap_enabled = 1; + } + + *vaddr = ion_map_kernel(*client, *handle); + if (IS_ERR_OR_NULL((void *)*vaddr)) { + pr_err("%s: ION memory mapping for AUDIO failed\n", __func__); + goto err_ion_handle; + } + pr_debug("%s: mapped address = %pK, size=%zd\n", __func__, + *vaddr, bufsz); + + if (bufsz != 0) { + pr_debug("%s: memset to 0 %pK %zd\n", __func__, *vaddr, bufsz); + memset((void *)*vaddr, 0, bufsz); + } + + rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len, *vaddr); + if (rc) { + pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n", + __func__, rc); + goto err_get_phys; + } + + return rc; + +err_get_phys: + ion_unmap_kernel(*client, *handle); +err_ion_handle: + ion_free(*client, *handle); +err_ion_client: + msm_audio_ion_client_destroy(*client); + *handle = NULL; + *client = NULL; +err: + return rc; +} +EXPORT_SYMBOL(msm_audio_ion_alloc); + +int msm_audio_ion_import(const char *name, struct ion_client **client, + struct ion_handle **handle, int fd, + unsigned long *ionflag, size_t bufsz, + ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr) +{ + int rc = 0; + + if ((msm_audio_ion_data.smmu_enabled == true) && + !(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) { + pr_debug("%s:probe is not done, deferred\n", __func__); + return -EPROBE_DEFER; + } + + if (!name || !client || !handle || !paddr || !vaddr || !pa_len) { + pr_err("%s: Invalid params\n", __func__); + rc = -EINVAL; + goto err; + } + + *client = msm_audio_ion_client_create(name); + if (IS_ERR_OR_NULL((void *)(*client))) { + pr_err("%s: ION create client for AUDIO failed\n", __func__); + rc = -EINVAL; + goto err; + } + + /* name should be audio_acdb_client or Audio_Dec_Client, + bufsz should be 0 and fd shouldn't be 0 as of now + */ + *handle = ion_import_dma_buf(*client, fd); + pr_debug("%s: DMA Buf name=%s, fd=%d handle=%pK\n", __func__, + name, fd, *handle); + if (IS_ERR_OR_NULL((void *) (*handle))) { + pr_err("%s: ion import dma buffer failed\n", + __func__); + rc = -EINVAL; + goto err_destroy_client; + } + + if (ionflag != NULL) { + rc = ion_handle_get_flags(*client, *handle, ionflag); + if (rc) { + pr_err("%s: could not get flags for the handle\n", + __func__); + goto err_ion_handle; + } + } + + *vaddr = ion_map_kernel(*client, *handle); + if (IS_ERR_OR_NULL((void *)*vaddr)) { + pr_err("%s: ION memory mapping for AUDIO failed\n", __func__); + rc = -ENOMEM; + goto err_ion_handle; + } + pr_debug("%s: mapped address = %pK, size=%zd\n", __func__, + *vaddr, bufsz); + + rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len, *vaddr); + if (rc) { + pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n", + __func__, rc); + goto err_get_phys; + } + + return 0; + +err_get_phys: + ion_unmap_kernel(*client, *handle); +err_ion_handle: + ion_free(*client, *handle); +err_destroy_client: + msm_audio_ion_client_destroy(*client); + *client = NULL; + *handle = NULL; +err: + return rc; +} + +int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle) +{ + int ret = 0; + + if (!client || !handle) { + pr_err("%s Invalid params\n", __func__); + return -EINVAL; + } + + if (msm_audio_ion_data.smmu_enabled) { + ret = msm_audio_ion_smmu_unmap(client, handle); + if (ret) + pr_err("%s: smmu unmap failed with ret %d\n", + __func__, ret); + } + + ion_unmap_kernel(client, handle); + + ion_free(client, handle); + msm_audio_ion_client_destroy(client); + return ret; +} +EXPORT_SYMBOL(msm_audio_ion_free); + +int msm_audio_ion_mmap(struct audio_buffer *ab, + struct vm_area_struct *vma) +{ + struct sg_table *table; + unsigned long addr = vma->vm_start; + unsigned long offset = vma->vm_pgoff * PAGE_SIZE; + struct scatterlist *sg; + unsigned int i; + struct page *page; + int ret; + + pr_debug("%s\n", __func__); + + table = ion_sg_table(ab->client, ab->handle); + + if (IS_ERR(table)) { + pr_err("%s: Unable to get sg_table from ion: %ld\n", + __func__, PTR_ERR(table)); + return PTR_ERR(table); + } else if (!table) { + pr_err("%s: sg_list is NULL\n", __func__); + return -EINVAL; + } + + /* uncached */ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + /* We need to check if a page is associated with this sg list because: + * If the allocation came from a carveout we currently don't have + * pages associated with carved out memory. This might change in the + * future and we can remove this check and the else statement. + */ + page = sg_page(table->sgl); + if (page) { + pr_debug("%s: page is NOT null\n", __func__); + for_each_sg(table->sgl, sg, table->nents, i) { + unsigned long remainder = vma->vm_end - addr; + unsigned long len = sg->length; + + page = sg_page(sg); + + if (offset >= len) { + offset -= len; + continue; + } else if (offset) { + page += offset / PAGE_SIZE; + len -= offset; + offset = 0; + } + len = min(len, remainder); + pr_debug("vma=%pK, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%ld\n", + vma, (unsigned int)addr, len, + (unsigned int)vma->vm_start, + (unsigned int)vma->vm_end, + (unsigned long int)vma->vm_page_prot); + remap_pfn_range(vma, addr, page_to_pfn(page), len, + vma->vm_page_prot); + addr += len; + if (addr >= vma->vm_end) + return 0; + } + } else { + ion_phys_addr_t phys_addr; + size_t phys_len; + size_t va_len = 0; + + pr_debug("%s: page is NULL\n", __func__); + + ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len); + if (ret) { + pr_err("%s: Unable to get phys address from ION buffer: %d\n" + , __func__ , ret); + return ret; + } + pr_debug("phys=%pK len=%zd\n", &phys_addr, phys_len); + pr_debug("vma=%pK, vm_start=%x vm_end=%x vm_pgoff=%ld vm_page_prot=%ld\n", + vma, (unsigned int)vma->vm_start, + (unsigned int)vma->vm_end, vma->vm_pgoff, + (unsigned long int)vma->vm_page_prot); + va_len = vma->vm_end - vma->vm_start; + if ((offset > phys_len) || (va_len > phys_len-offset)) { + pr_err("wrong offset size %ld, lens= %zd, va_len=%zd\n", + offset, phys_len, va_len); + return -EINVAL; + } + ret = remap_pfn_range(vma, vma->vm_start, + __phys_to_pfn(phys_addr) + vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + } + return 0; +} + + +bool msm_audio_ion_is_smmu_available(void) +{ + return msm_audio_ion_data.smmu_enabled; +} + +/* move to static section again */ +struct ion_client *msm_audio_ion_client_create(const char *name) +{ + struct ion_client *pclient = NULL; + + pclient = hvenv_ion_client_create(name); + return pclient; +} + + +void msm_audio_ion_client_destroy(struct ion_client *client) +{ + pr_debug("%s: client = %pK smmu_enabled = %d\n", __func__, + client, msm_audio_ion_data.smmu_enabled); + + ion_client_destroy(client); +} + +int msm_audio_ion_import_legacy(const char *name, struct ion_client *client, + struct ion_handle **handle, int fd, + unsigned long *ionflag, size_t bufsz, + ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr) +{ + int rc = 0; + + if (!name || !client || !handle || !paddr || !vaddr || !pa_len) { + pr_err("%s: Invalid params\n", __func__); + rc = -EINVAL; + goto err; + } + /* client is already created for legacy and given*/ + /* name should be audio_acdb_client or Audio_Dec_Client, + bufsz should be 0 and fd shouldn't be 0 as of now + */ + *handle = ion_import_dma_buf(client, fd); + pr_debug("%s: DMA Buf name=%s, fd=%d handle=%pK\n", __func__, + name, fd, *handle); + if (IS_ERR_OR_NULL((void *)(*handle))) { + pr_err("%s: ion import dma buffer failed\n", + __func__); + rc = -EINVAL; + goto err; + } + + if (ionflag != NULL) { + rc = ion_handle_get_flags(client, *handle, ionflag); + if (rc) { + pr_err("%s: could not get flags for the handle\n", + __func__); + rc = -EINVAL; + goto err_ion_handle; + } + } + + /*Need to add condition SMMU enable or not */ + *vaddr = ion_map_kernel(client, *handle); + if (IS_ERR_OR_NULL((void *)*vaddr)) { + pr_err("%s: ION memory mapping for AUDIO failed\n", __func__); + rc = -EINVAL; + goto err_ion_handle; + } + + if (bufsz != 0) + memset((void *)*vaddr, 0, bufsz); + + rc = msm_audio_ion_get_phys(client, *handle, paddr, pa_len, *vaddr); + if (rc) { + pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n", + __func__, rc); + goto err_get_phys; + } + + return 0; + +err_get_phys: + ion_unmap_kernel(client, *handle); +err_ion_handle: + ion_free(client, *handle); +err: + return rc; +} + +int msm_audio_ion_free_legacy(struct ion_client *client, + struct ion_handle *handle) +{ + ion_unmap_kernel(client, handle); + + ion_free(client, handle); + /* no client_destrody in legacy*/ + return 0; +} + +static int msm_audio_ion_get_phys(struct ion_client *client, + struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len, void *vaddr) +{ + int rc = 0; + + pr_debug("%s: smmu_enabled = %d\n", __func__, + msm_audio_ion_data.smmu_enabled); + + if (msm_audio_ion_data.smmu_enabled) { + rc = msm_audio_ion_smmu_map(client, handle, addr, len, vaddr); + if (rc) { + pr_err("%s: failed to do smmu map, err = %d\n", + __func__, rc); + goto err; + } + } else { + rc = ion_phys(client, handle, addr, len); + } + + pr_debug("%s: phys=%pK, len=%zd, rc=%d\n", + __func__, &(*addr), *len, rc); +err: + return rc; +} + +static const struct of_device_id msm_audio_ion_dt_match[] = { + { .compatible = "qcom,msm-audio-ion-vm" }, + { } +}; +MODULE_DEVICE_TABLE(of, msm_audio_ion_dt_match); + +u32 msm_audio_populate_upper_32_bits(ion_phys_addr_t pa) +{ + return upper_32_bits(pa); +} + +static int msm_audio_ion_probe(struct platform_device *pdev) +{ + int rc = 0; + const char *msm_audio_ion_dt = "qcom,smmu-enabled"; + bool smmu_enabled; + struct device *dev = &pdev->dev; + + if (dev->of_node == NULL) { + pr_err("%s: device tree is not found\n", + __func__); + msm_audio_ion_data.smmu_enabled = 0; + return 0; + } + + smmu_enabled = of_property_read_bool(dev->of_node, + msm_audio_ion_dt); + msm_audio_ion_data.smmu_enabled = smmu_enabled; + + pr_info("%s: SMMU is %s\n", __func__, + (smmu_enabled) ? "Enabled" : "Disabled"); + + if (smmu_enabled) { + rc = habmm_socket_open(&msm_audio_ion_hab_handle, + HAB_MMID_CREATE(MM_AUD_3, + MSM_AUDIO_SMMU_VM_HAB_MINOR_ID), + 0xFFFFFFFF, + HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_FE); + if (rc) { + pr_err("%s: habmm_socket_open failed %d\n", + __func__, rc); + return rc; + } + + pr_info("%s: msm_audio_ion_hab_handle %x\n", + __func__, msm_audio_ion_hab_handle); + + INIT_LIST_HEAD(&msm_audio_ion_data.smmu_map_list); + mutex_init(&(msm_audio_ion_data.smmu_map_mutex)); + } + + if (!rc) + msm_audio_ion_data.device_status |= MSM_AUDIO_ION_PROBED; + + return rc; +} + +static int msm_audio_ion_remove(struct platform_device *pdev) +{ + if (msm_audio_ion_data.smmu_enabled) { + if (msm_audio_ion_hab_handle) + habmm_socket_close(msm_audio_ion_hab_handle); + + mutex_destroy(&(msm_audio_ion_data.smmu_map_mutex)); + } + msm_audio_ion_data.smmu_enabled = 0; + msm_audio_ion_data.device_status = 0; + + return 0; +} + +static struct platform_driver msm_audio_ion_driver = { + .driver = { + .name = "msm-audio-ion-vm", + .owner = THIS_MODULE, + .of_match_table = msm_audio_ion_dt_match, + }, + .probe = msm_audio_ion_probe, + .remove = msm_audio_ion_remove, +}; + +static int __init msm_audio_ion_init(void) +{ + return platform_driver_register(&msm_audio_ion_driver); +} +module_init(msm_audio_ion_init); + +static void __exit msm_audio_ion_exit(void) +{ + platform_driver_unregister(&msm_audio_ion_driver); +} +module_exit(msm_audio_ion_exit); + +MODULE_DESCRIPTION("MSM Audio ION VM module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index f01ab2499a75a8fe83e6f164de22bddb52d9d6cd..0a49a322c9da9d63da39452727260b553c7174a6 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * 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,8 +68,9 @@ static void *dummy_q6_mvm; static void *dummy_q6_cvs; dev_t device_num; +static struct mutex session_lock; static spinlock_t voicesvc_lock; -static bool is_released; +static bool is_released = 1; static int voice_svc_dummy_reg(void); static int voice_svc_dummy_dereg(void); @@ -645,14 +646,23 @@ static int voice_svc_dummy_dereg(void) static int voice_svc_open(struct inode *inode, struct file *file) { struct voice_svc_prvt *prtd = NULL; + int ret = 0; pr_debug("%s\n", __func__); + mutex_lock(&session_lock); + if (is_released == 0) { + pr_err("%s: Access denied to device\n", __func__); + ret = -EBUSY; + goto done; + } + prtd = kmalloc(sizeof(struct voice_svc_prvt), GFP_KERNEL); if (prtd == NULL) { pr_err("%s: kmalloc failed\n", __func__); - return -ENOMEM; + ret = -ENOMEM; + goto done; } memset(prtd, 0, sizeof(struct voice_svc_prvt)); @@ -676,7 +686,9 @@ static int voice_svc_open(struct inode *inode, struct file *file) voice_svc_dummy_reg(); reg_dummy_sess = 1; } - return 0; +done: + mutex_unlock(&session_lock); + return ret; } static int voice_svc_release(struct inode *inode, struct file *file) @@ -810,6 +822,7 @@ static int voice_svc_probe(struct platform_device *pdev) } pr_debug("%s: Device created\n", __func__); spin_lock_init(&voicesvc_lock); + mutex_init(&session_lock); goto done; add_err: @@ -832,6 +845,7 @@ static int voice_svc_remove(struct platform_device *pdev) kfree(voice_svc_dev->cdev); device_destroy(voice_svc_class, device_num); class_destroy(voice_svc_class); + mutex_destroy(&session_lock); unregister_chrdev_region(0, MINOR_NUMBER); return 0; diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c new file mode 100644 index 0000000000000000000000000000000000000000..5294be9f0bd3d347952259160d4ad00f17c88f89 --- /dev/null +++ b/drivers/soc/qcom/qdss_bridge.c @@ -0,0 +1,461 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * 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. + */ + +#define KMSG_COMPONENT "QDSS diag bridge" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qdss_bridge.h" + +#define MODULE_NAME "qdss_bridge" + +#define QDSS_BUF_SIZE (16*1024) +#define MHI_CLIENT_QDSS_IN 9 + +/* Max number of objects needed */ +static int poolsize = 32; +module_param(poolsize, int, 0644); + +/* Size of single buffer */ +static int itemsize = QDSS_BUF_SIZE; +module_param(itemsize, int, 0644); + +static int qdss_destroy_buf_tbl(struct qdss_bridge_drvdata *drvdata) +{ + struct list_head *start, *temp; + struct qdss_buf_tbl_lst *entry = NULL; + + list_for_each_safe(start, temp, &drvdata->buf_tbl) { + entry = list_entry(start, struct qdss_buf_tbl_lst, link); + list_del(&entry->link); + kfree(entry->buf); + kfree(entry->usb_req); + kfree(entry); + } + + return 0; +} + +static int qdss_create_buf_tbl(struct qdss_bridge_drvdata *drvdata) +{ + struct qdss_buf_tbl_lst *entry; + void *buf; + struct qdss_request *usb_req; + int i; + + for (i = 0; i < poolsize; i++) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + goto err; + + buf = kzalloc(QDSS_BUF_SIZE, GFP_KERNEL); + usb_req = kzalloc(sizeof(*usb_req), GFP_KERNEL); + + entry->buf = buf; + entry->usb_req = usb_req; + atomic_set(&entry->available, 1); + list_add_tail(&entry->link, &drvdata->buf_tbl); + + if (!buf || !usb_req) + goto err; + } + + return 0; +err: + qdss_destroy_buf_tbl(drvdata); + return -ENOMEM; +} + +struct qdss_buf_tbl_lst *qdss_get_buf_tbl_entry( + struct qdss_bridge_drvdata *drvdata, + void *buf) +{ + struct qdss_buf_tbl_lst *entry; + + list_for_each_entry(entry , &drvdata->buf_tbl, link) { + if (atomic_read(&entry->available)) + continue; + if (entry->buf == buf) + return entry; + } + + return NULL; +} + +struct qdss_buf_tbl_lst *qdss_get_entry(struct qdss_bridge_drvdata *drvdata) +{ + struct qdss_buf_tbl_lst *item; + + list_for_each_entry(item, &drvdata->buf_tbl, link) + if (atomic_cmpxchg(&item->available, 1, 0) == 1) + return item; + + return NULL; +} + +static void qdss_buf_tbl_remove(struct qdss_bridge_drvdata *drvdata, + void *buf) +{ + struct qdss_buf_tbl_lst *entry = NULL; + + list_for_each_entry(entry, &drvdata->buf_tbl, link) { + if (entry->buf != buf) + continue; + atomic_set(&entry->available, 1); + return; + } + + pr_err_ratelimited("Failed to find buffer for removal\n"); +} + +static void mhi_ch_close(struct qdss_bridge_drvdata *drvdata) +{ + flush_workqueue(drvdata->mhi_wq); + qdss_destroy_buf_tbl(drvdata); + mhi_close_channel(drvdata->hdl); +} + +static void mhi_close_work_fn(struct work_struct *work) +{ + struct qdss_bridge_drvdata *drvdata = + container_of(work, + struct qdss_bridge_drvdata, + close_work); + + usb_qdss_close(drvdata->usb_ch); + mhi_ch_close(drvdata); +} + +static void mhi_read_work_fn(struct work_struct *work) +{ + int err = 0; + enum MHI_FLAGS mhi_flags = MHI_EOT; + struct qdss_buf_tbl_lst *entry; + + struct qdss_bridge_drvdata *drvdata = + container_of(work, + struct qdss_bridge_drvdata, + read_work); + + do { + if (!drvdata->opened) + break; + entry = qdss_get_entry(drvdata); + if (!entry) + break; + + err = mhi_queue_xfer(drvdata->hdl, entry->buf, QDSS_BUF_SIZE, + mhi_flags); + if (err) { + pr_err_ratelimited("Unable to read from MHI buffer err:%d", + err); + goto fail; + } + } while (entry); + + return; +fail: + qdss_buf_tbl_remove(drvdata, entry->buf); + queue_work(drvdata->mhi_wq, &drvdata->read_work); +} + +static int mhi_queue_read(struct qdss_bridge_drvdata *drvdata) +{ + queue_work(drvdata->mhi_wq, &(drvdata->read_work)); + return 0; +} + +static int usb_write(struct qdss_bridge_drvdata *drvdata, + struct mhi_result *result) +{ + int ret = 0; + struct qdss_buf_tbl_lst *entry; + + entry = qdss_get_buf_tbl_entry(drvdata, result->buf_addr); + if (!entry) + return -EINVAL; + + entry->usb_req->buf = result->buf_addr; + entry->usb_req->length = result->bytes_xferd; + ret = usb_qdss_data_write(drvdata->usb_ch, entry->usb_req); + + return ret; +} + +static void mhi_read_done_work_fn(struct work_struct *work) +{ + unsigned char *buf = NULL; + struct mhi_result result; + int err = 0; + struct qdss_bridge_drvdata *drvdata = + container_of(work, + struct qdss_bridge_drvdata, + read_done_work); + + do { + err = mhi_poll_inbound(drvdata->hdl, &result); + if (err) { + pr_debug("MHI poll failed err:%d\n", err); + break; + } + buf = result.buf_addr; + if (!buf) + break; + err = usb_write(drvdata, &result); + if (err) + qdss_buf_tbl_remove(drvdata, buf); + } while (1); +} + +static void usb_write_done(struct qdss_bridge_drvdata *drvdata, + struct qdss_request *d_req) +{ + if (d_req->status) { + pr_err_ratelimited("USB write failed err:%d\n", d_req->status); + mhi_queue_read(drvdata); + return; + } + qdss_buf_tbl_remove(drvdata, d_req->buf); + mhi_queue_read(drvdata); +} + +static void usb_notifier(void *priv, unsigned int event, + struct qdss_request *d_req, struct usb_qdss_ch *ch) +{ + struct qdss_bridge_drvdata *drvdata = priv; + + if (!drvdata) + return; + + switch (event) { + case USB_QDSS_CONNECT: + usb_qdss_alloc_req(drvdata->usb_ch, poolsize, 0); + mhi_queue_read(drvdata); + break; + + case USB_QDSS_DISCONNECT: + /* Leave MHI/USB open.Only close on MHI disconnect */ + break; + + case USB_QDSS_DATA_WRITE_DONE: + usb_write_done(drvdata, d_req); + break; + + default: + break; + } +} + +static int mhi_ch_open(struct qdss_bridge_drvdata *drvdata) +{ + int ret; + + if (drvdata->opened) + return 0; + + ret = mhi_open_channel(drvdata->hdl); + if (ret) { + pr_err("Unable to open MHI channel\n"); + return ret; + } + + ret = mhi_get_free_desc(drvdata->hdl); + if (ret <= 0) + return -EIO; + + drvdata->opened = 1; + return 0; +} + +static void qdss_bridge_open_work_fn(struct work_struct *work) +{ + struct qdss_bridge_drvdata *drvdata = + container_of(work, + struct qdss_bridge_drvdata, + open_work); + int ret; + + ret = mhi_ch_open(drvdata); + if (ret) + goto err_open; + + ret = qdss_create_buf_tbl(drvdata); + if (ret) + goto err; + + drvdata->usb_ch = usb_qdss_open("PCIE", drvdata, usb_notifier); + if (IS_ERR_OR_NULL(drvdata->usb_ch)) { + ret = PTR_ERR(drvdata->usb_ch); + goto err; + } + + return; +err: + mhi_ch_close(drvdata); +err_open: + pr_err("Open work failed with err:%d\n", ret); +} + +static void mhi_notifier(struct mhi_cb_info *cb_info) +{ + struct mhi_result *result; + struct qdss_bridge_drvdata *drvdata; + + if (!cb_info) + return; + + result = cb_info->result; + if (!result) { + pr_err_ratelimited("Failed to obtain MHI result\n"); + return; + } + + drvdata = (struct qdss_bridge_drvdata *)cb_info->result->user_data; + if (!drvdata) { + pr_err_ratelimited("MHI returned invalid drvdata\n"); + return; + } + + switch (cb_info->cb_reason) { + case MHI_CB_MHI_ENABLED: + queue_work(drvdata->mhi_wq, &drvdata->open_work); + break; + + case MHI_CB_XFER: + if (!drvdata->opened) + break; + + queue_work(drvdata->mhi_wq, &drvdata->read_done_work); + break; + + case MHI_CB_MHI_DISABLED: + if (!drvdata->opened) + break; + + drvdata->opened = 0; + queue_work(drvdata->mhi_wq, &drvdata->close_work); + break; + + default: + pr_err_ratelimited("MHI returned invalid cb reason 0x%x\n", + cb_info->cb_reason); + break; + } +} + +static int qdss_mhi_register_ch(struct qdss_bridge_drvdata *drvdata) +{ + struct mhi_client_info_t *client_info; + int ret; + struct mhi_client_info_t *mhi_info; + + client_info = devm_kzalloc(drvdata->dev, sizeof(*client_info), + GFP_KERNEL); + if (!client_info) + return -ENOMEM; + + client_info->mhi_client_cb = mhi_notifier; + drvdata->client_info = client_info; + + mhi_info = client_info; + mhi_info->chan = MHI_CLIENT_QDSS_IN; + mhi_info->dev = drvdata->dev; + mhi_info->node_name = "qcom,mhi"; + mhi_info->user_data = drvdata; + + ret = mhi_register_channel(&drvdata->hdl, mhi_info); + return ret; +} + +int qdss_mhi_init(struct qdss_bridge_drvdata *drvdata) +{ + int ret; + + drvdata->mhi_wq = create_singlethread_workqueue(MODULE_NAME); + if (!drvdata->mhi_wq) + return -ENOMEM; + + INIT_WORK(&(drvdata->read_work), mhi_read_work_fn); + INIT_WORK(&(drvdata->read_done_work), mhi_read_done_work_fn); + INIT_WORK(&(drvdata->open_work), qdss_bridge_open_work_fn); + INIT_WORK(&(drvdata->close_work), mhi_close_work_fn); + INIT_LIST_HEAD(&drvdata->buf_tbl); + drvdata->opened = 0; + + ret = qdss_mhi_register_ch(drvdata); + if (ret) { + destroy_workqueue(drvdata->mhi_wq); + pr_err("Unable to register MHI read channel err:%d\n", ret); + return ret; + } + + return 0; +} + +static int qdss_mhi_probe(struct platform_device *pdev) +{ + int ret; + struct device *dev = &pdev->dev; + struct qdss_bridge_drvdata *drvdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) { + ret = -ENOMEM; + return ret; + } + + drvdata->dev = &pdev->dev; + platform_set_drvdata(pdev, drvdata); + + ret = qdss_mhi_init(drvdata); + if (ret) + goto err; + + return 0; +err: + pr_err("Device probe failed err:%d\n", ret); + return ret; +} + +static const struct of_device_id qdss_mhi_table[] = { + {.compatible = "qcom,qdss-mhi"}, + {}, +}; + +static struct platform_driver qdss_mhi_driver = { + .probe = qdss_mhi_probe, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + .of_match_table = qdss_mhi_table, + }, +}; + +static int __init qdss_bridge_init(void) +{ + return platform_driver_register(&qdss_mhi_driver); +} + +static void __exit qdss_bridge_exit(void) +{ + platform_driver_unregister(&qdss_mhi_driver); +} + +module_init(qdss_bridge_init); +module_exit(qdss_bridge_exit); diff --git a/drivers/soc/qcom/qdss_bridge.h b/drivers/soc/qcom/qdss_bridge.h new file mode 100644 index 0000000000000000000000000000000000000000..97b9c4099141c10526a3375559dbbda771953e39 --- /dev/null +++ b/drivers/soc/qcom/qdss_bridge.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * 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. + */ + +#ifndef _QDSS_BRIDGE_H +#define _QDSS_BRIDGE_H + +struct qdss_buf_tbl_lst { + struct list_head link; + unsigned char *buf; + struct qdss_request *usb_req; + atomic_t available; +}; + +struct qdss_bridge_drvdata { + struct device *dev; + bool opened; + struct work_struct read_work; + struct work_struct read_done_work; + struct work_struct open_work; + struct work_struct close_work; + struct workqueue_struct *mhi_wq; + struct mhi_client_handle *hdl; + struct mhi_client_info_t *client_info; + struct list_head buf_tbl; + struct usb_qdss_ch *usb_ch; +}; + +#endif diff --git a/drivers/soc/qcom/qpnp-pbs.c b/drivers/soc/qcom/qpnp-pbs.c index 033ee63810170152ecdf40fa986845a1eee3b897..cbdadb80cbcd16a8bac47666fb0328f18ebb8a29 100644 --- a/drivers/soc/qcom/qpnp-pbs.c +++ b/drivers/soc/qcom/qpnp-pbs.c @@ -115,7 +115,7 @@ static int qpnp_pbs_wait_for_ack(struct qpnp_pbs *pbs, u8 bit_pos) u16 retries = 2000; u8 val; - while (retries--) { + while (retries) { rc = qpnp_pbs_read(pbs, pbs->base + PBS_CLIENT_SCRATCH2, &val, 1); if (rc < 0) { @@ -144,6 +144,7 @@ static int qpnp_pbs_wait_for_ack(struct qpnp_pbs *pbs, u8 bit_pos) } usleep_range(QPNP_PBS_RETRY_SLEEP, QPNP_PBS_RETRY_SLEEP + 100); + retries--; } if (!retries) { @@ -282,11 +283,8 @@ int qpnp_pbs_trigger_event(struct device_node *dev_node, u8 bitmap) error: /* Clear all the requested bitmap */ - rc = qpnp_pbs_masked_write(pbs, pbs->base + PBS_CLIENT_SCRATCH1, + qpnp_pbs_masked_write(pbs, pbs->base + PBS_CLIENT_SCRATCH1, bitmap, 0); - if (rc < 0) - pr_err("Failed to clear %x reg bit rc=%d\n", - PBS_CLIENT_SCRATCH1, rc); out: mutex_unlock(&pbs->pbs_lock); diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index 6f5bd217d0c9548eed95487976aa6f472015cafb..88e919af657a9247eef4af9a6f8515e5de46cc81 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved. * * 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 @@ -625,28 +625,7 @@ static int allocate_extra_arg_buffer(struct scm_desc *desc, gfp_t flags) return 0; } -/** - * scm_call2() - Invoke a syscall in the secure world - * @fn_id: The function ID for this syscall - * @desc: Descriptor structure containing arguments and return values - * - * Sends a command to the SCM and waits for the command to finish processing. - * This should *only* be called in pre-emptible context. - * - * A note on cache maintenance: - * Note that any buffers that are expected to be accessed by the secure world - * must be flushed before invoking scm_call and invalidated in the cache - * immediately after scm_call returns. An important point that must be noted - * is that on ARMV8 architectures, invalidation actually also causes a dirty - * cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of - * paramount importance that the buffer be flushed before invoking scm_call2, - * even if you don't care about the contents of that buffer. - * - * Note that cache maintenance on the argument buffer (desc->args) is taken care - * of by scm_call2; however, callers are responsible for any other cached - * buffers passed over to the secure world. -*/ -int scm_call2(u32 fn_id, struct scm_desc *desc) +static int __scm_call2(u32 fn_id, struct scm_desc *desc, bool retry) { int arglen = desc->arginfo & 0xf; int ret, retry_count = 0; @@ -660,7 +639,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) return ret; x0 = fn_id | scm_version_mask; - do { mutex_lock(&scm_lock); @@ -690,13 +668,15 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) mutex_unlock(&scm_lmh_lock); mutex_unlock(&scm_lock); + if (!retry) + goto out; if (ret == SCM_V2_EBUSY) msleep(SCM_EBUSY_WAIT_MS); if (retry_count == 33) pr_warn("scm: secure world has been busy for 1 second!\n"); - } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY)); - + } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY)); +out: if (ret < 0) pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]); @@ -707,8 +687,46 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) return scm_remap_error(ret); return 0; } + +/** + * scm_call2() - Invoke a syscall in the secure world + * @fn_id: The function ID for this syscall + * @desc: Descriptor structure containing arguments and return values + * + * Sends a command to the SCM and waits for the command to finish processing. + * This should *only* be called in pre-emptible context. + * + * A note on cache maintenance: + * Note that any buffers that are expected to be accessed by the secure world + * must be flushed before invoking scm_call and invalidated in the cache + * immediately after scm_call returns. An important point that must be noted + * is that on ARMV8 architectures, invalidation actually also causes a dirty + * cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of + * paramount importance that the buffer be flushed before invoking scm_call2, + * even if you don't care about the contents of that buffer. + * + * Note that cache maintenance on the argument buffer (desc->args) is taken care + * of by scm_call2; however, callers are responsible for any other cached + * buffers passed over to the secure world. + */ +int scm_call2(u32 fn_id, struct scm_desc *desc) +{ + return __scm_call2(fn_id, desc, true); +} EXPORT_SYMBOL(scm_call2); +/** + * scm_call2_noretry() - Invoke a syscall in the secure world + * + * Similar to scm_call2 except that there is no retry mechanism + * implemented. + */ +int scm_call2_noretry(u32 fn_id, struct scm_desc *desc) +{ + return __scm_call2(fn_id, desc, false); +} +EXPORT_SYMBOL(scm_call2_noretry); + /** * scm_call2_atomic() - Invoke a syscall in the secure world * diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c index 97bf4a5c31dd0c1d6e14a0d596aaeebbd7e80753..6576a954c425e6abf6f3bfa017260d6125490d27 100644 --- a/drivers/soc/qcom/secure_buffer.c +++ b/drivers/soc/qcom/secure_buffer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Google, Inc - * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * 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 @@ -43,11 +43,6 @@ struct mem_prot_info { u64 size; }; -struct info_list { - struct mem_prot_info *list_head; - u64 list_size; -}; - #define MEM_PROT_ASSIGN_ID 0x16 #define MEM_PROTECT_LOCK_ID2 0x0A #define MEM_PROTECT_LOCK_ID2_FLAT 0x11 @@ -61,14 +56,8 @@ struct dest_vm_and_perm_info { u32 ctx_size; }; -struct dest_info_list { - struct dest_vm_and_perm_info *dest_info; - u64 list_size; -}; - -static void *qcom_secure_mem; -#define QCOM_SECURE_MEM_SIZE (512*1024) -#define PADDING 32 +#define BATCH_MAX_SIZE SZ_2M +#define BATCH_MAX_SECTIONS 32 static int secure_buffer_change_chunk(u32 chunks, u32 nchunks, @@ -155,7 +144,8 @@ static int secure_buffer_change_table(struct sg_table *table, int lock) * secure environment to ensure the data is actually present * in RAM */ - dmac_flush_range(chunk_list, chunk_list + chunk_list_len); + dmac_flush_range(chunk_list, + (void *)chunk_list + chunk_list_len); ret = secure_buffer_change_chunk(virt_to_phys(chunk_list), nchunks, V2_CHUNK_SIZE, lock); @@ -200,14 +190,22 @@ int msm_unsecure_table(struct sg_table *table) } -static void populate_dest_info(int *dest_vmids, int nelements, - int *dest_perms, struct dest_info_list **list, - void *current_qcom_secure_mem) +static struct dest_vm_and_perm_info * +populate_dest_info(int *dest_vmids, int nelements, int *dest_perms, + size_t *size_in_bytes) { struct dest_vm_and_perm_info *dest_info; int i; + size_t size; - dest_info = (struct dest_vm_and_perm_info *)current_qcom_secure_mem; + /* Ensure allocated size is less than PAGE_ALLOC_COSTLY_ORDER */ + size = nelements * sizeof(*dest_info); + if (size > PAGE_SIZE) + return NULL; + + dest_info = kzalloc(size, GFP_KERNEL); + if (!dest_info) + return NULL; for (i = 0; i < nelements; i++) { dest_info[i].vm = dest_vmids[i]; @@ -216,30 +214,71 @@ static void populate_dest_info(int *dest_vmids, int nelements, dest_info[i].ctx_size = 0; } - *list = (struct dest_info_list *)&dest_info[i]; + *size_in_bytes = size; + return dest_info; +} - (*list)->dest_info = dest_info; - (*list)->list_size = nelements * sizeof(struct dest_vm_and_perm_info); +/* Must hold secure_buffer_mutex while allocated buffer is in use */ +static unsigned int get_batches_from_sgl(struct mem_prot_info *sg_table_copy, + struct scatterlist *sgl, + struct scatterlist **next_sgl) +{ + u64 batch_size = 0; + unsigned int i = 0; + struct scatterlist *curr_sgl = sgl; + + /* Ensure no zero size batches */ + do { + sg_table_copy[i].addr = page_to_phys(sg_page(curr_sgl)); + sg_table_copy[i].size = curr_sgl->length; + batch_size += sg_table_copy[i].size; + curr_sgl = sg_next(curr_sgl); + i++; + } while (curr_sgl && i < BATCH_MAX_SECTIONS && + curr_sgl->length + batch_size < BATCH_MAX_SIZE); + + *next_sgl = curr_sgl; + return i; } -static void get_info_list_from_table(struct sg_table *table, - struct info_list **list) +static int batched_hyp_assign(struct sg_table *table, struct scm_desc *desc) { - int i; - struct scatterlist *sg; - struct mem_prot_info *info; + unsigned int entries_size; + unsigned int batch_start = 0; + unsigned int batches_processed; + struct scatterlist *curr_sgl = table->sgl; + struct scatterlist *next_sgl; + int ret = 0; + struct mem_prot_info *sg_table_copy = kcalloc(BATCH_MAX_SECTIONS, + sizeof(*sg_table_copy), + GFP_KERNEL); - info = (struct mem_prot_info *)qcom_secure_mem; + if (!sg_table_copy) + return -ENOMEM; - for_each_sg(table->sgl, sg, table->nents, i) { - info[i].addr = page_to_phys(sg_page(sg)); - info[i].size = sg->length; - } + while (batch_start < table->nents) { + batches_processed = get_batches_from_sgl(sg_table_copy, + curr_sgl, &next_sgl); + curr_sgl = next_sgl; + entries_size = batches_processed * sizeof(*sg_table_copy); + dmac_flush_range(sg_table_copy, + (void *)sg_table_copy + entries_size); + desc->args[0] = virt_to_phys(sg_table_copy); + desc->args[1] = entries_size; - *list = (struct info_list *)&(info[i]); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + MEM_PROT_ASSIGN_ID), desc); + if (ret) { + pr_info("%s: Failed to assign memory protection, ret = %d\n", + __func__, ret); + break; + } + + batch_start += batches_processed; + } - (*list)->list_head = info; - (*list)->list_size = table->nents * sizeof(struct mem_prot_info); + kfree(sg_table_copy); + return ret; } int hyp_assign_table(struct sg_table *table, @@ -248,74 +287,56 @@ int hyp_assign_table(struct sg_table *table, int dest_nelems) { int ret; - struct info_list *info_list = NULL; - struct dest_info_list *dest_info_list = NULL; struct scm_desc desc = {0}; u32 *source_vm_copy; - void *current_qcom_secure_mem; + size_t source_vm_copy_size; + struct dest_vm_and_perm_info *dest_vm_copy; + size_t dest_vm_copy_size; - size_t reqd_size = dest_nelems * sizeof(struct dest_vm_and_perm_info) + - table->nents * sizeof(struct mem_prot_info) + - sizeof(dest_info_list) + sizeof(info_list) + PADDING; - - if (!qcom_secure_mem) { - pr_err("%s is not functional as qcom_secure_mem is not allocated.\n", - __func__); - return -ENOMEM; - } - - if (QCOM_SECURE_MEM_SIZE < reqd_size) { - pr_err("%s: Not enough memory allocated. Required size %zd\n", - __func__, reqd_size); + if (!table || !table->sgl || !source_vm_list || !source_nelems || + !dest_vmids || !dest_perms || !dest_nelems) return -EINVAL; - } /* * We can only pass cache-aligned sizes to hypervisor, so we need * to kmalloc and memcpy the source_vm_list here. */ - source_vm_copy = kmalloc_array( - source_nelems, sizeof(*source_vm_copy), GFP_KERNEL); - if (!source_vm_copy) { + source_vm_copy_size = sizeof(*source_vm_copy) * source_nelems; + source_vm_copy = kzalloc(source_vm_copy_size, GFP_KERNEL); + if (!source_vm_copy) return -ENOMEM; - } - memcpy(source_vm_copy, source_vm_list, - sizeof(*source_vm_list) * source_nelems); + memcpy(source_vm_copy, source_vm_list, source_vm_copy_size); - mutex_lock(&secure_buffer_mutex); - get_info_list_from_table(table, &info_list); + dest_vm_copy = populate_dest_info(dest_vmids, dest_nelems, dest_perms, + &dest_vm_copy_size); + if (!dest_vm_copy) { + ret = -ENOMEM; + goto out_free_source; + } - current_qcom_secure_mem = &(info_list[1]); - populate_dest_info(dest_vmids, dest_nelems, dest_perms, - &dest_info_list, current_qcom_secure_mem); + mutex_lock(&secure_buffer_mutex); - desc.args[0] = virt_to_phys(info_list->list_head); - desc.args[1] = info_list->list_size; desc.args[2] = virt_to_phys(source_vm_copy); - desc.args[3] = sizeof(*source_vm_copy) * source_nelems; - desc.args[4] = virt_to_phys(dest_info_list->dest_info); - desc.args[5] = dest_info_list->list_size; + desc.args[3] = source_vm_copy_size; + desc.args[4] = virt_to_phys(dest_vm_copy); + desc.args[5] = dest_vm_copy_size; desc.args[6] = 0; desc.arginfo = SCM_ARGS(7, SCM_RO, SCM_VAL, SCM_RO, SCM_VAL, SCM_RO, SCM_VAL, SCM_VAL); - dmac_flush_range(source_vm_copy, source_vm_copy + source_nelems); - dmac_flush_range(info_list->list_head, info_list->list_head + - (info_list->list_size / sizeof(*info_list->list_head))); - dmac_flush_range(dest_info_list->dest_info, dest_info_list->dest_info + - (dest_info_list->list_size / - sizeof(*dest_info_list->dest_info))); + dmac_flush_range(source_vm_copy, + (void *)source_vm_copy + source_vm_copy_size); + dmac_flush_range(dest_vm_copy, + (void *)dest_vm_copy + dest_vm_copy_size); - ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, - MEM_PROT_ASSIGN_ID), &desc); - if (ret) - pr_info("%s: Failed to assign memory protection, ret = %d\n", - __func__, ret); + ret = batched_hyp_assign(table, &desc); mutex_unlock(&secure_buffer_mutex); + kfree(dest_vm_copy); +out_free_source: kfree(source_vm_copy); return ret; } @@ -389,23 +410,3 @@ bool msm_secure_v2_is_supported(void) */ return version >= MAKE_CP_VERSION(1, 1, 0); } - -static int __init alloc_secure_shared_memory(void) -{ - int ret = 0; - dma_addr_t dma_handle; - - qcom_secure_mem = kzalloc(QCOM_SECURE_MEM_SIZE, GFP_KERNEL); - if (!qcom_secure_mem) { - /* Fallback to CMA-DMA memory */ - qcom_secure_mem = dma_alloc_coherent(NULL, QCOM_SECURE_MEM_SIZE, - &dma_handle, GFP_KERNEL); - if (!qcom_secure_mem) { - pr_err("Couldn't allocate memory for secure use-cases. hyp_assign_table will not work\n"); - return -ENOMEM; - } - } - - return ret; -} -pure_initcall(alloc_secure_shared_memory); diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index aa3eb8606626bd535d9d9c119915081501bf2aab..06f14bc0328e2a5604e4ffa8147845c74671cd02 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * 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 @@ -11,6 +11,8 @@ */ #include +#include +#include #include #include #include @@ -19,9 +21,16 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include "smcinvoke_object.h" +#include +#include "../../misc/qseecom_kernel.h" #define SMCINVOKE_TZ_PARAM_ID 0x224 #define SMCINVOKE_TZ_CMD 0x32000600 @@ -30,6 +39,14 @@ #define SMCINVOKE_TZ_MIN_BUF_SIZE 4096 #define SMCINVOKE_ARGS_ALIGN_SIZE (sizeof(uint64_t)) #define SMCINVOKE_TZ_OBJ_NULL 0 +#define SMCINVOKE_CE_CLK_100MHZ 100000000 +#define SMCINVOKE_CE_CLK_DIV 1000000 +#define SMCINVOKE_DEINIT_CLK(x) \ + { if (x) { clk_put(x); x = NULL; } } +#define SMCINVOKE_ENABLE_CLK(x) \ + { if (x) clk_prepare_enable(x); } +#define SMCINVOKE_DISABLE_CLK(x) \ + { if (x) clk_disable_unprepare(x); } #define FOR_ARGS(ndxvar, counts, section) \ for (ndxvar = object_counts_index_##section(counts); \ @@ -37,6 +54,7 @@ + object_counts_num_##section(counts)); \ ++ndxvar) +static DEFINE_MUTEX(smcinvoke_lock); static long smcinvoke_ioctl(struct file *, unsigned , unsigned long); static int smcinvoke_open(struct inode *, struct file *); static int smcinvoke_release(struct inode *, struct file *); @@ -49,11 +67,28 @@ static const struct file_operations smcinvoke_fops = { .release = smcinvoke_release, }; -static struct miscdevice smcinvoke_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "smcinvoke", - .fops = &smcinvoke_fops +enum clk_types { CE_CORE_SRC_CLK, CE_CORE_CLK, CE_CLK, CE_BUS_CLK, CE_MAX_CLK }; +static const char *clk_names[CE_MAX_CLK] = { + "core_clk_src", "core_clk", "iface_clk", "bus_clk" }; +enum bandwidth_request_mode {BW_INACTIVE = 0, BW_HIGH}; + +static dev_t smcinvoke_device_no; +static struct cdev smcinvoke_cdev; +static struct class *driver_class; +static struct device *class_dev; +static struct platform_device *smcinvoke_pdev; +static struct msm_bus_scale_pdata *bus_scale_pdata; +static uint32_t qsee_perf_client; +static bool support_clocks; +static uint32_t ce_opp_freq_hz; +static enum bandwidth_request_mode current_mode; + +struct smcinvoke_clk { + struct clk *clks[CE_MAX_CLK]; + uint32_t clk_access_cnt; +}; +static struct smcinvoke_clk g_clk; struct smcinvoke_buf_hdr { uint32_t offset; @@ -101,6 +136,130 @@ static inline size_t size_align(size_t a, size_t b) return size_add(a, pad_size(a, b)); } +static void disable_clocks(void) +{ + int i; + + if (g_clk.clk_access_cnt == 0 || --g_clk.clk_access_cnt > 0) + return; + + for (i = CE_MAX_CLK; i > 0; i--) + SMCINVOKE_DISABLE_CLK(g_clk.clks[i-1]); +} + +static int enable_clocks(void) +{ + int rc = 0, i, j; + + if (g_clk.clk_access_cnt > 0) + goto out; + + for (i = 0; i < CE_MAX_CLK; i++) { + if (g_clk.clks[i]) { + rc = clk_prepare_enable(g_clk.clks[i]); + if (rc) { + pr_err("Err %d enabling %s", rc, clk_names[i]); + break; + } + } + } + if (rc) { + for (j = i-1; j >= 0; j--) + SMCINVOKE_DISABLE_CLK(g_clk.clks[j]); + return rc; + } +out: + g_clk.clk_access_cnt++; + return rc; +} + +static int set_msm_bus_request_locked(enum bandwidth_request_mode mode) +{ + int ret = 0; + + if (support_clocks == 0) + return ret; + + if (g_clk.clks[CE_CORE_SRC_CLK] == NULL) { + pr_err("%s clock NULL\n", __func__); + return ret; + } + + if (mode == BW_INACTIVE) { + disable_clocks(); + } else { + ret = enable_clocks(); + if (ret) + goto out; + } + + if (current_mode != mode) { + ret = msm_bus_scale_client_update_request( + qsee_perf_client, mode); + if (ret) { + pr_err("BW req failed(%d) MODE (%d)\n", ret, mode); + if (mode == BW_INACTIVE) + enable_clocks(); + else + disable_clocks(); + goto out; + } + current_mode = mode; + } +out: + return ret; +} + +static void deinit_clocks(void) +{ + int i; + + for (i = CE_MAX_CLK; i > 0; i--) + SMCINVOKE_DEINIT_CLK(g_clk.clks[i-1]) + + g_clk.clk_access_cnt = 0; +} + +static struct clk *get_clk(const char *clk_name) +{ + int rc = 0; + struct clk *clk = clk_get(class_dev, clk_name); + + if (!IS_ERR(clk)) { + if (!strcmp(clk_name, clk_names[CE_CORE_SRC_CLK])) { + rc = clk_set_rate(clk, ce_opp_freq_hz); + if (rc) { + SMCINVOKE_DEINIT_CLK(clk); + pr_err("Err %d setting clk %s to %uMhz\n", + rc, clk_name, + ce_opp_freq_hz/SMCINVOKE_CE_CLK_DIV); + } + } + } else { + pr_warn("Err %d getting clk %s\n", IS_ERR(clk), clk_name); + clk = NULL; + } + return clk; +} + +static int init_clocks(void) +{ + int i = 0; + int rc = -1; + + for (i = 0; i < CE_MAX_CLK; i++) { + g_clk.clks[i] = get_clk(clk_names[i]); + if (!g_clk.clks[i]) + goto exit; + } + g_clk.clk_access_cnt = 0; + return 0; +exit: + for ( ; i >= 0; i--) + SMCINVOKE_DEINIT_CLK(g_clk.clks[i]); + return rc; +} + /* * This function retrieves file pointer corresponding to FD provided. It stores * retrived file pointer until IOCTL call is concluded. Once call is completed, @@ -190,21 +349,33 @@ static int prepare_send_scm_msg(const uint8_t *in_buf, size_t in_buf_len, desc.arginfo = SMCINVOKE_TZ_PARAM_ID; desc.args[0] = (uint64_t)virt_to_phys(in_buf); - desc.args[1] = in_buf_len; + desc.args[1] = inbuf_flush_size; desc.args[2] = (uint64_t)virt_to_phys(out_buf); - desc.args[3] = out_buf_len; + desc.args[3] = outbuf_flush_size; dmac_flush_range(in_buf, in_buf + inbuf_flush_size); dmac_flush_range(out_buf, out_buf + outbuf_flush_size); + mutex_lock(&smcinvoke_lock); + set_msm_bus_request_locked(BW_HIGH); + mutex_unlock(&smcinvoke_lock); ret = scm_call2(SMCINVOKE_TZ_CMD, &desc); + + /* process listener request */ + if (!ret && (desc.ret[0] == QSEOS_RESULT_INCOMPLETE || + desc.ret[0] == QSEOS_RESULT_BLOCKED_ON_LISTENER)) + ret = qseecom_process_listener_from_smcinvoke(&desc); + + mutex_lock(&smcinvoke_lock); + set_msm_bus_request_locked(BW_INACTIVE); + mutex_unlock(&smcinvoke_lock); + *smcinvoke_result = (int32_t)desc.ret[1]; - if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0]) { + if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0]) pr_err("SCM call failed with ret val = %d %d %d %d\n", ret, (int)desc.ret[0], (int)desc.ret[1], (int)desc.ret[2]); - ret = ret | desc.ret[0] | desc.ret[1] | desc.ret[2]; - } + dmac_inv_range(in_buf, in_buf + inbuf_flush_size); dmac_inv_range(out_buf, out_buf + outbuf_flush_size); return ret; @@ -235,7 +406,7 @@ static int marshal_out(void *buf, uint32_t buf_size, pr_err("%s: buffer overflow detected\n", __func__); goto out; } - if (copy_to_user((void __user *)(args_buf[i].b.addr), + if (copy_to_user((void __user *)(uintptr_t)(args_buf[i].b.addr), (uint8_t *)(buf) + tz_args->b.offset, tz_args->b.size)) { pr_err("Error %d copying ctxt to user\n", ret); @@ -295,7 +466,7 @@ static int marshal_in(const struct smcinvoke_cmd_req *req, const union smcinvoke_arg *args_buf, uint32_t tzhandle, uint8_t *buf, size_t buf_size, struct file **arr_filp) { - int ret = -EINVAL, i = 0; + int ret = -EINVAL, i = 0, j = 0; union smcinvoke_tz_args *tz_args = NULL; struct smcinvoke_msg_hdr msg_hdr = {tzhandle, req->op, req->counts}; uint32_t offset = sizeof(struct smcinvoke_msg_hdr) + @@ -320,7 +491,7 @@ static int marshal_in(const struct smcinvoke_cmd_req *req, tz_args++; if (copy_from_user(buf+offset, - (void __user *)(args_buf[i].b.addr), + (void __user *)(uintptr_t)(args_buf[i].b.addr), args_buf[i].b.size)) goto out; @@ -340,7 +511,7 @@ static int marshal_in(const struct smcinvoke_cmd_req *req, } FOR_ARGS(i, req->counts, OI) { if (get_tzhandle_from_fd(args_buf[i].o.fd, - &arr_filp[i], &(tz_args->tzhandle))) + &arr_filp[j++], &(tz_args->tzhandle))) goto out; tz_args++; } @@ -375,23 +546,27 @@ long smcinvoke_ioctl(struct file *filp, unsigned cmd, unsigned long arg) nr_args = object_counts_num_buffers(req.counts) + object_counts_num_objects(req.counts); - if (!nr_args || req.argsize != sizeof(union smcinvoke_arg)) { + if (req.argsize != sizeof(union smcinvoke_arg)) { ret = -EINVAL; goto out; } - args_buf = kzalloc(nr_args * req.argsize, GFP_KERNEL); - if (!args_buf) { - ret = -ENOMEM; - goto out; - } + if (nr_args) { - ret = copy_from_user(args_buf, (void __user *)(req.args), + args_buf = kzalloc(nr_args * req.argsize, GFP_KERNEL); + if (!args_buf) { + ret = -ENOMEM; + goto out; + } + + ret = copy_from_user(args_buf, + (void __user *)(uintptr_t)(req.args), nr_args * req.argsize); - if (ret) { - ret = -EFAULT; - goto out; + if (ret) { + ret = -EFAULT; + goto out; + } } inmsg_size = compute_in_msg_size(&req, args_buf); @@ -418,10 +593,17 @@ long smcinvoke_ioctl(struct file *filp, unsigned cmd, unsigned long arg) if (ret) goto out; - ret = marshal_out(in_msg, inmsg_size, &req, args_buf); + /* + * if invoke op results in an err, no need to marshal_out and + * copy args buf to user space + */ + if (!req.result) { + ret = marshal_out(in_msg, inmsg_size, &req, args_buf); - ret |= copy_to_user((void __user *)(req.args), args_buf, - nr_args * req.argsize); + ret |= copy_to_user( + (void __user *)(uintptr_t)(req.args), + args_buf, nr_args * req.argsize); + } ret |= copy_to_user((void __user *)arg, &req, sizeof(req)); if (ret) goto out; @@ -491,10 +673,136 @@ out: return ret; } -static int __init smcinvoke_init(void) +static int smcinvoke_probe(struct platform_device *pdev) { - return misc_register(&smcinvoke_miscdev); + unsigned int baseminor = 0; + unsigned int count = 1; + int rc = 0; + + rc = alloc_chrdev_region(&smcinvoke_device_no, baseminor, count, + SMCINVOKE_FILE); + if (rc < 0) { + pr_err("chrdev_region failed %d for %s\n", rc, SMCINVOKE_FILE); + return rc; + } + driver_class = class_create(THIS_MODULE, SMCINVOKE_FILE); + if (IS_ERR(driver_class)) { + rc = -ENOMEM; + pr_err("class_create failed %d\n", rc); + goto exit_unreg_chrdev_region; + } + class_dev = device_create(driver_class, NULL, smcinvoke_device_no, + NULL, SMCINVOKE_FILE); + if (!class_dev) { + pr_err("class_device_create failed %d\n", rc); + rc = -ENOMEM; + goto exit_destroy_class; + } + + cdev_init(&smcinvoke_cdev, &smcinvoke_fops); + smcinvoke_cdev.owner = THIS_MODULE; + + rc = cdev_add(&smcinvoke_cdev, MKDEV(MAJOR(smcinvoke_device_no), 0), + count); + if (rc < 0) { + pr_err("cdev_add failed %d for %s\n", rc, SMCINVOKE_FILE); + goto exit_destroy_device; + } + smcinvoke_pdev = pdev; + class_dev->of_node = pdev->dev.of_node; + + if (pdev->dev.of_node) { + support_clocks = + of_property_read_bool(pdev->dev.of_node, + "qcom,clock-support"); + if (of_property_read_u32(pdev->dev.of_node, + "qcom,ce-opp-freq", + &ce_opp_freq_hz)) { + pr_debug("CE op freq not defined, setting to 100MHZ\n"); + ce_opp_freq_hz = SMCINVOKE_CE_CLK_100MHZ; + } + } + if (support_clocks) { + init_clocks(); + bus_scale_pdata = msm_bus_cl_get_pdata(pdev); + if (bus_scale_pdata) + qsee_perf_client = msm_bus_scale_register_client( + bus_scale_pdata); + } + return 0; + +exit_destroy_device: + device_destroy(driver_class, smcinvoke_device_no); +exit_destroy_class: + class_destroy(driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(smcinvoke_device_no, count); + return rc; +} + +static int smcinvoke_remove(struct platform_device *pdev) +{ + int count = 1; + + if (support_clocks) { + /* ok to call with NULL */ + msm_bus_scale_unregister_client(qsee_perf_client); + if (bus_scale_pdata) + msm_bus_cl_clear_pdata(bus_scale_pdata); + deinit_clocks(); + support_clocks = false; + } + cdev_del(&smcinvoke_cdev); + device_destroy(driver_class, smcinvoke_device_no); + class_destroy(driver_class); + unregister_chrdev_region(smcinvoke_device_no, count); + return 0; +} + +static int smcinvoke_suspend(struct platform_device *pdev, pm_message_t state) +{ + if (current_mode == BW_HIGH) + return 1; + else + return 0; +} + +static int smcinvoke_resume(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id smcinvoke_match[] = { + { + .compatible = "qcom,smcinvoke", + }, + {}, +}; + +static struct platform_driver smcinvoke_plat_driver = { + .probe = smcinvoke_probe, + .remove = smcinvoke_remove, + .suspend = smcinvoke_suspend, + .resume = smcinvoke_resume, + .driver = { + .name = "smcinvoke", + .owner = THIS_MODULE, + .of_match_table = smcinvoke_match, + }, +}; + +static int smcinvoke_init(void) +{ + return platform_driver_register(&smcinvoke_plat_driver); +} + +static void smcinvoke_exit(void) +{ + platform_driver_unregister(&smcinvoke_plat_driver); } -device_initcall(smcinvoke_init); +module_init(smcinvoke_init); +module_exit(smcinvoke_exit); + MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SMC Invoke driver"); diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index ee0bade506d9140bd3673b1db6af32687f1e9bb5..31b3d019f9c99b32f91f8586f1cfd2461200a6fa 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015,2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015,2017,2019 The Linux Foundation. All rights reserved. * * 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 @@ -172,6 +172,20 @@ static struct restart_notifier_block restart_notifiers[] = { static int init_smem_remote_spinlock(void); +/** + * smem_get_toc() - Used for getting partitions TOC + * + * @return - Base address off partitions TOC + * + * Helper function to get base address of partition TOC, + * that is present in top 4K of first smem region. + */ +static struct smem_toc __iomem *smem_get_toc(void) +{ + return smem_areas[0].virt_addr + + smem_areas[0].size - 4 * 1024; +} + /** * is_probe_done() - Did the probe function successfully complete * @@ -306,6 +320,7 @@ static void *__smem_get_entry_nonsecure(unsigned id, unsigned *size, int use_spinlocks = spinlocks_initialized && use_rspinlock; void *ret = 0; unsigned long flags = 0; + uint32_t e_size; int rc; if (!skip_init_check && !smem_initialized_check()) @@ -324,7 +339,11 @@ static void *__smem_get_entry_nonsecure(unsigned id, unsigned *size, if (toc[id].allocated) { phys_addr_t phys_base; - *size = toc[id].size; + e_size = toc[id].size; + if (e_size > smem_ram_size) + return ret; + *size = e_size; + barrier(); phys_base = toc[id].reserved & BASE_ADDR_MASK; @@ -359,12 +378,19 @@ static void *__smem_get_entry_secure(unsigned id, bool skip_init_check, bool use_rspinlock) { + struct smem_partition_allocation_header *alloc_hdr; struct smem_partition_header *hdr; + uint32_t offset_free_uncached; + struct smem_toc __iomem *toc; + uint32_t offset_free_cached; unsigned long lflags = 0; - void *item = NULL; - struct smem_partition_allocation_header *alloc_hdr; + uint32_t partition_size; uint32_t partition_num; + uint32_t padding_data; + uint32_t padding_hdr; uint32_t a_hdr_size; + uint32_t item_size; + void *item = NULL; int rc; SMEM_DBG("%s(%u, %u, %u, %d, %d)\n", __func__, id, to_proc, @@ -387,8 +413,10 @@ static void *__smem_get_entry_secure(unsigned id, if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset) return __smem_get_entry_nonsecure(id, size, skip_init_check, use_rspinlock); + toc = smem_get_toc(); partition_num = partitions[to_proc].partition_num; + partition_size = readl_relaxed(&toc->entry[partition_num].size); hdr = smem_areas[0].virt_addr + partitions[to_proc].offset; if (unlikely(!spinlocks_initialized)) { rc = init_smem_remote_spinlock(); @@ -418,11 +446,20 @@ static void *__smem_get_entry_secure(unsigned id, if (flags & SMEM_ITEM_CACHED_FLAG) { a_hdr_size = ALIGN(sizeof(*alloc_hdr), partitions[to_proc].size_cacheline); - for (alloc_hdr = (void *)(hdr) + hdr->size - a_hdr_size; + offset_free_cached = hdr->offset_free_cached; + if (WARN_ON(offset_free_cached > partition_size)) + return NULL; + + for (alloc_hdr = (void *)(hdr) + partition_size - a_hdr_size; (void *)(alloc_hdr) > (void *)(hdr) + - hdr->offset_free_cached; + offset_free_cached; alloc_hdr = (void *)(alloc_hdr) - - alloc_hdr->size - a_hdr_size) { + item_size - a_hdr_size) { + item_size = alloc_hdr->size; + padding_data = alloc_hdr->padding_data; + if (WARN_ON(padding_data > item_size + || item_size > partition_size)) + return NULL; if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) { LOG_ERR( "%s: SMEM corruption detected. Partition %d to %d at %p\n", @@ -435,20 +472,30 @@ static void *__smem_get_entry_secure(unsigned id, } if (alloc_hdr->smem_type == id) { /* 8 byte alignment to match legacy */ - *size = ALIGN(alloc_hdr->size - - alloc_hdr->padding_data, 8); - item = (void *)(alloc_hdr) - alloc_hdr->size; + *size = ALIGN(item_size - padding_data, 8); + item = (void *)(alloc_hdr) - item_size; break; } } } else { + offset_free_uncached = hdr->offset_free_uncached; + if (WARN_ON(offset_free_uncached > partition_size)) + return NULL; + for (alloc_hdr = (void *)(hdr) + sizeof(*hdr); (void *)(alloc_hdr) < (void *)(hdr) + - hdr->offset_free_uncached; + offset_free_uncached; alloc_hdr = (void *)(alloc_hdr) + sizeof(*alloc_hdr) + - alloc_hdr->padding_hdr + - alloc_hdr->size) { + padding_hdr + + item_size) { + padding_hdr = alloc_hdr->padding_hdr; + padding_data = alloc_hdr->padding_data; + item_size = alloc_hdr->size; + if (WARN_ON(padding_hdr > partition_size + || item_size > partition_size + || padding_data > item_size)) + return NULL; if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) { LOG_ERR( "%s: SMEM corruption detected. Partition %d to %d at %p\n", @@ -461,11 +508,10 @@ static void *__smem_get_entry_secure(unsigned id, } if (alloc_hdr->smem_type == id) { /* 8 byte alignment to match legacy */ - *size = ALIGN(alloc_hdr->size - - alloc_hdr->padding_data, 8); + *size = ALIGN(item_size - padding_data, 8); item = (void *)(alloc_hdr) + sizeof(*alloc_hdr) + - alloc_hdr->padding_hdr; + padding_hdr; break; } } @@ -554,10 +600,17 @@ static void *alloc_item_nonsecure(unsigned id, unsigned size_in) void *smem_base = smem_ram_base; struct smem_shared *shared = smem_base; struct smem_heap_entry *toc = shared->heap_toc; + uint32_t free_offset, heap_remaining; void *ret = NULL; - if (shared->heap_info.heap_remaining >= size_in) { - toc[id].offset = shared->heap_info.free_offset; + heap_remaining = shared->heap_info.heap_remaining; + free_offset = shared->heap_info.free_offset; + if (WARN_ON(heap_remaining > smem_ram_size + || free_offset > smem_ram_size)) + return NULL; + + if (heap_remaining >= size_in) { + toc[id].offset = free_offset; toc[id].size = size_in; /* * wmb() is necessary to ensure the allocation data is @@ -569,7 +622,7 @@ static void *alloc_item_nonsecure(unsigned id, unsigned size_in) shared->heap_info.free_offset += size_in; shared->heap_info.heap_remaining -= size_in; - ret = smem_base + toc[id].offset; + ret = smem_base + free_offset; /* * wmb() is necessary to ensure the heap data is consistent * before continuing to prevent race conditions with remote @@ -605,11 +658,15 @@ static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc, void *smem_base = smem_ram_base; struct smem_partition_header *hdr; struct smem_partition_allocation_header *alloc_hdr; + uint32_t offset_free_uncached; + struct smem_toc __iomem *toc; + uint32_t offset_free_cached; + uint32_t partition_size; + uint32_t partition_num; uint32_t a_hdr_size; uint32_t a_data_size; uint32_t size_cacheline; uint32_t free_space; - uint32_t partition_num; void *ret = NULL; hdr = smem_base + partitions[to_proc].offset; @@ -626,27 +683,36 @@ static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc, } size_cacheline = partitions[to_proc].size_cacheline; - free_space = hdr->offset_free_cached - - hdr->offset_free_uncached; + + toc = smem_get_toc(); + partition_size = readl_relaxed(&toc->entry[partition_num].size); + + offset_free_cached = hdr->offset_free_cached; + offset_free_uncached = hdr->offset_free_uncached; + if (WARN_ON(offset_free_uncached > offset_free_cached + || offset_free_cached > partition_size)) + return NULL; + + free_space = offset_free_cached - offset_free_uncached; if (flags & SMEM_ITEM_CACHED_FLAG) { a_hdr_size = ALIGN(sizeof(*alloc_hdr), size_cacheline); a_data_size = ALIGN(size_in, size_cacheline); - if (free_space < a_hdr_size + a_data_size) { + if (free_space < a_hdr_size + a_data_size + || free_space < size_in) { SMEM_INFO( - "%s: id %u not enough memory %u (required %u)\n", - __func__, id, free_space, - a_hdr_size + a_data_size); + "%s: id %u not enough memory %u (required %u), (size_in %u)\n", + __func__, id, free_space, + a_hdr_size + a_data_size, size_in); return ret; } - alloc_hdr = (void *)(hdr) + hdr->offset_free_cached - - a_hdr_size; + alloc_hdr = (void *)(hdr) + offset_free_cached - a_hdr_size; alloc_hdr->canary = SMEM_ALLOCATION_CANARY; alloc_hdr->smem_type = id; alloc_hdr->size = a_data_size; alloc_hdr->padding_data = a_data_size - size_in; alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr); - hdr->offset_free_cached = hdr->offset_free_cached - + hdr->offset_free_cached = offset_free_cached - a_hdr_size - a_data_size; ret = (void *)(alloc_hdr) - a_data_size; /* @@ -661,20 +727,21 @@ static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc, } else { a_hdr_size = sizeof(*alloc_hdr); a_data_size = ALIGN(size_in, 8); - if (free_space < a_hdr_size + a_data_size) { + if (free_space < a_hdr_size + a_data_size + || free_space < size_in) { SMEM_INFO( - "%s: id %u not enough memory %u (required %u)\n", - __func__, id, free_space, - a_hdr_size + a_data_size); + "%s: id %u not enough memory %u (required %u) (size_in %u)\n", + __func__, id, free_space, + a_hdr_size + a_data_size, size_in); return ret; } - alloc_hdr = (void *)(hdr) + hdr->offset_free_uncached; + alloc_hdr = (void *)(hdr) + offset_free_uncached; alloc_hdr->canary = SMEM_ALLOCATION_CANARY; alloc_hdr->smem_type = id; alloc_hdr->size = a_data_size; alloc_hdr->padding_data = a_data_size - size_in; alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr); - hdr->offset_free_uncached = hdr->offset_free_uncached + + hdr->offset_free_uncached = offset_free_uncached + a_hdr_size + a_data_size; ret = alloc_hdr + 1; } @@ -861,6 +928,12 @@ unsigned smem_get_free_space(unsigned to_proc) { struct smem_partition_header *hdr; struct smem_shared *shared; + uint32_t offset_free_uncached; + struct smem_toc __iomem *toc; + uint32_t offset_free_cached; + uint32_t heap_remaining; + uint32_t p_size; + uint32_t p_num; if (to_proc >= NUM_SMEM_SUBSYSTEMS) { pr_err("%s: invalid to_proc:%d\n", __func__, to_proc); @@ -875,11 +948,24 @@ unsigned smem_get_free_space(unsigned to_proc) return UINT_MAX; } hdr = smem_areas[0].virt_addr + partitions[to_proc].offset; - return hdr->offset_free_cached - hdr->offset_free_uncached; - } else { - shared = smem_ram_base; - return shared->heap_info.heap_remaining; + offset_free_cached = hdr->offset_free_cached; + offset_free_uncached = hdr->offset_free_uncached; + + toc = smem_get_toc(); + p_num = partitions[to_proc].partition_num; + p_size = readl_relaxed(&toc->entry[p_num].size); + if (WARN_ON(offset_free_uncached > offset_free_cached + || offset_free_cached > p_size)) + return -EINVAL; + + return offset_free_cached - offset_free_uncached; } + shared = smem_ram_base; + heap_remaining = shared->heap_info.heap_remaining; + if (WARN_ON(heap_remaining > smem_ram_size)) + return -EINVAL; + + return heap_remaining; } EXPORT_SYMBOL(smem_get_free_space); @@ -1163,8 +1249,8 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d hdr magic is bad\n", num); BUG(); } - if (!hdr->size) { - LOG_ERR("Smem partition %d size is 0\n", num); + if (hdr->size != entry->size) { + LOG_ERR("Smem partition %d size is invalid\n", num); BUG(); } if (hdr->offset_free_uncached > hdr->size) { diff --git a/drivers/soc/qcom/smp2p_spinlock_test.c b/drivers/soc/qcom/smp2p_spinlock_test.c deleted file mode 100644 index 27ad4f4c5c643a6b6c6f23c73f7ca76c07ab1561..0000000000000000000000000000000000000000 --- a/drivers/soc/qcom/smp2p_spinlock_test.c +++ /dev/null @@ -1,804 +0,0 @@ -/* drivers/soc/qcom/smp2p_spinlock_test.c - * - * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. - * - * 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 -#include -#include -#include -#include -#include -#include -#include "smem_private.h" -#include "smp2p_private.h" -#include "smp2p_test_common.h" - -#define RS_END_THIEF_PID_BIT 20 -#define RS_END_THIEF_MASK 0x00f00000 - -/* Spinlock commands used for testing Apps<->RPM spinlocks. */ -enum RPM_SPINLOCK_CMDS { - RPM_CMD_INVALID, - RPM_CMD_START, - RPM_CMD_LOCKED, - RPM_CMD_UNLOCKED, - RPM_CMD_END, -}; - -/* Shared structure for testing Apps<->RPM spinlocks. */ -struct rpm_spinlock_test { - uint32_t apps_cmd; - uint32_t apps_lock_count; - uint32_t rpm_cmd; - uint32_t rpm_lock_count; -}; - -static uint32_t ut_remote_spinlock_run_time = 1; - -/** - * smp2p_ut_remote_spinlock_core - Verify remote spinlock. - * - * @s: Pointer to output file - * @remote_pid: Remote processor to test - * @use_trylock: Use trylock to prevent an Apps deadlock if the - * remote spinlock fails. - */ -static void smp2p_ut_remote_spinlock_core(struct seq_file *s, int remote_pid, - bool use_trylock) -{ - int failed = 0; - unsigned lock_count = 0; - struct msm_smp2p_out *handle = NULL; - int ret; - uint32_t test_request; - uint32_t test_response; - struct mock_cb_data cb_out; - struct mock_cb_data cb_in; - unsigned long flags; - unsigned n; - bool have_lock; - bool timeout; - int failed_tmp; - int spinlock_owner; - remote_spinlock_t *smem_spinlock; - unsigned long end; - - seq_printf(s, "Running %s for '%s' remote pid %d\n", - __func__, smp2p_pid_to_name(remote_pid), remote_pid); - - cb_out.initialized = false; - cb_in.initialized = false; - mock_cb_data_init(&cb_out); - mock_cb_data_init(&cb_in); - do { - smem_spinlock = smem_get_remote_spinlock(); - UT_ASSERT_PTR(smem_spinlock, !=, NULL); - - /* Open output entry */ - ret = msm_smp2p_out_open(remote_pid, SMP2P_RLPB_ENTRY_NAME, - &cb_out.nb, &handle); - UT_ASSERT_INT(ret, ==, 0); - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &cb_out.cb_completion, HZ * 2), - >, 0); - UT_ASSERT_INT(cb_out.cb_count, ==, 1); - UT_ASSERT_INT(cb_out.event_open, ==, 1); - - /* Open inbound entry */ - ret = msm_smp2p_in_register(remote_pid, SMP2P_RLPB_ENTRY_NAME, - &cb_in.nb); - UT_ASSERT_INT(ret, ==, 0); - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &cb_in.cb_completion, HZ * 2), - >, 0); - UT_ASSERT_INT(cb_in.cb_count, ==, 1); - UT_ASSERT_INT(cb_in.event_open, ==, 1); - - /* Send start */ - mock_cb_data_reset(&cb_in); - mock_cb_data_reset(&cb_out); - test_request = 0x0; - SMP2P_SET_RMT_CMD_TYPE_REQ(test_request); - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_START); - SMP2P_SET_RMT_DATA(test_request, 0x0); - ret = msm_smp2p_out_write(handle, test_request); - UT_ASSERT_INT(ret, ==, 0); - - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &cb_in.cb_completion, HZ * 2), - >, 0); - UT_ASSERT_INT(cb_in.cb_count, ==, 1); - UT_ASSERT_INT(cb_in.event_entry_update, ==, 1); - ret = msm_smp2p_in_read(remote_pid, SMP2P_RLPB_ENTRY_NAME, - &test_response); - UT_ASSERT_INT(ret, ==, 0); - - test_response = SMP2P_GET_RMT_CMD(test_response); - if (test_response != SMP2P_LB_CMD_RSPIN_LOCKED && - test_response != SMP2P_LB_CMD_RSPIN_UNLOCKED) { - /* invalid response from remote - abort test */ - test_request = 0x0; - SMP2P_SET_RMT_CMD_TYPE(test_request, 1); - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END); - SMP2P_SET_RMT_DATA(test_request, 0x0); - ret = msm_smp2p_out_write(handle, test_request); - UT_ASSERT_HEX(SMP2P_LB_CMD_RSPIN_LOCKED, ==, - test_response); - } - - /* Run spinlock test */ - if (use_trylock) - seq_puts(s, "\tUsing remote_spin_trylock\n"); - else - seq_puts(s, "\tUsing remote_spin_lock\n"); - - flags = 0; - have_lock = false; - timeout = false; - spinlock_owner = 0; - test_request = 0x0; - SMP2P_SET_RMT_CMD_TYPE_REQ(test_request); - end = jiffies + (ut_remote_spinlock_run_time * HZ); - if (ut_remote_spinlock_run_time < 300) { - seq_printf(s, "\tRunning test for %u seconds; ", - ut_remote_spinlock_run_time); - seq_puts(s, - "on physical hardware please run >= 300 seconds by doing 'echo 300 > ut_remote_spinlock_time'\n"); - } - while (time_is_after_jiffies(end)) { - /* try to acquire spinlock */ - if (use_trylock) { - unsigned long j_start = jiffies; - while (!remote_spin_trylock_irqsave( - smem_spinlock, flags)) { - if (jiffies_to_msecs(jiffies - j_start) - > 1000) { - seq_puts(s, - "\tFail: Timeout trying to get the lock\n"); - timeout = true; - break; - } - } - if (timeout) - break; - } else { - remote_spin_lock_irqsave(smem_spinlock, flags); - } - have_lock = true; - ++lock_count; - - /* tell the remote side that we have the lock */ - SMP2P_SET_RMT_DATA(test_request, lock_count); - SMP2P_SET_RMT_CMD(test_request, - SMP2P_LB_CMD_RSPIN_LOCKED); - ret = msm_smp2p_out_write(handle, test_request); - UT_ASSERT_INT(ret, ==, 0); - - /* verify the other side doesn't say it has the lock */ - for (n = 0; n < 1000; ++n) { - spinlock_owner = - remote_spin_owner(smem_spinlock); - if (spinlock_owner != SMEM_APPS) { - /* lock stolen by remote side */ - seq_puts(s, "\tFail: Remote side: "); - seq_printf(s, "%d stole lock pid: %d\n", - remote_pid, spinlock_owner); - failed = true; - break; - } - spinlock_owner = 0; - - ret = msm_smp2p_in_read(remote_pid, - SMP2P_RLPB_ENTRY_NAME, &test_response); - UT_ASSERT_INT(ret, ==, 0); - test_response = - SMP2P_GET_RMT_CMD(test_response); - UT_ASSERT_HEX(SMP2P_LB_CMD_RSPIN_UNLOCKED, ==, - test_response); - } - if (failed) - break; - - /* tell remote side we are unlocked and release lock */ - SMP2P_SET_RMT_CMD(test_request, - SMP2P_LB_CMD_RSPIN_UNLOCKED); - (void)msm_smp2p_out_write(handle, test_request); - have_lock = false; - remote_spin_unlock_irqrestore(smem_spinlock, flags); - } - if (have_lock) - remote_spin_unlock_irqrestore(smem_spinlock, flags); - - /* End test */ - mock_cb_data_reset(&cb_in); - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END); - SMP2P_SET_RMT_DATA(test_request, lock_count | - (spinlock_owner << RS_END_THIEF_PID_BIT)); - (void)msm_smp2p_out_write(handle, test_request); - - failed_tmp = failed; - failed = false; - do { - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &cb_in.cb_completion, HZ * 2), - >, 0); - reinit_completion(&cb_in.cb_completion); - ret = msm_smp2p_in_read(remote_pid, - SMP2P_RLPB_ENTRY_NAME, &test_response); - UT_ASSERT_INT(ret, ==, 0); - } while (!failed && - SMP2P_GET_RMT_CMD(test_response) != - SMP2P_LB_CMD_RSPIN_END); - if (failed) - break; - failed = failed_tmp; - - test_response = SMP2P_GET_RMT_DATA(test_response); - seq_puts(s, "\tLocked spinlock "); - seq_printf(s, "local %u times; remote %u times", - lock_count, - test_response & ((1 << RS_END_THIEF_PID_BIT) - 1) - ); - if (test_response & RS_END_THIEF_MASK) { - seq_puts(s, "Remote side reporting lock stolen by "); - seq_printf(s, "pid %d.\n", - SMP2P_GET_BITS(test_response, - RS_END_THIEF_MASK, - RS_END_THIEF_PID_BIT)); - failed = 1; - } - seq_puts(s, "\n"); - - /* Cleanup */ - ret = msm_smp2p_out_close(&handle); - UT_ASSERT_INT(ret, ==, 0); - UT_ASSERT_PTR(handle, ==, NULL); - ret = msm_smp2p_in_unregister(remote_pid, - SMP2P_RLPB_ENTRY_NAME, &cb_in.nb); - UT_ASSERT_INT(ret, ==, 0); - - if (!failed && !timeout) - seq_puts(s, "\tOK\n"); - } while (0); - - if (failed) { - if (handle) { - /* send end command */ - test_request = 0; - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END); - SMP2P_SET_RMT_DATA(test_request, lock_count); - (void)msm_smp2p_out_write(handle, test_request); - (void)msm_smp2p_out_close(&handle); - } - (void)msm_smp2p_in_unregister(remote_pid, - SMP2P_RLPB_ENTRY_NAME, &cb_in.nb); - - pr_err("%s: Failed\n", __func__); - seq_puts(s, "\tFailed\n"); - } -} - -/** - * smp2p_ut_remote_spinlock_pid - Verify remote spinlock for a processor. - * - * @s: Pointer to output file - * @pid: Processor to test - * @use_trylock: Use trylock to prevent an Apps deadlock if the - * remote spinlock fails. - */ -static void smp2p_ut_remote_spinlock_pid(struct seq_file *s, int pid, - bool use_trylock) -{ - struct smp2p_interrupt_config *int_cfg; - - int_cfg = smp2p_get_interrupt_config(); - if (!int_cfg) { - seq_puts(s, "Remote processor config unavailable\n"); - return; - } - - if (pid >= SMP2P_NUM_PROCS || !int_cfg[pid].is_configured) - return; - - msm_smp2p_deinit_rmt_lpb_proc(pid); - smp2p_ut_remote_spinlock_core(s, pid, use_trylock); - msm_smp2p_init_rmt_lpb_proc(pid); -} - -/** - * smp2p_ut_remote_spinlock - Verify remote spinlock for all processors. - * - * @s: pointer to output file - */ -static void smp2p_ut_remote_spinlock(struct seq_file *s) -{ - int pid; - - for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) - smp2p_ut_remote_spinlock_pid(s, pid, false); -} - -/** - * smp2p_ut_remote_spin_trylock - Verify remote trylock for all processors. - * - * @s: Pointer to output file - */ -static void smp2p_ut_remote_spin_trylock(struct seq_file *s) -{ - int pid; - - for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) - smp2p_ut_remote_spinlock_pid(s, pid, true); -} - -/** - * smp2p_ut_remote_spinlock - Verify remote spinlock for all processors. - * - * @s: pointer to output file - * - * This test verifies inbound and outbound functionality for all - * configured remote processor. - */ -static void smp2p_ut_remote_spinlock_modem(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_pid(s, SMP2P_MODEM_PROC, false); -} - -static void smp2p_ut_remote_spinlock_adsp(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_pid(s, SMP2P_AUDIO_PROC, false); -} - -static void smp2p_ut_remote_spinlock_dsps(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_pid(s, SMP2P_SENSOR_PROC, false); -} - -static void smp2p_ut_remote_spinlock_wcnss(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_pid(s, SMP2P_WIRELESS_PROC, false); -} - -static void smp2p_ut_remote_spinlock_tz(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_pid(s, SMP2P_TZ_PROC, false); -} - -/** - * smp2p_ut_remote_spinlock_rpm - Verify remote spinlock. - * - * @s: pointer to output file - * @remote_pid: Remote processor to test - */ -static void smp2p_ut_remote_spinlock_rpm(struct seq_file *s) -{ - int failed = 0; - unsigned long flags; - unsigned n; - unsigned test_num; - struct rpm_spinlock_test *data_ptr; - remote_spinlock_t *smem_spinlock; - bool have_lock; - - seq_printf(s, "Running %s for Apps<->RPM Test\n", - __func__); - do { - smem_spinlock = smem_get_remote_spinlock(); - UT_ASSERT_PTR(smem_spinlock, !=, NULL); - - data_ptr = smem_alloc(SMEM_ID_VENDOR0, - sizeof(struct rpm_spinlock_test), 0, - SMEM_ANY_HOST_FLAG); - UT_ASSERT_PTR(0, !=, data_ptr); - - /* Send start */ - writel_relaxed(0, &data_ptr->apps_lock_count); - writel_relaxed(RPM_CMD_START, &data_ptr->apps_cmd); - - seq_puts(s, "\tWaiting for RPM to start test\n"); - for (n = 0; n < 1000; ++n) { - if (readl_relaxed(&data_ptr->rpm_cmd) != - RPM_CMD_INVALID) - break; - usleep_range(1000, 1200); - } - if (readl_relaxed(&data_ptr->rpm_cmd) == RPM_CMD_INVALID) { - /* timeout waiting for RPM */ - writel_relaxed(RPM_CMD_INVALID, &data_ptr->apps_cmd); - UT_ASSERT_INT(RPM_CMD_LOCKED, !=, RPM_CMD_INVALID); - } - - /* Run spinlock test */ - flags = 0; - have_lock = false; - for (test_num = 0; !failed && test_num < 10000; ++test_num) { - /* acquire spinlock */ - remote_spin_lock_irqsave(smem_spinlock, flags); - have_lock = true; - data_ptr->apps_lock_count++; - writel_relaxed(data_ptr->apps_lock_count, - &data_ptr->apps_lock_count); - writel_relaxed(RPM_CMD_LOCKED, &data_ptr->apps_cmd); - /* - * Ensure that the remote side sees our lock has - * been acquired before we start polling their status. - */ - wmb(); - - /* verify the other side doesn't say it has the lock */ - for (n = 0; n < 1000; ++n) { - UT_ASSERT_HEX(RPM_CMD_UNLOCKED, ==, - readl_relaxed(&data_ptr->rpm_cmd)); - } - if (failed) - break; - - /* release spinlock */ - have_lock = false; - writel_relaxed(RPM_CMD_UNLOCKED, &data_ptr->apps_cmd); - /* - * Ensure that our status-update write was committed - * before we unlock the spinlock. - */ - wmb(); - remote_spin_unlock_irqrestore(smem_spinlock, flags); - } - if (have_lock) - remote_spin_unlock_irqrestore(smem_spinlock, flags); - - /* End test */ - writel_relaxed(RPM_CMD_INVALID, &data_ptr->apps_cmd); - seq_printf(s, "\tLocked spinlock local %u remote %u\n", - readl_relaxed(&data_ptr->apps_lock_count), - readl_relaxed(&data_ptr->rpm_lock_count)); - - if (!failed) - seq_puts(s, "\tOK\n"); - } while (0); - - if (failed) { - pr_err("%s: Failed\n", __func__); - seq_puts(s, "\tFailed\n"); - } -} - -struct rmt_spinlock_work_item { - struct work_struct work; - struct completion try_lock; - struct completion locked; - bool has_locked; -}; - -static void ut_remote_spinlock_ssr_worker(struct work_struct *work) -{ - remote_spinlock_t *smem_spinlock; - unsigned long flags; - struct rmt_spinlock_work_item *work_item = - container_of(work, struct rmt_spinlock_work_item, work); - - work_item->has_locked = false; - complete(&work_item->try_lock); - smem_spinlock = smem_get_remote_spinlock(); - if (!smem_spinlock) { - pr_err("%s Failed\n", __func__); - return; - } - - remote_spin_lock_irqsave(smem_spinlock, flags); - remote_spin_unlock_irqrestore(smem_spinlock, flags); - work_item->has_locked = true; - complete(&work_item->locked); -} - -/** - * smp2p_ut_remote_spinlock_ssr - Verify remote spinlock. - * - * @s: pointer to output file - */ -static void smp2p_ut_remote_spinlock_ssr(struct seq_file *s) -{ - int failed = 0; - unsigned long flags; - remote_spinlock_t *smem_spinlock; - int spinlock_owner = 0; - - struct workqueue_struct *ws = NULL; - struct rmt_spinlock_work_item work_item = { .has_locked = false }; - - seq_printf(s, " Running %s Test\n", - __func__); - do { - smem_spinlock = smem_get_remote_spinlock(); - UT_ASSERT_PTR(smem_spinlock, !=, NULL); - - ws = create_singlethread_workqueue("ut_remote_spinlock_ssr"); - UT_ASSERT_PTR(ws, !=, NULL); - INIT_WORK(&work_item.work, ut_remote_spinlock_ssr_worker); - init_completion(&work_item.try_lock); - init_completion(&work_item.locked); - - remote_spin_lock_irqsave(smem_spinlock, flags); - /* Unlock local spin lock and hold HW spinlock */ - spin_unlock_irqrestore(&((smem_spinlock)->local), flags); - - queue_work(ws, &work_item.work); - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &work_item.try_lock, HZ * 2), >, 0); - UT_ASSERT_INT((int)work_item.has_locked, ==, 0); - spinlock_owner = remote_spin_owner(smem_spinlock); - UT_ASSERT_INT(spinlock_owner, ==, SMEM_APPS); - remote_spin_release_all(SMEM_APPS); - - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &work_item.locked, HZ * 2), >, 0); - - if (!failed) - seq_puts(s, "\tOK\n"); - } while (0); - - if (failed) { - pr_err("%s: Failed\n", __func__); - seq_puts(s, "\tFailed\n"); - } -} - -/** - * smp2p_ut_remote_spinlock_track_core - Verify remote spinlock. - * - * @s: Pointer to output file - * @remote_pid: Remote processor to test - * - * This test has the remote subsystem grab the lock, and then has the local - * subsystem attempt to grab the lock using the trylock() API. It then verifies - * that the ID in the hw_spinlocks array matches the owner of the lock. - */ -static void smp2p_ut_remote_spinlock_track_core(struct seq_file *s, - int remote_pid) -{ - int failed = 0; - struct msm_smp2p_out *handle = NULL; - int ret; - uint32_t test_request; - uint32_t test_response; - struct mock_cb_data cb_out; - struct mock_cb_data cb_in; - unsigned long flags; - int stored_value; - remote_spinlock_t *smem_spinlock; - - seq_printf(s, "Running %s for '%s' remote pid %d\n", - __func__, smp2p_pid_to_name(remote_pid), remote_pid); - - cb_out.initialized = false; - cb_in.initialized = false; - mock_cb_data_init(&cb_out); - mock_cb_data_init(&cb_in); - do { - smem_spinlock = smem_get_remote_spinlock(); - UT_ASSERT_PTR(smem_spinlock, !=, NULL); - - /* Open output entry */ - ret = msm_smp2p_out_open(remote_pid, SMP2P_RLPB_ENTRY_NAME, - &cb_out.nb, &handle); - UT_ASSERT_INT(ret, ==, 0); - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &cb_out.cb_completion, HZ * 2), - >, 0); - UT_ASSERT_INT(cb_out.cb_count, ==, 1); - UT_ASSERT_INT(cb_out.event_open, ==, 1); - - /* Open inbound entry */ - ret = msm_smp2p_in_register(remote_pid, SMP2P_RLPB_ENTRY_NAME, - &cb_in.nb); - UT_ASSERT_INT(ret, ==, 0); - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &cb_in.cb_completion, HZ * 2), - >, 0); - UT_ASSERT_INT(cb_in.cb_count, ==, 1); - UT_ASSERT_INT(cb_in.event_open, ==, 1); - - /* Send start */ - mock_cb_data_reset(&cb_in); - mock_cb_data_reset(&cb_out); - test_request = 0x0; - SMP2P_SET_RMT_CMD_TYPE_REQ(test_request); - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_START); - SMP2P_SET_RMT_DATA(test_request, 0x0); - ret = msm_smp2p_out_write(handle, test_request); - UT_ASSERT_INT(ret, ==, 0); - - UT_ASSERT_INT( - (int)wait_for_completion_timeout( - &cb_in.cb_completion, HZ * 2), - >, 0); - UT_ASSERT_INT(cb_in.cb_count, ==, 1); - UT_ASSERT_INT(cb_in.event_entry_update, ==, 1); - ret = msm_smp2p_in_read(remote_pid, SMP2P_RLPB_ENTRY_NAME, - &test_response); - UT_ASSERT_INT(ret, ==, 0); - - test_response = SMP2P_GET_RMT_CMD(test_response); - if (test_response != SMP2P_LB_CMD_RSPIN_LOCKED && - test_response != SMP2P_LB_CMD_RSPIN_UNLOCKED) { - /* invalid response from remote - abort test */ - test_request = 0x0; - SMP2P_SET_RMT_CMD_TYPE(test_request, 1); - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END); - SMP2P_SET_RMT_DATA(test_request, 0x0); - ret = msm_smp2p_out_write(handle, test_request); - UT_ASSERT_HEX(SMP2P_LB_CMD_RSPIN_LOCKED, ==, - test_response); - } - - /* Run spinlock test */ - flags = 0; - test_request = 0x0; - SMP2P_SET_RMT_CMD_TYPE_REQ(test_request); - - /* try to acquire spinlock */ - remote_spin_trylock_irqsave(smem_spinlock, flags); - /* - * Need to check against the locking token (PID + 1) - * because the remote_spin_owner() API only returns the - * PID. - */ - stored_value = remote_spin_get_hw_spinlocks_element( - smem_spinlock); - UT_ASSERT_INT(stored_value, ==, - remote_spin_owner(smem_spinlock) + 1); - UT_ASSERT_INT(stored_value, ==, remote_pid + 1); - - /* End test */ - test_request = 0x0; - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END); - SMP2P_SET_RMT_DATA(test_request, 0x0); - (void)msm_smp2p_out_write(handle, test_request); - - /* Cleanup */ - ret = msm_smp2p_out_close(&handle); - UT_ASSERT_INT(ret, ==, 0); - UT_ASSERT_PTR(handle, ==, NULL); - ret = msm_smp2p_in_unregister(remote_pid, - SMP2P_RLPB_ENTRY_NAME, &cb_in.nb); - UT_ASSERT_INT(ret, ==, 0); - - if (!failed) - seq_puts(s, "\tOK\n"); - } while (0); - - if (failed) { - if (handle) { - /* send end command */ - test_request = 0x0; - SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END); - SMP2P_SET_RMT_DATA(test_request, 0x0); - (void)msm_smp2p_out_write(handle, test_request); - (void)msm_smp2p_out_close(&handle); - } - (void)msm_smp2p_in_unregister(remote_pid, - SMP2P_RLPB_ENTRY_NAME, &cb_in.nb); - - pr_err("%s: Failed\n", __func__); - seq_puts(s, "\tFailed\n"); - } -} - -/** - * smp2p_ut_remote_spinlock_track - Verify PID tracking for modem. - * - * @s: Pointer to output file - * @pid: The processor to test - */ -static void smp2p_ut_remote_spinlock_track(struct seq_file *s, int pid) -{ - struct smp2p_interrupt_config *int_cfg; - - int_cfg = smp2p_get_interrupt_config(); - if (!int_cfg) { - seq_puts(s, "Remote processor config unavailable\n"); - return; - } - - if (pid >= SMP2P_NUM_PROCS || !int_cfg[pid].is_configured) - return; - - msm_smp2p_deinit_rmt_lpb_proc(pid); - smp2p_ut_remote_spinlock_track_core(s, pid); - msm_smp2p_init_rmt_lpb_proc(pid); -} - -/** - * smp2p_ut_remote_spinlock_track - Verify PID tracking for all processors. - * - * @s: Pointer to output file - * - * This test verifies PID tracking for all configured remote processors. - */ -static void smp2p_ut_remote_spinlock_track_modem(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_track(s, SMP2P_MODEM_PROC); -} - -static void smp2p_ut_remote_spinlock_track_adsp(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_track(s, SMP2P_AUDIO_PROC); -} - -static void smp2p_ut_remote_spinlock_track_dsps(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_track(s, SMP2P_SENSOR_PROC); -} - -static void smp2p_ut_remote_spinlock_track_wcnss(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_track(s, SMP2P_WIRELESS_PROC); -} - -static void smp2p_ut_remote_spinlock_track_tz(struct seq_file *s) -{ - smp2p_ut_remote_spinlock_track(s, SMP2P_TZ_PROC); -} - -static int __init smp2p_debugfs_init(void) -{ - /* - * Add Unit Test entries. - * - * The idea with unit tests is that you can run all of them - * from ADB shell by doing: - * adb shell - * cat ut* - * - * And if particular tests fail, you can then repeatedly run the - * failing tests as you debug and resolve the failing test. - */ - smp2p_debug_create("ut_remote_spinlock", - smp2p_ut_remote_spinlock); - smp2p_debug_create("ut_remote_spin_trylock", - smp2p_ut_remote_spin_trylock); - smp2p_debug_create("ut_remote_spinlock_modem", - smp2p_ut_remote_spinlock_modem); - smp2p_debug_create("ut_remote_spinlock_adsp", - smp2p_ut_remote_spinlock_adsp); - smp2p_debug_create("ut_remote_spinlock_dsps", - smp2p_ut_remote_spinlock_dsps); - smp2p_debug_create("ut_remote_spinlock_wcnss", - smp2p_ut_remote_spinlock_wcnss); - smp2p_debug_create("ut_remote_spinlock_tz", - smp2p_ut_remote_spinlock_tz); - smp2p_debug_create("ut_remote_spinlock_rpm", - smp2p_ut_remote_spinlock_rpm); - smp2p_debug_create_u32("ut_remote_spinlock_time", - &ut_remote_spinlock_run_time); - smp2p_debug_create("ut_remote_spinlock_ssr", - &smp2p_ut_remote_spinlock_ssr); - smp2p_debug_create("ut_remote_spinlock_track_modem", - &smp2p_ut_remote_spinlock_track_modem); - smp2p_debug_create("ut_remote_spinlock_track_adsp", - &smp2p_ut_remote_spinlock_track_adsp); - smp2p_debug_create("ut_remote_spinlock_track_dsps", - &smp2p_ut_remote_spinlock_track_dsps); - smp2p_debug_create("ut_remote_spinlock_track_wcnss", - &smp2p_ut_remote_spinlock_track_wcnss); - smp2p_debug_create("ut_remote_spinlock_track_tz", - &smp2p_ut_remote_spinlock_track_tz); - return 0; -} -module_init(smp2p_debugfs_init); diff --git a/drivers/soc/qcom/smp2p_test_common.h b/drivers/soc/qcom/smp2p_test_common.h deleted file mode 100644 index 3be519bc0c96f3daf8efde3735b95ffbe1c822c1..0000000000000000000000000000000000000000 --- a/drivers/soc/qcom/smp2p_test_common.h +++ /dev/null @@ -1,214 +0,0 @@ -/* drivers/soc/qcom/smp2p_test_common.h - * - * Copyright (c) 2013-2014,2016 The Linux Foundation. All rights reserved. - * - * 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. - */ -#ifndef _SMP2P_TEST_COMMON_H_ -#define _SMP2P_TEST_COMMON_H_ - -#include - -/** - * Unit test assertion for logging test cases. - * - * @a lval - * @b rval - * @cmp comparison operator - * - * Assertion fails if (@a cmp @b) is not true which then - * logs the function and line number where the error occurred - * along with the values of @a and @b. - * - * Assumes that the following local variables exist: - * @s - sequential output file pointer - * @failed - set to true if test fails - */ -#define UT_ASSERT_INT(a, cmp, b) \ - { \ - int a_tmp = (a); \ - int b_tmp = (b); \ - if (!((a_tmp)cmp(b_tmp))) { \ - seq_printf(s, "%s:%d Fail: " #a "(%d) " #cmp " " #b "(%d)\n", \ - __func__, __LINE__, \ - a_tmp, b_tmp); \ - failed = 1; \ - break; \ - } \ - } - -#define UT_ASSERT_PTR(a, cmp, b) \ - { \ - void *a_tmp = (a); \ - void *b_tmp = (b); \ - if (!((a_tmp)cmp(b_tmp))) { \ - seq_printf(s, "%s:%d Fail: " #a "(%pK) " #cmp \ - " " #b "(%pK)\n", \ - __func__, __LINE__, \ - a_tmp, b_tmp); \ - failed = 1; \ - break; \ - } \ - } - -#define UT_ASSERT_UINT(a, cmp, b) \ - { \ - unsigned a_tmp = (a); \ - unsigned b_tmp = (b); \ - if (!((a_tmp)cmp(b_tmp))) { \ - seq_printf(s, "%s:%d Fail: " #a "(%u) " #cmp " " #b "(%u)\n", \ - __func__, __LINE__, \ - a_tmp, b_tmp); \ - failed = 1; \ - break; \ - } \ - } - -#define UT_ASSERT_HEX(a, cmp, b) \ - { \ - unsigned a_tmp = (a); \ - unsigned b_tmp = (b); \ - if (!((a_tmp)cmp(b_tmp))) { \ - seq_printf(s, "%s:%d Fail: " #a "(%x) " #cmp " " #b "(%x)\n", \ - __func__, __LINE__, \ - a_tmp, b_tmp); \ - failed = 1; \ - break; \ - } \ - } - -/** - * In-range unit test assertion for test cases. - * - * @a lval - * @minv Minimum value - * @maxv Maximum value - * - * Assertion fails if @a is not on the exclusive range minv, maxv - * ((@a < @minv) or (@a > @maxv)). In the failure case, the macro - * logs the function and line number where the error occurred along - * with the values of @a and @minv, @maxv. - * - * Assumes that the following local variables exist: - * @s - sequential output file pointer - * @failed - set to true if test fails - */ -#define UT_ASSERT_INT_IN_RANGE(a, minv, maxv) \ - { \ - int a_tmp = (a); \ - int minv_tmp = (minv); \ - int maxv_tmp = (maxv); \ - if (((a_tmp) < (minv_tmp)) || ((a_tmp) > (maxv_tmp))) { \ - seq_printf(s, "%s:%d Fail: " #a "(%d) < " #minv "(%d) or " \ - #a "(%d) > " #maxv "(%d)\n", \ - __func__, __LINE__, \ - a_tmp, minv_tmp, a_tmp, maxv_tmp); \ - failed = 1; \ - break; \ - } \ - } - -/* Structure to track state changes for the notifier callback. */ -struct mock_cb_data { - bool initialized; - spinlock_t lock; - struct notifier_block nb; - - /* events */ - struct completion cb_completion; - int cb_count; - int event_open; - int event_entry_update; - struct msm_smp2p_update_notif entry_data; -}; - -void smp2p_debug_create(const char *name, void (*show)(struct seq_file *)); -void smp2p_debug_create_u32(const char *name, uint32_t *value); -static inline int smp2p_test_notify(struct notifier_block *self, - unsigned long event, void *data); - -/** - * Reset mock callback data to default values. - * - * @cb: Mock callback data - */ -static inline void mock_cb_data_reset(struct mock_cb_data *cb) -{ - reinit_completion(&cb->cb_completion); - cb->cb_count = 0; - cb->event_open = 0; - cb->event_entry_update = 0; - memset(&cb->entry_data, 0, - sizeof(struct msm_smp2p_update_notif)); -} - - -/** - * Initialize mock callback data. - * - * @cb: Mock callback data - */ -static inline void mock_cb_data_init(struct mock_cb_data *cb) -{ - if (!cb->initialized) { - init_completion(&cb->cb_completion); - spin_lock_init(&cb->lock); - cb->initialized = true; - cb->nb.notifier_call = smp2p_test_notify; - memset(&cb->entry_data, 0, - sizeof(struct msm_smp2p_update_notif)); - } - mock_cb_data_reset(cb); -} - -/** - * Notifier function passed into SMP2P for testing. - * - * @self: Pointer to calling notifier block - * @event: Event - * @data: Event-specific data - * @returns: 0 - */ -static inline int smp2p_test_notify(struct notifier_block *self, - unsigned long event, void *data) -{ - struct mock_cb_data *cb_data_ptr; - unsigned long flags; - - cb_data_ptr = container_of(self, struct mock_cb_data, nb); - - spin_lock_irqsave(&cb_data_ptr->lock, flags); - - switch (event) { - case SMP2P_OPEN: - ++cb_data_ptr->event_open; - if (data) { - cb_data_ptr->entry_data = - *(struct msm_smp2p_update_notif *)(data); - } - break; - case SMP2P_ENTRY_UPDATE: - ++cb_data_ptr->event_entry_update; - if (data) { - cb_data_ptr->entry_data = - *(struct msm_smp2p_update_notif *)(data); - } - break; - default: - pr_err("%s Unknown event\n", __func__); - break; - } - - ++cb_data_ptr->cb_count; - complete(&cb_data_ptr->cb_completion); - spin_unlock_irqrestore(&cb_data_ptr->lock, flags); - return 0; -} -#endif /* _SMP2P_TEST_COMMON_H_ */ diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index c63a3690fea08c4ea7dede0806cdc375ee251953..fee1b51f16da9491a19b6e4beb05742bc3a6847d 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -1308,6 +1308,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 338; strlcpy(dummy_socinfo.build_id, "sdm450 - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_sda450()) { + dummy_socinfo.id = 351; + strlcpy(dummy_socinfo.build_id, "sda450 - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_mdm9607()) { dummy_socinfo.id = 290; strlcpy(dummy_socinfo.build_id, "mdm9607 - ", diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index 705666e7ab70ae267bdbd4afdde556db06a1bb76..23d19163e6e198ea1fed82df61bb672f79546c6b 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * 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 @@ -190,18 +190,12 @@ static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev) } static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev, - uint32_t vlevel) + uint32_t vlevel, uint32_t vctl_port) { unsigned int pmic_data = 0; - /** - * VCTL_PORT has to be 0, for PMIC_STS register to be updated. - * Ensure that vctl_port is always set to 0. - */ - WARN_ON(dev->vctl_port); - pmic_data |= vlevel; - pmic_data |= (dev->vctl_port & 0x7) << 16; + pmic_data |= (vctl_port & 0x7) << 16; dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] &= ~0x700FF; dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] |= pmic_data; @@ -506,10 +500,45 @@ static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev, unsigned int vlevel) { } #endif +static inline int msm_spm_drv_validate_data(struct msm_spm_driver_data *dev, + unsigned int vlevel, int vctl_port) +{ + int timeout_us = dev->vctl_timeout_us; + uint32_t new_level; + + /* Confirm the voltage we set was what hardware sent and + * FSM is idle */ + do { + udelay(1); + new_level = msm_spm_drv_get_sts_curr_pmic_data(dev); + + /** + * VCTL_PORT has to be 0, for vlevel to be updated. + * If port is not 0, check for PMIC_STATE only. + */ + + if (((new_level & 0x30000) == MSM_SPM_PMIC_STATE_IDLE) && + (vctl_port || ((new_level & 0xFF) == vlevel))) + break; + } while (--timeout_us); + + if (!timeout_us) { + pr_err("Wrong level %#x\n", new_level); + return -EIO; + } + + if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL) + pr_info("%s: done, remaining timeout %u us\n", + __func__, timeout_us); + + return 0; +} + int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel) { - uint32_t timeout_us, new_level; + uint32_t vlevel_set = vlevel; bool avs_enabled; + int ret = 0; if (!dev) return -EINVAL; @@ -525,45 +554,63 @@ int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel) if (avs_enabled) msm_spm_drv_disable_avs(dev); + if (dev->vctl_port_ub >= 0) { + /** + * VCTL can send 8bit voltage level at once. + * Send lower 8bit first, vlevel change happens + * when upper 8bit is sent. + */ + vlevel = vlevel_set & 0xFF; + } + /* Kick the state machine back to idle */ dev->reg_shadow[MSM_SPM_REG_SAW_RST] = 1; msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_RST); - msm_spm_drv_set_vctl2(dev, vlevel); + msm_spm_drv_set_vctl2(dev, vlevel, dev->vctl_port); - timeout_us = dev->vctl_timeout_us; - /* Confirm the voltage we set was what hardware sent */ - do { - udelay(1); - new_level = msm_spm_drv_get_sts_curr_pmic_data(dev); - /* FSM is idle */ - if (((new_level & 0x30000) == 0) && - ((new_level & 0xFF) == vlevel)) - break; - } while (--timeout_us); - if (!timeout_us) { - pr_info("Wrong level %#x\n", new_level); + ret = msm_spm_drv_validate_data(dev, vlevel, dev->vctl_port); + if (ret) goto set_vdd_bail; - } - if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL) - pr_info("%s: done, remaining timeout %u us\n", - __func__, timeout_us); + if (dev->vctl_port_ub >= 0) { + /* Send upper 8bit of voltage level */ + vlevel = (vlevel_set >> 8) & 0xFF; + + /* Kick the state machine back to idle */ + dev->reg_shadow[MSM_SPM_REG_SAW_RST] = 1; + msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_RST); + + /* + * Steps for sending for vctl port other than '0' + * Write VCTL register with pmic data and address index + * Perform system barrier + * Wait for 1us + * Read PMIC_STS register to make sure operation is complete + */ + msm_spm_drv_set_vctl2(dev, vlevel, dev->vctl_port_ub); + + mb(); /* To make sure data is sent before checking status */ + + ret = msm_spm_drv_validate_data(dev, vlevel, dev->vctl_port_ub); + if (ret) + goto set_vdd_bail; + } /* Set AVS min/max */ if (avs_enabled) { - msm_spm_drv_set_avs_vlevel(dev, vlevel); + msm_spm_drv_set_avs_vlevel(dev, vlevel_set); msm_spm_drv_enable_avs(dev); } - return 0; + return ret; set_vdd_bail: if (avs_enabled) msm_spm_drv_enable_avs(dev); - pr_err("%s: failed %#x, remaining timeout %uus, vlevel %#x\n", - __func__, vlevel, timeout_us, new_level); + pr_err("%s: failed %#x vlevel setting in timeout %uus\n", + __func__, vlevel_set, dev->vctl_timeout_us); return -EIO; } @@ -692,6 +739,7 @@ int msm_spm_drv_init(struct msm_spm_driver_data *dev, BUG_ON(!dev || !data); dev->vctl_port = data->vctl_port; + dev->vctl_port_ub = data->vctl_port_ub; dev->phase_port = data->phase_port; dev->pfm_port = data->pfm_port; dev->reg_base_addr = data->reg_base_addr; diff --git a/drivers/soc/qcom/spm_devices.c b/drivers/soc/qcom/spm_devices.c index 2ad4d09537f0830e64ab6a9d3e059761d5ec08b3..e3e9a1ba8523fa6995e69d8e702cd78c7b53c659 100644 --- a/drivers/soc/qcom/spm_devices.c +++ b/drivers/soc/qcom/spm_devices.c @@ -798,12 +798,16 @@ static int msm_spm_dev_probe(struct platform_device *pdev) } spm_data.vctl_port = -1; + spm_data.vctl_port_ub = -1; spm_data.phase_port = -1; spm_data.pfm_port = -1; key = "qcom,vctl-port"; of_property_read_u32(node, key, &spm_data.vctl_port); + key = "qcom,vctl-port-ub"; + of_property_read_u32(node, key, &spm_data.vctl_port_ub); + key = "qcom,phase-port"; of_property_read_u32(node, key, &spm_data.phase_port); diff --git a/drivers/soc/qcom/spm_driver.h b/drivers/soc/qcom/spm_driver.h index 7e10f11a3bc9c8a7864f5fed62c509cec6ea9b9e..376cd02337274bfea7b8e526a81284c3c7956efe 100644 --- a/drivers/soc/qcom/spm_driver.h +++ b/drivers/soc/qcom/spm_driver.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. * * 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 @@ -62,6 +62,7 @@ struct msm_spm_platform_data { uint32_t ver_reg; uint32_t vctl_port; + int vctl_port_ub; uint32_t phase_port; uint32_t pfm_port; @@ -84,6 +85,7 @@ struct msm_spm_driver_data { uint32_t minor; uint32_t ver_reg; uint32_t vctl_port; + int vctl_port_ub; uint32_t phase_port; uint32_t pfm_port; void __iomem *reg_base_addr; diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c index b4e49eb3d85f3fa13724a9e7f3d41f4df3a706a1..b613776d42f1ed44deccef01a3e5b3d01665e213 100644 --- a/drivers/soc/qcom/subsys-pil-bg.c +++ b/drivers/soc/qcom/subsys-pil-bg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * 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 @@ -30,6 +30,7 @@ #include "peripheral-loader.h" #include "../../misc/qseecom_kernel.h" #include "pil_bg_intf.h" +#include "bgcom_interface.h" #define INVALID_GPIO -1 #define NUM_GPIOS 4 @@ -37,7 +38,8 @@ #define desc_to_data(d) container_of(d, struct pil_bg_data, desc) #define subsys_to_data(d) container_of(d, struct pil_bg_data, subsys_desc) #define BG_RAMDUMP_SZ 0x00102000 -#define BG_CRASH_IN_TWM 2 +#define BG_VERSION_SZ 32 +#define BG_CRASH_IN_TWM -2 /** * struct pil_bg_data * @qseecom_handle: handle of TZ app @@ -90,9 +92,18 @@ static irqreturn_t bg_status_change(int irq, void *dev_id); static void bg_app_shutdown_notify(const struct subsys_desc *subsys) { struct pil_bg_data *bg_data = subsys_to_data(subsys); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ - if (gpio_is_valid(bg_data->gpios[2])) + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending Apps shutdown signal\n"); gpio_set_value(bg_data->gpios[2], 1); + } } /** @@ -106,9 +117,18 @@ static int bg_app_reboot_notify(struct notifier_block *nb, { struct pil_bg_data *bg_data = container_of(nb, struct pil_bg_data, reboot_blk); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ - if (gpio_is_valid(bg_data->gpios[2])) + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending reboot signal\n"); gpio_set_value(bg_data->gpios[2], 1); + } return NOTIFY_DONE; } @@ -173,6 +193,9 @@ static long bgpil_tzapp_comm(struct pil_bg_data *pbd, struct tzapp_bg_req *bg_tz_req; struct tzapp_bg_rsp *bg_tz_rsp; int rc, req_len, rsp_len; + unsigned char *ascii; + char fiwmare_version[100] = {'\0'}; + char ascii_string[5]; /* Fill command structure */ req_len = sizeof(struct tzapp_bg_req); @@ -194,6 +217,21 @@ static long bgpil_tzapp_comm(struct pil_bg_data *pbd, pbd->cmd_status = bg_tz_rsp->status; else pbd->cmd_status = 0; + /* if last command sent was BG_VERSION print the version*/ + if (req->tzapp_bg_cmd == BGPIL_GET_BG_VERSION) { + int i; + + pr_info("BG FW version "); + for (i = 0; i < bg_tz_rsp->bg_info_len; i++) { + pr_info("0x%08x ", bg_tz_rsp->bg_info[i]); + ascii = (unsigned char *)&bg_tz_rsp->bg_info[i]; + snprintf(ascii_string, PAGE_SIZE, "%c%c%c%c", ascii[0], + ascii[1], ascii[2], ascii[3]); + strlcat(fiwmare_version, ascii_string, + PAGE_SIZE); + } + pr_info("%s\n", fiwmare_version); + } end: return rc; } @@ -266,7 +304,6 @@ static int bg_powerup(const struct subsys_desc *subsys) return ret; } enable_irq(bg_data->status_irq); - enable_irq(bg_data->errfatal_irq); ret = wait_for_err_ready(bg_data); if (ret) { dev_err(bg_data->desc.dev, @@ -289,10 +326,12 @@ static int bg_shutdown(const struct subsys_desc *subsys, bool force_stop) { struct pil_bg_data *bg_data = subsys_to_data(subsys); - disable_irq(bg_data->status_irq); - devm_free_irq(bg_data->desc.dev, bg_data->status_irq, bg_data); - disable_irq(bg_data->errfatal_irq); - bg_data->is_ready = false; + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + devm_free_irq(bg_data->desc.dev, bg_data->status_irq, bg_data); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } return 0; } @@ -370,6 +409,28 @@ static int bg_get_firmware_addr(struct pil_desc *pil, return 0; } +static int bg_get_version(const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + struct pil_desc desc = bg_data->desc; + struct tzapp_bg_req bg_tz_req; + int ret; + + init_dma_attrs(&desc.attrs); + dma_set_attr(DMA_ATTR_SKIP_ZEROING, &desc.attrs); + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &desc.attrs); + + bg_tz_req.tzapp_bg_cmd = BGPIL_GET_BG_VERSION; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (ret || bg_data->cmd_status) { + dev_dbg(desc.dev, "%s: BG PIL get BG version failed error %d\n", + __func__, bg_data->cmd_status); + return bg_data->cmd_status; + } + + return 0; +} /** * bg_auth_and_xfer() - Called by Peripheral loader framework @@ -391,7 +452,9 @@ static int bg_auth_and_xfer(struct pil_desc *pil) ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); if (bg_data->cmd_status == BG_CRASH_IN_TWM) { /* Do ramdump and resend boot cmd */ - bg_data->subsys_desc.ramdump(true, &bg_data->subsys_desc); + if (is_twm_exit()) + bg_data->subsys_desc.ramdump(true, + &bg_data->subsys_desc); bg_tz_req.tzapp_bg_cmd = BGPIL_DLOAD_CONT; ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); } @@ -402,6 +465,7 @@ static int bg_auth_and_xfer(struct pil_desc *pil) pil_free_memory(&bg_data->desc); return bg_data->cmd_status; } + ret = bg_get_version(&bg_data->subsys_desc); /* BG Transfer of image is complete, free up the memory */ pr_debug("BG Firmware authentication and transfer done\n"); pil_free_memory(&bg_data->desc); @@ -519,7 +583,6 @@ static irqreturn_t bg_status_change(int irq, void *dev_id) } else if (value == false && drvdata->is_ready) { dev_err(drvdata->desc.dev, "BG got unexpected reset: irq state changed 1->0\n"); - drvdata->is_ready = false; queue_work(drvdata->bg_queue, &drvdata->restart_work); } else { dev_err(drvdata->desc.dev, @@ -581,7 +644,6 @@ static int setup_bg_gpio_irq(struct platform_device *pdev, goto err; } drvdata->errfatal_irq = irq; - enable_irq(drvdata->errfatal_irq); /* Configure outgoing GPIO's */ if (gpio_request(drvdata->gpios[2], "AP2BG_ERRFATAL")) { dev_err(&pdev->dev, diff --git a/drivers/soc/qcom/tracer_pkt.c b/drivers/soc/qcom/tracer_pkt.c index 4fa4b875094187e3041eeb78060a79cc9cca9351..db10998fdb1d191bd546c3e1d8f14f05661944c2 100644 --- a/drivers/soc/qcom/tracer_pkt.c +++ b/drivers/soc/qcom/tracer_pkt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. * * 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 diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 03eef82918d6286d793c4a38384f084cfb824a8b..62cb763c7549b9789c4c8423f78e9921875b46ce 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * 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 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "sound/wcd-dsp-glink.h" @@ -40,12 +41,14 @@ #define RESP_QUEUE_SIZE 3 #define QOS_PKT_SIZE 1024 #define TIMEOUT_MS 1000 +#define GLINK_EDGE_MAX 16 struct wdsp_glink_dev { struct class *cls; struct device *dev; struct cdev cdev; dev_t dev_num; + char glink_edge[GLINK_EDGE_MAX]; }; struct wdsp_glink_rsp_que { @@ -88,6 +91,9 @@ struct wdsp_glink_ch { /* Wait for ch connect state before sending any command */ wait_queue_head_t ch_connect_wait; + /* Wait for ch local and remote disconnect before channel free */ + wait_queue_head_t ch_free_wait; + /* * Glink channel configuration. This has to be the last * member of the strucuture as it has variable size @@ -115,6 +121,7 @@ struct wdsp_glink_priv { u8 no_of_channels; struct work_struct ch_open_cls_wrk; struct workqueue_struct *work_queue; + const char *glink_edge; wait_queue_head_t link_state_wait; @@ -308,7 +315,7 @@ static void wdsp_glink_notify_state(void *handle, const void *priv, mutex_lock(&ch->mutex); ch->channel_state = event; if (event == GLINK_CONNECTED) { - dev_dbg(wpriv->dev, "%s: glink channel: %s connected\n", + dev_info(wpriv->dev, "%s: glink channel: %s connected\n", __func__, ch->ch_cfg.name); for (i = 0; i < ch->ch_cfg.no_of_intents; i++) { @@ -330,31 +337,29 @@ static void wdsp_glink_notify_state(void *handle, const void *priv, ch->ch_cfg.name); wake_up(&ch->ch_connect_wait); - mutex_unlock(&ch->mutex); } else if (event == GLINK_LOCAL_DISCONNECTED) { /* * Don't use dev_dbg here as dev may not be valid if channel * closed from driver close. */ - pr_debug("%s: channel: %s disconnected locally\n", + pr_info("%s: channel: %s disconnected locally\n", __func__, ch->ch_cfg.name); mutex_unlock(&ch->mutex); - - if (ch->free_mem) { - kfree(ch); - ch = NULL; - } + ch->free_mem = true; + wake_up(&ch->ch_free_wait); + return; } else if (event == GLINK_REMOTE_DISCONNECTED) { - dev_dbg(wpriv->dev, "%s: remote channel: %s disconnected remotely\n", + pr_info("%s: remote channel: %s disconnected remotely\n", __func__, ch->ch_cfg.name); - mutex_unlock(&ch->mutex); /* * If remote disconnect happens, local side also has * to close the channel as per glink design in a * separate work_queue. */ - queue_work(wpriv->work_queue, &ch->lcl_ch_cls_wrk); + if (wpriv && wpriv->work_queue != NULL) + queue_work(wpriv->work_queue, &ch->lcl_ch_cls_wrk); } + mutex_unlock(&ch->mutex); } /* @@ -401,7 +406,7 @@ static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch) if (!ch->handle) { memset(&open_cfg, 0, sizeof(open_cfg)); open_cfg.options = GLINK_OPT_INITIAL_XPORT; - open_cfg.edge = WDSP_EDGE; + open_cfg.edge = wpriv->glink_edge; open_cfg.notify_rx = wdsp_glink_notify_rx; open_cfg.notify_tx_done = wdsp_glink_notify_tx_done; open_cfg.notify_tx_abort = wdsp_glink_notify_tx_abort; @@ -421,6 +426,7 @@ static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch) ch->handle = NULL; ret = -EINVAL; } + ch->free_mem = false; } else { dev_err(wpriv->dev, "%s: ch %s is already opened\n", __func__, ch->ch_cfg.name); @@ -511,10 +517,8 @@ static void wdsp_glink_link_state_cb(struct glink_link_state_cb_info *cb_info, wpriv = (struct wdsp_glink_priv *)priv; - mutex_lock(&wpriv->glink_mutex); wpriv->glink_state.link_state = cb_info->link_state; wake_up(&wpriv->link_state_wait); - mutex_unlock(&wpriv->glink_mutex); queue_work(wpriv->work_queue, &wpriv->ch_open_cls_wrk); } @@ -601,6 +605,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, goto err_ch_mem; } ch[i]->channel_state = GLINK_LOCAL_DISCONNECTED; + ch[i]->free_mem = true; memcpy(&ch[i]->ch_cfg, payload, ch_cfg_size); payload += ch_cfg_size; @@ -624,6 +629,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, INIT_WORK(&ch[i]->lcl_ch_open_wrk, wdsp_glink_lcl_ch_open_wrk); INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk); init_waitqueue_head(&ch[i]->ch_connect_wait); + init_waitqueue_head(&ch[i]->ch_free_wait); } INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk); @@ -631,7 +637,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, /* Register glink link_state notification */ link_info.glink_link_state_notif_cb = wdsp_glink_link_state_cb; link_info.transport = NULL; - link_info.edge = WDSP_EDGE; + link_info.edge = wpriv->glink_edge; wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN; wpriv->glink_state.handle = glink_register_link_state_cb(&link_info, @@ -971,7 +977,7 @@ static int wdsp_glink_open(struct inode *inode, struct file *file) ret = -EINVAL; goto err_wq; } - + wpriv->glink_edge = wdev->glink_edge; wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN; init_completion(&wpriv->rsp_complete); init_waitqueue_head(&wpriv->link_state_wait); @@ -1030,36 +1036,48 @@ static int wdsp_glink_release(struct inode *inode, struct file *file) goto done; } + dev_info(wpriv->dev, "%s: closing wdsp_glink driver\n", __func__); if (wpriv->glink_state.handle) glink_unregister_link_state_cb(wpriv->glink_state.handle); flush_workqueue(wpriv->work_queue); - destroy_workqueue(wpriv->work_queue); - /* - * Clean up glink channel memory in channel state - * callback only if close channels are called from here. + * Wait for channel local and remote disconnect state notifications + * before freeing channel memory. */ - if (wpriv->ch) { - for (i = 0; i < wpriv->no_of_channels; i++) { - if (wpriv->ch[i]) { - wpriv->ch[i]->free_mem = true; - /* - * Channel handle NULL means channel is already - * closed. Free the channel memory here itself. - */ - if (!wpriv->ch[i]->handle) { - kfree(wpriv->ch[i]); - wpriv->ch[i] = NULL; - } else { - wdsp_glink_close_ch(wpriv->ch[i]); - } + for (i = 0; i < wpriv->no_of_channels; i++) { + if (wpriv->ch && wpriv->ch[i]) { + /* + * Only close glink channel from here if REMOTE has + * not already disconnected it + */ + wdsp_glink_close_ch(wpriv->ch[i]); + + ret = wait_event_timeout(wpriv->ch[i]->ch_free_wait, + (wpriv->ch[i]->free_mem == true), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: glink ch %s failed to notify states properly %d\n", + __func__, wpriv->ch[i]->ch_cfg.name, + wpriv->ch[i]->channel_state); + ret = -EINVAL; + goto done; } } + } - kfree(wpriv->ch); - wpriv->ch = NULL; + flush_workqueue(wpriv->work_queue); + destroy_workqueue(wpriv->work_queue); + wpriv->work_queue = NULL; + + for (i = 0; i < wpriv->no_of_channels; i++) { + if (wpriv->ch && wpriv->ch[i]) { + kfree(wpriv->ch[i]); + wpriv->ch[i] = NULL; + } } + kfree(wpriv->ch); + wpriv->ch = NULL; mutex_destroy(&wpriv->glink_mutex); mutex_destroy(&wpriv->rsp_mutex); @@ -1087,6 +1105,7 @@ static int wdsp_glink_probe(struct platform_device *pdev) { int ret; struct wdsp_glink_dev *wdev; + const char *str = NULL; wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL); if (!wdev) { @@ -1126,6 +1145,20 @@ static int wdsp_glink_probe(struct platform_device *pdev) __func__, ret); goto err_cdev_add; } + ret = of_property_read_string(pdev->dev.of_node, + "qcom,msm-codec-glink-edge", &str); + if (ret < 0) { + strlcpy(wdev->glink_edge, WDSP_EDGE, GLINK_EDGE_MAX); + dev_info(&pdev->dev, + "%s: qcom,msm-codec-glink-edge not set use default %s\n", + __func__, wdev->glink_edge); + ret = 0; + } else { + strlcpy(wdev->glink_edge, str, GLINK_EDGE_MAX); + dev_info(&pdev->dev, "%s: glink edge is %s\n", __func__, + wdev->glink_edge); + } + platform_set_drvdata(pdev, wdev); goto done; diff --git a/drivers/soc/qcom/wlan_firmware_service_v01.c b/drivers/soc/qcom/wlan_firmware_service_v01.c deleted file mode 100644 index e899459a5a408a8f6caa111f91ff91fbc2951e67..0000000000000000000000000000000000000000 --- a/drivers/soc/qcom/wlan_firmware_service_v01.c +++ /dev/null @@ -1,1348 +0,0 @@ - /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * 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 - -#include - -#include "wlan_firmware_service_v01.h" - -static struct elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, - pipe_num), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_pipedir_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, - pipe_dir), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, - nentries), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, - nbytes_max), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, - flags), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -static struct elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, - service_id), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_pipedir_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, - pipe_dir), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, - pipe_num), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -static struct elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_2_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint16_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, - id), - }, - { - .data_type = QMI_UNSIGNED_2_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint16_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, - offset), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -static struct elem_info wlfw_memory_region_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint64_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_memory_region_info_s_v01, - region_addr), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_memory_region_info_s_v01, - size), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_memory_region_info_s_v01, - secure_flag), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -static struct elem_info wlfw_rf_chip_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_rf_chip_info_s_v01, - chip_id), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_rf_chip_info_s_v01, - chip_family), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -static struct elem_info wlfw_rf_board_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_rf_board_info_s_v01, - board_id), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -static struct elem_info wlfw_soc_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_soc_info_s_v01, - soc_id), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -static struct elem_info wlfw_fw_version_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_fw_version_info_s_v01, - fw_version), - }, - { - .data_type = QMI_STRING, - .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1, - .elem_size = sizeof(char), - .is_array = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct wlfw_fw_version_info_s_v01, - fw_build_timestamp), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_ind_register_req_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - fw_ready_enable_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - fw_ready_enable), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - initiate_cal_download_enable_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - initiate_cal_download_enable), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - initiate_cal_update_enable_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - initiate_cal_update_enable), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - msa_ready_enable_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - msa_ready_enable), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - pin_connect_result_enable_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - pin_connect_result_enable), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_ind_register_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_fw_ready_ind_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_msa_ready_ind_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct wlfw_pin_connect_result_ind_msg_v01, - pwr_pin_result_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct wlfw_pin_connect_result_ind_msg_v01, - pwr_pin_result), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof( - struct wlfw_pin_connect_result_ind_msg_v01, - phy_io_pin_result_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof( - struct wlfw_pin_connect_result_ind_msg_v01, - phy_io_pin_result), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof( - struct wlfw_pin_connect_result_ind_msg_v01, - rf_pin_result_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof( - struct wlfw_pin_connect_result_ind_msg_v01, - rf_pin_result), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_driver_mode_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, - mode), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - host_version_valid), - }, - { - .data_type = QMI_STRING, - .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1, - .elem_size = sizeof(char), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - host_version), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - tgt_cfg_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - tgt_cfg_len), - }, - { - .data_type = QMI_STRUCT, - .elem_len = QMI_WLFW_MAX_NUM_CE_V01, - .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - tgt_cfg), - .ei_array = wlfw_ce_tgt_pipe_cfg_s_v01_ei, - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - svc_cfg_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - svc_cfg_len), - }, - { - .data_type = QMI_STRUCT, - .elem_len = QMI_WLFW_MAX_NUM_SVC_V01, - .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - svc_cfg), - .ei_array = wlfw_ce_svc_pipe_cfg_s_v01_ei, - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - shadow_reg_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - shadow_reg_len), - }, - { - .data_type = QMI_STRUCT, - .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01, - .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, - shadow_reg), - .ei_array = wlfw_shadow_reg_cfg_s_v01_ei, - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cap_req_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cap_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - chip_info_valid), - }, - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - chip_info), - .ei_array = wlfw_rf_chip_info_s_v01_ei, - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - board_info_valid), - }, - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct wlfw_rf_board_info_s_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - board_info), - .ei_array = wlfw_rf_board_info_s_v01_ei, - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - soc_info_valid), - }, - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct wlfw_soc_info_s_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - soc_info), - .ei_array = wlfw_soc_info_s_v01_ei, - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - fw_version_info_valid), - }, - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct wlfw_fw_version_info_s_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cap_resp_msg_v01, - fw_version_info), - .ei_array = wlfw_fw_version_info_s_v01_ei, - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_bdf_download_req_msg_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - valid), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - file_id_valid), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - file_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - total_size_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - total_size), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - seg_id_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - seg_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - data_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint16_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - data_len), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, - .elem_size = sizeof(uint8_t), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - data), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - end_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, - end), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_bdf_download_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_bdf_download_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cal_report_req_msg_v01_ei[] = { - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_cal_report_req_msg_v01, - meta_data_len), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = QMI_WLFW_MAX_NUM_CAL_V01, - .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_cal_report_req_msg_v01, - meta_data), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cal_report_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_cal_report_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = { - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_initiate_cal_download_ind_msg_v01, - cal_id), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cal_download_req_msg_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - valid), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - file_id_valid), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - file_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - total_size_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - total_size), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - seg_id_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - seg_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - data_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint16_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - data_len), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, - .elem_size = sizeof(uint8_t), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - data), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - end_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_cal_download_req_msg_v01, - end), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cal_download_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_cal_download_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = { - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, - cal_id), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, - total_size), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cal_update_req_msg_v01_ei[] = { - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_cal_update_req_msg_v01, - cal_id), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_cal_update_req_msg_v01, - seg_id), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_cal_update_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - file_id_valid), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - file_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - total_size_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - total_size), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - seg_id_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - seg_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - data_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint16_t), - .is_array = NO_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - data_len), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, - .elem_size = sizeof(uint8_t), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x13, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - data), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - end_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x14, - .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, - end), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_msa_info_req_msg_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint64_t), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct wlfw_msa_info_req_msg_v01, - msa_addr), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_msa_info_req_msg_v01, - size), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_msa_info_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x03, - .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, - mem_region_info_len), - }, - { - .data_type = QMI_STRUCT, - .elem_len = QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01, - .elem_size = sizeof(struct wlfw_memory_region_info_s_v01), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x03, - .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, - mem_region_info), - .ei_array = wlfw_memory_region_info_s_v01_ei, - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_msa_ready_req_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_msa_ready_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_ini_req_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_ini_req_msg_v01, - enablefwlog_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct wlfw_ini_req_msg_v01, - enablefwlog), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info wlfw_ini_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct wlfw_ini_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, - }, -}; diff --git a/drivers/soc/qcom/wlan_firmware_service_v01.h b/drivers/soc/qcom/wlan_firmware_service_v01.h deleted file mode 100644 index 6e96cbabd9d8c414ef2f7a112e5e621827c7b496..0000000000000000000000000000000000000000 --- a/drivers/soc/qcom/wlan_firmware_service_v01.h +++ /dev/null @@ -1,372 +0,0 @@ - /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * 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. - * - */ -#ifndef WLAN_FIRMWARE_SERVICE_V01_H -#define WLAN_FIRMWARE_SERVICE_V01_H - -#define WLFW_SERVICE_ID_V01 0x45 -#define WLFW_SERVICE_VERS_V01 0x01 - -#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025 -#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A -#define QMI_WLFW_CAP_REQ_V01 0x0024 -#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026 -#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029 -#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027 -#define QMI_WLFW_INI_RESP_V01 0x002F -#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026 -#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028 -#define QMI_WLFW_MSA_READY_IND_V01 0x002B -#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022 -#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020 -#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023 -#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022 -#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C -#define QMI_WLFW_FW_READY_IND_V01 0x0021 -#define QMI_WLFW_MSA_READY_RESP_V01 0x002E -#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029 -#define QMI_WLFW_INI_REQ_V01 0x002F -#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025 -#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D -#define QMI_WLFW_MSA_READY_REQ_V01 0x002E -#define QMI_WLFW_CAP_RESP_V01 0x0024 -#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D -#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027 -#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023 -#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020 - -#define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2 -#define QMI_WLFW_MAX_NUM_CAL_V01 5 -#define QMI_WLFW_MAX_DATA_SIZE_V01 6144 -#define QMI_WLFW_MAX_NUM_CE_V01 12 -#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32 -#define QMI_WLFW_MAX_STR_LEN_V01 16 -#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24 -#define QMI_WLFW_MAX_NUM_SVC_V01 24 - -enum wlfw_driver_mode_enum_v01 { - WLFW_DRIVER_MODE_ENUM_MIN_VAL_V01 = INT_MIN, - QMI_WLFW_MISSION_V01 = 0, - QMI_WLFW_FTM_V01 = 1, - QMI_WLFW_EPPING_V01 = 2, - QMI_WLFW_WALTEST_V01 = 3, - QMI_WLFW_OFF_V01 = 4, - QMI_WLFW_CCPM_V01 = 5, - QMI_WLFW_QVIT_V01 = 6, - WLFW_DRIVER_MODE_ENUM_MAX_VAL_V01 = INT_MAX, -}; - -enum wlfw_cal_temp_id_enum_v01 { - WLFW_CAL_TEMP_ID_ENUM_MIN_VAL_V01 = INT_MIN, - QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0, - QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1, - QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2, - QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3, - QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4, - WLFW_CAL_TEMP_ID_ENUM_MAX_VAL_V01 = INT_MAX, -}; - -enum wlfw_pipedir_enum_v01 { - WLFW_PIPEDIR_ENUM_MIN_VAL_V01 = INT_MIN, - QMI_WLFW_PIPEDIR_NONE_V01 = 0, - QMI_WLFW_PIPEDIR_IN_V01 = 1, - QMI_WLFW_PIPEDIR_OUT_V01 = 2, - QMI_WLFW_PIPEDIR_INOUT_V01 = 3, - WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX, -}; - -#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((uint32_t)0x00) -#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((uint32_t)0x01) -#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((uint32_t)0x02) -#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((uint32_t)0x04) -#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((uint32_t)0x08) -#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((uint32_t)0x10) - -struct wlfw_ce_tgt_pipe_cfg_s_v01 { - uint32_t pipe_num; - enum wlfw_pipedir_enum_v01 pipe_dir; - uint32_t nentries; - uint32_t nbytes_max; - uint32_t flags; -}; - -struct wlfw_ce_svc_pipe_cfg_s_v01 { - uint32_t service_id; - enum wlfw_pipedir_enum_v01 pipe_dir; - uint32_t pipe_num; -}; - -struct wlfw_shadow_reg_cfg_s_v01 { - uint16_t id; - uint16_t offset; -}; - -struct wlfw_memory_region_info_s_v01 { - uint64_t region_addr; - uint32_t size; - uint8_t secure_flag; -}; - -struct wlfw_rf_chip_info_s_v01 { - uint32_t chip_id; - uint32_t chip_family; -}; - -struct wlfw_rf_board_info_s_v01 { - uint32_t board_id; -}; - -struct wlfw_soc_info_s_v01 { - uint32_t soc_id; -}; - -struct wlfw_fw_version_info_s_v01 { - uint32_t fw_version; - char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1]; -}; - -struct wlfw_ind_register_req_msg_v01 { - uint8_t fw_ready_enable_valid; - uint8_t fw_ready_enable; - uint8_t initiate_cal_download_enable_valid; - uint8_t initiate_cal_download_enable; - uint8_t initiate_cal_update_enable_valid; - uint8_t initiate_cal_update_enable; - uint8_t msa_ready_enable_valid; - uint8_t msa_ready_enable; - uint8_t pin_connect_result_enable_valid; - uint8_t pin_connect_result_enable; -}; -#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 20 -extern struct elem_info wlfw_ind_register_req_msg_v01_ei[]; - -struct wlfw_ind_register_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_ind_register_resp_msg_v01_ei[]; - -struct wlfw_fw_ready_ind_msg_v01 { - char placeholder; -}; -#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0 -extern struct elem_info wlfw_fw_ready_ind_msg_v01_ei[]; - -struct wlfw_msa_ready_ind_msg_v01 { - char placeholder; -}; -#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0 -extern struct elem_info wlfw_msa_ready_ind_msg_v01_ei[]; - -struct wlfw_pin_connect_result_ind_msg_v01 { - uint8_t pwr_pin_result_valid; - uint32_t pwr_pin_result; - uint8_t phy_io_pin_result_valid; - uint32_t phy_io_pin_result; - uint8_t rf_pin_result_valid; - uint32_t rf_pin_result; -}; -#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21 -extern struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[]; - -struct wlfw_wlan_mode_req_msg_v01 { - enum wlfw_driver_mode_enum_v01 mode; -}; -#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_wlan_mode_req_msg_v01_ei[]; - -struct wlfw_wlan_mode_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[]; - -struct wlfw_wlan_cfg_req_msg_v01 { - uint8_t host_version_valid; - char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1]; - uint8_t tgt_cfg_valid; - uint32_t tgt_cfg_len; - struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01]; - uint8_t svc_cfg_valid; - uint32_t svc_cfg_len; - struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01]; - uint8_t shadow_reg_valid; - uint32_t shadow_reg_len; - struct wlfw_shadow_reg_cfg_s_v01 shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01]; -}; -#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 655 -extern struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[]; - -struct wlfw_wlan_cfg_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[]; - -struct wlfw_cap_req_msg_v01 { - char placeholder; -}; -#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0 -extern struct elem_info wlfw_cap_req_msg_v01_ei[]; - -struct wlfw_cap_resp_msg_v01 { - struct qmi_response_type_v01 resp; - uint8_t chip_info_valid; - struct wlfw_rf_chip_info_s_v01 chip_info; - uint8_t board_info_valid; - struct wlfw_rf_board_info_s_v01 board_info; - uint8_t soc_info_valid; - struct wlfw_soc_info_s_v01 soc_info; - uint8_t fw_version_info_valid; - struct wlfw_fw_version_info_s_v01 fw_version_info; -}; -#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 72 -extern struct elem_info wlfw_cap_resp_msg_v01_ei[]; - -struct wlfw_bdf_download_req_msg_v01 { - uint8_t valid; - uint8_t file_id_valid; - enum wlfw_cal_temp_id_enum_v01 file_id; - uint8_t total_size_valid; - uint32_t total_size; - uint8_t seg_id_valid; - uint32_t seg_id; - uint8_t data_valid; - uint32_t data_len; - uint8_t data[QMI_WLFW_MAX_DATA_SIZE_V01]; - uint8_t end_valid; - uint8_t end; -}; -#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178 -extern struct elem_info wlfw_bdf_download_req_msg_v01_ei[]; - -struct wlfw_bdf_download_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_bdf_download_resp_msg_v01_ei[]; - -struct wlfw_cal_report_req_msg_v01 { - uint32_t meta_data_len; - enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01]; -}; -#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 24 -extern struct elem_info wlfw_cal_report_req_msg_v01_ei[]; - -struct wlfw_cal_report_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_cal_report_resp_msg_v01_ei[]; - -struct wlfw_initiate_cal_download_ind_msg_v01 { - enum wlfw_cal_temp_id_enum_v01 cal_id; -}; -#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[]; - -struct wlfw_cal_download_req_msg_v01 { - uint8_t valid; - uint8_t file_id_valid; - enum wlfw_cal_temp_id_enum_v01 file_id; - uint8_t total_size_valid; - uint32_t total_size; - uint8_t seg_id_valid; - uint32_t seg_id; - uint8_t data_valid; - uint32_t data_len; - uint8_t data[QMI_WLFW_MAX_DATA_SIZE_V01]; - uint8_t end_valid; - uint8_t end; -}; -#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178 -extern struct elem_info wlfw_cal_download_req_msg_v01_ei[]; - -struct wlfw_cal_download_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_cal_download_resp_msg_v01_ei[]; - -struct wlfw_initiate_cal_update_ind_msg_v01 { - enum wlfw_cal_temp_id_enum_v01 cal_id; - uint32_t total_size; -}; -#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14 -extern struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[]; - -struct wlfw_cal_update_req_msg_v01 { - enum wlfw_cal_temp_id_enum_v01 cal_id; - uint32_t seg_id; -}; -#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14 -extern struct elem_info wlfw_cal_update_req_msg_v01_ei[]; - -struct wlfw_cal_update_resp_msg_v01 { - struct qmi_response_type_v01 resp; - uint8_t file_id_valid; - enum wlfw_cal_temp_id_enum_v01 file_id; - uint8_t total_size_valid; - uint32_t total_size; - uint8_t seg_id_valid; - uint32_t seg_id; - uint8_t data_valid; - uint32_t data_len; - uint8_t data[QMI_WLFW_MAX_DATA_SIZE_V01]; - uint8_t end_valid; - uint8_t end; -}; -#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181 -extern struct elem_info wlfw_cal_update_resp_msg_v01_ei[]; - -struct wlfw_msa_info_req_msg_v01 { - uint64_t msa_addr; - uint32_t size; -}; -#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 -extern struct elem_info wlfw_msa_info_req_msg_v01_ei[]; - -struct wlfw_msa_info_resp_msg_v01 { - struct qmi_response_type_v01 resp; - uint32_t mem_region_info_len; - struct wlfw_memory_region_info_s_v01 - mem_region_info[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01]; -}; -#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37 -extern struct elem_info wlfw_msa_info_resp_msg_v01_ei[]; - -struct wlfw_msa_ready_req_msg_v01 { - char placeholder; -}; -#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0 -extern struct elem_info wlfw_msa_ready_req_msg_v01_ei[]; - -struct wlfw_msa_ready_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_msa_ready_resp_msg_v01_ei[]; - -struct wlfw_ini_req_msg_v01 { - uint8_t enablefwlog_valid; - uint8_t enablefwlog; -}; -#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4 -extern struct elem_info wlfw_ini_req_msg_v01_ei[]; - -struct wlfw_ini_resp_msg_v01 { - struct qmi_response_type_v01 resp; -}; -#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7 -extern struct elem_info wlfw_ini_resp_msg_v01_ei[]; - -#endif diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c index 49dd07818a4df033d291d3fd781969cdf8de9de2..22ac66a4f7dac7433f9e28b3806e23d6141689e3 100644 --- a/drivers/soundwire/swr-wcd-ctrl.c +++ b/drivers/soundwire/swr-wcd-ctrl.c @@ -373,11 +373,17 @@ static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable) return -EINVAL; if (enable) { - swrm->clk(swrm->handle, true); - swrm->state = SWR_MSTR_UP; - } else { + swrm->clk_ref_count++; + if (swrm->clk_ref_count == 1) { + swrm->clk(swrm->handle, true); + swrm->state = SWR_MSTR_UP; + } + } else if (--swrm->clk_ref_count == 0) { swrm->clk(swrm->handle, false); swrm->state = SWR_MSTR_DOWN; + } else if (swrm->clk_ref_count < 0) { + pr_err("%s: swrm clk count mismatch\n", __func__); + swrm->clk_ref_count = 0; } return 0; } @@ -1136,7 +1142,10 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev) u8 devnum = 0; int ret = IRQ_HANDLED; - pm_runtime_get_sync(&swrm->pdev->dev); + mutex_lock(&swrm->reslock); + swrm_clk_request(swrm, true); + mutex_unlock(&swrm->reslock); + intr_sts = swrm->read(swrm->handle, SWRM_INTERRUPT_STATUS); intr_sts &= SWRM_INTERRUPT_STATUS_RMSK; for (i = 0; i < SWRM_INTERRUPT_MAX; i++) { @@ -1224,8 +1233,10 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev) break; } } - pm_runtime_mark_last_busy(&swrm->pdev->dev); - pm_runtime_put_autosuspend(&swrm->pdev->dev); + + mutex_lock(&swrm->reslock); + swrm_clk_request(swrm, false); + mutex_unlock(&swrm->reslock); return ret; } @@ -1416,6 +1427,7 @@ static int swrm_probe(struct platform_device *pdev) swrm->wcmd_id = 0; swrm->slave_status = 0; swrm->num_rx_chs = 0; + swrm->clk_ref_count = 0; swrm->state = SWR_MSTR_RESUME; init_completion(&swrm->reset); init_completion(&swrm->broadcast); diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h index 8992318cdbd3577db1041a4c4a0fbbc6c0094ed3..57327cb87bcca4d2be6bcfadae3f74aa96f56570 100644 --- a/drivers/soundwire/swr-wcd-ctrl.h +++ b/drivers/soundwire/swr-wcd-ctrl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * 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 @@ -74,6 +74,7 @@ struct swr_mstr_ctrl { struct device *dev; struct resource *supplies; struct clk *mclk; + int clk_ref_count; struct completion reset; struct completion broadcast; struct mutex mlock; diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 4bf337aa4fd532c06c24cceb61773a3281feec1c..fab124d3b8a669ebb70a3adfeb62baadc32bf4a6 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1416,12 +1416,12 @@ static int atmel_spi_remove(struct platform_device *pdev) struct atmel_spi *as = spi_master_get_devdata(master); /* reset the hardware and block queue progress */ - spin_lock_irq(&as->lock); if (as->use_dma) { atmel_spi_stop_dma(as); atmel_spi_release_dma(as); } + spin_lock_irq(&as->lock); spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ spi_readl(as, SR); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 63700ab7bd9ff6687d03d7f900f1ddbc98a69d27..1107a5d5a2565879608a8aa15f64b62b1aef9ff8 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -230,7 +230,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) } /* program delay transfers if tx_delay is non zero */ - if (spicfg->wdelay) + if (spicfg && spicfg->wdelay) spidat1 |= SPIDAT1_WDEL; /* diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 21ce0e36fa0016725fddc3c6998a38b5a00d8e49..d3b6501db535c8811c529fbc1c9e9f04751c6b6f 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -118,8 +118,8 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) { struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); - clk_disable_unprepare(dwsmmio->clk); dw_spi_remove_host(&dwsmmio->dws); + clk_disable_unprepare(dwsmmio->clk); return 0; } diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index bf0effb861372d01e2badc2e0225bce0ce6a7f87..4c5e43f6f7f636507838ca9c0e8e3d146568314e 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1220,12 +1220,23 @@ static int spi_imx_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct spi_imx_data *spi_imx = spi_master_get_devdata(master); + int ret; spi_bitbang_stop(&spi_imx->bitbang); + ret = clk_enable(spi_imx->clk_per); + if (ret) + return ret; + + ret = clk_enable(spi_imx->clk_ipg); + if (ret) { + clk_disable(spi_imx->clk_per); + return ret; + } + writel(0, spi_imx->base + MXC_CSPICTRL); - clk_unprepare(spi_imx->clk_ipg); - clk_unprepare(spi_imx->clk_per); + clk_disable_unprepare(spi_imx->clk_ipg); + clk_disable_unprepare(spi_imx->clk_per); spi_imx_sdma_exit(spi_imx); spi_master_put(master); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 352eed7463aca0dc23d104178538236f5534257c..7f48cb57822c6fcdd9ddffed7067ca8895123647 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -441,6 +441,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, int elements = 0; int word_len, element_count; struct omap2_mcspi_cs *cs = spi->controller_state; + void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; + mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; count = xfer->len; @@ -501,8 +503,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, if (l & OMAP2_MCSPI_CHCONF_TURBO) { elements--; - if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { + if (!mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_RXS)) { u32 w; w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); @@ -520,8 +522,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, return count; } } - if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { + if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) { u32 w; w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 54bb0faec1555810b07e43245d56df1eb884f4f2..4ee0bfa86e4a567fa172db5d7cd9b0df5c9d9b0a 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -538,11 +538,13 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, ret = wait_event_interruptible_timeout(rspi->wait, rspi->dma_callbacked, HZ); - if (ret > 0 && rspi->dma_callbacked) + if (ret > 0 && rspi->dma_callbacked) { ret = 0; - else if (!ret) { - dev_err(&rspi->master->dev, "DMA timeout\n"); - ret = -ETIMEDOUT; + } else { + if (!ret) { + dev_err(&rspi->master->dev, "DMA timeout\n"); + ret = -ETIMEDOUT; + } if (tx) dmaengine_terminate_all(rspi->master->dma_tx); if (rx) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 14052936b1c5196063b1315f158cc8c106a9a719..df6eca8088c262f152c794e55a6283a82372790c 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -332,7 +332,8 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p) { - sh_msiof_write(p, STR, sh_msiof_read(p, STR)); + sh_msiof_write(p, STR, + sh_msiof_read(p, STR) & ~(STR_TDREQ | STR_RDREQ)); } static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p, @@ -818,7 +819,7 @@ static int sh_msiof_transfer_one(struct spi_master *master, break; copy32 = copy_bswap32; } else if (bits <= 16) { - if (l & 1) + if (l & 3) break; copy32 = copy_wswap32; } else { diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 19169bf9bf4d38e3b8b7b53612fe491ff674395a..510f7d8d9a6a1380da33e6ec48171c0972e116f7 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -458,7 +458,7 @@ err_free_master: static int sun4i_spi_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); + pm_runtime_force_suspend(&pdev->dev); return 0; } diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 04e90851504c55960fb6693b684bfb57421e916e..6c042384a8c1016b9ca9ebde4a85b5e6ebc50ca0 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -457,7 +457,7 @@ err_free_master: static int sun6i_spi_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); + pm_runtime_force_suspend(&pdev->dev); return 0; } diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 0b9e32e9f493fee14ad73acb48cd6ebce9e96c00..4ba5bbb619511fdd8de9a8aa9017d60eddf444a2 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1063,6 +1063,24 @@ static int tegra_slink_probe(struct platform_device *pdev) goto exit_free_master; } + /* disabled clock may cause interrupt storm upon request */ + tspi->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(tspi->clk)) { + ret = PTR_ERR(tspi->clk); + dev_err(&pdev->dev, "Can not get clock %d\n", ret); + goto exit_free_master; + } + ret = clk_prepare(tspi->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Clock prepare failed %d\n", ret); + goto exit_free_master; + } + ret = clk_enable(tspi->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Clock enable failed %d\n", ret); + goto exit_free_master; + } + spi_irq = platform_get_irq(pdev, 0); tspi->irq = spi_irq; ret = request_threaded_irq(tspi->irq, tegra_slink_isr, @@ -1071,14 +1089,7 @@ static int tegra_slink_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", tspi->irq); - goto exit_free_master; - } - - tspi->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(tspi->clk)) { - dev_err(&pdev->dev, "can not get clock\n"); - ret = PTR_ERR(tspi->clk); - goto exit_free_irq; + goto exit_clk_disable; } tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); @@ -1138,6 +1149,8 @@ exit_rx_dma_free: tegra_slink_deinit_dma_param(tspi, true); exit_free_irq: free_irq(spi_irq, tspi); +exit_clk_disable: + clk_disable(tspi->clk); exit_free_master: spi_master_put(master); return ret; @@ -1150,6 +1163,8 @@ static int tegra_slink_remove(struct platform_device *pdev) free_irq(tspi->irq, tspi); + clk_disable(tspi->clk); + if (tspi->tx_dma_chan) tegra_slink_deinit_dma_param(tspi, false); diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 0887bc76b5f1db053c2809278e59ba7687321d42..610ac23a6a85fe34379758a19899f4e543beb1ba 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -44,6 +44,16 @@ config ANDROID_BINDER_DEVICES created. Each binder device has its own context manager, and is therefore logically separated from the other devices. +config ANDROID_BINDER_IPC_SELFTEST + bool "Android Binder IPC Driver Selftest" + depends on ANDROID_BINDER_IPC + ---help--- + This feature allows binder selftest to run. + + Binder selftest checks the allocation and free of binder buffers + exhaustively with combinations of various buffer sizes and + alignments. + config ASHMEM bool "Enable the Anonymous Shared Memory Subsystem" default n @@ -138,13 +148,14 @@ config ONESHOT_SYNC_USER help Provide a userspace API for creating oneshot sync objects. -config SYNC_DEBUG - bool "Debug software synchronization" +config ANDROID_VSOC + tristate "Android Virtual SoC support" default n - depends on SYNC + depends on PCI_MSI ---help--- - This makes the sync driver keep track of fence names. - + This option adds support for the Virtual SoC driver needed to boot + a 'cuttlefish' Android image inside QEmu. The driver interacts with + a QEmu ivshmem device. If built as a module, it will be called vsoc. source "drivers/staging/android/ion/Kconfig" diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 29642b930201fca30e290242bbacf78160aa6485..d8ccbcdf94461e8ea598b06464e84cadbe21f2ff 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -4,6 +4,7 @@ obj-y += ion/ obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/ obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o +obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_LOGGER) += logger.o obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o @@ -12,3 +13,4 @@ obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o obj-$(CONFIG_SYNC) += sync.o obj-$(CONFIG_SW_SYNC) += sw_sync.o obj-$(CONFIG_ONESHOT_SYNC) += oneshot_sync.o +obj-$(CONFIG_ANDROID_VSOC) += vsoc.o diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 986d2a77ce02b57aaadd922c0ff3c8ecf707f0f1..47aeac9e7d1d5cc3dce79f777ff538982dc28b39 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -334,24 +334,23 @@ static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&ashmem_mutex); if (asma->size == 0) { - ret = -EINVAL; - goto out; + mutex_unlock(&ashmem_mutex); + return -EINVAL; } if (!asma->file) { - ret = -EBADF; - goto out; + mutex_unlock(&ashmem_mutex); + return -EBADF; } + mutex_unlock(&ashmem_mutex); + ret = vfs_llseek(asma->file, offset, origin); if (ret < 0) - goto out; + return ret; /** Copy f_pos from backing file, since f_ops->llseek() sets it */ file->f_pos = asma->file->f_pos; - -out: - mutex_unlock(&ashmem_mutex); return ret; } diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 312153269f3d04be35e1e2a95ed9930331628945..a6ce187e2a06c18bec3e69ff2c67016001c29da1 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -52,6 +52,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -240,14 +241,6 @@ struct binder_transaction_log { static struct binder_transaction_log binder_transaction_log; static struct binder_transaction_log binder_transaction_log_failed; -static struct kmem_cache *binder_node_pool; -static struct kmem_cache *binder_proc_pool; -static struct kmem_cache *binder_ref_death_pool; -static struct kmem_cache *binder_ref_pool; -static struct kmem_cache *binder_thread_pool; -static struct kmem_cache *binder_transaction_pool; -static struct kmem_cache *binder_work_pool; - static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) { @@ -364,7 +357,6 @@ struct binder_error { * @min_priority: minimum scheduling priority * (invariant after initialized) * @inherit_rt: inherit RT scheduling policy from caller - * @txn_security_ctx: require sender's security context * (invariant after initialized) * @async_todo: list of async work items * (protected by @proc->inner_lock) @@ -404,7 +396,6 @@ struct binder_node { u8 sched_policy:2; u8 inherit_rt:1; u8 accept_fds:1; - u8 txn_security_ctx:1; u8 min_priority; }; bool has_async_transaction; @@ -662,7 +653,6 @@ struct binder_transaction { struct binder_priority saved_priority; bool set_priority_called; kuid_t sender_euid; - binder_uintptr_t security_ctx; /** * @lock: protects @from, @to_proc, and @to_thread * @@ -1372,7 +1362,6 @@ static struct binder_node *binder_init_node_ilocked( node->min_priority = to_kernel_prio(node->sched_policy, priority); node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT); - node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX); spin_lock_init(&node->lock); INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); @@ -1387,9 +1376,9 @@ static struct binder_node *binder_init_node_ilocked( static struct binder_node *binder_new_node(struct binder_proc *proc, struct flat_binder_object *fp) { - struct binder_node *node, *new_node; + struct binder_node *node; + struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL); - new_node = kmem_cache_zalloc(binder_node_pool, GFP_KERNEL); if (!new_node) return NULL; binder_inner_proc_lock(proc); @@ -1399,14 +1388,14 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, /* * The node was already added by another thread */ - kmem_cache_free(binder_node_pool, new_node); + kfree(new_node); return node; } static void binder_free_node(struct binder_node *node) { - kmem_cache_free(binder_node_pool, node); + kfree(node); binder_stats_deleted(BINDER_STAT_NODE); } @@ -1894,9 +1883,8 @@ static void binder_free_ref(struct binder_ref *ref) { if (ref->node) binder_free_node(ref->node); - if (ref->death) - kmem_cache_free(binder_ref_death_pool, ref->death); - kmem_cache_free(binder_ref_pool, ref); + kfree(ref->death); + kfree(ref); } /** @@ -1989,7 +1977,7 @@ static int binder_inc_ref_for_node(struct binder_proc *proc, ref = binder_get_ref_for_node_olocked(proc, node, NULL); if (!ref) { binder_proc_unlock(proc); - new_ref = kmem_cache_zalloc(binder_ref_pool, GFP_KERNEL); + new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); if (!new_ref) return -ENOMEM; binder_proc_lock(proc); @@ -2003,7 +1991,7 @@ static int binder_inc_ref_for_node(struct binder_proc *proc, * Another thread created the ref first so * free the one we allocated */ - kmem_cache_free(binder_ref_pool, new_ref); + kfree(new_ref); return ret; } @@ -2128,7 +2116,7 @@ static void binder_free_transaction(struct binder_transaction *t) { if (t->buffer) t->buffer->transaction = NULL; - kmem_cache_free(binder_transaction_pool, t); + kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); } @@ -2358,7 +2346,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, int debug_id = buffer->debug_id; binder_debug(BINDER_DEBUG_TRANSACTION, - "%d buffer release %d, size %zd-%zd, failed at %p\n", + "%d buffer release %d, size %zd-%zd, failed at %pK\n", proc->pid, buffer->debug_id, buffer->data_size, buffer->offsets_size, failed_at); @@ -2906,8 +2894,6 @@ static void binder_transaction(struct binder_proc *proc, binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; int t_debug_id = atomic_inc_return(&binder_last_id); - char *secctx = NULL; - u32 secctx_sz = 0; e = binder_transaction_log_add(&binder_transaction_log); e->debug_id = t_debug_id; @@ -3072,7 +3058,7 @@ static void binder_transaction(struct binder_proc *proc, e->to_proc = target_proc->pid; /* TODO: reuse incoming transaction for reply */ - t = kmem_cache_zalloc(binder_transaction_pool, GFP_KERNEL); + t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) { return_error = BR_FAILED_REPLY; return_error_param = -ENOMEM; @@ -3082,7 +3068,7 @@ static void binder_transaction(struct binder_proc *proc, binder_stats_created(BINDER_STAT_TRANSACTION); spin_lock_init(&t->lock); - tcomplete = kmem_cache_zalloc(binder_work_pool, GFP_KERNEL); + tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; return_error_param = -ENOMEM; @@ -3131,29 +3117,6 @@ static void binder_transaction(struct binder_proc *proc, t->priority = target_proc->default_priority; } - if (target_node && target_node->txn_security_ctx) { - u32 secid; - size_t added_size; - - security_task_getsecid(proc->tsk, &secid); - ret = security_secid_to_secctx(secid, &secctx, &secctx_sz); - if (ret) { - return_error = BR_FAILED_REPLY; - return_error_param = ret; - return_error_line = __LINE__; - goto err_get_secctx_failed; - } - added_size = ALIGN(secctx_sz, sizeof(u64)); - extra_buffers_size += added_size; - if (extra_buffers_size < added_size) { - /* integer overflow of extra_buffers_size */ - return_error = BR_FAILED_REPLY; - return_error_param = EINVAL; - return_error_line = __LINE__; - goto err_bad_extra_size; - } - } - trace_binder_transaction(reply, t, target_node); t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, @@ -3170,19 +3133,7 @@ static void binder_transaction(struct binder_proc *proc, t->buffer = NULL; goto err_binder_alloc_buf_failed; } - if (secctx) { - size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) + - ALIGN(tr->offsets_size, sizeof(void *)) + - ALIGN(extra_buffers_size, sizeof(void *)) - - ALIGN(secctx_sz, sizeof(u64)); - char *kptr = t->buffer->data + buf_offset; - - t->security_ctx = (uintptr_t)kptr + - binder_alloc_get_user_buffer_offset(&target_proc->alloc); - memcpy(kptr, secctx, secctx_sz); - security_release_secctx(secctx, secctx_sz); - secctx = NULL; - } + t->buffer->allow_user_free = 0; t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; @@ -3391,8 +3342,8 @@ static void binder_transaction(struct binder_proc *proc, BUG_ON(t->buffer->async_transaction != 0); binder_pop_transaction_ilocked(target_thread, in_reply_to); binder_enqueue_thread_work_ilocked(target_thread, &t->work); - wake_up_interruptible(&target_thread->wait); binder_inner_proc_unlock(target_proc); + wake_up_interruptible_sync(&target_thread->wait); binder_restore_priority(current, in_reply_to->saved_priority); binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { @@ -3453,14 +3404,10 @@ err_copy_data_failed: t->buffer->transaction = NULL; binder_alloc_free_buf(&target_proc->alloc, t->buffer); err_binder_alloc_buf_failed: -err_bad_extra_size: - if (secctx) - security_release_secctx(secctx, secctx_sz); -err_get_secctx_failed: - kmem_cache_free(binder_work_pool, tcomplete); + kfree(tcomplete); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); err_alloc_tcomplete_failed: - kmem_cache_free(binder_transaction_pool, t); + kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: err_bad_call_stack: @@ -3682,18 +3629,14 @@ static int binder_thread_write(struct binder_proc *proc, buffer = binder_alloc_prepare_to_free(&proc->alloc, data_ptr); - if (IS_ERR_OR_NULL(buffer)) { - if (PTR_ERR(buffer) == -EPERM) { - binder_user_error( - "%d:%d BC_FREE_BUFFER u%016llx matched unreturned or currently freeing buffer\n", - proc->pid, thread->pid, - (u64)data_ptr); - } else { - binder_user_error( - "%d:%d BC_FREE_BUFFER u%016llx no match\n", - proc->pid, thread->pid, - (u64)data_ptr); - } + if (buffer == NULL) { + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, (u64)data_ptr); + break; + } + if (!buffer->allow_user_free) { + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", + proc->pid, thread->pid, (u64)data_ptr); break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, @@ -3810,7 +3753,7 @@ static int binder_thread_write(struct binder_proc *proc, * Allocate memory for death notification * before taking lock */ - death = kmem_cache_zalloc(binder_ref_death_pool, GFP_KERNEL); + death = kzalloc(sizeof(*death), GFP_KERNEL); if (death == NULL) { WARN_ON(thread->return_error.cmd != BR_OK); @@ -3835,8 +3778,7 @@ static int binder_thread_write(struct binder_proc *proc, "BC_CLEAR_DEATH_NOTIFICATION", target); binder_proc_unlock(proc); - if (death) - kmem_cache_free(binder_ref_death_pool, death); + kfree(death); break; } @@ -3857,7 +3799,7 @@ static int binder_thread_write(struct binder_proc *proc, proc->pid, thread->pid); binder_node_unlock(ref->node); binder_proc_unlock(proc); - kmem_cache_free(binder_ref_death_pool, death); + kfree(death); break; } binder_stats_created(BINDER_STAT_DEATH); @@ -3940,7 +3882,7 @@ static int binder_thread_write(struct binder_proc *proc, } } binder_debug(BINDER_DEBUG_DEAD_BINDER, - "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", + "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n", proc->pid, thread->pid, (u64)cookie, death); if (death == NULL) { @@ -4104,13 +4046,11 @@ retry: while (1) { uint32_t cmd; - struct binder_transaction_data_secctx tr; - struct binder_transaction_data *trd = &tr.transaction_data; + struct binder_transaction_data tr; struct binder_work *w = NULL; struct list_head *list = NULL; struct binder_transaction *t = NULL; struct binder_thread *t_from; - size_t trsize = sizeof(*trd); binder_inner_proc_lock(proc); if (!binder_worklist_empty_ilocked(&thread->todo)) @@ -4164,7 +4104,7 @@ retry: binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, "%d:%d BR_TRANSACTION_COMPLETE\n", proc->pid, thread->pid); - kmem_cache_free(binder_work_pool, w); + kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; case BINDER_WORK_NODE: { @@ -4277,7 +4217,7 @@ retry: (u64)cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { binder_inner_proc_unlock(proc); - kmem_cache_free(binder_ref_death_pool, death); + kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } else { binder_enqueue_work_ilocked( @@ -4305,47 +4245,41 @@ retry: struct binder_node *target_node = t->buffer->target_node; struct binder_priority node_prio; - trd->target.ptr = target_node->ptr; - trd->cookie = target_node->cookie; + tr.target.ptr = target_node->ptr; + tr.cookie = target_node->cookie; node_prio.sched_policy = target_node->sched_policy; node_prio.prio = target_node->min_priority; binder_transaction_priority(current, t, node_prio, target_node->inherit_rt); cmd = BR_TRANSACTION; } else { - trd->target.ptr = 0; - trd->cookie = 0; + tr.target.ptr = 0; + tr.cookie = 0; cmd = BR_REPLY; } - trd->code = t->code; - trd->flags = t->flags; - trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid); + tr.code = t->code; + tr.flags = t->flags; + tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); t_from = binder_get_txn_from(t); if (t_from) { struct task_struct *sender = t_from->proc->tsk; - trd->sender_pid = - task_tgid_nr_ns(sender, - task_active_pid_ns(current)); + tr.sender_pid = task_tgid_nr_ns(sender, + task_active_pid_ns(current)); } else { - trd->sender_pid = 0; + tr.sender_pid = 0; } - trd->data_size = t->buffer->data_size; - trd->offsets_size = t->buffer->offsets_size; - trd->data.ptr.buffer = (binder_uintptr_t) + tr.data_size = t->buffer->data_size; + tr.offsets_size = t->buffer->offsets_size; + tr.data.ptr.buffer = (binder_uintptr_t) ((uintptr_t)t->buffer->data + binder_alloc_get_user_buffer_offset(&proc->alloc)); - trd->data.ptr.offsets = trd->data.ptr.buffer + + tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); - tr.secctx = t->security_ctx; - if (t->security_ctx) { - cmd = BR_TRANSACTION_SEC_CTX; - trsize = sizeof(tr); - } if (put_user(cmd, (uint32_t __user *)ptr)) { if (t_from) binder_thread_dec_tmpref(t_from); @@ -4356,7 +4290,7 @@ retry: return -EFAULT; } ptr += sizeof(uint32_t); - if (copy_to_user(ptr, &tr, trsize)) { + if (copy_to_user(ptr, &tr, sizeof(tr))) { if (t_from) binder_thread_dec_tmpref(t_from); @@ -4365,7 +4299,7 @@ retry: return -EFAULT; } - ptr += trsize; + ptr += sizeof(tr); trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); @@ -4373,18 +4307,16 @@ retry: "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : - (cmd == BR_TRANSACTION_SEC_CTX) ? - "BR_TRANSACTION_SEC_CTX" : "BR_REPLY", + "BR_REPLY", t->debug_id, t_from ? t_from->proc->pid : 0, t_from ? t_from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - (u64)trd->data.ptr.buffer, - (u64)trd->data.ptr.offsets); + (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); if (t_from) binder_thread_dec_tmpref(t_from); t->buffer->allow_user_free = 1; - if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) { + if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { binder_inner_proc_lock(thread->proc); t->to_parent = thread->transaction_stack; t->to_thread = thread; @@ -4449,7 +4381,7 @@ static void binder_release_work(struct binder_proc *proc, case BINDER_WORK_TRANSACTION_COMPLETE: { binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "undelivered TRANSACTION_COMPLETE\n"); - kmem_cache_free(binder_work_pool, w); + kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; case BINDER_WORK_DEAD_BINDER_AND_CLEAR: @@ -4460,7 +4392,7 @@ static void binder_release_work(struct binder_proc *proc, binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "undelivered death notification, %016llx\n", (u64)death->cookie); - kmem_cache_free(binder_ref_death_pool, death); + kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; default: @@ -4521,14 +4453,14 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) thread = binder_get_thread_ilocked(proc, NULL); binder_inner_proc_unlock(proc); if (!thread) { - new_thread = kmem_cache_zalloc(binder_thread_pool, GFP_KERNEL); + new_thread = kzalloc(sizeof(*thread), GFP_KERNEL); if (new_thread == NULL) return NULL; binder_inner_proc_lock(proc); thread = binder_get_thread_ilocked(proc, new_thread); binder_inner_proc_unlock(proc); if (thread != new_thread) - kmem_cache_free(binder_thread_pool, new_thread); + kfree(new_thread); } return thread; } @@ -4540,7 +4472,7 @@ static void binder_free_proc(struct binder_proc *proc) binder_alloc_deferred_release(&proc->alloc); put_task_struct(proc->tsk); binder_stats_deleted(BINDER_STAT_PROC); - kmem_cache_free(binder_proc_pool, proc); + kfree(proc); } static void binder_free_thread(struct binder_thread *thread) @@ -4549,7 +4481,7 @@ static void binder_free_thread(struct binder_thread *thread) binder_stats_deleted(BINDER_STAT_THREAD); binder_proc_dec_tmpref(thread->proc); put_task_struct(thread->task); - kmem_cache_free(binder_thread_pool, thread); + kfree(thread); } static int binder_thread_release(struct binder_proc *proc, @@ -4727,8 +4659,7 @@ out: return ret; } -static int binder_ioctl_set_ctx_mgr(struct file *filp, - struct flat_binder_object *fbo) +static int binder_ioctl_set_ctx_mgr(struct file *filp) { int ret = 0; struct binder_proc *proc = filp->private_data; @@ -4757,7 +4688,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp, } else { context->binder_context_mgr_uid = curr_euid; } - new_node = binder_new_node(proc, fbo); + new_node = binder_new_node(proc, NULL); if (!new_node) { ret = -ENOMEM; goto out; @@ -4879,20 +4810,8 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) binder_inner_proc_unlock(proc); break; } - case BINDER_SET_CONTEXT_MGR_EXT: { - struct flat_binder_object fbo; - - if (copy_from_user(&fbo, ubuf, sizeof(fbo))) { - ret = -EINVAL; - goto err; - } - ret = binder_ioctl_set_ctx_mgr(filp, &fbo); - if (ret) - goto err; - break; - } case BINDER_SET_CONTEXT_MGR: - ret = binder_ioctl_set_ctx_mgr(filp, NULL); + ret = binder_ioctl_set_ctx_mgr(filp); if (ret) goto err; break; @@ -5053,7 +4972,7 @@ static int binder_open(struct inode *nodp, struct file *filp) binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", current->group_leader->pid, current->pid); - proc = kmem_cache_zalloc(binder_proc_pool, GFP_KERNEL); + proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; spin_lock_init(&proc->inner_lock); @@ -5920,73 +5839,6 @@ static int __init init_binder_device(const char *name) return ret; } -static int __init binder_create_pools(void) -{ - int ret; - - ret = binder_buffer_pool_create(); - if (ret) - return ret; - - binder_node_pool = KMEM_CACHE(binder_node, SLAB_HWCACHE_ALIGN); - if (!binder_node_pool) - goto err_node_pool; - - binder_proc_pool = KMEM_CACHE(binder_proc, SLAB_HWCACHE_ALIGN); - if (!binder_proc_pool) - goto err_proc_pool; - - binder_ref_death_pool = KMEM_CACHE(binder_ref_death, SLAB_HWCACHE_ALIGN); - if (!binder_ref_death_pool) - goto err_ref_death_pool; - - binder_ref_pool = KMEM_CACHE(binder_ref, SLAB_HWCACHE_ALIGN); - if (!binder_ref_pool) - goto err_ref_pool; - - binder_thread_pool = KMEM_CACHE(binder_thread, SLAB_HWCACHE_ALIGN); - if (!binder_thread_pool) - goto err_thread_pool; - - binder_transaction_pool = KMEM_CACHE(binder_transaction, SLAB_HWCACHE_ALIGN); - if (!binder_transaction_pool) - goto err_transaction_pool; - - binder_work_pool = KMEM_CACHE(binder_work, SLAB_HWCACHE_ALIGN); - if (!binder_work_pool) - goto err_work_pool; - - return 0; - -err_work_pool: - kmem_cache_destroy(binder_transaction_pool); -err_transaction_pool: - kmem_cache_destroy(binder_thread_pool); -err_thread_pool: - kmem_cache_destroy(binder_ref_pool); -err_ref_pool: - kmem_cache_destroy(binder_ref_death_pool); -err_ref_death_pool: - kmem_cache_destroy(binder_proc_pool); -err_proc_pool: - kmem_cache_destroy(binder_node_pool); -err_node_pool: - binder_buffer_pool_destroy(); - return -ENOMEM; -} - -static void __init binder_destroy_pools(void) -{ - binder_buffer_pool_destroy(); - kmem_cache_destroy(binder_node_pool); - kmem_cache_destroy(binder_proc_pool); - kmem_cache_destroy(binder_ref_death_pool); - kmem_cache_destroy(binder_ref_pool); - kmem_cache_destroy(binder_thread_pool); - kmem_cache_destroy(binder_transaction_pool); - kmem_cache_destroy(binder_work_pool); -} - static int __init binder_init(void) { int ret; @@ -5994,17 +5846,12 @@ static int __init binder_init(void) struct binder_device *device; struct hlist_node *tmp; - ret = binder_create_pools(); - if (ret) - return ret; - binder_alloc_shrinker_init(); - atomic_set(&binder_transaction_log.cur, ~0U); atomic_set(&binder_transaction_log_failed.cur, ~0U); binder_deferred_workqueue = create_singlethread_workqueue("binder"); if (!binder_deferred_workqueue) - goto err_workqueue_init_failed; + return -ENOMEM; binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); if (binder_debugfs_dir_entry_root) @@ -6068,8 +5915,6 @@ err_alloc_device_names_failed: debugfs_remove_recursive(binder_debugfs_dir_entry_root); destroy_workqueue(binder_deferred_workqueue); -err_workqueue_init_failed: - binder_destroy_pools(); return ret; } diff --git a/drivers/staging/android/binder_alloc.c b/drivers/staging/android/binder_alloc.c index ed1d5e4eb7143c6ea7392da89f3992e3092d4c40..b900b0722b8bd9a5d341f209b5ed503b5a8566ff 100644 --- a/drivers/staging/android/binder_alloc.c +++ b/drivers/staging/android/binder_alloc.c @@ -51,22 +51,6 @@ module_param_named(debug_mask, binder_alloc_debug_mask, pr_info(x); \ } while (0) -static struct kmem_cache *binder_buffer_pool; - -int binder_buffer_pool_create(void) -{ - binder_buffer_pool = KMEM_CACHE(binder_buffer, SLAB_HWCACHE_ALIGN); - if (!binder_buffer_pool) - return -ENOMEM; - - return 0; -} - -void binder_buffer_pool_destroy(void) -{ - kmem_cache_destroy(binder_buffer_pool); -} - static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) { return list_entry(buffer->entry.next, struct binder_buffer, entry); @@ -165,12 +149,14 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked( else { /* * Guard against user threads attempting to - * free the buffer when in use by kernel or - * after it's already been freed. + * free the buffer twice */ - if (!buffer->allow_user_free) - return ERR_PTR(-EPERM); - buffer->allow_user_free = 0; + if (buffer->free_in_progress) { + pr_err("%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", + alloc->pid, current->pid, (u64)user_ptr); + return NULL; + } + buffer->free_in_progress = 1; return buffer; } } @@ -462,7 +448,7 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, if (buffer_size != size) { struct binder_buffer *new_buffer; - new_buffer = kmem_cache_zalloc(binder_buffer_pool, GFP_KERNEL); + new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (!new_buffer) { pr_err("%s: %d failed to alloc new buffer struct\n", __func__, alloc->pid); @@ -476,7 +462,7 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, rb_erase(best_fit, &alloc->free_buffers); buffer->free = 0; - buffer->allow_user_free = 0; + buffer->free_in_progress = 0; binder_insert_allocated_buffer_locked(alloc, buffer); binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, "%d: binder_alloc_buf size %zd got %pK\n", @@ -583,7 +569,7 @@ static void binder_delete_free_buffer(struct binder_alloc *alloc, buffer_start_page(buffer) + PAGE_SIZE); } list_del(&buffer->entry); - kmem_cache_free(binder_buffer_pool, buffer); + kfree(buffer); } static void binder_free_buf_locked(struct binder_alloc *alloc, @@ -716,7 +702,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, } alloc->buffer_size = vma->vm_end - vma->vm_start; - buffer = kmem_cache_zalloc(binder_buffer_pool, GFP_KERNEL); + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (!buffer) { ret = -ENOMEM; failure_string = "alloc buffer struct"; @@ -779,7 +765,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) list_del(&buffer->entry); WARN_ON_ONCE(!list_empty(&alloc->buffers)); - kmem_cache_free(binder_buffer_pool, buffer); + kfree(buffer); } page_count = 0; @@ -978,7 +964,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item, return LRU_REMOVED_RETRY; err_down_write_mmap_sem_failed: - mmput(mm); + mmput_async(mm); err_mmget: err_page_already_freed: mutex_unlock(&alloc->mutex); diff --git a/drivers/staging/android/binder_alloc.h b/drivers/staging/android/binder_alloc.h index c1eb75802aca76cff812117cee6052cb0bb2f88a..36b38558513c4ea1b5ed65193d05bc8a0ff9311e 100644 --- a/drivers/staging/android/binder_alloc.h +++ b/drivers/staging/android/binder_alloc.h @@ -50,7 +50,8 @@ struct binder_buffer { unsigned free:1; unsigned allow_user_free:1; unsigned async_transaction:1; - unsigned debug_id:29; + unsigned free_in_progress:1; + unsigned debug_id:28; struct binder_transaction *transaction; @@ -115,13 +116,15 @@ struct binder_alloc { size_t pages_high; }; +enum lru_status binder_alloc_free_page(struct list_head *item, + spinlock_t *lock, void *cb_arg); + #ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST void binder_selftest_alloc(struct binder_alloc *alloc); #else static inline void binder_selftest_alloc(struct binder_alloc *alloc) {} #endif -enum lru_status binder_alloc_free_page(struct list_head *item, - spinlock_t *lock, void *cb_arg); + extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t data_size, size_t offsets_size, @@ -143,8 +146,6 @@ extern void binder_alloc_print_allocated(struct seq_file *m, struct binder_alloc *alloc); void binder_alloc_print_pages(struct seq_file *m, struct binder_alloc *alloc); -extern int binder_buffer_pool_create(void); -extern void binder_buffer_pool_destroy(void); /** * binder_alloc_get_free_async_space() - get free space available for async diff --git a/drivers/staging/android/binder_alloc_selftest.c b/drivers/staging/android/binder_alloc_selftest.c new file mode 100644 index 0000000000000000000000000000000000000000..8bd7bcef967d28cf2921938ecd25dd8bea71b2c6 --- /dev/null +++ b/drivers/staging/android/binder_alloc_selftest.c @@ -0,0 +1,310 @@ +/* binder_alloc_selftest.c + * + * Android IPC Subsystem + * + * Copyright (C) 2017 Google, 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. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include "binder_alloc.h" + +#define BUFFER_NUM 5 +#define BUFFER_MIN_SIZE (PAGE_SIZE / 8) + +static bool binder_selftest_run = true; +static int binder_selftest_failures; +static DEFINE_MUTEX(binder_selftest_lock); + +/** + * enum buf_end_align_type - Page alignment of a buffer + * end with regard to the end of the previous buffer. + * + * In the pictures below, buf2 refers to the buffer we + * are aligning. buf1 refers to previous buffer by addr. + * Symbol [ means the start of a buffer, ] means the end + * of a buffer, and | means page boundaries. + */ +enum buf_end_align_type { + /** + * @SAME_PAGE_UNALIGNED: The end of this buffer is on + * the same page as the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 ][ ... + * buf1 ]|[ buf2 ][ ... + */ + SAME_PAGE_UNALIGNED = 0, + /** + * @SAME_PAGE_ALIGNED: When the end of the previous buffer + * is not page aligned, the end of this buffer is on the + * same page as the end of the previous buffer and is page + * aligned. When the previous buffer is page aligned, the + * end of this buffer is aligned to the next page boundary. + * Examples: + * buf1 ][ buf2 ]| ... + * buf1 ]|[ buf2 ]| ... + */ + SAME_PAGE_ALIGNED, + /** + * @NEXT_PAGE_UNALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 ][ ... + */ + NEXT_PAGE_UNALIGNED, + /** + * @NEXT_PAGE_ALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is page aligned. Examples: + * buf1 ][ buf2 | buf2 ]| ... + * buf1 ]|[ buf2 | buf2 ]| ... + */ + NEXT_PAGE_ALIGNED, + /** + * @NEXT_NEXT_UNALIGNED: The end of this buffer is on + * the page that follows the page after the end of the + * previous buffer and is not page aligned. Examples: + * buf1 ][ buf2 | buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 | buf2 ][ ... + */ + NEXT_NEXT_UNALIGNED, + LOOP_END, +}; + +static void pr_err_size_seq(size_t *sizes, int *seq) +{ + int i; + + pr_err("alloc sizes: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%zu]", sizes[i]); + pr_cont("\n"); + pr_err("free seq: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%d]", seq[i]); + pr_cont("\n"); +} + +static bool check_buffer_pages_allocated(struct binder_alloc *alloc, + struct binder_buffer *buffer, + size_t size) +{ + void *page_addr, *end; + int page_index; + + end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); + page_addr = buffer->data; + for (; page_addr < end; page_addr += PAGE_SIZE) { + page_index = (page_addr - alloc->buffer) / PAGE_SIZE; + if (!alloc->pages[page_index].page_ptr || + !list_empty(&alloc->pages[page_index].lru)) { + pr_err("expect alloc but is %s at page index %d\n", + alloc->pages[page_index].page_ptr ? + "lru" : "free", page_index); + return false; + } + } + return true; +} + +static void binder_selftest_alloc_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) { + buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); + if (IS_ERR(buffers[i]) || + !check_buffer_pages_allocated(alloc, buffers[i], + sizes[i])) { + pr_err_size_seq(sizes, seq); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq, size_t end) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) + binder_alloc_free_buf(alloc, buffers[seq[i]]); + + for (i = 0; i < end / PAGE_SIZE; i++) { + /** + * Error message on a free page can be false positive + * if binder shrinker ran during binder_alloc_free_buf + * calls above. + */ + if (list_empty(&alloc->pages[i].lru)) { + pr_err_size_seq(sizes, seq); + pr_err("expect lru but is %s at page index %d\n", + alloc->pages[i].page_ptr ? "alloc" : "free", i); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_free_page(struct binder_alloc *alloc) +{ + int i; + unsigned long count; + + while ((count = list_lru_count(&binder_alloc_lru))) { + list_lru_walk(&binder_alloc_lru, binder_alloc_free_page, + NULL, count); + } + + for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { + if (alloc->pages[i].page_ptr) { + pr_err("expect free but is %s at page index %d\n", + list_empty(&alloc->pages[i].lru) ? + "alloc" : "lru", i); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_alloc_free(struct binder_alloc *alloc, + size_t *sizes, int *seq, size_t end) +{ + struct binder_buffer *buffers[BUFFER_NUM]; + + binder_selftest_alloc_buf(alloc, buffers, sizes, seq); + binder_selftest_free_buf(alloc, buffers, sizes, seq, end); + + /* Allocate from lru. */ + binder_selftest_alloc_buf(alloc, buffers, sizes, seq); + if (list_lru_count(&binder_alloc_lru)) + pr_err("lru list should be empty but is not\n"); + + binder_selftest_free_buf(alloc, buffers, sizes, seq, end); + binder_selftest_free_page(alloc); +} + +static bool is_dup(int *seq, int index, int val) +{ + int i; + + for (i = 0; i < index; i++) { + if (seq[i] == val) + return true; + } + return false; +} + +/* Generate BUFFER_NUM factorial free orders. */ +static void binder_selftest_free_seq(struct binder_alloc *alloc, + size_t *sizes, int *seq, + int index, size_t end) +{ + int i; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_free(alloc, sizes, seq, end); + return; + } + for (i = 0; i < BUFFER_NUM; i++) { + if (is_dup(seq, index, i)) + continue; + seq[index] = i; + binder_selftest_free_seq(alloc, sizes, seq, index + 1, end); + } +} + +static void binder_selftest_alloc_size(struct binder_alloc *alloc, + size_t *end_offset) +{ + int i; + int seq[BUFFER_NUM] = {0}; + size_t front_sizes[BUFFER_NUM]; + size_t back_sizes[BUFFER_NUM]; + size_t last_offset, offset = 0; + + for (i = 0; i < BUFFER_NUM; i++) { + last_offset = offset; + offset = end_offset[i]; + front_sizes[i] = offset - last_offset; + back_sizes[BUFFER_NUM - i - 1] = front_sizes[i]; + } + /* + * Buffers share the first or last few pages. + * Only BUFFER_NUM - 1 buffer sizes are adjustable since + * we need one giant buffer before getting to the last page. + */ + back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1]; + binder_selftest_free_seq(alloc, front_sizes, seq, 0, + end_offset[BUFFER_NUM - 1]); + binder_selftest_free_seq(alloc, back_sizes, seq, 0, alloc->buffer_size); +} + +static void binder_selftest_alloc_offset(struct binder_alloc *alloc, + size_t *end_offset, int index) +{ + int align; + size_t end, prev; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_size(alloc, end_offset); + return; + } + prev = index == 0 ? 0 : end_offset[index - 1]; + end = prev; + + BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE); + + for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) { + if (align % 2) + end = ALIGN(end, PAGE_SIZE); + else + end += BUFFER_MIN_SIZE; + end_offset[index] = end; + binder_selftest_alloc_offset(alloc, end_offset, index + 1); + } +} + +/** + * binder_selftest_alloc() - Test alloc and free of buffer pages. + * @alloc: Pointer to alloc struct. + * + * Allocate BUFFER_NUM buffers to cover all page alignment cases, + * then free them in all orders possible. Check that pages are + * correctly allocated, put onto lru when buffers are freed, and + * are freed when binder_alloc_free_page is called. + */ +void binder_selftest_alloc(struct binder_alloc *alloc) +{ + size_t end_offset[BUFFER_NUM]; + + if (!binder_selftest_run) + return; + mutex_lock(&binder_selftest_lock); + if (!binder_selftest_run || !alloc->vma) + goto done; + pr_info("STARTED\n"); + binder_selftest_alloc_offset(alloc, end_offset, 0); + binder_selftest_run = false; + if (binder_selftest_failures > 0) + pr_info("%d tests FAILED\n", binder_selftest_failures); + else + pr_info("PASSED\n"); + +done: + mutex_unlock(&binder_selftest_lock); +} diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index ad1d8741b6673338398407e2734156814c4fb4a8..2bd8a564251aa2c23baa8889afe18634d2037a7a 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -10,8 +10,3 @@ endif obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o obj-$(CONFIG_ION_TEGRA) += tegra/ obj-$(CONFIG_ION_MSM) += msm/ - -#TODO: remove me b/62058353 -# WE SHOULD FIX THIS ONE -subdir-ccflags-y += \ - -Wno-enum-conversion diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 021d07f43f0b8e71a606ddd81991f7594c868eb7..7f4233a4a32b284720e7f9dead9789c6ed96b43d 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -17,6 +17,10 @@ */ #include + + +#include + #include #include #include @@ -47,6 +51,81 @@ #include "ion_priv.h" #include "compat_ion.h" +/** + * struct ion_device - the metadata of the ion device node + * @dev: the actual misc device + * @buffers: an rb tree of all the existing buffers + * @buffer_lock: lock protecting the tree of buffers + * @lock: rwsem protecting the tree of heaps and clients + * @heaps: list of all the heaps in the system + * @user_clients: list of all the clients created from userspace + */ +struct ion_device { + struct miscdevice dev; + struct rb_root buffers; + struct mutex buffer_lock; + struct rw_semaphore lock; + struct plist_head heaps; + long (*custom_ioctl)(struct ion_client *client, unsigned int cmd, + unsigned long arg); + struct rb_root clients; + struct dentry *debug_root; + struct dentry *heaps_debug_root; + struct dentry *clients_debug_root; +}; + +/** + * struct ion_client - a process/hw block local address space + * @node: node in the tree of all clients + * @dev: backpointer to ion device + * @handles: an rb tree of all the handles in this client + * @idr: an idr space for allocating handle ids + * @lock: lock protecting the tree of handles + * @name: used for debugging + * @display_name: used for debugging (unique version of @name) + * @display_serial: used for debugging (to make display_name unique) + * @task: used for debugging + * + * A client represents a list of buffers this client may access. + * The mutex stored here is used to protect both handles tree + * as well as the handles themselves, and should be held while modifying either. + */ +struct ion_client { + struct rb_node node; + struct ion_device *dev; + struct rb_root handles; + struct idr idr; + struct mutex lock; + char *name; + char *display_name; + int display_serial; + struct task_struct *task; + pid_t pid; + struct dentry *debug_root; +}; + +/** + * ion_handle - a client local reference to a buffer + * @ref: reference count + * @client: back pointer to the client the buffer resides in + * @buffer: pointer to the buffer + * @node: node in the client's handle rbtree + * @kmap_cnt: count of times this client has mapped to kernel + * @id: client-unique id allocated by client->idr + * + * Modifications to node, map_cnt or mapping should be protected by the + * lock in the client. Other fields are never changed after initialization. + */ +struct ion_handle { + struct kref ref; + unsigned int user_ref_count; + struct ion_client *client; + struct ion_buffer *buffer; + struct rb_node node; + unsigned int kmap_cnt; + int id; +}; + static struct ion_device *ion_dev; bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer) @@ -329,7 +408,9 @@ static void ion_handle_get(struct ion_handle *handle) } /* Must hold the client lock */ -static struct ion_handle* ion_handle_get_check_overflow(struct ion_handle *handle) + +static struct ion_handle* ion_handle_get_check_overflow( + struct ion_handle *handle) { if (atomic_read(&handle->ref.refcount) + 1 == 0) return ERR_PTR(-EOVERFLOW); @@ -420,7 +501,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client, } struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, - int id) + int id) { struct ion_handle *handle; @@ -431,7 +512,7 @@ struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, return ERR_PTR(-EINVAL); } -static bool ion_handle_validate(struct ion_client *client, +bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle) { WARN_ON(!mutex_is_locked(&client->lock)); @@ -586,7 +667,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, } EXPORT_SYMBOL(ion_alloc); -static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle) +void ion_free_nolock(struct ion_client *client, struct ion_handle *handle) { bool valid_handle; @@ -629,32 +710,48 @@ void ion_free(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_free); -int ion_phys(struct ion_client *client, struct ion_handle *handle, - ion_phys_addr_t *addr, size_t *len) +static int __ion_phys(struct ion_client *client, struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len, bool lock_client) { - struct ion_buffer *buffer; - int ret; + struct ion_buffer *buffer; + int ret; - mutex_lock(&client->lock); - if (!ion_handle_validate(client, handle)) { - mutex_unlock(&client->lock); - return -EINVAL; - } + if(lock_client) + mutex_lock(&client->lock); + if (!ion_handle_validate(client, handle)) { + if(lock_client) + mutex_unlock(&client->lock); + return -EINVAL; + } - buffer = handle->buffer; + buffer = handle->buffer; - if (!buffer->heap->ops->phys) { - pr_err("%s: ion_phys is not implemented by this heap (name=%s, type=%d).\n", - __func__, buffer->heap->name, buffer->heap->type); - mutex_unlock(&client->lock); - return -ENODEV; - } - mutex_unlock(&client->lock); - ret = buffer->heap->ops->phys(buffer->heap, buffer, addr, len); - return ret; + if (!buffer->heap->ops->phys) { + pr_err("%s: ion_phys is not implemented by this heap (name=%s, type=%d).\n", + __func__, buffer->heap->name, buffer->heap->type); + if(lock_client) + mutex_unlock(&client->lock); + return -ENODEV; + } + if(lock_client) + mutex_unlock(&client->lock); + ret = buffer->heap->ops->phys(buffer->heap, buffer, addr, len); + return ret; +} + +int ion_phys(struct ion_client *client, struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len) +{ + return __ion_phys(client,handle,addr,len,true); } EXPORT_SYMBOL(ion_phys); +int ion_phys_nolock(struct ion_client *client, struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len) +{ + return __ion_phys(client,handle,addr,len,false); +} + static void *ion_buffer_kmap_get(struct ion_buffer *buffer) { void *vaddr; @@ -1386,54 +1483,72 @@ static int ion_share_dma_buf_fd_nolock(struct ion_client *client, return __ion_share_dma_buf_fd(client, handle, false); } -struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) +static struct ion_handle *__ion_import_dma_buf(struct ion_client *client, + int fd, bool lock_client) { - struct dma_buf *dmabuf; - struct ion_buffer *buffer; - struct ion_handle *handle; - int ret; + struct dma_buf *dmabuf; + struct ion_buffer *buffer; + struct ion_handle *handle; + int ret; - dmabuf = dma_buf_get(fd); - if (IS_ERR(dmabuf)) - return ERR_CAST(dmabuf); - /* if this memory came from ion */ + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return ERR_CAST(dmabuf); + /* if this memory came from ion */ - if (dmabuf->ops != &dma_buf_ops) { - pr_err("%s: can not import dmabuf from another exporter\n", - __func__); - dma_buf_put(dmabuf); - return ERR_PTR(-EINVAL); - } - buffer = dmabuf->priv; + if (dmabuf->ops != &dma_buf_ops) { + pr_err("%s: can not import dmabuf from another exporter\n", + __func__); + dma_buf_put(dmabuf); + return ERR_PTR(-EINVAL); + } + buffer = dmabuf->priv; - mutex_lock(&client->lock); - /* if a handle exists for this buffer just take a reference to it */ - handle = ion_handle_lookup(client, buffer); - if (!IS_ERR(handle)) { - handle = ion_handle_get_check_overflow(handle); - mutex_unlock(&client->lock); - goto end; - } + if (lock_client) + mutex_lock(&client->lock); + /* if a handle exists for this buffer just take a reference to it */ + handle = ion_handle_lookup(client, buffer); + if (!IS_ERR(handle)) { + handle = ion_handle_get_check_overflow(handle); + if (lock_client) + mutex_unlock(&client->lock); + goto end; + } - handle = ion_handle_create(client, buffer); - if (IS_ERR(handle)) { - mutex_unlock(&client->lock); - goto end; - } + handle = ion_handle_create(client, buffer); + if (IS_ERR(handle)) { + if (lock_client) + mutex_unlock(&client->lock); + goto end; + } - ret = ion_handle_add(client, handle); - mutex_unlock(&client->lock); - if (ret) { - ion_handle_put(handle); - handle = ERR_PTR(ret); - } + ret = ion_handle_add(client, handle); + if (lock_client) + mutex_unlock(&client->lock); + if (ret) { + if (lock_client) + ion_handle_put(handle); + else + ion_handle_put_nolock(handle); + handle = ERR_PTR(ret); + } end: - dma_buf_put(dmabuf); - return handle; + dma_buf_put(dmabuf); + return handle; +} + +struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) +{ + return __ion_import_dma_buf(client,fd,true); } EXPORT_SYMBOL(ion_import_dma_buf); +struct ion_handle *ion_import_dma_buf_nolock(struct ion_client *client, int fd) +{ + return __ion_import_dma_buf(client,fd,false); +} + static int ion_sync_for_device(struct ion_client *client, int fd) { struct dma_buf *dmabuf; @@ -1955,7 +2070,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) } int ion_walk_heaps(struct ion_client *client, int heap_id, - unsigned int type, void *data, + enum ion_heap_type type, void *data, int (*f)(struct ion_heap *heap, void *data)) { int ret_val = 0; @@ -2069,3 +2184,18 @@ void __init ion_reserve(struct ion_platform_data *data) data->heaps[i].size); } } + +void lock_client(struct ion_client *client) +{ + mutex_lock(&client->lock); +} + +void unlock_client(struct ion_client *client) +{ + mutex_unlock(&client->lock); +} + +struct ion_buffer *get_buffer(struct ion_handle *handle) +{ + return handle->buffer; +} diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index b5263b8667c46d2d9c492b67c74cb5a0e15086c3..e8d89d0a4a695a7b76ed27b2754cd6d570762027 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -312,37 +312,14 @@ err: return ret; } -static void *ion_secure_cma_map_kernel(struct ion_heap *heap, - struct ion_buffer *buffer) -{ - if (!is_buffer_hlos_assigned(buffer)) { - pr_info("%s: Mapping non-HLOS accessible buffer disallowed\n", - __func__); - return NULL; - } - return ion_cma_map_kernel(heap, buffer); -} - -static int ion_secure_cma_map_user(struct ion_heap *mapper, - struct ion_buffer *buffer, - struct vm_area_struct *vma) -{ - if (!is_buffer_hlos_assigned(buffer)) { - pr_info("%s: Mapping non-HLOS accessible buffer disallowed\n", - __func__); - return -EINVAL; - } - return ion_cma_mmap(mapper, buffer, vma); -} - static struct ion_heap_ops ion_secure_cma_ops = { .allocate = ion_secure_cma_allocate, .free = ion_secure_cma_free, .map_dma = ion_cma_heap_map_dma, .unmap_dma = ion_cma_heap_unmap_dma, .phys = ion_cma_phys, - .map_user = ion_secure_cma_map_user, - .map_kernel = ion_secure_cma_map_kernel, + .map_user = ion_cma_mmap, + .map_kernel = ion_cma_map_kernel, .unmap_kernel = ion_cma_unmap_kernel, .print_debug = ion_cma_print_debug, }; diff --git a/drivers/staging/android/ion/ion_cma_secure_heap.c b/drivers/staging/android/ion/ion_cma_secure_heap.c index 6102b1765182c797bf338dbf9c3a7b553c342252..90ae7eb65b65992bc234f4c85a4783f9fba3265f 100644 --- a/drivers/staging/android/ion/ion_cma_secure_heap.c +++ b/drivers/staging/android/ion/ion_cma_secure_heap.c @@ -3,7 +3,7 @@ * * Copyright (C) Linaro 2012 * Author: for ST-Ericsson. - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -344,8 +344,7 @@ static void ion_secure_cma_free_chunk(struct ion_cma_secure_heap *sheap, } -static unsigned long -__ion_secure_cma_shrink_pool(struct ion_cma_secure_heap *sheap, int max_nr) +void __ion_secure_cma_shrink_pool(struct ion_cma_secure_heap *sheap, int max_nr) { struct list_head *entry, *_n; unsigned long drained_size = 0, skipped_size = 0; @@ -369,7 +368,6 @@ __ion_secure_cma_shrink_pool(struct ion_cma_secure_heap *sheap, int max_nr) } trace_ion_secure_cma_shrink_pool_end(drained_size, skipped_size); - return drained_size; } int ion_secure_cma_drain_pool(struct ion_heap *heap, void *unused) @@ -387,7 +385,6 @@ int ion_secure_cma_drain_pool(struct ion_heap *heap, void *unused) static unsigned long ion_secure_cma_shrinker(struct shrinker *shrinker, struct shrink_control *sc) { - unsigned long freed; struct ion_cma_secure_heap *sheap = container_of(shrinker, struct ion_cma_secure_heap, shrinker); int nr_to_scan = sc->nr_to_scan; @@ -400,11 +397,11 @@ static unsigned long ion_secure_cma_shrinker(struct shrinker *shrinker, if (!mutex_trylock(&sheap->chunk_lock)) return -1; - freed = __ion_secure_cma_shrink_pool(sheap, nr_to_scan); + __ion_secure_cma_shrink_pool(sheap, nr_to_scan); mutex_unlock(&sheap->chunk_lock); - return freed; + return atomic_read(&sheap->total_pool_size); } static unsigned long ion_secure_cma_shrinker_count(struct shrinker *shrinker, diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index ad86ce34323469b05b3a7c28519fbd78a3397985..00c0b8845dac67a83e86d04688377793727e6d28 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -34,7 +34,6 @@ #ifdef CONFIG_ION_POOL_CACHE_POLICY #include #endif -#include #include "ion.h" @@ -98,81 +97,6 @@ struct ion_buffer { }; void ion_buffer_destroy(struct ion_buffer *buffer); -/** - * struct ion_device - the metadata of the ion device node - * @dev: the actual misc device - * @buffers: an rb tree of all the existing buffers - * @buffer_lock: lock protecting the tree of buffers - * @lock: rwsem protecting the tree of heaps and clients - * @heaps: list of all the heaps in the system - * @user_clients: list of all the clients created from userspace - */ -struct ion_device { - struct miscdevice dev; - struct rb_root buffers; - struct mutex buffer_lock; - struct rw_semaphore lock; - struct plist_head heaps; - long (*custom_ioctl)(struct ion_client *client, unsigned int cmd, - unsigned long arg); - struct rb_root clients; - struct dentry *debug_root; - struct dentry *heaps_debug_root; - struct dentry *clients_debug_root; -}; - -/** - * struct ion_client - a process/hw block local address space - * @node: node in the tree of all clients - * @dev: backpointer to ion device - * @handles: an rb tree of all the handles in this client - * @idr: an idr space for allocating handle ids - * @lock: lock protecting the tree of handles - * @name: used for debugging - * @display_name: used for debugging (unique version of @name) - * @display_serial: used for debugging (to make display_name unique) - * @task: used for debugging - * - * A client represents a list of buffers this client may access. - * The mutex stored here is used to protect both handles tree - * as well as the handles themselves, and should be held while modifying either. - */ -struct ion_client { - struct rb_node node; - struct ion_device *dev; - struct rb_root handles; - struct idr idr; - struct mutex lock; - char *name; - char *display_name; - int display_serial; - struct task_struct *task; - pid_t pid; - struct dentry *debug_root; -}; - -/** - * ion_handle - a client local reference to a buffer - * @ref: reference count - * @client: back pointer to the client the buffer resides in - * @buffer: pointer to the buffer - * @node: node in the client's handle rbtree - * @kmap_cnt: count of times this client has mapped to kernel - * @id: client-unique id allocated by client->idr - * - * Modifications to node, map_cnt or mapping should be protected by the - * lock in the client. Other fields are never changed after initialization. - */ -struct ion_handle { - struct kref ref; - unsigned int user_ref_count; - struct ion_client *client; - struct ion_buffer *buffer; - struct rb_node node; - unsigned int kmap_cnt; - int id; -}; - /** * struct ion_heap_ops - ops to operate on a given heap * @allocate: allocate memory @@ -262,7 +186,7 @@ struct ion_heap_ops { struct ion_heap { struct plist_node node; struct ion_device *dev; - unsigned int type; + enum ion_heap_type type; struct ion_heap_ops *ops; unsigned long flags; unsigned int id; @@ -576,12 +500,37 @@ void ion_pages_sync_for_device(struct device *dev, struct page *page, size_t size, enum dma_data_direction dir); int ion_walk_heaps(struct ion_client *client, int heap_id, - unsigned int type, void *data, + enum ion_heap_type type, void *data, int (*f)(struct ion_heap *heap, void *data)); struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, - int id); + int id); int ion_handle_put(struct ion_handle *handle); +bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle); + +void lock_client(struct ion_client *client); + +void unlock_client(struct ion_client *client); + +struct ion_buffer *get_buffer(struct ion_handle *handle); + +/** + * This function is same as ion_free() except it won't use client->lock. + */ +void ion_free_nolock(struct ion_client *client, struct ion_handle *handle); + +/** + * This function is same as ion_phys() except it won't use client->lock. + */ +int ion_phys_nolock(struct ion_client *client, struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len); + +/** + * This function is same as ion_import_dma_buf() except it won't use + * client->lock. + */ +struct ion_handle *ion_import_dma_buf_nolock(struct ion_client *client, int fd); + #endif /* _ION_PRIV_H */ diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index f6fd7fb6ec778fe56ef4ea1a5882244397cabd27..6bfe16f1e73fa50f441e2b4c91862a30fd59f36f 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -37,7 +37,7 @@ static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN | static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN); #ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS -static const unsigned int orders[] = {4, 0}; +static const unsigned int orders[] = {9, 8, 4, 0}; #else static const unsigned int orders[] = {0}; #endif @@ -72,11 +72,6 @@ struct page_info { struct list_head list; }; -static int ion_heap_is_system_heap_type(enum ion_heap_type type) -{ - return type == ((enum ion_heap_type)ION_HEAP_TYPE_SYSTEM); -} - static struct page *alloc_buffer_page(struct ion_system_heap *heap, struct ion_buffer *buffer, unsigned long order, @@ -228,13 +223,6 @@ static int ion_system_heap_allocate(struct ion_heap *heap, unsigned int sz; int vmid = get_secure_vmid(buffer->flags); - if (ion_heap_is_system_heap_type(buffer->heap->type) && - is_secure_vmid_valid(vmid)) { - pr_info("%s: System heap doesn't support secure allocations\n", - __func__); - return -EINVAL; - } - if (align > PAGE_SIZE) return -EINVAL; @@ -341,7 +329,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap, err_free_sg2: /* We failed to zero buffers. Bypass pool */ - buffer->flags |= ION_PRIV_FLAG_SHRINKER_FREE; + buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE; if (vmid > 0) ion_system_secure_heap_unassign_sg(table, vmid); diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index 0fd8199217ef14ece540bad600fde7ad2cf65529..3e55753b92b5ff6e2327ab5ac755ec52281ebb54 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -39,10 +39,10 @@ struct prefetch_info { static bool is_cp_flag_present(unsigned long flags) { - return flags & (ION_FLAG_CP_TOUCH | - ION_FLAG_CP_BITSTREAM | - ION_FLAG_CP_PIXEL | - ION_FLAG_CP_NON_PIXEL | + return flags && (ION_FLAG_CP_TOUCH || + ION_FLAG_CP_BITSTREAM || + ION_FLAG_CP_PIXEL || + ION_FLAG_CP_NON_PIXEL || ION_FLAG_CP_CAMERA); } diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index 9e2ad632cad861133dc6969e14c63c8c76543c08..a577ad95d4bf9581e84036e10d7f94974f7a27cb 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * 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 @@ -149,7 +149,13 @@ EXPORT_SYMBOL(msm_ion_client_create); int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, void *vaddr, unsigned long len, unsigned int cmd) { - return ion_do_cache_op(client, handle, vaddr, 0, len, cmd); + int ret; + + lock_client(client); + ret = ion_do_cache_op(client, handle, vaddr, 0, len, cmd); + unlock_client(client); + + return ret; } EXPORT_SYMBOL(msm_ion_do_cache_op); @@ -166,7 +172,7 @@ static int ion_no_pages_cache_ops(struct ion_client *client, ion_phys_addr_t buff_phys_start = 0; size_t buf_length = 0; - ret = ion_phys(client, handle, &buff_phys_start, &buf_length); + ret = ion_phys_nolock(client, handle, &buff_phys_start, &buf_length); if (ret) return -EINVAL; @@ -280,9 +286,10 @@ static int ion_pages_cache_ops(struct ion_client *client, int i; unsigned int len = 0; void (*op)(const void *, const void *); + struct ion_buffer *buffer; - - table = ion_sg_table(client, handle); + buffer = get_buffer(handle); + table = buffer->sg_table; if (IS_ERR_OR_NULL(table)) return PTR_ERR(table); @@ -321,10 +328,18 @@ int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, unsigned long flags; struct sg_table *table; struct page *page; + struct ion_buffer *buffer; - ret = ion_handle_get_flags(client, handle, &flags); - if (ret) + if (!ion_handle_validate(client, handle)) { + pr_err("%s: invalid handle passed to %s.\n", + __func__, __func__); return -EINVAL; + } + + buffer = get_buffer(handle); + mutex_lock(&buffer->lock); + flags = buffer->flags; + mutex_unlock(&buffer->lock); if (!ION_IS_CACHED(flags)) return 0; @@ -332,7 +347,7 @@ int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, if (get_secure_vmid(flags) > 0) return 0; - table = ion_sg_table(client, handle); + table = buffer->sg_table; if (IS_ERR_OR_NULL(table)) return PTR_ERR(table); @@ -650,21 +665,6 @@ int get_secure_vmid(unsigned long flags) return VMID_CP_APP; return -EINVAL; } - -bool is_buffer_hlos_assigned(struct ion_buffer *buffer) -{ - bool is_hlos = false; - - if (buffer->heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA && - (buffer->flags & ION_FLAG_CP_HLOS)) - is_hlos = true; - - if (get_secure_vmid(buffer->flags) <= 0) - is_hlos = true; - - return is_hlos; -} - /* fix up the cases where the ioctl direction bits are incorrect */ static unsigned int msm_ion_ioctl_dir(unsigned int cmd) { @@ -709,22 +709,23 @@ long msm_ion_custom_ioctl(struct ion_client *client, int ret; struct mm_struct *mm = current->active_mm; + lock_client(client); if (data.flush_data.handle > 0) { - mutex_lock(&client->lock); handle = ion_handle_get_by_id_nolock(client, (int)data.flush_data.handle); if (IS_ERR(handle)) { - mutex_unlock(&client->lock); pr_info("%s: Could not find handle: %d\n", __func__, (int)data.flush_data.handle); + unlock_client(client); return PTR_ERR(handle); } - mutex_unlock(&client->lock); } else { - handle = ion_import_dma_buf(client, data.flush_data.fd); + handle = ion_import_dma_buf_nolock(client, + data.flush_data.fd); if (IS_ERR(handle)) { pr_info("%s: Could not import handle: %pK\n", __func__, handle); + unlock_client(client); return -EINVAL; } } @@ -735,7 +736,7 @@ long msm_ion_custom_ioctl(struct ion_client *client, data.flush_data.offset; end = start + data.flush_data.length; - if (start && check_vaddr_bounds(start, end)) { + if (check_vaddr_bounds(start, end)) { pr_err("%s: virtual address %pK is out of bounds\n", __func__, data.flush_data.vaddr); ret = -EINVAL; @@ -747,8 +748,9 @@ long msm_ion_custom_ioctl(struct ion_client *client, } up_read(&mm->mmap_sem); - ion_free(client, handle); + ion_free_nolock(client, handle); + unlock_client(client); if (ret < 0) return ret; break; diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h index 7359194556fdb2b30069fe850e1dd5a5e7bf9d8d..d8677b2fb55a79b916fcc4650e977b414debf17d 100644 --- a/drivers/staging/android/ion/msm/msm_ion.h +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -157,8 +157,6 @@ int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle, int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, void *vaddr, unsigned long len, unsigned int cmd); -bool is_buffer_hlos_assigned(struct ion_buffer *buffer); - #else static inline struct ion_client *msm_ion_client_create(const char *name) { @@ -178,11 +176,6 @@ static inline int msm_ion_do_cache_op(struct ion_client *client, return -ENODEV; } -static bool is_buffer_hlos_assigned(struct ion_buffer *buffer) -{ - return true; -} - #endif /* CONFIG_ION */ #endif diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 216430864574ab94bf5b439bca16d7f8cc62348e..4a8ade96858d482bda6f4c0e99c1951073f1be4b 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -152,7 +152,7 @@ int adjust_minadj(short *min_score_adj) static int lmk_vmpressure_notifier(struct notifier_block *nb, unsigned long action, void *data) { - int other_free = 0, other_file = 0; + int other_free, other_file; unsigned long pressure = action; int array_size = ARRAY_SIZE(lowmem_adj); @@ -162,7 +162,6 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, if (pressure >= 95) { other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); @@ -176,7 +175,6 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); @@ -188,11 +186,6 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, other_file); } } else if (atomic_read(&shift_adj)) { - other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - - global_page_state(NR_SHMEM) - - total_swapcache_pages(); - - other_free = global_page_state(NR_FREE_PAGES); /* * shift_adj would have been set by a previous invocation * of notifier, which is not followed by a lowmem_shrink yet. @@ -226,6 +219,22 @@ static int test_task_flag(struct task_struct *p, int flag) return 0; } +static int test_task_state(struct task_struct *p, int state) +{ + struct task_struct *t; + + for_each_thread(p, t) { + task_lock(t); + if (t->state & state) { + task_unlock(t); + return 1; + } + task_unlock(t); + } + + return 0; +} + static DEFINE_MUTEX(scan_mutex); int can_use_cma_pages(gfp_t gfp_mask) @@ -413,12 +422,12 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) int other_free; int other_file; - if (mutex_lock_interruptible(&scan_mutex) < 0) + if (!mutex_trylock(&scan_mutex)) return 0; other_free = global_page_state(NR_FREE_PAGES); - if (global_page_state(NR_SHMEM) + global_page_state(NR_UNEVICTABLE) + total_swapcache_pages() < + if (global_page_state(NR_SHMEM) + total_swapcache_pages() < global_page_state(NR_FILE_PAGES) + zcache_pages()) other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - @@ -472,8 +481,6 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) if (time_before_eq(jiffies, lowmem_deathpending_timeout)) { if (test_task_flag(tsk, TIF_MEMDIE)) { rcu_read_unlock(); - /* give the system time to free up the memory */ - msleep_interruptible(20); mutex_unlock(&scan_mutex); return 0; } @@ -510,6 +517,17 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) long cache_limit = minfree * (long)(PAGE_SIZE / 1024); long free = other_free * (long)(PAGE_SIZE / 1024); trace_lowmemory_kill(selected, cache_size, cache_limit, free); + + if (test_task_flag(selected, TIF_MEMDIE) && + (test_task_state(selected, TASK_UNINTERRUPTIBLE))) { + lowmem_print(2, "'%s' (%d) is already killed\n", + selected->comm, + selected->pid); + rcu_read_unlock(); + mutex_unlock(&scan_mutex); + return 0; + } + lowmem_print(1, "Killing '%s' (%d), adj %hd,\n" \ " to free %ldkB on behalf of '%s' (%d) because\n" \ " cache %ldkB is below limit %ldkB for oom_score_adj %hd\n" \ diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index 5fba2721a683a373822bfc6a096237c01420ecf7..2df8a1337c4a0921b1a6ab08d626ede70dc59d2b 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -269,9 +269,7 @@ static struct sync_fence *sync_fence_alloc(const char *name) goto err; kref_init(&fence->kref); -#ifdef CONFIG_SYNC_DEBUG strlcpy(fence->name, name, sizeof(fence->name)); -#endif INIT_LIST_HEAD(&fence->pt_list_head); INIT_LIST_HEAD(&fence->waiter_list_head); diff --git a/drivers/staging/android/uapi/binder.h b/drivers/staging/android/uapi/binder.h index 046aac6727efc3d9780132f7980d57b60a188823..f11a160b80d06fe319227e7af6c359781eb16c0a 100644 --- a/drivers/staging/android/uapi/binder.h +++ b/drivers/staging/android/uapi/binder.h @@ -86,14 +86,6 @@ enum flat_binder_object_flags { * scheduling policy from the caller (for synchronous transactions). */ FLAT_BINDER_FLAG_INHERIT_RT = 0x800, - - /** - * @FLAT_BINDER_FLAG_TXN_SECURITY_CTX: request security contexts - * - * Only when set, causes senders to include their security - * context - */ - FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000, }; #ifdef BINDER_IPC_32BIT @@ -271,7 +263,6 @@ struct binder_node_info_for_ref { #define BINDER_VERSION _IOWR('b', 9, struct binder_version) #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) -#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) /* * NOTE: Two special error codes you should check for when calling @@ -330,11 +321,6 @@ struct binder_transaction_data { } data; }; -struct binder_transaction_data_secctx { - struct binder_transaction_data transaction_data; - binder_uintptr_t secctx; -}; - struct binder_transaction_data_sg { struct binder_transaction_data transaction_data; binder_size_t buffers_size; @@ -370,11 +356,6 @@ enum binder_driver_return_protocol { BR_OK = _IO('r', 1), /* No parameters! */ - BR_TRANSACTION_SEC_CTX = _IOR('r', 2, - struct binder_transaction_data_secctx), - /* - * binder_transaction_data_secctx: the received command. - */ BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), BR_REPLY = _IOR('r', 3, struct binder_transaction_data), /* diff --git a/drivers/staging/android/uapi/vsoc_shm.h b/drivers/staging/android/uapi/vsoc_shm.h new file mode 100644 index 0000000000000000000000000000000000000000..741b1387c25b730a96a00ec8b881749f7272097e --- /dev/null +++ b/drivers/staging/android/uapi/vsoc_shm.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2017 Google, 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. + * + */ + +#ifndef _UAPI_LINUX_VSOC_SHM_H +#define _UAPI_LINUX_VSOC_SHM_H + +#include + +/** + * A permission is a token that permits a receiver to read and/or write an area + * of memory within a Vsoc region. + * + * An fd_scoped permission grants both read and write access, and can be + * attached to a file description (see open(2)). + * Ownership of the area can then be shared by passing a file descriptor + * among processes. + * + * begin_offset and end_offset define the area of memory that is controlled by + * the permission. owner_offset points to a word, also in shared memory, that + * controls ownership of the area. + * + * ownership of the region expires when the associated file description is + * released. + * + * At most one permission can be attached to each file description. + * + * This is useful when implementing HALs like gralloc that scope and pass + * ownership of shared resources via file descriptors. + * + * The caller is responsibe for doing any fencing. + * + * The calling process will normally identify a currently free area of + * memory. It will construct a proposed fd_scoped_permission_arg structure: + * + * begin_offset and end_offset describe the area being claimed + * + * owner_offset points to the location in shared memory that indicates the + * owner of the area. + * + * owned_value is the value that will be stored in owner_offset iff the + * permission can be granted. It must be different than VSOC_REGION_FREE. + * + * Two fd_scoped_permission structures are compatible if they vary only by + * their owned_value fields. + * + * The driver ensures that, for any group of simultaneous callers proposing + * compatible fd_scoped_permissions, it will accept exactly one of the + * propopsals. The other callers will get a failure with errno of EAGAIN. + * + * A process receiving a file descriptor can identify the region being + * granted using the VSOC_GET_FD_SCOPED_PERMISSION ioctl. + */ +struct fd_scoped_permission { + __u32 begin_offset; + __u32 end_offset; + __u32 owner_offset; + __u32 owned_value; +}; + +/* + * This value represents a free area of memory. The driver expects to see this + * value at owner_offset when creating a permission otherwise it will not do it, + * and will write this value back once the permission is no longer needed. + */ +#define VSOC_REGION_FREE ((__u32)0) + +/** + * ioctl argument for VSOC_CREATE_FD_SCOPE_PERMISSION + */ +struct fd_scoped_permission_arg { + struct fd_scoped_permission perm; + __s32 managed_region_fd; +}; + +#define VSOC_NODE_FREE ((__u32)0) + +/* + * Describes a signal table in shared memory. Each non-zero entry in the + * table indicates that the receiver should signal the futex at the given + * offset. Offsets are relative to the region, not the shared memory window. + * + * interrupt_signalled_offset is used to reliably signal interrupts across the + * vmm boundary. There are two roles: transmitter and receiver. For example, + * in the host_to_guest_signal_table the host is the transmitter and the + * guest is the receiver. The protocol is as follows: + * + * 1. The transmitter should convert the offset of the futex to an offset + * in the signal table [0, (1 << num_nodes_lg2)) + * The transmitter can choose any appropriate hashing algorithm, including + * hash = futex_offset & ((1 << num_nodes_lg2) - 1) + * + * 3. The transmitter should atomically compare and swap futex_offset with 0 + * at hash. There are 3 possible outcomes + * a. The swap fails because the futex_offset is already in the table. + * The transmitter should stop. + * b. Some other offset is in the table. This is a hash collision. The + * transmitter should move to another table slot and try again. One + * possible algorithm: + * hash = (hash + 1) & ((1 << num_nodes_lg2) - 1) + * c. The swap worked. Continue below. + * + * 3. The transmitter atomically swaps 1 with the value at the + * interrupt_signalled_offset. There are two outcomes: + * a. The prior value was 1. In this case an interrupt has already been + * posted. The transmitter is done. + * b. The prior value was 0, indicating that the receiver may be sleeping. + * The transmitter will issue an interrupt. + * + * 4. On waking the receiver immediately exchanges a 0 with the + * interrupt_signalled_offset. If it receives a 0 then this a spurious + * interrupt. That may occasionally happen in the current protocol, but + * should be rare. + * + * 5. The receiver scans the signal table by atomicaly exchanging 0 at each + * location. If a non-zero offset is returned from the exchange the + * receiver wakes all sleepers at the given offset: + * futex((int*)(region_base + old_value), FUTEX_WAKE, MAX_INT); + * + * 6. The receiver thread then does a conditional wait, waking immediately + * if the value at interrupt_signalled_offset is non-zero. This catches cases + * here additional signals were posted while the table was being scanned. + * On the guest the wait is handled via the VSOC_WAIT_FOR_INCOMING_INTERRUPT + * ioctl. + */ +struct vsoc_signal_table_layout { + /* log_2(Number of signal table entries) */ + __u32 num_nodes_lg2; + /* + * Offset to the first signal table entry relative to the start of the + * region + */ + __u32 futex_uaddr_table_offset; + /* + * Offset to an atomic_t / atomic uint32_t. A non-zero value indicates + * that one or more offsets are currently posted in the table. + * semi-unique access to an entry in the table + */ + __u32 interrupt_signalled_offset; +}; + +#define VSOC_REGION_WHOLE ((__s32)0) +#define VSOC_DEVICE_NAME_SZ 16 + +/** + * Each HAL would (usually) talk to a single device region + * Mulitple entities care about these regions: + * - The ivshmem_server will populate the regions in shared memory + * - The guest kernel will read the region, create minor device nodes, and + * allow interested parties to register for FUTEX_WAKE events in the region + * - HALs will access via the minor device nodes published by the guest kernel + * - Host side processes will access the region via the ivshmem_server: + * 1. Pass name to ivshmem_server at a UNIX socket + * 2. ivshmemserver will reply with 2 fds: + * - host->guest doorbell fd + * - guest->host doorbell fd + * - fd for the shared memory region + * - region offset + * 3. Start a futex receiver thread on the doorbell fd pointed at the + * signal_nodes + */ +struct vsoc_device_region { + __u16 current_version; + __u16 min_compatible_version; + __u32 region_begin_offset; + __u32 region_end_offset; + __u32 offset_of_region_data; + struct vsoc_signal_table_layout guest_to_host_signal_table; + struct vsoc_signal_table_layout host_to_guest_signal_table; + /* Name of the device. Must always be terminated with a '\0', so + * the longest supported device name is 15 characters. + */ + char device_name[VSOC_DEVICE_NAME_SZ]; + /* There are two ways that permissions to access regions are handled: + * - When subdivided_by is VSOC_REGION_WHOLE, any process that can + * open the device node for the region gains complete access to it. + * - When subdivided is set processes that open the region cannot + * access it. Access to a sub-region must be established by invoking + * the VSOC_CREATE_FD_SCOPE_PERMISSION ioctl on the region + * referenced in subdivided_by, providing a fileinstance + * (represented by a fd) opened on this region. + */ + __u32 managed_by; +}; + +/* + * The vsoc layout descriptor. + * The first 4K should be reserved for the shm header and region descriptors. + * The regions should be page aligned. + */ + +struct vsoc_shm_layout_descriptor { + __u16 major_version; + __u16 minor_version; + + /* size of the shm. This may be redundant but nice to have */ + __u32 size; + + /* number of shared memory regions */ + __u32 region_count; + + /* The offset to the start of region descriptors */ + __u32 vsoc_region_desc_offset; +}; + +/* + * This specifies the current version that should be stored in + * vsoc_shm_layout_descriptor.major_version and + * vsoc_shm_layout_descriptor.minor_version. + * It should be updated only if the vsoc_device_region and + * vsoc_shm_layout_descriptor structures have changed. + * Versioning within each region is transferred + * via the min_compatible_version and current_version fields in + * vsoc_device_region. The driver does not consult these fields: they are left + * for the HALs and host processes and will change independently of the layout + * version. + */ +#define CURRENT_VSOC_LAYOUT_MAJOR_VERSION 2 +#define CURRENT_VSOC_LAYOUT_MINOR_VERSION 0 + +#define VSOC_CREATE_FD_SCOPED_PERMISSION \ + _IOW(0xF5, 0, struct fd_scoped_permission) +#define VSOC_GET_FD_SCOPED_PERMISSION _IOR(0xF5, 1, struct fd_scoped_permission) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt if one is not already + * in flight. + */ +#define VSOC_MAYBE_SEND_INTERRUPT_TO_HOST _IO(0xF5, 2) + +/* + * When this returns the guest will scan host_to_guest_signal_table to + * check for new futexes to wake. + */ +/* TODO(ghartman): Consider moving this to the bottom half */ +#define VSOC_WAIT_FOR_INCOMING_INTERRUPT _IO(0xF5, 3) + +/* + * Guest HALs will use this to retrieve the region description after + * opening their device node. + */ +#define VSOC_DESCRIBE_REGION _IOR(0xF5, 4, struct vsoc_device_region) + +/* + * Wake any threads that may be waiting for a host interrupt on this region. + * This is mostly used during shutdown. + */ +#define VSOC_SELF_INTERRUPT _IO(0xF5, 5) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt unconditionally. + */ +#define VSOC_SEND_INTERRUPT_TO_HOST _IO(0xF5, 6) + +enum wait_types { + VSOC_WAIT_UNDEFINED = 0, + VSOC_WAIT_IF_EQUAL = 1, + VSOC_WAIT_IF_EQUAL_TIMEOUT = 2 +}; + +/* + * Wait for a condition to be true + * + * Note, this is sized and aligned so the 32 bit and 64 bit layouts are + * identical. + */ +struct vsoc_cond_wait { + /* Input: Offset of the 32 bit word to check */ + __u32 offset; + /* Input: Value that will be compared with the offset */ + __u32 value; + /* Monotonic time to wake at in seconds */ + __u64 wake_time_sec; + /* Input: Monotonic time to wait in nanoseconds */ + __u32 wake_time_nsec; + /* Input: Type of wait */ + __u32 wait_type; + /* Output: Number of times the thread woke before returning. */ + __u32 wakes; + /* Ensure that we're 8-byte aligned and 8 byte length for 32/64 bit + * compatibility. + */ + __u32 reserved_1; +}; + +#define VSOC_COND_WAIT _IOWR(0xF5, 7, struct vsoc_cond_wait) + +/* Wake any local threads waiting at the offset given in arg */ +#define VSOC_COND_WAKE _IO(0xF5, 8) + +#endif /* _UAPI_LINUX_VSOC_SHM_H */ diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c new file mode 100644 index 0000000000000000000000000000000000000000..dfe7914cce813be757a9e92de9891f8492015193 --- /dev/null +++ b/drivers/staging/android/vsoc.c @@ -0,0 +1,1168 @@ +/* + * drivers/android/staging/vsoc.c + * + * Android Virtual System on a Chip (VSoC) driver + * + * Copyright (C) 2017 Google, Inc. + * + * Author: ghartman@google.com + * + * 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. + * + * + * Based on drivers/char/kvm_ivshmem.c - driver for KVM Inter-VM shared memory + * Copyright 2009 Cam Macdonell + * + * Based on cirrusfb.c and 8139cp.c: + * Copyright 1999-2001 Jeff Garzik + * Copyright 2001-2004 Jeff Garzik + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uapi/vsoc_shm.h" + +#define VSOC_DEV_NAME "vsoc" + +/* + * Description of the ivshmem-doorbell PCI device used by QEmu. These + * constants follow docs/specs/ivshmem-spec.txt, which can be found in + * the QEmu repository. This was last reconciled with the version that + * came out with 2.8 + */ + +/* + * These constants are determined KVM Inter-VM shared memory device + * register offsets + */ +enum { + INTR_MASK = 0x00, /* Interrupt Mask */ + INTR_STATUS = 0x04, /* Interrupt Status */ + IV_POSITION = 0x08, /* VM ID */ + DOORBELL = 0x0c, /* Doorbell */ +}; + +static const int REGISTER_BAR; /* Equal to 0 */ +static const int MAX_REGISTER_BAR_LEN = 0x100; +/* + * The MSI-x BAR is not used directly. + * + * static const int MSI_X_BAR = 1; + */ +static const int SHARED_MEMORY_BAR = 2; + +struct vsoc_region_data { + char name[VSOC_DEVICE_NAME_SZ + 1]; + wait_queue_head_t interrupt_wait_queue; + /* TODO(b/73664181): Use multiple futex wait queues */ + wait_queue_head_t futex_wait_queue; + /* Flag indicating that an interrupt has been signalled by the host. */ + atomic_t *incoming_signalled; + /* Flag indicating the guest has signalled the host. */ + atomic_t *outgoing_signalled; + bool irq_requested; + bool device_created; +}; + +struct vsoc_device { + /* Kernel virtual address of REGISTER_BAR. */ + void __iomem *regs; + /* Physical address of SHARED_MEMORY_BAR. */ + phys_addr_t shm_phys_start; + /* Kernel virtual address of SHARED_MEMORY_BAR. */ + void __iomem *kernel_mapped_shm; + /* Size of the entire shared memory window in bytes. */ + size_t shm_size; + /* + * Pointer to the virtual address of the shared memory layout structure. + * This is probably identical to kernel_mapped_shm, but saving this + * here saves a lot of annoying casts. + */ + struct vsoc_shm_layout_descriptor *layout; + /* + * Points to a table of region descriptors in the kernel's virtual + * address space. Calculated from + * vsoc_shm_layout_descriptor.vsoc_region_desc_offset + */ + struct vsoc_device_region *regions; + /* Head of a list of permissions that have been granted. */ + struct list_head permissions; + struct pci_dev *dev; + /* Per-region (and therefore per-interrupt) information. */ + struct vsoc_region_data *regions_data; + /* + * Table of msi-x entries. This has to be separated from struct + * vsoc_region_data because the kernel deals with them as an array. + */ + struct msix_entry *msix_entries; + /* Mutex that protectes the permission list */ + struct mutex mtx; + /* Major number assigned by the kernel */ + int major; + /* Character device assigned by the kernel */ + struct cdev cdev; + /* Device class assigned by the kernel */ + struct class *class; + /* + * Flags that indicate what we've initialized. These are used to do an + * orderly cleanup of the device. + */ + bool enabled_device; + bool requested_regions; + bool cdev_added; + bool class_added; + bool msix_enabled; +}; + +static struct vsoc_device vsoc_dev; + +/* + * TODO(ghartman): Add a /sys filesystem entry that summarizes the permissions. + */ + +struct fd_scoped_permission_node { + struct fd_scoped_permission permission; + struct list_head list; +}; + +struct vsoc_private_data { + struct fd_scoped_permission_node *fd_scoped_permission_node; +}; + +static long vsoc_ioctl(struct file *, unsigned int, unsigned long); +static int vsoc_mmap(struct file *, struct vm_area_struct *); +static int vsoc_open(struct inode *, struct file *); +static int vsoc_release(struct inode *, struct file *); +static ssize_t vsoc_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t vsoc_write(struct file *, const char __user *, size_t, loff_t *); +static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin); +static int do_create_fd_scoped_permission( + struct vsoc_device_region *region_p, + struct fd_scoped_permission_node *np, + struct fd_scoped_permission_arg __user *arg); +static void do_destroy_fd_scoped_permission( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission *perm); +static long do_vsoc_describe_region(struct file *, + struct vsoc_device_region __user *); +static ssize_t vsoc_get_area(struct file *filp, __u32 *perm_off); + +/** + * Validate arguments on entry points to the driver. + */ +inline int vsoc_validate_inode(struct inode *inode) +{ + if (iminor(inode) >= vsoc_dev.layout->region_count) { + dev_err(&vsoc_dev.dev->dev, + "describe_region: invalid region %d\n", iminor(inode)); + return -ENODEV; + } + return 0; +} + +inline int vsoc_validate_filep(struct file *filp) +{ + int ret = vsoc_validate_inode(file_inode(filp)); + + if (ret) + return ret; + if (!filp->private_data) { + dev_err(&vsoc_dev.dev->dev, + "No private data on fd, region %d\n", + iminor(file_inode(filp))); + return -EBADFD; + } + return 0; +} + +/* Converts from shared memory offset to virtual address */ +static inline void *shm_off_to_virtual_addr(__u32 offset) +{ + return (void __force *)vsoc_dev.kernel_mapped_shm + offset; +} + +/* Converts from shared memory offset to physical address */ +static inline phys_addr_t shm_off_to_phys_addr(__u32 offset) +{ + return vsoc_dev.shm_phys_start + offset; +} + +/** + * Convenience functions to obtain the region from the inode or file. + * Dangerous to call before validating the inode/file. + */ +static inline struct vsoc_device_region *vsoc_region_from_inode( + struct inode *inode) +{ + return &vsoc_dev.regions[iminor(inode)]; +} + +static inline struct vsoc_device_region *vsoc_region_from_filep( + struct file *inode) +{ + return vsoc_region_from_inode(file_inode(inode)); +} + +static inline uint32_t vsoc_device_region_size(struct vsoc_device_region *r) +{ + return r->region_end_offset - r->region_begin_offset; +} + +static const struct file_operations vsoc_ops = { + .owner = THIS_MODULE, + .open = vsoc_open, + .mmap = vsoc_mmap, + .read = vsoc_read, + .unlocked_ioctl = vsoc_ioctl, + .compat_ioctl = vsoc_ioctl, + .write = vsoc_write, + .llseek = vsoc_lseek, + .release = vsoc_release, +}; + +static struct pci_device_id vsoc_id_table[] = { + {0x1af4, 0x1110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0}, +}; + +MODULE_DEVICE_TABLE(pci, vsoc_id_table); + +static void vsoc_remove_device(struct pci_dev *pdev); +static int vsoc_probe_device(struct pci_dev *pdev, + const struct pci_device_id *ent); + +static struct pci_driver vsoc_pci_driver = { + .name = "vsoc", + .id_table = vsoc_id_table, + .probe = vsoc_probe_device, + .remove = vsoc_remove_device, +}; + +static int do_create_fd_scoped_permission( + struct vsoc_device_region *region_p, + struct fd_scoped_permission_node *np, + struct fd_scoped_permission_arg __user *arg) +{ + struct file *managed_filp; + s32 managed_fd; + atomic_t *owner_ptr = NULL; + struct vsoc_device_region *managed_region_p; + + if (copy_from_user(&np->permission, &arg->perm, sizeof(*np)) || + copy_from_user(&managed_fd, + &arg->managed_region_fd, sizeof(managed_fd))) { + return -EFAULT; + } + managed_filp = fdget(managed_fd).file; + /* Check that it's a valid fd, */ + if (!managed_filp || vsoc_validate_filep(managed_filp)) + return -EPERM; + /* EEXIST if the given fd already has a permission. */ + if (((struct vsoc_private_data *)managed_filp->private_data)-> + fd_scoped_permission_node) + return -EEXIST; + managed_region_p = vsoc_region_from_filep(managed_filp); + /* Check that the provided region is managed by this one */ + if (&vsoc_dev.regions[managed_region_p->managed_by] != region_p) + return -EPERM; + /* The area must be well formed and have non-zero size */ + if (np->permission.begin_offset >= np->permission.end_offset) + return -EINVAL; + /* The area must fit in the memory window */ + if (np->permission.end_offset > + vsoc_device_region_size(managed_region_p)) + return -ERANGE; + /* The area must be in the region data section */ + if (np->permission.begin_offset < + managed_region_p->offset_of_region_data) + return -ERANGE; + /* The area must be page aligned */ + if (!PAGE_ALIGNED(np->permission.begin_offset) || + !PAGE_ALIGNED(np->permission.end_offset)) + return -EINVAL; + /* Owner offset must be naturally aligned in the window */ + if (np->permission.owner_offset & + (sizeof(np->permission.owner_offset) - 1)) + return -EINVAL; + /* The owner flag must reside in the owner memory */ + if (np->permission.owner_offset + sizeof(np->permission.owner_offset) > + vsoc_device_region_size(region_p)) + return -ERANGE; + /* The owner flag must reside in the data section */ + if (np->permission.owner_offset < region_p->offset_of_region_data) + return -EINVAL; + /* The owner value must change to claim the memory */ + if (np->permission.owned_value == VSOC_REGION_FREE) + return -EINVAL; + owner_ptr = + (atomic_t *)shm_off_to_virtual_addr(region_p->region_begin_offset + + np->permission.owner_offset); + /* We've already verified that this is in the shared memory window, so + * it should be safe to write to this address. + */ + if (atomic_cmpxchg(owner_ptr, + VSOC_REGION_FREE, + np->permission.owned_value) != VSOC_REGION_FREE) { + return -EBUSY; + } + ((struct vsoc_private_data *)managed_filp->private_data)-> + fd_scoped_permission_node = np; + /* The file offset needs to be adjusted if the calling + * process did any read/write operations on the fd + * before creating the permission. + */ + if (managed_filp->f_pos) { + if (managed_filp->f_pos > np->permission.end_offset) { + /* If the offset is beyond the permission end, set it + * to the end. + */ + managed_filp->f_pos = np->permission.end_offset; + } else { + /* If the offset is within the permission interval + * keep it there otherwise reset it to zero. + */ + if (managed_filp->f_pos < np->permission.begin_offset) { + managed_filp->f_pos = 0; + } else { + managed_filp->f_pos -= + np->permission.begin_offset; + } + } + } + return 0; +} + +static void do_destroy_fd_scoped_permission_node( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission_node *node) +{ + if (node) { + do_destroy_fd_scoped_permission(owner_region_p, + &node->permission); + mutex_lock(&vsoc_dev.mtx); + list_del(&node->list); + mutex_unlock(&vsoc_dev.mtx); + kfree(node); + } +} + +static void do_destroy_fd_scoped_permission( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission *perm) +{ + atomic_t *owner_ptr = NULL; + int prev = 0; + + if (!perm) + return; + owner_ptr = (atomic_t *)shm_off_to_virtual_addr( + owner_region_p->region_begin_offset + perm->owner_offset); + prev = atomic_xchg(owner_ptr, VSOC_REGION_FREE); + if (prev != perm->owned_value) + dev_err(&vsoc_dev.dev->dev, + "%x-%x: owner (%s) %x: expected to be %x was %x", + perm->begin_offset, perm->end_offset, + owner_region_p->device_name, perm->owner_offset, + perm->owned_value, prev); +} + +static long do_vsoc_describe_region(struct file *filp, + struct vsoc_device_region __user *dest) +{ + struct vsoc_device_region *region_p; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + region_p = vsoc_region_from_filep(filp); + if (copy_to_user(dest, region_p, sizeof(*region_p))) + return -EFAULT; + return 0; +} + +/** + * Implements the inner logic of cond_wait. Copies to and from userspace are + * done in the helper function below. + */ +static int handle_vsoc_cond_wait(struct file *filp, struct vsoc_cond_wait *arg) +{ + DEFINE_WAIT(wait); + u32 region_number = iminor(file_inode(filp)); + struct vsoc_region_data *data = vsoc_dev.regions_data + region_number; + struct hrtimer_sleeper timeout, *to = NULL; + int ret = 0; + struct vsoc_device_region *region_p = vsoc_region_from_filep(filp); + atomic_t *address = NULL; + struct timespec ts; + + /* Ensure that the offset is aligned */ + if (arg->offset & (sizeof(uint32_t) - 1)) + return -EADDRNOTAVAIL; + /* Ensure that the offset is within shared memory */ + if (((uint64_t)arg->offset) + region_p->region_begin_offset + + sizeof(uint32_t) > region_p->region_end_offset) + return -E2BIG; + address = shm_off_to_virtual_addr(region_p->region_begin_offset + + arg->offset); + + /* Ensure that the type of wait is valid */ + switch (arg->wait_type) { + case VSOC_WAIT_IF_EQUAL: + break; + case VSOC_WAIT_IF_EQUAL_TIMEOUT: + to = &timeout; + break; + default: + return -EINVAL; + } + + if (to) { + /* Copy the user-supplied timesec into the kernel structure. + * We do things this way to flatten differences between 32 bit + * and 64 bit timespecs. + */ + ts.tv_sec = arg->wake_time_sec; + ts.tv_nsec = arg->wake_time_nsec; + + if (!timespec_valid(&ts)) + return -EINVAL; + hrtimer_init_on_stack(&to->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_ABS); + hrtimer_set_expires_range_ns(&to->timer, timespec_to_ktime(ts), + current->timer_slack_ns); + + hrtimer_init_sleeper(to, current); + } + + while (1) { + prepare_to_wait(&data->futex_wait_queue, &wait, + TASK_INTERRUPTIBLE); + /* + * Check the sentinel value after prepare_to_wait. If the value + * changes after this check the writer will call signal, + * changing the task state from INTERRUPTIBLE to RUNNING. That + * will ensure that schedule() will eventually schedule this + * task. + */ + if (atomic_read(address) != arg->value) { + ret = 0; + break; + } + if (to) { + hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS); + if (likely(to->task)) + freezable_schedule(); + hrtimer_cancel(&to->timer); + if (!to->task) { + ret = -ETIMEDOUT; + break; + } + } else { + freezable_schedule(); + } + /* Count the number of times that we woke up. This is useful + * for unit testing. + */ + ++arg->wakes; + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + finish_wait(&data->futex_wait_queue, &wait); + if (to) + destroy_hrtimer_on_stack(&to->timer); + return ret; +} + +/** + * Handles the details of copying from/to userspace to ensure that the copies + * happen on all of the return paths of cond_wait. + */ +static int do_vsoc_cond_wait(struct file *filp, + struct vsoc_cond_wait __user *untrusted_in) +{ + struct vsoc_cond_wait arg; + int rval = 0; + + if (copy_from_user(&arg, untrusted_in, sizeof(arg))) + return -EFAULT; + /* wakes is an out parameter. Initialize it to something sensible. */ + arg.wakes = 0; + rval = handle_vsoc_cond_wait(filp, &arg); + if (copy_to_user(untrusted_in, &arg, sizeof(arg))) + return -EFAULT; + return rval; +} + +static int do_vsoc_cond_wake(struct file *filp, uint32_t offset) +{ + struct vsoc_device_region *region_p = vsoc_region_from_filep(filp); + u32 region_number = iminor(file_inode(filp)); + struct vsoc_region_data *data = vsoc_dev.regions_data + region_number; + /* Ensure that the offset is aligned */ + if (offset & (sizeof(uint32_t) - 1)) + return -EADDRNOTAVAIL; + /* Ensure that the offset is within shared memory */ + if (((uint64_t)offset) + region_p->region_begin_offset + + sizeof(uint32_t) > region_p->region_end_offset) + return -E2BIG; + /* + * TODO(b/73664181): Use multiple futex wait queues. + * We need to wake every sleeper when the condition changes. Typically + * only a single thread will be waiting on the condition, but there + * are exceptions. The worst case is about 10 threads. + */ + wake_up_interruptible_all(&data->futex_wait_queue); + return 0; +} + +static long vsoc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int rv = 0; + struct vsoc_device_region *region_p; + u32 reg_num; + struct vsoc_region_data *reg_data; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + region_p = vsoc_region_from_filep(filp); + reg_num = iminor(file_inode(filp)); + reg_data = vsoc_dev.regions_data + reg_num; + switch (cmd) { + case VSOC_CREATE_FD_SCOPED_PERMISSION: + { + struct fd_scoped_permission_node *node = NULL; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + /* We can't allocate memory for the permission */ + if (!node) + return -ENOMEM; + INIT_LIST_HEAD(&node->list); + rv = do_create_fd_scoped_permission( + region_p, + node, + (struct fd_scoped_permission_arg __user *)arg); + if (!rv) { + mutex_lock(&vsoc_dev.mtx); + list_add(&node->list, &vsoc_dev.permissions); + mutex_unlock(&vsoc_dev.mtx); + } else { + kfree(node); + return rv; + } + } + break; + + case VSOC_GET_FD_SCOPED_PERMISSION: + { + struct fd_scoped_permission_node *node = + ((struct vsoc_private_data *)filp->private_data)-> + fd_scoped_permission_node; + if (!node) + return -ENOENT; + if (copy_to_user + ((struct fd_scoped_permission __user *)arg, + &node->permission, sizeof(node->permission))) + return -EFAULT; + } + break; + + case VSOC_MAYBE_SEND_INTERRUPT_TO_HOST: + if (!atomic_xchg( + reg_data->outgoing_signalled, + 1)) { + writel(reg_num, vsoc_dev.regs + DOORBELL); + return 0; + } else { + return -EBUSY; + } + break; + + case VSOC_SEND_INTERRUPT_TO_HOST: + writel(reg_num, vsoc_dev.regs + DOORBELL); + return 0; + + case VSOC_WAIT_FOR_INCOMING_INTERRUPT: + wait_event_interruptible( + reg_data->interrupt_wait_queue, + (atomic_read(reg_data->incoming_signalled) != 0)); + break; + + case VSOC_DESCRIBE_REGION: + return do_vsoc_describe_region( + filp, + (struct vsoc_device_region __user *)arg); + + case VSOC_SELF_INTERRUPT: + atomic_set(reg_data->incoming_signalled, 1); + wake_up_interruptible(®_data->interrupt_wait_queue); + break; + + case VSOC_COND_WAIT: + return do_vsoc_cond_wait(filp, + (struct vsoc_cond_wait __user *)arg); + case VSOC_COND_WAKE: + return do_vsoc_cond_wake(filp, arg); + + default: + return -EINVAL; + } + return 0; +} + +static ssize_t vsoc_read(struct file *filp, char __user *buffer, size_t len, + loff_t *poffset) +{ + __u32 area_off; + const void *area_p; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + area_p = shm_off_to_virtual_addr(area_off); + area_p += *poffset; + area_len -= *poffset; + if (area_len <= 0) + return 0; + if (area_len < len) + len = area_len; + if (copy_to_user(buffer, area_p, len)) + return -EFAULT; + *poffset += len; + return len; +} + +static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin) +{ + ssize_t area_len = 0; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, NULL); + switch (origin) { + case SEEK_SET: + break; + + case SEEK_CUR: + if (offset > 0 && offset + filp->f_pos < 0) + return -EOVERFLOW; + offset += filp->f_pos; + break; + + case SEEK_END: + if (offset > 0 && offset + area_len < 0) + return -EOVERFLOW; + offset += area_len; + break; + + case SEEK_DATA: + if (offset >= area_len) + return -EINVAL; + if (offset < 0) + offset = 0; + break; + + case SEEK_HOLE: + /* Next hole is always the end of the region, unless offset is + * beyond that + */ + if (offset < area_len) + offset = area_len; + break; + + default: + return -EINVAL; + } + + if (offset < 0 || offset > area_len) + return -EINVAL; + filp->f_pos = offset; + + return offset; +} + +static ssize_t vsoc_write(struct file *filp, const char __user *buffer, + size_t len, loff_t *poffset) +{ + __u32 area_off; + void *area_p; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + area_p = shm_off_to_virtual_addr(area_off); + area_p += *poffset; + area_len -= *poffset; + if (area_len <= 0) + return 0; + if (area_len < len) + len = area_len; + if (copy_from_user(area_p, buffer, len)) + return -EFAULT; + *poffset += len; + return len; +} + +static irqreturn_t vsoc_interrupt(int irq, void *region_data_v) +{ + struct vsoc_region_data *region_data = + (struct vsoc_region_data *)region_data_v; + int reg_num = region_data - vsoc_dev.regions_data; + + if (unlikely(!region_data)) + return IRQ_NONE; + + if (unlikely(reg_num < 0 || + reg_num >= vsoc_dev.layout->region_count)) { + dev_err(&vsoc_dev.dev->dev, + "invalid irq @%p reg_num=0x%04x\n", + region_data, reg_num); + return IRQ_NONE; + } + if (unlikely(vsoc_dev.regions_data + reg_num != region_data)) { + dev_err(&vsoc_dev.dev->dev, + "irq not aligned @%p reg_num=0x%04x\n", + region_data, reg_num); + return IRQ_NONE; + } + wake_up_interruptible(®ion_data->interrupt_wait_queue); + return IRQ_HANDLED; +} + +static int vsoc_probe_device(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int result; + int i; + resource_size_t reg_size; + dev_t devt; + + vsoc_dev.dev = pdev; + result = pci_enable_device(pdev); + if (result) { + dev_err(&pdev->dev, + "pci_enable_device failed %s: error %d\n", + pci_name(pdev), result); + return result; + } + vsoc_dev.enabled_device = true; + result = pci_request_regions(pdev, "vsoc"); + if (result < 0) { + dev_err(&pdev->dev, "pci_request_regions failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.requested_regions = true; + /* Set up the control registers in BAR 0 */ + reg_size = pci_resource_len(pdev, REGISTER_BAR); + if (reg_size > MAX_REGISTER_BAR_LEN) + vsoc_dev.regs = + pci_iomap(pdev, REGISTER_BAR, MAX_REGISTER_BAR_LEN); + else + vsoc_dev.regs = pci_iomap(pdev, REGISTER_BAR, reg_size); + + if (!vsoc_dev.regs) { + dev_err(&pdev->dev, + "cannot map registers of size %zu\n", + (size_t)reg_size); + vsoc_remove_device(pdev); + return -EBUSY; + } + + /* Map the shared memory in BAR 2 */ + vsoc_dev.shm_phys_start = pci_resource_start(pdev, SHARED_MEMORY_BAR); + vsoc_dev.shm_size = pci_resource_len(pdev, SHARED_MEMORY_BAR); + + dev_info(&pdev->dev, "shared memory @ DMA %pa size=0x%zx\n", + &vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + /* TODO(ghartman): ioremap_wc should work here */ + vsoc_dev.kernel_mapped_shm = ioremap_nocache( + vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + if (!vsoc_dev.kernel_mapped_shm) { + dev_err(&vsoc_dev.dev->dev, "cannot iomap region\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + + vsoc_dev.layout = (struct vsoc_shm_layout_descriptor __force *) + vsoc_dev.kernel_mapped_shm; + dev_info(&pdev->dev, "major_version: %d\n", + vsoc_dev.layout->major_version); + dev_info(&pdev->dev, "minor_version: %d\n", + vsoc_dev.layout->minor_version); + dev_info(&pdev->dev, "size: 0x%x\n", vsoc_dev.layout->size); + dev_info(&pdev->dev, "regions: %d\n", vsoc_dev.layout->region_count); + if (vsoc_dev.layout->major_version != + CURRENT_VSOC_LAYOUT_MAJOR_VERSION) { + dev_err(&vsoc_dev.dev->dev, + "driver supports only major_version %d\n", + CURRENT_VSOC_LAYOUT_MAJOR_VERSION); + vsoc_remove_device(pdev); + return -EBUSY; + } + result = alloc_chrdev_region(&devt, 0, vsoc_dev.layout->region_count, + VSOC_DEV_NAME); + if (result) { + dev_err(&vsoc_dev.dev->dev, "alloc_chrdev_region failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.major = MAJOR(devt); + cdev_init(&vsoc_dev.cdev, &vsoc_ops); + vsoc_dev.cdev.owner = THIS_MODULE; + result = cdev_add(&vsoc_dev.cdev, devt, vsoc_dev.layout->region_count); + if (result) { + dev_err(&vsoc_dev.dev->dev, "cdev_add error\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.cdev_added = true; + vsoc_dev.class = class_create(THIS_MODULE, VSOC_DEV_NAME); + if (IS_ERR(vsoc_dev.class)) { + dev_err(&vsoc_dev.dev->dev, "class_create failed\n"); + vsoc_remove_device(pdev); + return PTR_ERR(vsoc_dev.class); + } + vsoc_dev.class_added = true; + vsoc_dev.regions = (struct vsoc_device_region __force *) + ((void *)vsoc_dev.layout + + vsoc_dev.layout->vsoc_region_desc_offset); + vsoc_dev.msix_entries = kcalloc( + vsoc_dev.layout->region_count, + sizeof(vsoc_dev.msix_entries[0]), GFP_KERNEL); + if (!vsoc_dev.msix_entries) { + dev_err(&vsoc_dev.dev->dev, + "unable to allocate msix_entries\n"); + vsoc_remove_device(pdev); + return -ENOSPC; + } + vsoc_dev.regions_data = kcalloc( + vsoc_dev.layout->region_count, + sizeof(vsoc_dev.regions_data[0]), GFP_KERNEL); + if (!vsoc_dev.regions_data) { + dev_err(&vsoc_dev.dev->dev, + "unable to allocate regions' data\n"); + vsoc_remove_device(pdev); + return -ENOSPC; + } + for (i = 0; i < vsoc_dev.layout->region_count; ++i) + vsoc_dev.msix_entries[i].entry = i; + + result = pci_enable_msix_exact(vsoc_dev.dev, vsoc_dev.msix_entries, + vsoc_dev.layout->region_count); + if (result) { + dev_info(&pdev->dev, "pci_enable_msix failed: %d\n", result); + vsoc_remove_device(pdev); + return -ENOSPC; + } + /* Check that all regions are well formed */ + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + const struct vsoc_device_region *region = vsoc_dev.regions + i; + + if (!PAGE_ALIGNED(region->region_begin_offset) || + !PAGE_ALIGNED(region->region_end_offset)) { + dev_err(&vsoc_dev.dev->dev, + "region %d not aligned (%x:%x)", i, + region->region_begin_offset, + region->region_end_offset); + vsoc_remove_device(pdev); + return -EFAULT; + } + if (region->region_begin_offset >= region->region_end_offset || + region->region_end_offset > vsoc_dev.shm_size) { + dev_err(&vsoc_dev.dev->dev, + "region %d offsets are wrong: %x %x %zx", + i, region->region_begin_offset, + region->region_end_offset, vsoc_dev.shm_size); + vsoc_remove_device(pdev); + return -EFAULT; + } + if (region->managed_by >= vsoc_dev.layout->region_count) { + dev_err(&vsoc_dev.dev->dev, + "region %d has invalid owner: %u", + i, region->managed_by); + vsoc_remove_device(pdev); + return -EFAULT; + } + } + vsoc_dev.msix_enabled = true; + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + const struct vsoc_device_region *region = vsoc_dev.regions + i; + size_t name_sz = sizeof(vsoc_dev.regions_data[i].name) - 1; + const struct vsoc_signal_table_layout *h_to_g_signal_table = + ®ion->host_to_guest_signal_table; + const struct vsoc_signal_table_layout *g_to_h_signal_table = + ®ion->guest_to_host_signal_table; + + vsoc_dev.regions_data[i].name[name_sz] = '\0'; + memcpy(vsoc_dev.regions_data[i].name, region->device_name, + name_sz); + dev_info(&pdev->dev, "region %d name=%s\n", + i, vsoc_dev.regions_data[i].name); + init_waitqueue_head( + &vsoc_dev.regions_data[i].interrupt_wait_queue); + init_waitqueue_head(&vsoc_dev.regions_data[i].futex_wait_queue); + vsoc_dev.regions_data[i].incoming_signalled = + shm_off_to_virtual_addr(region->region_begin_offset) + + h_to_g_signal_table->interrupt_signalled_offset; + vsoc_dev.regions_data[i].outgoing_signalled = + shm_off_to_virtual_addr(region->region_begin_offset) + + g_to_h_signal_table->interrupt_signalled_offset; + result = request_irq( + vsoc_dev.msix_entries[i].vector, + vsoc_interrupt, 0, + vsoc_dev.regions_data[i].name, + vsoc_dev.regions_data + i); + if (result) { + dev_info(&pdev->dev, + "request_irq failed irq=%d vector=%d\n", + i, vsoc_dev.msix_entries[i].vector); + vsoc_remove_device(pdev); + return -ENOSPC; + } + vsoc_dev.regions_data[i].irq_requested = true; + if (!device_create(vsoc_dev.class, NULL, + MKDEV(vsoc_dev.major, i), + NULL, vsoc_dev.regions_data[i].name)) { + dev_err(&vsoc_dev.dev->dev, "device_create failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.regions_data[i].device_created = true; + } + return 0; +} + +/* + * This should undo all of the allocations in the probe function in reverse + * order. + * + * Notes: + * + * The device may have been partially initialized, so double check + * that the allocations happened. + * + * This function may be called multiple times, so mark resources as freed + * as they are deallocated. + */ +static void vsoc_remove_device(struct pci_dev *pdev) +{ + int i; + /* + * pdev is the first thing to be set on probe and the last thing + * to be cleared here. If it's NULL then there is no cleanup. + */ + if (!pdev || !vsoc_dev.dev) + return; + dev_info(&pdev->dev, "remove_device\n"); + if (vsoc_dev.regions_data) { + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + if (vsoc_dev.regions_data[i].device_created) { + device_destroy(vsoc_dev.class, + MKDEV(vsoc_dev.major, i)); + vsoc_dev.regions_data[i].device_created = false; + } + if (vsoc_dev.regions_data[i].irq_requested) + free_irq(vsoc_dev.msix_entries[i].vector, NULL); + vsoc_dev.regions_data[i].irq_requested = false; + } + kfree(vsoc_dev.regions_data); + vsoc_dev.regions_data = NULL; + } + if (vsoc_dev.msix_enabled) { + pci_disable_msix(pdev); + vsoc_dev.msix_enabled = false; + } + kfree(vsoc_dev.msix_entries); + vsoc_dev.msix_entries = NULL; + vsoc_dev.regions = NULL; + if (vsoc_dev.class_added) { + class_destroy(vsoc_dev.class); + vsoc_dev.class_added = false; + } + if (vsoc_dev.cdev_added) { + cdev_del(&vsoc_dev.cdev); + vsoc_dev.cdev_added = false; + } + if (vsoc_dev.major && vsoc_dev.layout) { + unregister_chrdev_region(MKDEV(vsoc_dev.major, 0), + vsoc_dev.layout->region_count); + vsoc_dev.major = 0; + } + vsoc_dev.layout = NULL; + if (vsoc_dev.kernel_mapped_shm) { + pci_iounmap(pdev, vsoc_dev.kernel_mapped_shm); + vsoc_dev.kernel_mapped_shm = NULL; + } + if (vsoc_dev.regs) { + pci_iounmap(pdev, vsoc_dev.regs); + vsoc_dev.regs = NULL; + } + if (vsoc_dev.requested_regions) { + pci_release_regions(pdev); + vsoc_dev.requested_regions = false; + } + if (vsoc_dev.enabled_device) { + pci_disable_device(pdev); + vsoc_dev.enabled_device = false; + } + /* Do this last: it indicates that the device is not initialized. */ + vsoc_dev.dev = NULL; +} + +static void __exit vsoc_cleanup_module(void) +{ + vsoc_remove_device(vsoc_dev.dev); + pci_unregister_driver(&vsoc_pci_driver); +} + +static int __init vsoc_init_module(void) +{ + int err = -ENOMEM; + + INIT_LIST_HEAD(&vsoc_dev.permissions); + mutex_init(&vsoc_dev.mtx); + + err = pci_register_driver(&vsoc_pci_driver); + if (err < 0) + return err; + return 0; +} + +static int vsoc_open(struct inode *inode, struct file *filp) +{ + /* Can't use vsoc_validate_filep because filp is still incomplete */ + int ret = vsoc_validate_inode(inode); + + if (ret) + return ret; + filp->private_data = + kzalloc(sizeof(struct vsoc_private_data), GFP_KERNEL); + if (!filp->private_data) + return -ENOMEM; + return 0; +} + +static int vsoc_release(struct inode *inode, struct file *filp) +{ + struct vsoc_private_data *private_data = NULL; + struct fd_scoped_permission_node *node = NULL; + struct vsoc_device_region *owner_region_p = NULL; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + private_data = (struct vsoc_private_data *)filp->private_data; + if (!private_data) + return 0; + + node = private_data->fd_scoped_permission_node; + if (node) { + owner_region_p = vsoc_region_from_inode(inode); + if (owner_region_p->managed_by != VSOC_REGION_WHOLE) { + owner_region_p = + &vsoc_dev.regions[owner_region_p->managed_by]; + } + do_destroy_fd_scoped_permission_node(owner_region_p, node); + private_data->fd_scoped_permission_node = NULL; + } + kfree(private_data); + filp->private_data = NULL; + + return 0; +} + +/* + * Returns the device relative offset and length of the area specified by the + * fd scoped permission. If there is no fd scoped permission set, a default + * permission covering the entire region is assumed, unless the region is owned + * by another one, in which case the default is a permission with zero size. + */ +static ssize_t vsoc_get_area(struct file *filp, __u32 *area_offset) +{ + __u32 off = 0; + ssize_t length = 0; + struct vsoc_device_region *region_p; + struct fd_scoped_permission *perm; + + region_p = vsoc_region_from_filep(filp); + off = region_p->region_begin_offset; + perm = &((struct vsoc_private_data *)filp->private_data)-> + fd_scoped_permission_node->permission; + if (perm) { + off += perm->begin_offset; + length = perm->end_offset - perm->begin_offset; + } else if (region_p->managed_by == VSOC_REGION_WHOLE) { + /* No permission set and the regions is not owned by another, + * default to full region access. + */ + length = vsoc_device_region_size(region_p); + } else { + /* return zero length, access is denied. */ + length = 0; + } + if (area_offset) + *area_offset = off; + return length; +} + +static int vsoc_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long len = vma->vm_end - vma->vm_start; + __u32 area_off; + phys_addr_t mem_off; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + /* Add the requested offset */ + area_off += (vma->vm_pgoff << PAGE_SHIFT); + area_len -= (vma->vm_pgoff << PAGE_SHIFT); + if (area_len < len) + return -EINVAL; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + mem_off = shm_off_to_phys_addr(area_off); + if (io_remap_pfn_range(vma, vma->vm_start, mem_off >> PAGE_SHIFT, + len, vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +module_init(vsoc_init_module); +module_exit(vsoc_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Hartman "); +MODULE_DESCRIPTION("VSoC interpretation of QEmu's ivshmem device"); +MODULE_VERSION("1.0"); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 04f7a3bd3ddc40ecc89d8fbceb1116a1dea13ce3..0c36f5557abcbca6e99232f4c5c9bfa0a0cf81ed 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -5601,11 +5601,11 @@ static int ni_E_init(struct comedi_device *dev, /* Digital I/O (PFI) subdevice */ s = &dev->subdevices[NI_PFI_DIO_SUBDEV]; s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->maxdata = 1; if (devpriv->is_m_series) { s->n_chan = 16; s->insn_bits = ni_pfi_insn_bits; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; ni_writew(dev, s->state, M_Offset_PFI_DO); for (i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i) { @@ -5614,6 +5614,7 @@ static int ni_E_init(struct comedi_device *dev, } } else { s->n_chan = 10; + s->subdev_flags = SDF_INTERNAL; } s->insn_config = ni_pfi_insn_config; diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 8343a780f63dc6931bbeb8a5bc868e1150bfaf53..dbf30524fa73c0cbaf93b6c403f671a5561785f8 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -206,11 +206,9 @@ static int ad7192_setup(struct ad7192_state *st, struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi); unsigned long long scale_uv; int i, ret, id; - u8 ones[6]; /* reset the serial interface */ - memset(&ones, 0xFF, 6); - ret = spi_write(st->sd.spi, &ones, 6); + ret = ad_sd_reset(&st->sd, 48); if (ret < 0) goto out; usleep_range(500, 1000); /* Wait for at least 500us */ diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index a2b7ae3329c0e56cd345340a7c0c6426cfe621fd..9fe1d5793cee085354f27bd0b991e2be30524b93 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -275,7 +275,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev, error_ret: mutex_unlock(&chip->state_lock); - return 0; + return ret; } static int ad7150_read_event_value(struct iio_dev *indio_dev, diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c index a21b7c514776c9b618eb546a7dd0446421157c19..b412f567a9c1d004a8993c07e7533e65f8c63d90 100644 --- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c @@ -258,7 +258,7 @@ out_free_irq: out1: iio_trigger_unregister(st->trig); out: - iio_trigger_put(st->trig); + iio_trigger_free(st->trig); return ret; } @@ -271,7 +271,7 @@ static int iio_bfin_tmr_trigger_remove(struct platform_device *pdev) peripheral_free(st->t->pin); free_irq(st->irq, st); iio_trigger_unregister(st->trig); - iio_trigger_put(st->trig); + iio_trigger_free(st->trig); return 0; } diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 8f0a2ffa7150366aa743f6ac9dcc89dc4714252b..0ba55312990f12df8b84b425434df24b5de046ce 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -137,7 +137,7 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev) trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); if (!trig_info) { ret = -ENOMEM; - goto error_put_trigger_and_remove_from_list; + goto error_free_trigger_and_remove_from_list; } iio_trigger_set_drvdata(trig, trig_info); trig->ops = &iio_prtc_trigger_ops; @@ -164,9 +164,9 @@ error_close_rtc: rtc_class_close(trig_info->rtc); error_free_trig_info: kfree(trig_info); -error_put_trigger_and_remove_from_list: +error_free_trigger_and_remove_from_list: list_del(&trig->alloc_list); - iio_trigger_put(trig); + iio_trigger_free(trig); error_free_completed_registrations: list_for_each_entry_safe(trig, trig2, diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index 4662e00b456a25d4c08b755bc68b6bdbf37e8ed2..62fdd670509c0417c600064d857c845a61651d3c 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -460,6 +460,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(imx_ldb->regmap); } + /* disable LDB by resetting the control register to POR default */ + regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0); + imx_ldb->dev = dev; if (of_id) @@ -497,14 +500,14 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) if (ret || i < 0 || i > 1) return -EINVAL; + if (!of_device_is_available(child)) + continue; + if (dual && i > 0) { dev_warn(dev, "dual-channel mode, ignoring second output\n"); continue; } - if (!of_device_is_available(child)) - continue; - channel = &imx_ldb->channel[i]; channel->ldb = imx_ldb; channel->chno = i; diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h index 89794fdfec9d2f34931198301904b4b586149b2b..3b93270d5146107983ae14f56dcbdf9a5615402b 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h @@ -1066,23 +1066,21 @@ struct hsm_action_item { * \retval buffer */ static inline char *hai_dump_data_field(struct hsm_action_item *hai, - char *buffer, int len) + char *buffer, size_t len) { - int i, sz, data_len; + int i, data_len; char *ptr; ptr = buffer; - sz = len; data_len = hai->hai_len - sizeof(*hai); - for (i = 0 ; (i < data_len) && (sz > 0) ; i++) { - int cnt; - - cnt = snprintf(ptr, sz, "%.2X", - (unsigned char)hai->hai_data[i]); - ptr += cnt; - sz -= cnt; + for (i = 0; (i < data_len) && (len > 2); i++) { + snprintf(ptr, 3, "%02X", (unsigned char)hai->hai_data[i]); + ptr += 2; + len -= 2; } + *ptr = '\0'; + return buffer; } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index 6140130b60563bd9df13073d4ea8b317395c11d0..23ce4a9d09f44e7ec7a6729c87086d5ce69efb47 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -573,6 +573,13 @@ struct ldlm_lock *__ldlm_handle2lock(const struct lustre_handle *handle, if (lock == NULL) return NULL; + if (lock->l_export && lock->l_export->exp_failed) { + CDEBUG(D_INFO, "lock export failed: lock %p, exp %p\n", + lock, lock->l_export); + LDLM_LOCK_PUT(lock); + return NULL; + } + /* It's unlikely but possible that someone marked the lock as * destroyed after we did handle2object on it */ if (flags == 0 && ((lock->l_flags & LDLM_FL_DESTROYED)== 0)) { diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index ae605a6d9dc269ce537c5b04f3ae366eb55e16e1..dde9fd9a39b922cea97ca6d3dd4a72459a35fcb2 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -407,15 +407,13 @@ static int ll_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) result = VM_FAULT_LOCKED; break; case -ENODATA: + case -EAGAIN: case -EFAULT: result = VM_FAULT_NOPAGE; break; case -ENOMEM: result = VM_FAULT_OOM; break; - case -EAGAIN: - result = VM_FAULT_RETRY; - break; default: result = VM_FAULT_SIGBUS; break; diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index a8df8a792333025b956f883a003766fcd41038e7..7ca8d24464f66be24b6ec715f4c5e4304ed4ddb4 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -1506,20 +1506,15 @@ static int ptlrpc_server_hpreq_init(struct ptlrpc_service_part *svcpt, * it may hit swab race at LU-1044. */ if (req->rq_ops->hpreq_check) { rc = req->rq_ops->hpreq_check(req); - /** - * XXX: Out of all current - * ptlrpc_hpreq_ops::hpreq_check(), only - * ldlm_cancel_hpreq_check() can return an error code; - * other functions assert in similar places, which seems - * odd. What also does not seem right is that handlers - * for those RPCs do not assert on the same checks, but - * rather handle the error cases. e.g. see - * ost_rw_hpreq_check(), and ost_brw_read(), - * ost_brw_write(). + if (rc == -ESTALE) { + req->rq_status = rc; + ptlrpc_error(req); + } + /** can only return error, + * 0 for normal request, + * or 1 for high priority request */ - if (rc < 0) - return rc; - LASSERT(rc == 0 || rc == 1); + LASSERT(rc <= 1); } spin_lock_bh(&req->rq_export->exp_rpc_lock); diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 5d6250337fec112224f67b4319569c82953f9e0f..4f84de43de7c8ce1204b17e3322f886e0c89cc69 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -11,7 +11,6 @@ * (at your option) any later version. */ -#include #include #include #include @@ -22,6 +21,8 @@ #include #include +#include + #include "iss_video.h" #include "iss.h" diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c index 3f631c067f5419cdf206025c314eda91f8f484a6..dd2ebd223867209324c8ece673ddf16c8520eaf0 100644 --- a/drivers/staging/nvec/nvec_ps2.c +++ b/drivers/staging/nvec/nvec_ps2.c @@ -165,8 +165,8 @@ static int nvec_mouse_resume(struct device *dev) } #endif -static const SIMPLE_DEV_PM_OPS(nvec_mouse_pm_ops, nvec_mouse_suspend, - nvec_mouse_resume); +static SIMPLE_DEV_PM_OPS(nvec_mouse_pm_ops, nvec_mouse_suspend, + nvec_mouse_resume); static struct platform_driver nvec_mouse_driver = { .probe = nvec_mouse_probe, diff --git a/drivers/staging/rtl8188eu/include/rtw_debug.h b/drivers/staging/rtl8188eu/include/rtw_debug.h index a38616e3cad2825bcc044992857792b17fc2df0b..acef31275b0e437231035e1244443d4d03e793e9 100644 --- a/drivers/staging/rtl8188eu/include/rtw_debug.h +++ b/drivers/staging/rtl8188eu/include/rtw_debug.h @@ -75,7 +75,7 @@ extern u32 GlobalDebugLevel; #define DBG_88E_LEVEL(_level, fmt, arg...) \ do { \ if (_level <= GlobalDebugLevel) \ - pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg); \ + pr_info(DRIVER_PREFIX fmt, ##arg); \ } while (0) #define DBG_88E(...) \ diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index d598fec4abbf75df2374c4df014aee5710c4c0be..0bfb4fe8a86ebe48201b3ebf901dd0c5996ced4b 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -1396,19 +1396,13 @@ static int rtw_wx_get_essid(struct net_device *dev, if ((check_fwstate(pmlmepriv, _FW_LINKED)) || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) { len = pcur_bss->Ssid.SsidLength; - - wrqu->essid.length = len; - memcpy(extra, pcur_bss->Ssid.Ssid, len); - - wrqu->essid.flags = 1; } else { - ret = -1; - goto exit; + len = 0; + *extra = 0; } - -exit: - + wrqu->essid.length = len; + wrqu->essid.flags = 1; return ret; } diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 929ac29197ccee79094a81600d1f1480874e5f58..fb476c00bf44ac933cc104a49a66067e937dd132 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -1682,6 +1682,8 @@ static short rtl8192_usb_initendpoints(struct net_device *dev) priv->rx_urb[16] = usb_alloc_urb(0, GFP_KERNEL); priv->oldaddr = kmalloc(16, GFP_KERNEL); + if (!priv->oldaddr) + return -ENOMEM; oldaddr = priv->oldaddr; align = ((long)oldaddr) & 3; if (align) { diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h index 8269be80437ac747846f9b0714778fe872d41dad..53c39ca99ee426a74ccefebd36078cf110ebc44b 100644 --- a/drivers/staging/rtl8712/ieee80211.h +++ b/drivers/staging/rtl8712/ieee80211.h @@ -142,52 +142,52 @@ struct ieee_ibss_seq { }; struct ieee80211_hdr { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; -} __packed; +} __packed __aligned(2); struct ieee80211_hdr_3addr { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; -} __packed; + __le16 seq_ctl; +} __packed __aligned(2); struct ieee80211_hdr_qos { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; - u16 qc; -} __packed; + __le16 qc; +} __packed __aligned(2); struct ieee80211_hdr_3addr_qos { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; - u16 qc; + __le16 seq_ctl; + __le16 qc; } __packed; struct eapol { u8 snap[6]; - u16 ethertype; + __be16 ethertype; u8 version; u8 type; - u16 length; + __le16 length; } __packed; @@ -554,13 +554,13 @@ Total: 28-2340 bytes */ struct ieee80211_header_data { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[6]; u8 addr2[6]; u8 addr3[6]; - u16 seq_ctrl; -}; + __le16 seq_ctrl; +} __packed __aligned(2); #define BEACON_PROBE_SSID_ID_POSITION 12 @@ -592,18 +592,18 @@ struct ieee80211_info_element { /* * These are the data types that can make up management packets * - u16 auth_algorithm; - u16 auth_sequence; - u16 beacon_interval; - u16 capability; + __le16 auth_algorithm; + __le16 auth_sequence; + __le16 beacon_interval; + __le16 capability; u8 current_ap[ETH_ALEN]; - u16 listen_interval; + __le16 listen_interval; struct { u16 association_id:14, reserved:2; } __packed; - u32 time_stamp[2]; - u16 reason; - u16 status; + __le32 time_stamp[2]; + __le16 reason; + __le16 status; */ #define IEEE80211_DEFAULT_TX_ESSID "Penguin" @@ -611,16 +611,16 @@ struct ieee80211_info_element { struct ieee80211_authentication { struct ieee80211_header_data header; - u16 algorithm; - u16 transaction; - u16 status; + __le16 algorithm; + __le16 transaction; + __le16 status; } __packed; struct ieee80211_probe_response { struct ieee80211_header_data header; - u32 time_stamp[2]; - u16 beacon_interval; - u16 capability; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; struct ieee80211_info_element info_element; } __packed; @@ -630,16 +630,16 @@ struct ieee80211_probe_request { struct ieee80211_assoc_request_frame { struct ieee80211_hdr_3addr header; - u16 capability; - u16 listen_interval; + __le16 capability; + __le16 listen_interval; struct ieee80211_info_element_hdr info_element; } __packed; struct ieee80211_assoc_response_frame { struct ieee80211_hdr_3addr header; - u16 capability; - u16 status; - u16 aid; + __le16 capability; + __le16 status; + __le16 aid; } __packed; struct ieee80211_txb { diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c index f49acaf04076f3a2ecb2add4aa75c4b2bbd6f53a..565290b0991d67c6343a4981f620143a58469dae 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.c +++ b/drivers/staging/rtl8712/rtl871x_xmit.c @@ -340,7 +340,8 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, /* if in MP_STATE, update pkt_attrib from mp_txcmd, and overwrite * some settings above.*/ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) - pattrib->priority = (txdesc.txdw1 >> QSEL_SHT) & 0x1f; + pattrib->priority = + (le32_to_cpu(txdesc.txdw1) >> QSEL_SHT) & 0x1f; return _SUCCESS; } @@ -481,7 +482,7 @@ static sint make_wlanhdr(struct _adapter *padapter , u8 *hdr, struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct qos_priv *pqospriv = &pmlmepriv->qospriv; - u16 *fctrl = &pwlanhdr->frame_ctl; + __le16 *fctrl = &pwlanhdr->frame_ctl; memset(hdr, 0, WLANHDR_OFFSET); SetFrameSubType(fctrl, pattrib->subtype); @@ -569,7 +570,7 @@ static sint r8712_put_snap(u8 *data, u16 h_proto) snap->oui[0] = oui[0]; snap->oui[1] = oui[1]; snap->oui[2] = oui[2]; - *(u16 *)(data + SNAP_SIZE) = htons(h_proto); + *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); return SNAP_SIZE + sizeof(u16); } diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c index 0615a7e77576c562121388c5b877eac0b444451a..34cf9dc13acd0eac453e759ed7ac48188514762a 100644 --- a/drivers/staging/rts5208/rtsx_scsi.c +++ b/drivers/staging/rts5208/rtsx_scsi.c @@ -539,7 +539,7 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (sendbytes > 8) { memcpy(buf, inquiry_buf, 8); - memcpy(buf + 8, inquiry_string, sendbytes - 8); + strncpy(buf + 8, inquiry_string, sendbytes - 8); if (pro_formatter_flag) { /* Additional Length */ buf[4] = 0x33; diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c index 0d029fe92b40346028d1b05f5db2775d40ecd312..0526dc783d647c98519daeaa1e3cdcf8f27c48b0 100644 --- a/drivers/staging/rts5208/xd.c +++ b/drivers/staging/rts5208/xd.c @@ -1095,7 +1095,7 @@ static int xd_copy_page(struct rtsx_chip *chip, u32 old_blk, u32 new_blk, reg = 0; rtsx_read_register(chip, XD_CTL, ®); if (reg & (XD_ECC1_ERROR | XD_ECC2_ERROR)) { - wait_timeout(100); + mdelay(100); if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index 013a6240f193a3d96ce4aacacdf9d0548e3b4c42..c1ad0aea23b92f3bf53ce79d76ef094c3d8728cf 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -169,7 +169,7 @@ int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) hw->ident_sta_fw.variant) > HFA384x_FIRMWARE_VERSION(1, 5, 0)) { if (msg->scantype.data != P80211ENUM_scantype_active) - word = cpu_to_le16(msg->maxchanneltime.data); + word = msg->maxchanneltime.data; else word = 0; diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index ce844e98099011662215cd5c8395109b1a62fd24..185059773f1b918d7b8f772b6ea713bba0e7ea88 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -428,6 +428,7 @@ int iscsit_reset_np_thread( return 0; } np->np_thread_state = ISCSI_NP_THREAD_RESET; + atomic_inc(&np->np_reset_count); if (np->np_thread) { spin_unlock_bh(&np->np_thread_lock); @@ -673,6 +674,7 @@ static int iscsit_add_reject_from_cmd( unsigned char *buf) { struct iscsi_conn *conn; + const bool do_put = cmd->se_cmd.se_tfo != NULL; if (!cmd->conn) { pr_err("cmd->conn is NULL for ITT: 0x%08x\n", @@ -703,7 +705,7 @@ static int iscsit_add_reject_from_cmd( * Perform the kref_put now if se_cmd has already been setup by * scsit_setup_scsi_cmd() */ - if (cmd->se_cmd.se_tfo != NULL) { + if (do_put) { pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n"); target_put_sess_cmd(&cmd->se_cmd); } @@ -1748,8 +1750,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, struct iscsi_tmr_req *tmr_req; struct iscsi_tm *hdr; int out_of_order_cmdsn = 0, ret; - bool sess_ref = false; - u8 function; + u8 function, tcm_function = TMR_UNKNOWN; hdr = (struct iscsi_tm *) buf; hdr->flags &= ~ISCSI_FLAG_CMD_FINAL; @@ -1790,23 +1791,17 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, buf); } + transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops, + conn->sess->se_sess, 0, DMA_NONE, + MSG_SIMPLE_TAG, cmd->sense_buffer + 2); + + target_get_sess_cmd(&cmd->se_cmd, true); + /* * TASK_REASSIGN for ERL=2 / connection stays inside of * LIO-Target $FABRIC_MOD */ if (function != ISCSI_TM_FUNC_TASK_REASSIGN) { - - u8 tcm_function; - int ret; - - transport_init_se_cmd(&cmd->se_cmd, - &lio_target_fabric_configfs->tf_ops, - conn->sess->se_sess, 0, DMA_NONE, - MSG_SIMPLE_TAG, cmd->sense_buffer + 2); - - target_get_sess_cmd(&cmd->se_cmd, true); - sess_ref = true; - switch (function) { case ISCSI_TM_FUNC_ABORT_TASK: tcm_function = TMR_ABORT_TASK; @@ -1835,15 +1830,14 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, return iscsit_add_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); } - - ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req, - tcm_function, GFP_KERNEL); - if (ret < 0) - return iscsit_add_reject_cmd(cmd, + } + ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req, tcm_function, + GFP_KERNEL); + if (ret < 0) + return iscsit_add_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); - cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req; - } + cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req; cmd->iscsi_opcode = ISCSI_OP_SCSI_TMFUNC; cmd->i_state = ISTATE_SEND_TASKMGTRSP; @@ -1919,12 +1913,14 @@ attach: if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); - if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) + if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) { out_of_order_cmdsn = 1; - else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) + } else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { + target_put_sess_cmd(&cmd->se_cmd); return 0; - else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) + } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { return -1; + } } iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); @@ -1944,12 +1940,8 @@ attach: * For connection recovery, this is also the default action for * TMR TASK_REASSIGN. */ - if (sess_ref) { - pr_debug("Handle TMR, using sess_ref=true check\n"); - target_put_sess_cmd(&cmd->se_cmd); - } - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); + target_put_sess_cmd(&cmd->se_cmd); return 0; } EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd); diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index ab4915c0d933a07021b076cf15232b85dc9dcf08..8cf853f71c931cc1ec872d18efac2333cf824a99 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -26,27 +26,6 @@ #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" -static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len) -{ - int j = DIV_ROUND_UP(len, 2), rc; - - rc = hex2bin(dst, src, j); - if (rc < 0) - pr_debug("CHAP string contains non hex digit symbols\n"); - - dst[j] = '\0'; - return j; -} - -static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len) -{ - int i; - - for (i = 0; i < src_len; i++) { - sprintf(&dst[i*2], "%02x", (int) src[i] & 0xff); - } -} - static void chap_gen_challenge( struct iscsi_conn *conn, int caller, @@ -59,7 +38,7 @@ static void chap_gen_challenge( memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1); get_random_bytes(chap->challenge, CHAP_CHALLENGE_LENGTH); - chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge, + bin2hex(challenge_asciihex, chap->challenge, CHAP_CHALLENGE_LENGTH); /* * Set CHAP_C, and copy the generated challenge into c_str. @@ -241,9 +220,16 @@ static int chap_server_compute_md5( pr_err("Could not find CHAP_R.\n"); goto out; } + if (strlen(chap_r) != MD5_SIGNATURE_SIZE * 2) { + pr_err("Malformed CHAP_R\n"); + goto out; + } + if (hex2bin(client_digest, chap_r, MD5_SIGNATURE_SIZE) < 0) { + pr_err("Malformed CHAP_R\n"); + goto out; + } pr_debug("[server] Got CHAP_R=%s\n", chap_r); - chap_string_to_hex(client_digest, chap_r, strlen(chap_r)); tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { @@ -292,7 +278,7 @@ static int chap_server_compute_md5( } crypto_free_hash(tfm); - chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE); + bin2hex(response, server_digest, MD5_SIGNATURE_SIZE); pr_debug("[server] MD5 Server Digest: %s\n", response); if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) { @@ -348,9 +334,7 @@ static int chap_server_compute_md5( pr_err("Could not find CHAP_C.\n"); goto out; } - pr_debug("[server] Got CHAP_C=%s\n", challenge); - challenge_len = chap_string_to_hex(challenge_binhex, challenge, - strlen(challenge)); + challenge_len = DIV_ROUND_UP(strlen(challenge), 2); if (!challenge_len) { pr_err("Unable to convert incoming challenge\n"); goto out; @@ -359,6 +343,11 @@ static int chap_server_compute_md5( pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n"); goto out; } + if (hex2bin(challenge_binhex, challenge, challenge_len) < 0) { + pr_err("Malformed CHAP_C\n"); + goto out; + } + pr_debug("[server] Got CHAP_C=%s\n", challenge); /* * During mutual authentication, the CHAP_C generated by the * initiator must not match the original CHAP_C generated by @@ -433,7 +422,7 @@ static int chap_server_compute_md5( /* * Convert response from binary hex to ascii hext. */ - chap_binaryhex_to_asciihex(response, digest, MD5_SIGNATURE_SIZE); + bin2hex(response, digest, MD5_SIGNATURE_SIZE); *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s", response); *nr_out_len += 1; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index bf8c6e446b6873f158437053840e3a56c519f390..c0bfd1624ebbc705c2fa5a5525aa6a833d5e3b00 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1458,7 +1458,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( wwn, &tpg->tpg_se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) - return NULL; + goto free_out; ret = iscsit_tpg_add_portal_group(tiqn, tpg); if (ret != 0) @@ -1470,6 +1470,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( return &tpg->tpg_se_tpg; out: core_tpg_deregister(&tpg->tpg_se_tpg); +free_out: kfree(tpg); return NULL; } diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 1863de28ce462f17c98d5cb813317c7ebae1a8ee..bf3da8e461f7ec11d9ed79fc4b1967f6590a365a 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -783,6 +783,7 @@ struct iscsi_np { int np_sock_type; enum np_thread_state_table np_thread_state; bool enabled; + atomic_t np_reset_count; enum iscsi_timer_flags_table np_login_timer_flags; u32 np_exports; enum np_flags_table np_flags; diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index f900de64e26700504720f2eb0de6f013add9cc17..b58c97ab1f8e3c6840aba0d871cdb091441dda55 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -45,10 +45,8 @@ void iscsit_set_dataout_sequence_values( */ if (cmd->unsolicited_data) { cmd->seq_start_offset = cmd->write_data_done; - cmd->seq_end_offset = (cmd->write_data_done + - ((cmd->se_cmd.data_length > - conn->sess->sess_ops->FirstBurstLength) ? - conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length)); + cmd->seq_end_offset = min(cmd->se_cmd.data_length, + conn->sess->sess_ops->FirstBurstLength); return; } diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 4608d8dac04cf267d7644b6b3647302bdfd056af..540af1be2f92f93bff1cbd8032b81c4bb4c45a33 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -1275,9 +1275,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) flush_signals(current); spin_lock_bh(&np->np_thread_lock); - if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { + if (atomic_dec_if_positive(&np->np_reset_count) >= 0) { np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; + spin_unlock_bh(&np->np_thread_lock); complete(&np->np_restart_comp); + return 1; } else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) { spin_unlock_bh(&np->np_thread_lock); goto exit; @@ -1310,7 +1312,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) goto exit; } else if (rc < 0) { spin_lock_bh(&np->np_thread_lock); - if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { + if (atomic_dec_if_positive(&np->np_reset_count) >= 0) { + np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; spin_unlock_bh(&np->np_thread_lock); complete(&np->np_restart_comp); iscsit_put_transport(conn->conn_transport); diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 5530321c44f2f12f2ac96652303256a48c1e9fab..afef70b1aaafd01169abfe816850d53b3b5388d6 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -651,8 +651,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) none = strstr(buf1, NONE); if (none) goto out; - strncat(buf1, ",", strlen(",")); - strncat(buf1, NONE, strlen(NONE)); + strlcat(buf1, "," NONE, sizeof(buf1)); if (iscsi_update_param_value(param, buf1) < 0) return -EINVAL; } diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index fb87780929d24f99d304b2e904538bb7c45f0bd6..701f94ae5eef0692d36a8f7e7d3f918ab3dcfb89 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1126,13 +1126,11 @@ static int core_alua_do_transition_tg_pt( unsigned long transition_tmo; transition_tmo = tg_pt_gp->tg_pt_gp_implicit_trans_secs * HZ; - queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq, - &tg_pt_gp->tg_pt_gp_transition_work, - transition_tmo); + schedule_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work, + transition_tmo); } else { tg_pt_gp->tg_pt_gp_transition_complete = &wait; - queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq, - &tg_pt_gp->tg_pt_gp_transition_work, 0); + schedule_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work, 0); wait_for_completion(&wait); tg_pt_gp->tg_pt_gp_transition_complete = NULL; } diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 9233b653cc72e58466fe8c540b83857b3b20bdcf..98dd0044dca3917e44b73a5fb608b8094decf3b4 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -592,6 +592,10 @@ fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) struct inode *inode = file->f_mapping->host; int ret; + if (!nolb) { + return 0; + } + if (cmd->se_dev->dev_attrib.pi_prot_type) { ret = fd_do_prot_unmap(cmd, lba, nolb); if (ret) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 45837a4e950d7e10b9bee51d84c57d2f2f2abe4a..cba541860e70322ba86e16f56f5ef1cfe479fb70 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -58,8 +58,10 @@ void core_pr_dump_initiator_port( char *buf, u32 size) { - if (!pr_reg->isid_present_at_reg) + if (!pr_reg->isid_present_at_reg) { buf[0] = '\0'; + return; + } snprintf(buf, size, ",i,0x%s", pr_reg->pr_reg_isid); } diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 9b1a4000d0f9354b95b32be7328e06ef25b47990..93724738000a96d3d2a6c9aa3e8bb49ce42b20a2 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -137,6 +137,15 @@ static bool __target_check_io_state(struct se_cmd *se_cmd, spin_unlock(&se_cmd->t_state_lock); return false; } + if (se_cmd->transport_state & CMD_T_PRE_EXECUTE) { + if (se_cmd->scsi_status) { + pr_debug("Attempted to abort io tag: %u early failure" + " status: 0x%02x\n", se_cmd->se_tfo->get_task_tag(se_cmd), + se_cmd->scsi_status); + spin_unlock(&se_cmd->t_state_lock); + return false; + } + } if (sess->sess_tearing_down || se_cmd->cmd_wait_set) { pr_debug("Attempted to abort io tag: %u already shutdown," " skipping\n", se_cmd->se_tfo->get_task_tag(se_cmd)); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e59c8b3fd4f16669d553e18069d4b994ed20d9ed..96f13d713f1860c971d59531d04b52073ae825bb 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -323,6 +323,7 @@ void __transport_register_session( void *fabric_sess_ptr) { unsigned char buf[PR_REG_ISID_LEN]; + unsigned long flags; se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; @@ -345,7 +346,7 @@ void __transport_register_session( } kref_get(&se_nacl->acl_kref); - spin_lock_irq(&se_nacl->nacl_sess_lock); + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); /* * The se_nacl->nacl_sess pointer will be set to the * last active I_T Nexus for each struct se_node_acl. @@ -354,7 +355,7 @@ void __transport_register_session( list_add_tail(&se_sess->sess_acl_list, &se_nacl->acl_sess_list); - spin_unlock_irq(&se_nacl->nacl_sess_lock); + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); } list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list); @@ -1796,6 +1797,7 @@ void target_execute_cmd(struct se_cmd *cmd) } cmd->t_state = TRANSPORT_PROCESSING; + cmd->transport_state &= ~CMD_T_PRE_EXECUTE; cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT; spin_unlock_irq(&cmd->t_state_lock); /* @@ -2436,6 +2438,7 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) ret = -ESHUTDOWN; goto out; } + se_cmd->transport_state |= CMD_T_PRE_EXECUTE; list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 31ada06c7dc6afa5cf12b7edf4a8fc3b4da2f715..9b51b0da9283813836156953645c2ba9bbb278f2 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -489,6 +489,9 @@ static int imx_thermal_probe(struct platform_device *pdev) if (data->irq < 0) return data->irq; + data->irq_enabled = true; + data->mode = THERMAL_DEVICE_ENABLED; + ret = devm_request_threaded_irq(&pdev->dev, data->irq, imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, 0, "imx_thermal", data); @@ -572,9 +575,6 @@ static int imx_thermal_probe(struct platform_device *pdev) regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); - data->irq_enabled = true; - data->mode = THERMAL_DEVICE_ENABLED; - return 0; } diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index dd3c69cbed471c2b4e27aff4b2616d8cd8d0e581..148649b5cb9c18d42db040a0c677ee87691928fc 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -1392,7 +1392,8 @@ static int msm_tsens_get_temp(int sensor_client_id, unsigned long *temp) bool last_temp_valid = false, last_temp2_valid = false; bool last_temp3_valid = false; struct tsens_tm_device *tmdev = NULL; - uint32_t sensor_hw_num = 0, idx = 0; + uint32_t idx = 0; + int sensor_hw_num = 0; unsigned long flags; tmdev = get_tsens_controller_for_client_id(sensor_client_id); diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index b82b23780f171c7a954f43a8824f2bb5ddfecb16..d7c5e861bbb246d4267751dc94bccda5658d24bb 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, 2019 The Linux Foundation. All rights reserved. * * 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 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,7 @@ #define SENSOR_SCALING_FACTOR 1 #define MSM_THERMAL_NAME "msm_thermal" #define MSM_TSENS_PRINT "log_tsens_temperature" +#define MSM_TSENS_SAMPLING "tsens_hw_sampling" #define CPU_BUF_SIZE 64 #define CPU_DEVICE "cpu%d" #define MAX_DEBUGFS_CONFIG_LEN 32 @@ -79,6 +81,18 @@ #define THERM_DDR_SLAVE_ID 512 #define THERM_DDR_IB_VOTE_REQ 366000000 +#define SCM_TSENS_GET_NUM_OF_SAMPLING_LEVELS \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_STD, SCM_SVC_TSENS, 0x01) + +#define SCM_TSENS_GET_SAMPLING_LEVEL_VAL \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_STD, SCM_SVC_TSENS, 0x02) + +#define SCM_TSENS_SET_SAMPLING_LEVEL \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_STD, SCM_SVC_TSENS, 0x03) + +#define SCM_TSENS_GET_CURRENT_SAMPLING_VAL \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_STD, SCM_SVC_TSENS, 0x04) + #define VALIDATE_AND_SET_MASK(_node, _key, _mask, _cpu) \ do { \ if (of_property_read_bool(_node, _key)) \ @@ -299,6 +313,7 @@ enum msm_thresh_list { MSM_OCR, MSM_VDD_MX_RESTRICTION, MSM_THERM_DDR_LM, + MSM_THERM_HW_SAMPLING, MSM_LIST_MAX_NR, }; @@ -345,10 +360,19 @@ struct msm_thermal_debugfs_thresh_config { struct msm_thermal_debugfs_entry { struct dentry *parent; struct dentry *tsens_print; + struct dentry *tsens_sampling; struct dentry *config; struct dentry *config_data; }; +struct msm_thermal_tsens_sampling_info { + bool enabled; + uint32_t max_lvl; + uint32_t req_lvl; + uint32_t cur_lvl; + uint32_t def_lvl; +}; + static struct psm_rail *psm_rails; static struct psm_rail *ocr_rails; static struct rail *rails; @@ -362,6 +386,7 @@ static struct devmgr_devices *devices; static struct msm_thermal_debugfs_thresh_config *mit_config; static struct msm_bus_scale_pdata *therm_ddr_lm_data; static uint8_t therm_ddr_lm_handle; +static struct msm_thermal_tsens_sampling_info *tsens_sampling; struct vdd_rstr_enable { struct kobj_attribute ko_attr; @@ -1108,6 +1133,70 @@ static ssize_t cluster_info_show( return tot_size; } +static int therm_tsens_sampling_scm_cmd(struct scm_desc *desc_arg, + uint32_t cmd_id, uint32_t *cmd_arg, uint32_t *tz_ret) +{ + int ret = 0; + + if (!is_scm_armv8()) { + ret = scm_call(SCM_SVC_TSENS, cmd_id, (void *)cmd_arg, + cmd_arg ? SCM_BUFFER_SIZE(*cmd_arg) : 0, + tz_ret, tz_ret ? SCM_BUFFER_SIZE(*tz_ret) : 0); + } else { + ret = scm_call2(cmd_id, desc_arg); + if (tz_ret) + *tz_ret = desc_arg->ret[0]; + } + /* Have barrier before reading from TZ data */ + mb(); + + if (ret) + pr_err("Error in SCM v%d get type. cmd:%x err:%d\n", + (is_scm_armv8()) ? 8 : 7, cmd_id, ret); + + return ret; +}; + +static int thermal_tsens_sampling_debugfs_read(struct seq_file *m, void *data) +{ + uint32_t ret_sampling = 0; + int ret = 0; + struct scm_desc desc_arg; + + if (!tsens_sampling || !tsens_sampling->enabled) { + seq_puts(m, "TSENS dynamic sampling is not initialized\n"); + return 0; + } + + desc_arg.arginfo = SCM_ARGS(0); + ret = therm_tsens_sampling_scm_cmd(&desc_arg, + SCM_TSENS_GET_CURRENT_SAMPLING_VAL, NULL, &ret_sampling); + if (ret) { + seq_puts(m, "Error in reading current sampling\n"); + } else { + pr_debug("SCM call is success for sampling[%d]:%d\n", + tsens_sampling->cur_lvl, ret_sampling); + seq_printf(m, "tsens hw sampling:cur level:%d value:%u ms\n", + tsens_sampling->cur_lvl, ret_sampling); + } + + return 0; +} + +static int thermal_tsens_sampling_debugfs_open(struct inode *inode, + struct file *file) +{ + return single_open(file, thermal_tsens_sampling_debugfs_read, + inode->i_private); +} + +static const struct file_operations thermal_debugfs_tsens_sampling_ops = { + .open = thermal_tsens_sampling_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int thermal_config_debugfs_open(struct inode *inode, struct file *file) { @@ -1201,6 +1290,15 @@ static int create_thermal_debugfs(void) goto create_exit; } + msm_therm_debugfs->tsens_sampling = debugfs_create_file( + MSM_TSENS_SAMPLING, 0400, msm_therm_debugfs->parent, + NULL, &thermal_debugfs_tsens_sampling_ops); + if (!msm_therm_debugfs->tsens_sampling) { + pr_err("Error creating debugfs:[%s]\n", + MSM_TSENS_SAMPLING); + goto create_exit; + } + THERM_CREATE_DEBUGFS_DIR(msm_therm_debugfs->config, MSM_THERMAL_CONFIG, msm_therm_debugfs->parent, ret); if (ret) @@ -2872,6 +2970,117 @@ static void therm_ddr_lm_notify(struct therm_threshold *trig_thresh) } } +static int msm_thermal_handle_dynamic_sampling(bool triggered) +{ + uint32_t level; + int ret = 0; + struct scm_desc desc_arg; + + level = triggered ? tsens_sampling->req_lvl : tsens_sampling->def_lvl; + + if (level >= tsens_sampling->max_lvl) + level = tsens_sampling->max_lvl - 1; + + if (tsens_sampling->cur_lvl == level) + return 0; + + desc_arg.args[0] = level; + desc_arg.arginfo = SCM_ARGS(1, SCM_VAL); + + ret = therm_tsens_sampling_scm_cmd(&desc_arg, + SCM_TSENS_SET_SAMPLING_LEVEL, &level, NULL); + if (ret) + return ret; + + tsens_sampling->cur_lvl = level; + pr_debug("Thermal TSENS sampling is updated with level:%d\n", level); + + return ret; +} + +static void therm_dynamic_sampling_notify(struct therm_threshold *trig_thresh) +{ + static uint32_t sampling_sens_status; + int ret; + + pr_debug("Sensor%d trigger recevied for type %d\n", + trig_thresh->sensor_id, + trig_thresh->trip_triggered); + + if (!tsens_sampling || !tsens_sampling->enabled) + return; + + switch (trig_thresh->trip_triggered) { + case THERMAL_TRIP_CONFIGURABLE_HI: + sampling_sens_status |= BIT(trig_thresh->sensor_id); + break; + case THERMAL_TRIP_CONFIGURABLE_LOW: + if (sampling_sens_status & BIT(trig_thresh->sensor_id)) + sampling_sens_status ^= BIT(trig_thresh->sensor_id); + break; + default: + pr_err("Unsupported trip type\n"); + break; + } + + ret = msm_thermal_handle_dynamic_sampling( + sampling_sens_status ? true : false); + if (ret) + pr_err("Failed to apply mx restriction\n"); + + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, + trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } +} + +static int do_therm_dynamic_sampling(void) +{ + long temp = 0; + int ret = 0; + int i = 0; + int dis_cnt = 0; + + if (!tsens_sampling || !tsens_sampling->enabled) + return ret; + + for (i = 0; i < thresh[MSM_THERM_HW_SAMPLING].thresh_ct; i++) { + ret = therm_get_temp( + thresh[MSM_THERM_HW_SAMPLING].thresh_list[i].sensor_id, + thresh[MSM_THERM_HW_SAMPLING].thresh_list[i].id_type, + &temp); + if (ret) { + pr_err("Unable to read TSENS sensor:%d, err:%d\n", + thresh[MSM_THERM_HW_SAMPLING].thresh_list[i]. + sensor_id, ret); + dis_cnt++; + continue; + } + if (temp >= thresh[MSM_THERM_HW_SAMPLING].thresh_list[ + i].threshold[0].temp) { + ret = msm_thermal_handle_dynamic_sampling(true); + if (ret) + pr_err( + "Failed to apply mx restriction\n"); + goto exit; + } else if (temp <= + thresh[MSM_THERM_HW_SAMPLING].thresh_list[ + i].threshold[1].temp) { + dis_cnt++; + } + } + + if (dis_cnt == thresh[MSM_THERM_HW_SAMPLING].thresh_ct) { + ret = msm_thermal_handle_dynamic_sampling(false); + if (ret) + pr_err("Failed to clear dynamic sampling\n"); + } + +exit: + return ret; +} + static void retry_hotplug(struct work_struct *work) { mutex_lock(&core_control_mutex); @@ -3503,6 +3712,7 @@ static void check_temp(struct work_struct *work) } do_core_control(temp); do_vdd_mx(); + do_therm_dynamic_sampling(); do_psm(); do_gfx_phase_cond(); do_cx_phase_cond(); @@ -4548,6 +4758,17 @@ static void thermal_monitor_init(void) if (!IS_HI_THRESHOLD_SET(ret)) therm_ddr_lm_apply_limit(true); } + + if (tsens_sampling && tsens_sampling->enabled && + !(convert_to_zone_id(&thresh[MSM_THERM_HW_SAMPLING]))) { + thresh[MSM_THERM_HW_SAMPLING].thresh_list->trip_triggered = -1; + ret = sensor_mgr_set_threshold( + thresh[MSM_THERM_HW_SAMPLING].thresh_list->sensor_id, + thresh[MSM_THERM_HW_SAMPLING].thresh_list->threshold); + if (!IS_HI_THRESHOLD_SET(ret)) + msm_thermal_handle_dynamic_sampling(true); + } + init_exit: return; } @@ -5818,6 +6039,16 @@ static void thermal_vdd_mit_disable(void) pr_err("Disable vdd rstr for all failed. err:%d\n", ret); } +static void thermal_dynamic_sampling_disable(void) +{ + int ret = 0; + + THERM_MITIGATION_DISABLE(tsens_sampling->enabled, + MSM_THERM_HW_SAMPLING); + ret = msm_thermal_handle_dynamic_sampling(false); + if (ret) + pr_err("Disable dynamic sampling update error. err:%d\n", ret); +} static void thermal_psm_mit_disable(void) { int ret = 0; @@ -6852,6 +7083,113 @@ probe_cx_exit: return ret; } +static int therm_tsens_dynamic_sampling_init(uint32_t req_lvl, uint32_t def_lvl) +{ + int ret = 0, max_lvl = 0; + struct scm_desc desc_arg; + + desc_arg.arginfo = SCM_ARGS(0); + ret = therm_tsens_sampling_scm_cmd(&desc_arg, + SCM_TSENS_GET_NUM_OF_SAMPLING_LEVELS, NULL, &max_lvl); + if (ret) + return ret; + + pr_debug("TSENS_GET_NUM_OF_SAMPLING_LEVELS is success with value=%d\n", + max_lvl); + + if (req_lvl >= max_lvl || def_lvl >= max_lvl) { + pr_err( + "Invalid Tsens sampling req lvl:%d or def lvl:%d, max lvl:%d\n", + req_lvl, def_lvl, max_lvl); + return -EINVAL; + } + + return max_lvl; +} + +static int probe_therm_dynamic_hw_sampling(struct device_node *node, + struct msm_thermal_data *data, + struct platform_device *pdev) +{ + char *key = NULL; + int ret = 0, arr_size = 0; + enum sampling_therm_cfg { + THERM_SAMP_SENS_ID = 0, + THERM_SAMP_HIGH_TEMP, + THERM_SAMP_LOW_TEMP, + THERM_SAMP_REQ_LVL, + THERM_SAMP_DEF_LVL, + THERM_SAMP_MAX_ENTRY + }; + uint32_t therm_sampling_data[THERM_SAMP_MAX_ENTRY] = {0}; + + key = "qcom,therm-dynamic-hw-sampling-info"; + if (!of_get_property(node, key, &arr_size) || + arr_size <= 0) + return 0; + + arr_size = arr_size / sizeof(__be32); + if (arr_size != THERM_SAMP_MAX_ENTRY) { + ret = -EINVAL; + pr_err("Therm dynamic sampling invalid number of entries\n"); + goto PROBE_DYN_EXIT; + } + + ret = of_property_read_u32_array(node, key, + therm_sampling_data, THERM_SAMP_MAX_ENTRY); + if (ret) + goto PROBE_DYN_EXIT; + + tsens_sampling = devm_kzalloc(&pdev->dev, sizeof(*tsens_sampling), + GFP_KERNEL); + if (!tsens_sampling) { + ret = -ENOMEM; + goto PROBE_DYN_EXIT; + } + + ret = therm_tsens_dynamic_sampling_init( + therm_sampling_data[THERM_SAMP_REQ_LVL], + therm_sampling_data[THERM_SAMP_DEF_LVL]); + if (ret < 0) { + pr_err("Therm dynamic sampling init failed, err:%d\n", ret); + goto PROBE_DYN_EXIT; + } + + tsens_sampling->max_lvl = ret; + tsens_sampling->req_lvl = therm_sampling_data[THERM_SAMP_REQ_LVL]; + tsens_sampling->def_lvl = therm_sampling_data[THERM_SAMP_DEF_LVL]; + tsens_sampling->cur_lvl = tsens_sampling->max_lvl; + + msm_thermal_handle_dynamic_sampling(false); + + ret = sensor_mgr_init_threshold(&thresh[MSM_THERM_HW_SAMPLING], + therm_sampling_data[THERM_SAMP_SENS_ID], + therm_sampling_data[THERM_SAMP_HIGH_TEMP], + therm_sampling_data[THERM_SAMP_LOW_TEMP], + therm_dynamic_sampling_notify); + if (ret) { + pr_err("Therm dynamic sampling data structure init failed\n"); + goto PROBE_DYN_EXIT; + } + + tsens_sampling->enabled = true; + snprintf(mit_config[MSM_THERM_HW_SAMPLING].config_name, + MAX_DEBUGFS_CONFIG_LEN, "tsens_sampling"); + mit_config[MSM_THERM_HW_SAMPLING].disable_config + = thermal_dynamic_sampling_disable; + +PROBE_DYN_EXIT: + if (ret) { + dev_info(&pdev->dev, + "%s:Failed reading node=%s, key=%s err=%d. KTM continues\n", + __func__, node->full_name, key, ret); + if (tsens_sampling) + devm_kfree(&pdev->dev, tsens_sampling); + tsens_sampling = NULL; + } + return ret; +} + static int probe_therm_reset(struct device_node *node, struct msm_thermal_data *data, struct platform_device *pdev) @@ -7072,6 +7410,24 @@ static void therm_ddr_lm_config_read(struct seq_file *m, void *data) } } +static void therm_dynamic_sampling_config_read(struct seq_file *m, void *data) +{ + if (tsens_sampling && tsens_sampling->enabled) { + seq_puts(m, "\n-----Dynamic HW sampling-----\n"); + seq_printf(m, "threshold:%ld degC\n", + thresh[ + MSM_THERM_HW_SAMPLING].thresh_list->threshold[0].temp / + tsens_scaling_factor); + seq_printf(m, "threshold clear:%ld degC\n", + thresh[ + MSM_THERM_HW_SAMPLING].thresh_list->threshold[1].temp / + tsens_scaling_factor); + seq_printf(m, "sensor id:%d id_type:%d\n", + thresh[MSM_THERM_HW_SAMPLING].thresh_list->sensor_id, + thresh[MSM_THERM_HW_SAMPLING].thresh_list->id_type); + } +} + static void thermal_phase_ctrl_config_read(struct seq_file *m, void *data) { if (cx_phase_ctrl_enabled) { @@ -7111,6 +7467,7 @@ static void thermal_disable_all_mitigation(void) thermal_psm_mit_disable(); thermal_ocr_mit_disable(); thermal_ddr_lm_disable(); + thermal_dynamic_sampling_disable(); thermal_cx_phase_ctrl_mit_disable(); thermal_gfx_phase_warm_ctrl_mit_disable(); thermal_gfx_phase_crit_ctrl_mit_disable(); @@ -7143,6 +7500,9 @@ static void enable_config(int config_id) case MSM_THERM_DDR_LM: therm_ddr_lm_enabled = 1; break; + case MSM_THERM_HW_SAMPLING: + tsens_sampling->enabled = 1; + break; case MSM_LIST_MAX_NR + HOTPLUG_CONFIG: hotplug_enabled = 1; break; @@ -7247,6 +7607,7 @@ static int thermal_config_debugfs_read(struct seq_file *m, void *data) thermal_ocr_config_read(m, data); thermal_phase_ctrl_config_read(m, data); therm_ddr_lm_config_read(m, data); + therm_dynamic_sampling_config_read(m, data); return 0; } @@ -7330,6 +7691,7 @@ static int msm_thermal_dev_probe(struct platform_device *pdev) goto fail; ret = probe_ocr(node, &data, pdev); + ret = probe_therm_dynamic_hw_sampling(node, &data, pdev); ret = fetch_cpu_mitigaiton_info(&data, pdev); if (ret) { pr_err("Error fetching CPU mitigation information. err:%d\n", @@ -7441,6 +7803,9 @@ static int msm_thermal_dev_exit(struct platform_device *inp_dev) &thresh[MSM_THERM_DDR_LM]); cleanup_bus_data(therm_ddr_lm_data, inp_dev); } + if (tsens_sampling) + sensor_mgr_remove_threshold( + &thresh[MSM_THERM_HW_SAMPLING]); kfree(thresh); thresh = NULL; diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c index 943cf214af24e9140ddf2761df47900da8f320f3..05d30b1932451c4b6a9c7b867b9ff12d0ff33a60 100644 --- a/drivers/thermal/qpnp-adc-tm.c +++ b/drivers/thermal/qpnp-adc-tm.c @@ -2189,8 +2189,11 @@ static int qpnp_adc_tm_disable_rearm_high_thresholds( return rc; } - queue_work(chip->sensor[sensor_num].req_wq, - &chip->sensor[sensor_num].work); + if (!queue_work(chip->sensor[sensor_num].req_wq, + &chip->sensor[sensor_num].work)) { + /* The item is already queued, reduce the count */ + atomic_dec(&chip->wq_cnt); + } return rc; } @@ -2288,8 +2291,11 @@ static int qpnp_adc_tm_disable_rearm_low_thresholds( return rc; } - queue_work(chip->sensor[sensor_num].req_wq, - &chip->sensor[sensor_num].work); + if (!queue_work(chip->sensor[sensor_num].req_wq, + &chip->sensor[sensor_num].work)) { + /* The item is already queued, reduce the count */ + atomic_dec(&chip->wq_cnt); + } return rc; } @@ -2762,13 +2768,14 @@ static irqreturn_t qpnp_adc_tm_rc_thr_isr(int irq, void *data) } if (sensor_low_notify_num) { - atomic_inc(&chip->wq_cnt); - queue_work(chip->low_thr_wq, &chip->trigger_low_thr_work); + if (queue_work(chip->low_thr_wq, &chip->trigger_low_thr_work)) + atomic_inc(&chip->wq_cnt); } if (sensor_high_notify_num) { - atomic_inc(&chip->wq_cnt); - queue_work(chip->high_thr_wq, &chip->trigger_high_thr_work); + if (queue_work(chip->high_thr_wq, + &chip->trigger_high_thr_work)) + atomic_inc(&chip->wq_cnt); } return IRQ_HANDLED; diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index dc4b69671d8790e337a63001b9875153716c1bad..eed5b448fbf92c9ff091b8bf61023275f77f0b83 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -31,8 +31,7 @@ * If the temperature is higher than a trip point, * a. if the trend is THERMAL_TREND_RAISING, use higher cooling * state for this trip point - * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling - * state for this trip point + * b. if the trend is THERMAL_TREND_DROPPING, do nothing * c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit * for this trip point * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit @@ -94,9 +93,11 @@ static unsigned long get_target_state(struct thermal_instance *instance, if (!throttle) next_target = THERMAL_NO_TARGET; } else { - next_target = cur_state - 1; - if (next_target > instance->upper) - next_target = instance->upper; + if (!throttle) { + next_target = cur_state - 1; + if (next_target > instance->upper) + next_target = instance->upper; + } } break; case THERMAL_TREND_DROP_FULL: diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index c68fe1222c16aa111e6734c6aa21432461f47c76..5f3c4f45ab65dc3fd793a51a62df49dac04b1287 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -627,6 +627,7 @@ static const struct dev_pm_ops nhi_pm_ops = { * we just disable hotplug, the * pci-tunnels stay alive. */ + .thaw_noirq = nhi_resume_noirq, .restore_noirq = nhi_resume_noirq, }; diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index a2cc5f834c633836065b215a07f597a4d458fba7..ed18a98a15d882e2337ca71673e6261356ab9277 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -337,7 +337,6 @@ static void udbg_init_opal_common(void) udbg_putc = udbg_opal_putc; udbg_getc = udbg_opal_getc; udbg_getc_poll = udbg_opal_getc_poll; - tb_ticks_per_usec = 0x200; /* Make udelay not suck */ } void __init hvc_opal_init_early(void) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index db37ee49c3bf26407a0b15606cc47b01fa36231d..0b9f2550973fa7f714061c8fd75479b292330897 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -137,6 +137,9 @@ struct gsm_dlci { struct mutex mutex; /* Link layer */ + int mode; +#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */ +#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */ spinlock_t lock; /* Protects the internal state */ struct timer_list t1; /* Retransmit timer for SABM and UA */ int retries; @@ -1380,7 +1383,13 @@ retry: ctrl->data = data; ctrl->len = clen; gsm->pending_cmd = ctrl; - gsm->cretries = gsm->n2; + + /* If DLCI0 is in ADM mode skip retries, it won't respond */ + if (gsm->dlci[0]->mode == DLCI_MODE_ADM) + gsm->cretries = 1; + else + gsm->cretries = gsm->n2; + mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100); gsm_control_transmit(gsm, ctrl); spin_unlock_irqrestore(&gsm->control_lock, flags); @@ -1467,6 +1476,10 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) * in which case an opening port goes back to closed and a closing port * is simply put into closed state (any further frames from the other * end will get a DM response) + * + * Some control dlci can stay in ADM mode with other dlci working just + * fine. In that case we can just keep the control dlci open after the + * DLCI_OPENING retries time out. */ static void gsm_dlci_t1(unsigned long data) @@ -1480,8 +1493,16 @@ static void gsm_dlci_t1(unsigned long data) if (dlci->retries) { gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); - } else + } else if (!dlci->addr && gsm->control == (DM | PF)) { + if (debug & 8) + pr_info("DLCI %d opening in ADM mode.\n", + dlci->addr); + dlci->mode = DLCI_MODE_ADM; + gsm_dlci_open(dlci); + } else { gsm_dlci_close(dlci); + } + break; case DLCI_CLOSING: dlci->retries--; @@ -1499,8 +1520,8 @@ static void gsm_dlci_t1(unsigned long data) * @dlci: DLCI to open * * Commence opening a DLCI from the Linux side. We issue SABM messages - * to the modem which should then reply with a UA, at which point we - * will move into open state. Opening is done asynchronously with retry + * to the modem which should then reply with a UA or ADM, at which point + * we will move into open state. Opening is done asynchronously with retry * running off timers and the responses. */ @@ -2871,11 +2892,22 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) static int gsm_carrier_raised(struct tty_port *port) { struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port); + struct gsm_mux *gsm = dlci->gsm; + /* Not yet open so no carrier info */ if (dlci->state != DLCI_OPEN) return 0; if (debug & 2) return 1; + + /* + * Basic mode with control channel in ADM mode may not respond + * to CMD_MSC at all and modem_rx is empty. + */ + if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM && + !dlci->modem_rx) + return 1; + return dlci->modem_rx & TIOCM_CD; } diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index b2a53de62065ee69cdc93173a0b197079a23a0ec..a896159dca60ee11e1eb62713c784ec91cebd724 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -128,6 +128,8 @@ struct n_tty_data { struct mutex output_lock; }; +#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1)) + static inline size_t read_cnt(struct n_tty_data *ldata) { return ldata->read_head - ldata->read_tail; @@ -1028,14 +1030,15 @@ static void eraser(unsigned char c, struct tty_struct *tty) } seen_alnums = 0; - while (ldata->read_head != ldata->canon_head) { + while (MASK(ldata->read_head) != MASK(ldata->canon_head)) { head = ldata->read_head; /* erase a single possibly multibyte character */ do { head--; c = read_buf(ldata, head); - } while (is_continuation(c, tty) && head != ldata->canon_head); + } while (is_continuation(c, tty) && + MASK(head) != MASK(ldata->canon_head)); /* do not partially erase */ if (is_continuation(c, tty)) @@ -1077,7 +1080,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) * This info is used to go back the correct * number of columns. */ - while (tail != ldata->canon_head) { + while (MASK(tail) != MASK(ldata->canon_head)) { tail--; c = read_buf(ldata, tail); if (c == '\t') { @@ -1334,7 +1337,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) finish_erasing(ldata); echo_char(c, tty); echo_char_raw('\n', ldata); - while (tail != ldata->read_head) { + while (MASK(tail) != MASK(ldata->read_head)) { echo_char(read_buf(ldata, tail), tty); tail++; } @@ -1805,7 +1808,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { struct n_tty_data *ldata = tty->disc_data; - if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) { + if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) { bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); ldata->line_start = ldata->read_tail; if (!L_ICANON(tty) || !read_cnt(ldata)) { @@ -2503,7 +2506,7 @@ static unsigned long inq_canon(struct n_tty_data *ldata) tail = ldata->read_tail; nr = head - tail; /* Skip EOF-chars.. */ - while (head != tail) { + while (MASK(head) != MASK(tail)) { if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) && read_buf(ldata, tail) == __DISABLED_CHAR) nr--; @@ -2523,7 +2526,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, return put_user(tty_chars_in_buffer(tty), (int __user *) arg); case TIOCINQ: down_write(&tty->termios_rwsem); - if (L_ICANON(tty)) + if (L_ICANON(tty) && !L_EXTPROC(tty)) retval = inq_canon(ldata); else retval = read_cnt(ldata); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 5222805bfb15845b3dd7da60c5821633ac3604ef..07428642821d4c2d685fd5ae17b4dd8c41c60a83 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -114,16 +114,19 @@ static int pty_space(struct tty_struct *to) static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) { struct tty_struct *to = tty->link; + unsigned long flags; if (tty->stopped) return 0; if (c > 0) { + spin_lock_irqsave(&to->port->lock, flags); /* Stuff the data into the input queue of the other end */ c = tty_insert_flip_string(to->port, buf, c); /* And shovel */ if (c) tty_flip_buffer_push(to->port); + spin_unlock_irqrestore(&to->port->lock, flags); } return c; } diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 383c4c796637713e12bede50677803a0d639a855..347fe7ace24c3a241d4519679742a0517142df08 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -1928,7 +1928,7 @@ static __init int register_PCI(int i, struct pci_dev *dev) ByteIO_t UPCIRingInd = 0; if (!dev || !pci_match_id(rocket_pci_ids, dev) || - pci_enable_device(dev)) + pci_enable_device(dev) || i >= NUM_BOARDS) return 0; rcktpt_io_addr[i] = pci_resource_start(dev, 0); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5c247d7943aa533a0016f815045ac5f3a695e67f..077e0667bbf85d509313bb265d435d1b0f484ed6 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -202,7 +202,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, unsigned int rate; int ret; - if (IS_ERR(d->clk) || !old) + if (IS_ERR(d->clk)) goto out; /* Not requesting clock rates below 1.8432Mhz */ diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 1bb28cb69493af36dc394ace3d0122c7a1bc930c..c72283f2be6d07586bc770b226a58844ca2c2cd6 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -118,7 +118,7 @@ static int fintek_8250_rs4850_config(struct uart_8250_port *uart, if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) == (!!(rs485->flags & SER_RS485_RTS_AFTER_SEND))) - rs485->flags &= SER_RS485_ENABLED; + rs485->flags &= ~SER_RS485_ENABLED; else config |= RS485_URA; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 54921ac390ed8c6a7439c01b64206025187ac121..2a928c18c8ea1ffc886aa75df62a64a3a96b2c6b 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -4981,6 +4981,17 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */ pbn_b2_4_115200 }, + /* + * BrainBoxes UC-260 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0D21, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0E34, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b2_4_115200 }, /* * Perle PCI-RAS cards */ @@ -5483,6 +5494,9 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 }, { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 }, + /* Amazon PCI serial device */ + { PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 4d180c9423effe3994f2226bbfc7325829cf2156..1a14948c86d6eb32c6c1fb299a0d07c48745a1dc 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -629,8 +629,10 @@ static int serial_config(struct pcmcia_device * link) (link->has_func_id) && (link->socket->pcmcia_pfc == 0) && ((link->func_id == CISTPL_FUNCID_MULTI) || - (link->func_id == CISTPL_FUNCID_SERIAL))) - pcmcia_loop_config(link, serial_check_for_multi, info); + (link->func_id == CISTPL_FUNCID_SERIAL))) { + if (pcmcia_loop_config(link, serial_check_for_multi, info)) + goto failed; + } /* * Apply any multi-port quirk. diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index a59d1d77e7506460bcac1968f4299a173c1fb466..f6f9a039afce9b2b9766349f2dd3ce25122e471e 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -597,6 +597,11 @@ static int arc_serial_probe(struct platform_device *pdev) if (dev_id < 0) dev_id = 0; + if (dev_id >= ARRAY_SIZE(arc_uart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", dev_id); + return -EINVAL; + } + uart = &arc_uart_ports[dev_id]; port = &uart->port; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 0efb37e2fac9803dbcf82aba409ad14c2560fb50..26b0cbfe80e7f84007d24342ab793630de0804d2 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1643,6 +1643,7 @@ static void atmel_get_ip_name(struct uart_port *port) switch (version) { case 0x302: case 0x10213: + case 0x10302: dev_dbg(port->dev, "This version is usart\n"); atmel_port->is_usart = true; break; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 533852eb87786d5ecd929b7bbade897df94ee24f..fd877ef1dc6e76286ba58342dbe3bb13f0399ffc 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1054,8 +1054,8 @@ static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo) /* Get the address of the host memory buffer. */ bdp = pinfo->rx_cur; - while (bdp->cbd_sc & BD_SC_EMPTY) - ; + if (bdp->cbd_sc & BD_SC_EMPTY) + return NO_POLL_CHAR; /* If the buffer address is in the CPM DPRAM, don't * convert it. @@ -1089,7 +1089,11 @@ static int cpm_get_poll_char(struct uart_port *port) poll_chars = 0; } if (poll_chars <= 0) { - poll_chars = poll_wait_key(poll_buf, pinfo); + int ret = poll_wait_key(poll_buf, pinfo); + + if (ret == NO_POLL_CHAR) + return ret; + poll_chars = ret; pollp = poll_buf; } poll_chars--; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 1883478d6a8d80ffef7baed13317af402b017112..af3047d8322a339a9ac03ffdf79433d4ee40a966 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1791,6 +1791,10 @@ static int lpuart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); return ret; } + if (ret >= ARRAY_SIZE(lpuart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", ret); + return -EINVAL; + } sport->port.line = ret; sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 696d4b5af293abd16e2d06e849df8ef2375ab26b..99126b8b44c1c919d5bb806bf8e545bb35ba8095 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1899,6 +1899,12 @@ static int serial_imx_probe(struct platform_device *pdev) else if (ret < 0) return ret; + if (sport->port.line >= ARRAY_SIZE(imx_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", + sport->port.line); + return -EINVAL; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index c751604d385658deda4e8e65e9cb546b95fc5427..ba59a76edc8b1f1d821d3ad6d33fc0813654183c 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1288,6 +1288,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index); + if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", index); + return -EINVAL; + } ourport = &s3c24xx_serial_ports[index]; ourport->drv_data = s3c24xx_get_driver_data(pdev); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 75850f70b4796eb9663edc355a8dca57d93faad6..72f4146e8eeddfef401f0531495e3583443881df 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -884,14 +884,19 @@ static int sccnxp_probe(struct platform_device *pdev) clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { - if (PTR_ERR(clk) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + ret = PTR_ERR(clk); + if (ret == -EPROBE_DEFER) goto err_out; - } + uartclk = 0; + } else { + clk_prepare_enable(clk); + uartclk = clk_get_rate(clk); + } + + if (!uartclk) { dev_notice(&pdev->dev, "Using default clock frequency\n"); uartclk = s->chip->freq_std; - } else - uartclk = clk_get_rate(clk); + } /* Check input frequency */ if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) { diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index f6c7f043c1762ee89dfc9eace9323581100cc773..c8f1af8a053f3103b9e5099da809df0fbee75064 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -171,18 +171,17 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { }, /* - * Common definitions for legacy IrDA ports, dependent on - * regshift value. + * Common definitions for legacy IrDA ports. */ [SCIx_IRDA_REGTYPE] = { [SCSMR] = { 0x00, 8 }, - [SCBRR] = { 0x01, 8 }, - [SCSCR] = { 0x02, 8 }, - [SCxTDR] = { 0x03, 8 }, - [SCxSR] = { 0x04, 8 }, - [SCxRDR] = { 0x05, 8 }, - [SCFCR] = { 0x06, 8 }, - [SCFDR] = { 0x07, 16 }, + [SCBRR] = { 0x02, 8 }, + [SCSCR] = { 0x04, 8 }, + [SCxTDR] = { 0x06, 8 }, + [SCxSR] = { 0x08, 16 }, + [SCxRDR] = { 0x0a, 8 }, + [SCFCR] = { 0x0c, 8 }, + [SCFDR] = { 0x0e, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, @@ -737,6 +736,8 @@ static void sci_receive_chars(struct uart_port *port) /* Tell the rest of the system the news. New characters! */ tty_flip_buffer_push(tport); } else { + /* TTY buffers full; read from RX reg to prevent lockup */ + serial_port_in(port, SCxRDR); serial_port_in(port, SCxSR); /* dummy read */ serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index fabde0e878e0639d5cbc01373f89aacbe84ea718..df28ef14382b4a0363eefe5a2514aa184dcc7711 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1001,7 +1001,7 @@ static struct uart_port *cdns_uart_get_port(int id) struct uart_port *port; /* Try the given port id if failed use default method */ - if (cdns_uart_port[id].mapbase != 0) { + if (id < CDNS_UART_NR_PORTS && cdns_uart_port[id].mapbase != 0) { /* Find the next unused port */ for (id = 0; id < CDNS_UART_NR_PORTS; id++) if (cdns_uart_port[id].mapbase == 0) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 71f5e5240636ebf46fac9005933376540239ea35..2e4019bbd294a6eaa9d814a356e05b65546b9470 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -247,8 +247,10 @@ static void sysrq_handle_showallcpus(int key) * architecture has no support for it: */ if (!trigger_all_cpu_backtrace()) { - struct pt_regs *regs = get_irq_regs(); + struct pt_regs *regs = NULL; + if (in_irq()) + regs = get_irq_regs(); if (regs) { printk(KERN_INFO "CPU%d:\n", smp_processor_id()); show_regs(regs); @@ -267,7 +269,10 @@ static struct sysrq_key_op sysrq_showallcpus_op = { static void sysrq_handle_showregs(int key) { - struct pt_regs *regs = get_irq_regs(); + struct pt_regs *regs = NULL; + + if (in_irq()) + regs = get_irq_regs(); if (regs) show_regs(regs); perf_event_print_debug(); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 9693f76733d3d71ca354519610d717cbf3b32948..d8e3577007fe402684e3913deeeee6e37a3a35d7 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -171,12 +171,11 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) return ERR_CAST(ldops); } - ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); - if (ld == NULL) { - put_ldops(ldops); - return ERR_PTR(-ENOMEM); - } - + /* + * There is no way to handle allocation failure of only 16 bytes. + * Let's simplify error handling and save more memory. + */ + ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL); ld->ops = ldops; ld->tty = tty; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 322c4818dd0ccbcaf4194a95d692399c88e3fa9d..d7b435af42d3f4153e2504204fb76a6969d7c571 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1303,6 +1303,11 @@ static void csi_m(struct vc_data *vc) case 3: vc->vc_italic = 1; break; + case 21: + /* + * No console drivers support double underline, so + * convert it to a single underline. + */ case 4: vc->vc_underline = 1; break; @@ -1339,7 +1344,6 @@ static void csi_m(struct vc_data *vc) vc->vc_disp_ctrl = 1; vc->vc_toggle_meta = 1; break; - case 21: case 22: vc->vc_intensity = 1; break; @@ -1705,7 +1709,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) default_attr(vc); update_attr(vc); - vc->vc_tab_stop[0] = 0x01010100; + vc->vc_tab_stop[0] = vc->vc_tab_stop[1] = vc->vc_tab_stop[2] = vc->vc_tab_stop[3] = @@ -1748,7 +1752,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_pos -= (vc->vc_x << 1); while (vc->vc_x < vc->vc_cols - 1) { vc->vc_x++; - if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31))) + if (vc->vc_tab_stop[7 & (vc->vc_x >> 5)] & (1 << (vc->vc_x & 31))) break; } vc->vc_pos += (vc->vc_x << 1); @@ -1808,7 +1812,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) lf(vc); return; case 'H': - vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31)); + vc->vc_tab_stop[7 & (vc->vc_x >> 5)] |= (1 << (vc->vc_x & 31)); return; case 'Z': respond_ID(tty); @@ -2001,7 +2005,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) return; case 'g': if (!vc->vc_par[0]) - vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31)); + vc->vc_tab_stop[7 & (vc->vc_x >> 5)] &= ~(1 << (vc->vc_x & 31)); else if (vc->vc_par[0] == 3) { vc->vc_tab_stop[0] = vc->vc_tab_stop[1] = diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 60fa6278fbceffd460890de52e50c9c31ade080c..86055f663a0115592b16d0e9135d3d52577f7268 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -832,8 +832,6 @@ int __uio_register_device(struct module *owner, if (ret) goto err_uio_dev_add_attributes; - info->uio_dev = idev; - if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { ret = devm_request_irq(idev->dev, info->irq, uio_interrupt, info->irq_flags, info->name, idev); @@ -841,6 +839,7 @@ int __uio_register_device(struct module *owner, goto err_request_irq; } + info->uio_dev = idev; return 0; err_request_irq: diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e0014f81fdb8202ee0dcc48c7ba3abbf2a4575f7..491ba15c2bff0c09ac9f1ac5bc18372704b5a668 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2264,41 +2264,49 @@ static int usb_enumerate_device_otg(struct usb_device *udev) && udev->parent == udev->bus->root_hub) { struct usb_otg_descriptor *desc = NULL; struct usb_bus *bus = udev->bus; + unsigned port1 = udev->portnum; /* descriptor may appear anywhere in config */ - if (__usb_get_extra_descriptor (udev->rawdescriptors[0], - le16_to_cpu(udev->config[0].desc.wTotalLength), - USB_DT_OTG, (void **) &desc) == 0) { - if (desc->bmAttributes & USB_OTG_HNP) { - unsigned port1 = udev->portnum; - - dev_info(&udev->dev, - "Dual-Role OTG device on %sHNP port\n", - (port1 == bus->otg_port) - ? "" : "non-"); - - /* enable HNP before suspend, it's simpler */ - if (port1 == bus->otg_port) - bus->b_hnp_enable = 1; - err = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, 0, - bus->b_hnp_enable - ? USB_DEVICE_B_HNP_ENABLE - : USB_DEVICE_A_ALT_HNP_SUPPORT, - 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (err < 0) { - /* OTG MESSAGE: report errors here, - * customize to match your product. - */ - dev_info(&udev->dev, - "can't set HNP mode: %d\n", - err); - bus->b_hnp_enable = 0; - } + err = __usb_get_extra_descriptor(udev->rawdescriptors[0], + le16_to_cpu(udev->config[0].desc.wTotalLength), + USB_DT_OTG, (void **) &desc, sizeof(*desc)); + if (err || !(desc->bmAttributes & USB_OTG_HNP)) + return 0; + dev_info(&udev->dev, "Dual-Role OTG device on %sHNP port\n", + (port1 == bus->otg_port) ? "" : "non-"); + + /* enable HNP before suspend, it's simpler */ + if (port1 == bus->otg_port) { + bus->b_hnp_enable = 1; + err = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_B_HNP_ENABLE, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (err < 0) { + /* + * OTG MESSAGE: report errors here, + * customize to match your product. + */ + dev_err(&udev->dev, "can't set HNP mode: %d\n", + err); + bus->b_hnp_enable = 0; } + } else if (desc->bLength == sizeof + (struct usb_otg_descriptor)) { + /* Set a_alt_hnp_support for legacy otg device */ + err = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_A_ALT_HNP_SUPPORT, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (err < 0) + dev_err(&udev->dev, + "set a_alt_hnp_support failed: %d\n", + err); } - } #endif return err; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 29ee9363faa51bf4a8e6cb58f574c3c3628db4f4..870fc9079b5b1ce586fe0b775806051848da1514 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -662,14 +662,14 @@ EXPORT_SYMBOL_GPL(usb_get_current_frame_number); */ int __usb_get_extra_descriptor(char *buffer, unsigned size, - unsigned char type, void **ptr) + unsigned char type, void **ptr, size_t minsize) { struct usb_descriptor_header *header; while (size >= sizeof(struct usb_descriptor_header)) { header = (struct usb_descriptor_header *)buffer; - if (header->bLength < 2) { + if (header->bLength < 2 || header->bLength > size) { printk(KERN_ERR "%s: bogus descriptor, type %d length %d\n", usbcore_name, @@ -678,7 +678,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, return -1; } - if (header->bDescriptorType == type) { + if (header->bDescriptorType == type && header->bLength >= minsize) { *ptr = header; return 0; } diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 309b2eadad2590c6545e8a6271f4641474f5de61..debaf6b9208ba5e5e3eca0759f824e35e27b851a 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -52,8 +52,8 @@ #include "debug.h" #include "xhci.h" -#define DWC3_IDEV_CHG_MAX 2000 -#define DWC3_HVDCP_CHG_MAX 2000 +#define DWC3_IDEV_CHG_MAX 1500 +#define DWC3_HVDCP_CHG_MAX 1800 #define DWC3_WAKEUP_SRC_TIMEOUT 5000 #define MICRO_5V 5000000 @@ -2170,10 +2170,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) dev_dbg(mdwc->dev, "defer suspend with %d(msecs)\n", mdwc->lpm_to_suspend_delay); pm_wakeup_event(mdwc->dev, mdwc->lpm_to_suspend_delay); -#if 0 } else { pm_relax(mdwc->dev); -#endif } atomic_set(&dwc->in_lpm, 1); @@ -2213,9 +2211,7 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) return 0; } -#if 0 pm_stay_awake(mdwc->dev); -#endif /* Vote for TCXO while waking up USB HSPHY */ ret = clk_prepare_enable(mdwc->xo_clk); @@ -2366,9 +2362,7 @@ static void dwc3_ext_event_notify(struct dwc3_msm *mdwc) return; } - if (mdwc->no_wakeup_src_in_hostmode && mdwc->in_host_mode) - pm_stay_awake(mdwc->dev); - + pm_stay_awake(mdwc->dev); queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 6549710e59e09f9676ee78ecffaf40e523a4d390..68db80966a1df224d01cad84eb67ff6e1dcfb739 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -267,7 +267,7 @@ out: return ret; } -static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) +void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) { struct dwc3_ep *dep; @@ -1119,9 +1119,22 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, switch (event->status) { case DEPEVT_STATUS_CONTROL_DATA: - dwc3_trace(trace_dwc3_ep0, "Control Data"); dep->dbg_ep_events.control_data++; + /* + * When we issue a STALL and RESTART of EP0 OUT, then + * ep0_next_event is set as DWC3_EP0_COMPLETE and we wait for + * the next setup packet. We will ignore a XferNotReady (DATA) + * event until setup packet arrives, so as to avoid HW latency + * issues. + */ + if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) { + dwc3_trace(trace_dwc3_ep0, "Ignore Control Data"); + return; + } + + dwc3_trace(trace_dwc3_ep0, "Control Data"); + /* * We already have a DATA transfer in the controller's cache, * if we receive a XferNotReady(DATA) we will ignore it, unless diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index ddb03879a1af6f378b90904577d5fec471f0d16f..22f0c5ab354e0c7126a0920c3443f35af45a7298 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1883,7 +1883,7 @@ static int dwc_gadget_func_wakeup(struct usb_gadget *g, int interface_id) if (dwc3_gadget_is_suspended(dwc)) { pr_debug("USB bus is suspended. Scheduling wakeup and returning -EAGAIN.\n"); dwc3_gadget_wakeup(&dwc->gadget); - return -EAGAIN; + return -EACCES; } /* @@ -3001,6 +3001,15 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; + /* + * From SNPS databook section 8.1.2 + * the EP0 should be in setup phase. So ensure + * that EP0 is in setup phase by issuing a stall + * and restart if EP0 is not in setup phase. + */ + if (dwc->ep0state != EP0_SETUP_PHASE) + dwc3_ep0_stall_and_restart(dwc); + dwc3_stop_active_transfers(dwc); dwc3_clear_stall_all_ep(dwc); @@ -3484,6 +3493,13 @@ static void dwc3_process_event_entry(struct dwc3 *dwc, /* Endpoint IRQ, handle it and return early */ if (event->type.is_devspec == 0) { /* depevt */ + /* If remote-wakeup attempt by device had failed, then core + * wouldn't give wakeup event after resume. Handle that + * here on ep event which indicates that bus is resumed. + */ + if (dwc->b_suspend && + dwc3_get_link_state(dwc) == DWC3_LINK_STATE_U0) + dwc3_gadget_wakeup_interrupt(dwc, false); return dwc3_endpoint_interrupt(dwc, &event->depevt); } diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index a21962c8f5136ea72e5116624e16b43d2851e9e7..ca943d18a9ad971bf1173b677763a8875ba0379e 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -98,6 +98,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); void dwc3_ep0_out_start(struct dwc3 *dwc); +void dwc3_ep0_stall_and_restart(struct dwc3 *dwc); int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 10416b19473417b4fe45e0ffd7445c44d56eb9d6..4afaaaadff3151c00e82b8ff0e048ff94e755833 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -19,5 +19,3 @@ obj-$(CONFIG_USB_G_ANDROID) += g_android.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_CI13XXX_MSM_HSIC) += ci13xxx_msm_hsic.o - -CFLAGS_android.o += $(call cc-disable-warning, array-bounds) diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index a87fee903b29d49b75058af46aa077b7914bd5bc..7e2f9a2f91dfbd7c650c07c3dbcfd0132376419a 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -1613,11 +1613,14 @@ done: } static DEVICE_ATTR(dtds, S_IWUSR, NULL, print_dtds); +#define CI_PM_RESUME_RETRIES 5 /* Max Number of retries */ + static int ci13xxx_wakeup(struct usb_gadget *_gadget) { struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); unsigned long flags; int ret = 0; + static int retry_count; trace(); @@ -1629,7 +1632,27 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget) } spin_unlock_irqrestore(udc->lock, flags); - pm_runtime_get_sync(&_gadget->dev); + ret = pm_runtime_get_sync(&_gadget->dev); + if (ret) { + /* pm_runtime_get_sync returns -EACCES error between + * late_suspend and early_resume, wait for system resume to + * finish and perform resume from work_queue again + */ + pr_debug("PM runtime get sync failed, ret %d\n", ret); + if (ret == -EACCES) { + pm_runtime_put_noidle(&_gadget->dev); + if (retry_count == CI_PM_RESUME_RETRIES) { + pr_err("pm_runtime_get_sync timed out\n"); + retry_count = 0; + return 0; + } + retry_count++; + schedule_delayed_work(&udc->rw_work, + REMOTE_WAKEUP_DELAY); + return 0; + } + } + retry_count = 0; udc->udc_driver->notify_event(udc, CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT); @@ -2253,6 +2276,12 @@ static void release_ep_request(struct ci13xxx_ep *mEp, mReq->map = 0; } + if (mReq->zptr) { + dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); + mReq->zptr = NULL; + mReq->zdma = 0; + } + if (mEp->multi_req) { restore_original_req(mReq); mEp->multi_req = false; @@ -2314,6 +2343,12 @@ __acquires(mEp->lock) release_ep_request(mEp, mReq); } + if (mEp->last_zptr) { + dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma); + mEp->last_zptr = NULL; + mEp->last_zdma = 0; + } + return 0; } @@ -2348,12 +2383,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) _ep_nuke(&udc->ep0in); spin_unlock_irqrestore(udc->lock, flags); - if (udc->ep0in.last_zptr) { - dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr, - udc->ep0in.last_zdma); - udc->ep0in.last_zptr = NULL; - } - return 0; } @@ -2851,6 +2880,7 @@ __acquires(udc->lock) default: break; } + break; default: goto delegate; } @@ -2982,12 +3012,6 @@ static int ep_disable(struct usb_ep *ep) } while (mEp->dir != direction); - if (mEp->last_zptr) { - dma_pool_free(mEp->td_pool, mEp->last_zptr, - mEp->last_zdma); - mEp->last_zptr = NULL; - } - mEp->desc = NULL; mEp->ep.desc = NULL; mEp->ep.maxpacket = USHRT_MAX; @@ -3242,7 +3266,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) dbg_event(_usb_addr(mEp), "DEQUEUE", 0); - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { + if ((mEp->type == USB_ENDPOINT_XFER_CONTROL)) { hw_ep_flush(_udc->ep0out.num, RX); hw_ep_flush(_udc->ep0in.num, TX); } else { @@ -3937,10 +3961,9 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, _udc = udc; return retval; -#ifdef CONFIG_USB_GADGET_DEBUG_FILES + del_udc: usb_del_gadget_udc(&udc->gadget); -#endif remove_trans: if (udc->transceiver) otg_set_peripheral(udc->transceiver->otg, &udc->gadget); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f038204d949e348564eebf63e9c9ec5784179fd5..aa6d1010b400b4b650d8fb18f95eada71be87b44 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -413,11 +413,17 @@ int usb_func_wakeup(struct usb_function *func) spin_lock_irqsave(&func->config->cdev->lock, flags); ret = usb_func_wakeup_int(func); - if (ret == -EAGAIN) { + if (ret == -EACCES) { DBG(func->config->cdev, "Function wakeup for %s could not complete due to suspend state. Delayed until after bus resume.\n", func->name ? func->name : ""); ret = 0; + func->func_wakeup_pending = 1; + } else if (ret == -EAGAIN) { + DBG(func->config->cdev, + "Function wakeup for %s sent.\n", + func->name ? func->name : ""); + ret = 0; } else if (ret < 0 && ret != -ENOTSUPP) { ERROR(func->config->cdev, "Failed to wake function %s from suspend state. ret=%d. Canceling USB request.\n", @@ -448,7 +454,12 @@ int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep, if (func->func_is_suspended && func->func_wakeup_allowed) { ret = usb_gadget_func_wakeup(gadget, func->intf_id); - if (ret == -EAGAIN) { + if (ret == -EACCES) { + pr_debug("bus suspended func wakeup for %s delayed until bus resume.\n", + func->name ? func->name : ""); + func->func_wakeup_pending = 1; + ret = -EAGAIN; + } else if (ret == -EAGAIN) { pr_debug("bus suspended func wakeup for %s delayed until bus resume.\n", func->name ? func->name : ""); } else if (ret < 0 && ret != -ENOTSUPP) { @@ -1921,6 +1932,16 @@ unknown: } break; } + + if (value < 0) { + DBG(cdev, "%s: unhandled os desc request\n", + __func__); + DBG(cdev, "req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + return value; + } + req->length = value; req->zero = value < w_length; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); @@ -2322,21 +2343,29 @@ composite_resume(struct usb_gadget *gadget) spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) { list_for_each_entry(f, &cdev->config->functions, list) { - ret = usb_func_wakeup_int(f); - if (ret) { - if (ret == -EAGAIN) { - ERROR(f->config->cdev, - "Function wakeup for %s could not complete due to suspend state.\n", - f->name ? f->name : ""); - break; - } else if (ret != -ENOTSUPP) { - ERROR(f->config->cdev, - "Failed to wake function %s from suspend state. ret=%d. Canceling USB request.\n", - f->name ? f->name : "", - ret); + if (f->func_wakeup_pending) { + ret = usb_func_wakeup_int(f); + if (ret) { + if (ret == -EAGAIN) { + ERROR(f->config->cdev, + "Function wakeup for %s could not complete due to suspend state.\n", + f->name ? f->name : ""); + } else if (ret != -ENOTSUPP) { + ERROR(f->config->cdev, + "Failed to wake function %s from suspend state. ret=%d. Canceling USB request.\n", + f->name ? f->name : "", + ret); + } } + f->func_wakeup_pending = 0; } + /* + * Call function resume irrespective of the speed. + * Individual function needs to retain the USB3 Function + * suspend state through out the Device suspend entry + * and exit process. + */ if (f->resume) f->resume(f); } diff --git a/drivers/usb/gadget/function/configfs.h b/drivers/usb/gadget/function/configfs.h deleted file mode 100644 index 34025df6182962952e094f9c98e7a38b3c25bab4..0000000000000000000000000000000000000000 --- a/drivers/usb/gadget/function/configfs.h +++ /dev/null @@ -1,260 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; -*- - * vim: noexpandtab sw=8 ts=8 sts=0: - * - * configfs.h - definitions for the device driver filesystem - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - * - * Based on sysfs: - * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel - * - * Based on kobject.h: - * Copyright (c) 2002-2003 Patrick Mochel - * Copyright (c) 2002-2003 Open Source Development Labs - * - * configfs Copyright (C) 2005 Oracle. All rights reserved. - * - * Please read Documentation/filesystems/configfs/configfs.txt before using - * the configfs interface, ESPECIALLY the parts about reference counts and - * item destructors. - */ - -#ifndef _CONFIGFS_H_ -#define _CONFIGFS_H_ - -#include -#include -#include -#include -#include -#include - -#include - -#define CONFIGFS_ITEM_NAME_LEN 20 - -struct module; - -struct configfs_item_operations; -struct configfs_group_operations; -struct configfs_attribute; -struct configfs_subsystem; - -struct config_item { - char *ci_name; - char ci_namebuf[CONFIGFS_ITEM_NAME_LEN]; - struct kref ci_kref; - struct list_head ci_entry; - struct config_item *ci_parent; - struct config_group *ci_group; - struct config_item_type *ci_type; - struct dentry *ci_dentry; -}; - -extern int config_item_set_name(struct config_item *, const char *, ...); - -static inline char *config_item_name(struct config_item * item) -{ - return item->ci_name; -} - -extern void config_item_init(struct config_item *); -extern void config_item_init_type_name(struct config_item *item, - const char *name, - struct config_item_type *type); - -extern struct config_item * config_item_get(struct config_item *); -extern void config_item_put(struct config_item *); - -struct config_item_type { - struct module *ct_owner; - struct configfs_item_operations *ct_item_ops; - struct configfs_group_operations *ct_group_ops; - struct configfs_attribute **ct_attrs; -}; - -/** - * group - a group of config_items of a specific type, belonging - * to a specific subsystem. - */ -struct config_group { - struct config_item cg_item; - struct list_head cg_children; - struct configfs_subsystem *cg_subsys; - struct config_group **default_groups; -}; - -extern void config_group_init(struct config_group *group); -extern void config_group_init_type_name(struct config_group *group, - const char *name, - struct config_item_type *type); - -static inline struct config_group *to_config_group(struct config_item *item) -{ - return item ? container_of(item,struct config_group,cg_item) : NULL; -} - -static inline struct config_group *config_group_get(struct config_group *group) -{ - return group ? to_config_group(config_item_get(&group->cg_item)) : NULL; -} - -static inline void config_group_put(struct config_group *group) -{ - config_item_put(&group->cg_item); -} - -extern struct config_item *config_group_find_item(struct config_group *, - const char *); - - -struct configfs_attribute { - const char *ca_name; - struct module *ca_owner; - umode_t ca_mode; -}; - -/* - * Users often need to create attribute structures for their configurable - * attributes, containing a configfs_attribute member and function pointers - * for the show() and store() operations on that attribute. If they don't - * need anything else on the extended attribute structure, they can use - * this macro to define it The argument _item is the name of the - * config_item structure. - */ -#define CONFIGFS_ATTR_STRUCT(_item) \ -struct _item##_attribute { \ - struct configfs_attribute attr; \ - ssize_t (*show)(struct _item *, char *); \ - ssize_t (*store)(struct _item *, const char *, size_t); \ -} - -/* - * With the extended attribute structure, users can use this macro - * (similar to sysfs' __ATTR) to make defining attributes easier. - * An example: - * #define MYITEM_ATTR(_name, _mode, _show, _store) \ - * struct myitem_attribute childless_attr_##_name = \ - * __CONFIGFS_ATTR(_name, _mode, _show, _store) - */ -#define __CONFIGFS_ATTR(_name, _mode, _show, _store) \ -{ \ - .attr = { \ - .ca_name = __stringify(_name), \ - .ca_mode = _mode, \ - .ca_owner = THIS_MODULE, \ - }, \ - .show = _show, \ - .store = _store, \ -} -/* Here is a readonly version, only requiring a show() operation */ -#define __CONFIGFS_ATTR_RO(_name, _show) \ -{ \ - .attr = { \ - .ca_name = __stringify(_name), \ - .ca_mode = 0444, \ - .ca_owner = THIS_MODULE, \ - }, \ - .show = _show, \ -} - -/* - * With these extended attributes, the simple show_attribute() and - * store_attribute() operations need to call the show() and store() of the - * attributes. This is a common pattern, so we provide a macro to define - * them. The argument _item is the name of the config_item structure. - * This macro expects the attributes to be named "struct _attribute" - * and the function to_() to exist; - */ -#define CONFIGFS_ATTR_OPS(_item) \ -static ssize_t _item##_attr_show(struct config_item *item, \ - struct configfs_attribute *attr, \ - char *page) \ -{ \ - struct _item *_item = to_##_item(item); \ - struct _item##_attribute *_item##_attr = \ - container_of(attr, struct _item##_attribute, attr); \ - ssize_t ret = 0; \ - \ - if (_item##_attr->show) \ - ret = _item##_attr->show(_item, page); \ - return ret; \ -} \ -static ssize_t _item##_attr_store(struct config_item *item, \ - struct configfs_attribute *attr, \ - const char *page, size_t count) \ -{ \ - struct _item *_item = to_##_item(item); \ - struct _item##_attribute *_item##_attr = \ - container_of(attr, struct _item##_attribute, attr); \ - ssize_t ret = -EINVAL; \ - \ - if (_item##_attr->store) \ - ret = _item##_attr->store(_item, page, count); \ - return ret; \ -} - -/* - * If allow_link() exists, the item can symlink(2) out to other - * items. If the item is a group, it may support mkdir(2). - * Groups supply one of make_group() and make_item(). If the - * group supports make_group(), one can create group children. If it - * supports make_item(), one can create config_item children. make_group() - * and make_item() return ERR_PTR() on errors. If it has - * default_groups on group->default_groups, it has automatically created - * group children. default_groups may coexist alongsize make_group() or - * make_item(), but if the group wishes to have only default_groups - * children (disallowing mkdir(2)), it need not provide either function. - * If the group has commit(), it supports pending and committed (active) - * items. - */ -struct configfs_item_operations { - void (*release)(struct config_item *); - ssize_t (*show_attribute)(struct config_item *, struct configfs_attribute *,char *); - ssize_t (*store_attribute)(struct config_item *,struct configfs_attribute *,const char *, size_t); - int (*allow_link)(struct config_item *src, struct config_item *target); - int (*drop_link)(struct config_item *src, struct config_item *target); -}; - -struct configfs_group_operations { - struct config_item *(*make_item)(struct config_group *group, const char *name); - struct config_group *(*make_group)(struct config_group *group, const char *name); - int (*commit_item)(struct config_item *item); - void (*disconnect_notify)(struct config_group *group, struct config_item *item); - void (*drop_item)(struct config_group *group, struct config_item *item); -}; - -struct configfs_subsystem { - struct config_group su_group; - struct mutex su_mutex; -}; - -static inline struct configfs_subsystem *to_configfs_subsystem(struct config_group *group) -{ - return group ? - container_of(group, struct configfs_subsystem, su_group) : - NULL; -} - -int configfs_register_subsystem(struct configfs_subsystem *subsys); -void configfs_unregister_subsystem(struct configfs_subsystem *subsys); - -/* These functions can sleep and can alloc with GFP_KERNEL */ -/* WARNING: These cannot be called underneath configfs callbacks!! */ -int configfs_depend_item(struct configfs_subsystem *subsys, struct config_item *target); -void configfs_undepend_item(struct configfs_subsystem *subsys, struct config_item *target); - -#endif /* _CONFIGFS_H_ */ diff --git a/drivers/usb/gadget/function/debug.h b/drivers/usb/gadget/function/debug.h deleted file mode 100644 index 8729aca0a69e1f27c267e6ef7483b6ac0afb9e39..0000000000000000000000000000000000000000 --- a/drivers/usb/gadget/function/debug.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * 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. - * - */ - -#ifndef __DEBUG_H_ -#define __DEBUG_H_ - -#define DBG_MAX_MSG 1024UL -#define DBG_MSG_LEN 80UL -#define TIME_BUF_LEN 17 -#define DBG_EVENT_LEN (DBG_MSG_LEN - TIME_BUF_LEN) - -extern unsigned int enable_event_log; -extern void put_timestamp(char *tbuf); -extern void add_event_to_buf(char *tbuf); -extern int debug_debugfs_init(void); -extern void debug_debugfs_exit(void); - -#define LOGLEVEL_NONE 8 -#define LOGLEVEL_DEBUG 7 -#define LOGLEVEL_INFO 6 -#define LOGLEVEL_ERR 3 - -#define log_event(log_level, x...) \ -do { \ - char buf[DBG_MSG_LEN]; \ - if (log_level == LOGLEVEL_DEBUG) \ - pr_debug(x); \ - else if (log_level == LOGLEVEL_ERR) \ - pr_err(x); \ - else if (log_level == LOGLEVEL_INFO) \ - pr_info(x); \ - if (enable_event_log) { \ - put_timestamp(buf); \ - snprintf(&buf[TIME_BUF_LEN - 1], DBG_EVENT_LEN, x); \ - add_event_to_buf(buf); \ - } \ -} while (0) - -#define log_event_none(x, ...) log_event(LOGLEVEL_NONE, x, ##__VA_ARGS__) -#define log_event_dbg(x, ...) log_event(LOGLEVEL_DEBUG, x, ##__VA_ARGS__) -#define log_event_err(x, ...) log_event(LOGLEVEL_ERR, x, ##__VA_ARGS__) -#define log_event_info(x, ...) log_event(LOGLEVEL_INFO, x, ##__VA_ARGS__) - -#endif /* __DEBUG_H_ */ diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index bf46a87c56e49f45378ebaa17c520b3e0c0d8290..4820762394579f0a7f3d17bac499f12976c7a70b 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -19,7 +19,6 @@ /* #define VERBOSE_DEBUG */ #include -#include #include #include #include @@ -749,7 +748,7 @@ retry: * and wait for next epfile open to happen */ if (!atomic_read(&epfile->error)) { - ret = wait_event_freezable(epfile->wait, + ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); if (ret < 0) goto error; @@ -865,7 +864,7 @@ retry: } if (io_data->aio) { - req = usb_ep_alloc_request(ep->ep, GFP_KERNEL); + req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC); if (unlikely(!req)) goto error_lock; @@ -1715,7 +1714,7 @@ static void functionfs_unbind(struct ffs_data *ffs) static int ffs_epfiles_create(struct ffs_data *ffs) { struct ffs_epfile *epfile, *epfiles; - short i, count; + unsigned i, count; ENTER(); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index d29524970369dfeb50317b2b09522b0d050a8d38..c50778039da53d3d87d9ca6baac51579c5e960df 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, Linux Foundation. All rights reserved. * * 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 @@ -372,26 +372,22 @@ static const struct file_operations fops_usb_gsi = { .llseek = default_llseek, }; -static void debugfs_rw_timer_func(unsigned long arg) +static void gsi_rw_timer_func(unsigned long arg) { - struct f_gsi *gsi; - - gsi = (struct f_gsi *)arg; + struct f_gsi *gsi = (struct f_gsi *)arg; - if (gsi && atomic_read(&gsi->connected)) { - log_event_dbg("%s: calling gsi_wakeup_host\n", __func__); - gsi_wakeup_host(gsi); - } else { - log_event_dbg("%s: gsi not connected..del timer\n", __func__); - gsi->debugfs_rw_enable = 0; - del_timer(&gsi->debugfs_rw_timer); + if (!atomic_read(&gsi->connected)) { + log_event_dbg("%s: gsi not connected.. bail-out\n", __func__); + gsi->debugfs_rw_timer_enable = 0; return; } - if (gsi->debugfs_rw_enable) { + gsi_wakeup_host(gsi); + + if (gsi->debugfs_rw_timer_enable) { log_event_dbg("%s: re-arm the timer\n", __func__); - mod_timer(&gsi->debugfs_rw_timer, - jiffies + msecs_to_jiffies(gsi->debugfs_rw_interval)); + mod_timer(&gsi->gsi_rw_timer, + jiffies + msecs_to_jiffies(gsi->gsi_rw_timer_interval)); } } @@ -440,7 +436,7 @@ static ssize_t usb_gsi_rw_write(struct file *file, goto err; } - if (gsi->debugfs_rw_enable == !!input) { + if (gsi->debugfs_rw_timer_enable == !!input) { if (!!input) log_event_dbg("%s: RW already enabled\n", __func__); else @@ -448,21 +444,14 @@ static ssize_t usb_gsi_rw_write(struct file *file, goto err; } - gsi->debugfs_rw_enable = !!input; - if (gsi->debugfs_rw_enable) { - init_timer(&gsi->debugfs_rw_timer); - gsi->debugfs_rw_timer.data = (unsigned long) gsi; - gsi->debugfs_rw_timer.function = debugfs_rw_timer_func; + gsi->debugfs_rw_timer_enable = !!input; - /* Use default remote wakeup timer interval if it is not set */ - if (!gsi->debugfs_rw_interval) - gsi->debugfs_rw_interval = DEFAULT_RW_TIMER_INTERVAL; - gsi->debugfs_rw_timer.expires = jiffies + - msecs_to_jiffies(gsi->debugfs_rw_interval); - add_timer(&gsi->debugfs_rw_timer); + if (gsi->debugfs_rw_timer_enable) { + mod_timer(&gsi->gsi_rw_timer, jiffies + + msecs_to_jiffies(gsi->gsi_rw_timer_interval)); log_event_dbg("%s: timer initialized\n", __func__); } else { - del_timer_sync(&gsi->debugfs_rw_timer); + del_timer_sync(&gsi->gsi_rw_timer); log_event_dbg("%s: timer deleted\n", __func__); } @@ -481,7 +470,7 @@ static int usb_gsi_rw_show(struct seq_file *s, void *unused) return 0; } - seq_printf(s, "%d\n", gsi->debugfs_rw_enable); + seq_printf(s, "%d\n", gsi->debugfs_rw_timer_enable); return 0; } @@ -529,7 +518,7 @@ static ssize_t usb_gsi_rw_timer_write(struct file *file, goto err; } - gsi->debugfs_rw_interval = timer_val; + gsi->gsi_rw_timer_interval = timer_val; err: return count; } @@ -537,7 +526,6 @@ err: static int usb_gsi_rw_timer_show(struct seq_file *s, void *unused) { struct f_gsi *gsi; - unsigned timer_interval; gsi = get_connected_gsi(); if (!gsi) { @@ -545,11 +533,7 @@ static int usb_gsi_rw_timer_show(struct seq_file *s, void *unused) return 0; } - timer_interval = DEFAULT_RW_TIMER_INTERVAL; - if (gsi->debugfs_rw_interval) - timer_interval = gsi->debugfs_rw_interval; - - seq_printf(s, "%ums\n", timer_interval); + seq_printf(s, "%ums\n", gsi->gsi_rw_timer_interval); return 0; } @@ -1295,8 +1279,9 @@ static void gsi_ctrl_clear_cpkt_queues(struct f_gsi *gsi, bool skip_req_q) { struct gsi_ctrl_pkt *cpkt = NULL; struct list_head *act, *tmp; + unsigned long flags; - spin_lock(&gsi->c_port.lock); + spin_lock_irqsave(&gsi->c_port.lock, flags); if (skip_req_q) goto clean_resp_q; @@ -1311,7 +1296,7 @@ clean_resp_q: list_del(&cpkt->list); gsi_ctrl_pkt_free(cpkt); } - spin_unlock(&gsi->c_port.lock); + spin_unlock_irqrestore(&gsi->c_port.lock, flags); } static int gsi_ctrl_send_cpkt_tomodem(struct f_gsi *gsi, void *buf, size_t len) @@ -2599,6 +2584,9 @@ static void gsi_disable(struct usb_function *f) atomic_set(&gsi->connected, 0); + del_timer(&gsi->gsi_rw_timer); + gsi->debugfs_rw_timer_enable = 0; + if (gsi->prot_id == IPA_USB_RNDIS) rndis_uninit(gsi->config); @@ -2649,6 +2637,15 @@ static void gsi_suspend(struct usb_function *f) post_event(&gsi->d_port, EVT_SUSPEND); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); log_event_dbg("gsi suspended"); + + /* If host suspended bus without receiving notification request then + * initiate remote-wakeup. As driver won't be able to do it later since + * notification request is already queued. + */ + if (gsi->c_port.notify_req_queued && usb_gsi_remote_wakeup_allowed(f)) { + mod_timer(&gsi->gsi_rw_timer, jiffies + msecs_to_jiffies(2000)); + log_event_dbg("%s: pending response, arm rw_timer\n", __func__); + } } static void gsi_resume(struct usb_function *f) @@ -2671,6 +2668,10 @@ static void gsi_resume(struct usb_function *f) f->func_is_suspended) return; + /* Keep timer enabled if user enabled using debugfs */ + if (!gsi->debugfs_rw_timer_enable) + del_timer(&gsi->gsi_rw_timer); + if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); @@ -2695,6 +2696,11 @@ static void gsi_resume(struct usb_function *f) static int gsi_get_status(struct usb_function *f) { unsigned remote_wakeup_en_status = f->func_wakeup_allowed ? 1 : 0; + struct f_gsi *gsi = func_to_gsi(f); + + /* Disable function remote wake-up for DPL interface */ + if (gsi->prot_id == IPA_USB_DIAG) + return 0; return (remote_wakeup_en_status << FUNC_WAKEUP_ENABLE_SHIFT) | (1 << FUNC_WAKEUP_CAPABLE_SHIFT); @@ -3371,6 +3377,8 @@ static int gsi_function_init(enum ipa_usb_teth_prot prot_id) gsi_prot_ctx[prot_id] = gsi; gsi->d_port.ipa_usb_wq = ipa_usb_wq; + gsi->gsi_rw_timer_interval = DEFAULT_RW_TIMER_INTERVAL; + setup_timer(&gsi->gsi_rw_timer, gsi_rw_timer_func, (unsigned long) gsi); ret = gsi_function_ctrl_port_init(prot_id); if (ret) { diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index c64b8f8328b282259a9a7e06d55a9074a5c2c976..474ce0ce774415d5436131ce71bf6410031b8c87 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -228,9 +228,9 @@ struct f_gsi { struct gsi_data_port d_port; struct gsi_ctrl_port c_port; /* To test remote wakeup using debugfs */ - struct timer_list debugfs_rw_timer; - u8 debugfs_rw_enable; - u16 debugfs_rw_interval; + struct timer_list gsi_rw_timer; + u8 debugfs_rw_timer_enable; + u16 gsi_rw_timer_interval; }; static struct f_gsi *gsi_prot_ctx[IPA_USB_MAX_TETH_PROT_SIZE]; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 59ab62c92b66667e77b4ba35cd59f754584e0fd2..5fb678385cfb8839d7205fe3499f9e39722fd7c8 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -197,6 +197,13 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, /* pick the first one */ list = list_first_entry(&hidg->completed_out_req, struct f_hidg_req_list, list); + + /* + * Remove this from list to protect it from beign free() + * while host disables our function + */ + list_del(&list->list); + req = list->req; count = min_t(unsigned int, count, req->actual - list->pos); spin_unlock_irqrestore(&hidg->spinlock, flags); @@ -212,15 +219,20 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, * call, taking into account its current read position. */ if (list->pos == req->actual) { - spin_lock_irqsave(&hidg->spinlock, flags); - list_del(&list->list); kfree(list); - spin_unlock_irqrestore(&hidg->spinlock, flags); req->length = hidg->report_length; ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL); - if (ret < 0) + if (ret < 0) { + free_ep_req(hidg->out_ep, req); return ret; + } + } else { + spin_lock_irqsave(&hidg->spinlock, flags); + list_add(&list->list, &hidg->completed_out_req); + spin_unlock_irqrestore(&hidg->spinlock, flags); + + wake_up(&hidg->read_queue); } return count; @@ -455,6 +467,7 @@ static void hidg_disable(struct usb_function *f) { struct f_hidg *hidg = func_to_hidg(f); struct f_hidg_req_list *list, *next; + unsigned long flags; usb_ep_disable(hidg->in_ep); hidg->in_ep->driver_data = NULL; @@ -462,10 +475,13 @@ static void hidg_disable(struct usb_function *f) usb_ep_disable(hidg->out_ep); hidg->out_ep->driver_data = NULL; + spin_lock_irqsave(&hidg->spinlock, flags); list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) { + free_ep_req(hidg->out_ep, list->req); list_del(&list->list); kfree(list); } + spin_unlock_irqrestore(&hidg->spinlock, flags); } static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) diff --git a/drivers/usb/gadget/function/f_ipc.c b/drivers/usb/gadget/function/f_ipc.c index 604c17b3ca01bbd54a083ded094f3e24519c2a83..da83b12a903e0193d121a85296c5e23e8249ec05 100644 --- a/drivers/usb/gadget/function/f_ipc.c +++ b/drivers/usb/gadget/function/f_ipc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * 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,6 +28,8 @@ #define IPC_BRIDGE_MAX_READ_SZ (8 * 1024) #define IPC_BRIDGE_MAX_WRITE_SZ (8 * 1024) +#define IPC_WRITE_WAIT_TIMEOUT 10000 + /* for configfs support */ struct ipc_opts { struct usb_function_instance func_inst; @@ -240,6 +242,7 @@ static int ipc_write(struct platform_device *pdev, char *buf, unsigned long flags; struct usb_request *req; struct usb_ep *in; + int ret; if (!ipc_dev) return -ENODEV; @@ -266,6 +269,8 @@ retry_write: return -EINVAL; } + reinit_completion(&ipc_dev->write_done); + if (usb_ep_queue(in, req, GFP_KERNEL)) { wait_event_interruptible(ipc_dev->state_wq, ipc_dev->online || ipc_dev->current_state == IPC_DISCONNECTED); @@ -273,12 +278,23 @@ retry_write: goto retry_write; } - if (unlikely(wait_for_completion_interruptible(&ipc_dev->write_done))) { - usb_ep_dequeue(in, req); - return -EINTR; + ret = wait_for_completion_interruptible_timeout(&ipc_dev->write_done, + msecs_to_jiffies(IPC_WRITE_WAIT_TIMEOUT)); + if (ret < 0) { + pr_err("%s: Interruption triggered\n", __func__); + ret = -EINTR; + goto fail; + } else if (ret == 0) { + pr_err("%s: Request timed out\n", __func__); + ret = -ETIMEDOUT; + goto fail; } return !req->status ? req->actual : req->status; + +fail: + usb_ep_dequeue(in, req); + return ret; } static void ipc_out_complete(struct usb_ep *ep, struct usb_request *req) @@ -333,6 +349,8 @@ retry_read: return -EINVAL; } + reinit_completion(&ipc_dev->read_done); + if (usb_ep_queue(out, req, GFP_KERNEL)) { wait_event_interruptible(ipc_dev->state_wq, ipc_dev->online || ipc_dev->current_state == IPC_DISCONNECTED); diff --git a/drivers/usb/gadget/function/f_mbim.c b/drivers/usb/gadget/function/f_mbim.c index e853c54889bd06d182d72ca60779da94407aa928..78cbf280f905903d9289defc693e62a9e1a058d4 100644 --- a/drivers/usb/gadget/function/f_mbim.c +++ b/drivers/usb/gadget/function/f_mbim.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016,2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -35,6 +35,15 @@ #define MBIM_BULK_BUFFER_SIZE 4096 #define MAX_CTRL_PKT_SIZE 4096 +enum mbim_peripheral_ep_type { + MBIM_DATA_EP_TYPE_RESERVED = 0x0, + MBIM_DATA_EP_TYPE_HSIC = 0x1, + MBIM_DATA_EP_TYPE_HSUSB = 0x2, + MBIM_DATA_EP_TYPE_PCIE = 0x3, + MBIM_DATA_EP_TYPE_EMBEDDED = 0x4, + MBIM_DATA_EP_TYPE_BAM_DMUX = 0x5, +}; + struct mbim_peripheral_ep_info { enum peripheral_ep_type ep_type; u32 peripheral_iface_id; @@ -78,15 +87,8 @@ struct mbim_ep_descs { struct mbim_notify_port { struct usb_ep *notify; struct usb_request *notify_req; - u8 notify_state; - atomic_t notify_count; -}; - -enum mbim_notify_state { - MBIM_NOTIFY_NONE, - MBIM_NOTIFY_CONNECT, - MBIM_NOTIFY_SPEED, - MBIM_NOTIFY_RESPONSE_AVAILABLE, + bool notify_req_queued; + bool notify_pending; }; struct f_mbim { @@ -123,7 +125,9 @@ struct f_mbim { atomic_t error; unsigned int cpkt_drop_cnt; + bool remote_wakeup_enabled; + struct delayed_work rwake_work; }; struct mbim_ntb_input_size { @@ -658,95 +662,91 @@ static void mbim_clear_queues(struct f_mbim *mbim) spin_unlock(&mbim->lock); } -/* - * Context: mbim->lock held - */ -static void mbim_do_notify(struct f_mbim *mbim) +static void mbim_remote_wakeup_work(struct work_struct *w) { - struct usb_request *req = mbim->not_port.notify_req; - struct usb_cdc_notification *event; - int status; - - pr_debug("notify_state: %d\n", mbim->not_port.notify_state); + struct f_mbim *mbim = container_of(w, struct f_mbim, rwake_work.work); + int ret = 0; - if (!req) + if ((mbim->cdev->gadget->speed == USB_SPEED_SUPER) && + !mbim->function.func_is_suspended){ + pr_debug("%s: resume in progress\n", __func__); return; + } - event = req->buf; - - switch (mbim->not_port.notify_state) { + if ((mbim->cdev->gadget->speed == USB_SPEED_SUPER) && + mbim->function.func_is_suspended) + ret = usb_func_wakeup(&mbim->function); + else + ret = usb_gadget_wakeup(mbim->cdev->gadget); - case MBIM_NOTIFY_NONE: - if (atomic_read(&mbim->not_port.notify_count) > 0) - pr_err("Pending notifications in MBIM_NOTIFY_NONE\n"); - else - pr_debug("No pending notifications\n"); + if (ret == -EBUSY || ret == -EAGAIN) + pr_debug("%s:RW delayed due to LPM exit %d\n", __func__, ret); + else + pr_info("%s: remote wake-up failed: %d\n", __func__, ret); +} - return; +/* + * Context: mbim->lock held + */ +static int mbim_do_notify(struct f_mbim *mbim) +{ + struct usb_request *req = mbim->not_port.notify_req; + int status; - case MBIM_NOTIFY_RESPONSE_AVAILABLE: - pr_debug("Notification %02x sent\n", event->bNotificationType); + if (!req) + return 0; - if (atomic_read(&mbim->not_port.notify_count) <= 0) { - pr_debug("notify_response_avaliable: done\n"); - return; - } + if (!atomic_read(&mbim->online)) { + pr_debug("Ignore notify in disconnect state, responses-[%d]\n", + !list_empty(&mbim->cpkt_resp_q)); + return 0; + } - spin_unlock(&mbim->lock); - status = usb_func_ep_queue(&mbim->function, - mbim->not_port.notify, - req, GFP_ATOMIC); - spin_lock(&mbim->lock); - if (status) { - atomic_dec(&mbim->not_port.notify_count); - pr_err("Queue notify request failed, err: %d\n", - status); - } + if (list_empty(&mbim->cpkt_resp_q)) { + pr_debug("ctrl resp queue empty\n"); + return 0; + } - return; + if (mbim->not_port.notify_req_queued) { + pr_debug("notify_req already queued\n"); + return 0; } + mbim->not_port.notify_req_queued = true; - event->bmRequestType = 0xA1; - event->wIndex = cpu_to_le16(mbim->ctrl_id); + pr_debug("Notification sent\n"); - /* - * In double buffering if there is a space in FIFO, - * completion callback can be called right after the call, - * so unlocking - */ - atomic_inc(&mbim->not_port.notify_count); - pr_debug("queue request: notify_count = %d\n", - atomic_read(&mbim->not_port.notify_count)); spin_unlock(&mbim->lock); - status = usb_func_ep_queue(&mbim->function, mbim->not_port.notify, req, - GFP_ATOMIC); + status = usb_func_ep_queue(&mbim->function, mbim->not_port.notify, + req, GFP_ATOMIC); spin_lock(&mbim->lock); if (status) { - atomic_dec(&mbim->not_port.notify_count); - pr_err("usb_func_ep_queue failed, err: %d\n", status); + /* ignore if request already queued before bus_resume */ + if (status != -EBUSY) + mbim->not_port.notify_req_queued = false; + pr_err("Queue notify request failed, err: %d\n", status); } + + return status; } static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req) { - struct f_mbim *mbim = req->context; - struct usb_cdc_notification *event = req->buf; + struct f_mbim *mbim = req->context; - pr_debug("dev:%pK\n", mbim); + pr_debug("dev:%pK, pending:%d\n", mbim, mbim->not_port.notify_pending); spin_lock(&mbim->lock); + mbim->not_port.notify_req_queued = false; switch (req->status) { case 0: - atomic_dec(&mbim->not_port.notify_count); - pr_debug("notify_count = %d\n", - atomic_read(&mbim->not_port.notify_count)); + /* Notify now if send_response completed before it */ + if (mbim->not_port.notify_pending) + mbim_do_notify(mbim); break; case -ECONNRESET: case -ESHUTDOWN: /* connection gone */ - mbim->not_port.notify_state = MBIM_NOTIFY_NONE; - atomic_set(&mbim->not_port.notify_count, 0); pr_info("ESHUTDOWN/ECONNRESET, connection gone\n"); spin_unlock(&mbim->lock); mbim_clear_queues(mbim); @@ -754,10 +754,10 @@ static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&mbim->lock); break; default: - pr_err("Unknown event %02x --> %d\n", - event->bNotificationType, req->status); + pr_err("Unknown status --> %d\n", req->status); break; } + mbim->not_port.notify_pending = false; spin_unlock(&mbim->lock); @@ -872,10 +872,17 @@ static void mbim_response_complete(struct usb_ep *ep, struct usb_request *req) { struct f_mbim *mbim = req->context; - pr_debug("%s: queue notify request if any new response available\n" - , __func__); + pr_debug("%s: queue notify request if any new response available [%d]\n" + , __func__, mbim->not_port.notify_req_queued); + /* + * Some UDCs could report response_complete before nofify_complete. + * Handle this by marking flag and notify from delayed notify_complete. + */ spin_lock(&mbim->lock); - mbim_do_notify(mbim); + if (mbim->not_port.notify_req_queued) + mbim->not_port.notify_pending = true; + else + mbim_do_notify(mbim); spin_unlock(&mbim->lock); } @@ -1234,9 +1241,6 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } notify_ready: mbim->data_interface_up = alt; - spin_lock(&mbim->lock); - mbim->not_port.notify_state = MBIM_NOTIFY_RESPONSE_AVAILABLE; - spin_unlock(&mbim->lock); } else { goto fail; } @@ -1274,6 +1278,8 @@ static void mbim_disable(struct usb_function *f) struct usb_composite_dev *cdev = mbim->cdev; pr_info("SET DEVICE OFFLINE\n"); + + cancel_delayed_work(&mbim->rwake_work); atomic_set(&mbim->online, 0); mbim->remote_wakeup_enabled = 0; @@ -1282,8 +1288,7 @@ static void mbim_disable(struct usb_function *f) usb_ep_disable(mbim->not_port.notify); mbim->not_port.notify->driver_data = NULL; } - atomic_set(&mbim->not_port.notify_count, 0); - mbim->not_port.notify_state = MBIM_NOTIFY_NONE; + mbim->not_port.notify_req_queued = false; mbim_clear_queues(mbim); mbim_reset_function_queue(mbim); @@ -1351,6 +1356,12 @@ static void mbim_suspend(struct usb_function *f) bam_data_suspend(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM, mbim->remote_wakeup_enabled); + + if (mbim->remote_wakeup_enabled && mbim->not_port.notify_req_queued) { + pr_info("%s: pending notification, wakeup host\n", __func__); + schedule_delayed_work(&mbim->rwake_work, + msecs_to_jiffies(2000)); + } } static void mbim_resume(struct usb_function *f) @@ -1370,6 +1381,11 @@ static void mbim_resume(struct usb_function *f) f->func_is_suspended) return; + cancel_delayed_work(&mbim->rwake_work); + + if (!mbim->remote_wakeup_enabled) + atomic_set(&mbim->online, 1); + /* resume control path by queuing notify req */ spin_lock(&mbim->lock); mbim_do_notify(mbim); @@ -1381,9 +1397,6 @@ static void mbim_resume(struct usb_function *f) return; } - if (!mbim->remote_wakeup_enabled) - atomic_set(&mbim->online, 1); - bam_data_resume(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM, mbim->remote_wakeup_enabled); } @@ -1737,6 +1750,7 @@ int mbim_bind_config(struct usb_configuration *c, unsigned portno, INIT_LIST_HEAD(&mbim->cpkt_req_q); INIT_LIST_HEAD(&mbim->cpkt_resp_q); + INIT_DELAYED_WORK(&mbim->rwake_work, mbim_remote_wakeup_work); status = usb_add_function(c, &mbim->function); @@ -1831,6 +1845,7 @@ mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) struct usb_request *req = dev->not_port.notify_req; int ret = 0; unsigned long flags; + bool do_notify = false; pr_debug("Enter(%zu)\n", count); @@ -1856,13 +1871,6 @@ mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) return -EPIPE; } - if (dev->not_port.notify_state != MBIM_NOTIFY_RESPONSE_AVAILABLE) { - pr_err("dev:%pK state=%d error\n", dev, - dev->not_port.notify_state); - mbim_unlock(&dev->write_excl); - return -EINVAL; - } - if (dev->function.func_is_suspended && !dev->function.func_wakeup_allowed) { dev->cpkt_drop_cnt++; @@ -1886,25 +1894,34 @@ mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) } spin_lock_irqsave(&dev->lock, flags); + /* + * If there was no pending response then send notification. + * Otherwise notification would be sent after previous response + * is fetched by host. + */ + if (list_empty(&dev->cpkt_resp_q)) + do_notify = true; list_add_tail(&cpkt->list, &dev->cpkt_resp_q); - if (atomic_inc_return(&dev->not_port.notify_count) != 1) { + if (!do_notify) { pr_debug("delay ep_queue: notifications queue is busy[%d]\n", - atomic_read(&dev->not_port.notify_count)); + dev->not_port.notify_req_queued); spin_unlock_irqrestore(&dev->lock, flags); mbim_unlock(&dev->write_excl); return count; + } + ret = mbim_do_notify(dev); spin_unlock_irqrestore(&dev->lock, flags); - ret = usb_func_ep_queue(&dev->function, dev->not_port.notify, - req, GFP_ATOMIC); - if (ret == -ENOTSUPP || (ret < 0 && ret != -EAGAIN)) { + if (ret < 0 && ret != -EAGAIN && ret != -EBUSY) { spin_lock_irqsave(&dev->lock, flags); - /* check if device disconnected while we dropped lock */ + /* + * cpkt already freed if device disconnected while we + * dropped lock. Nothing to be done in that case. + */ if (atomic_read(&dev->online)) { list_del(&cpkt->list); - atomic_dec(&dev->not_port.notify_count); mbim_free_ctrl_pkt(cpkt); } dev->cpkt_drop_cnt++; @@ -2010,7 +2027,7 @@ static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg) * This channel number 8 should be in sync with * the one defined in u_bam.c. */ - info.ph_ep_info.ep_type = DATA_EP_TYPE_BAM_DMUX; + info.ph_ep_info.ep_type = MBIM_DATA_EP_TYPE_BAM_DMUX; info.ph_ep_info.peripheral_iface_id = BAM_DMUX_CHANNEL_ID; info.ipa_ep_pair.cons_pipe_num = 0; @@ -2025,7 +2042,7 @@ static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg) break; } - info.ph_ep_info.ep_type = DATA_EP_TYPE_HSUSB; + info.ph_ep_info.ep_type = MBIM_DATA_EP_TYPE_HSUSB; info.ph_ep_info.peripheral_iface_id = mbim->data_id; info.ipa_ep_pair.cons_pipe_num = port->ipa_consumer_ep; info.ipa_ep_pair.prod_pipe_num = port->ipa_producer_ep; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 46839f01e7690640131fda4a5d3b4806ff887a4d..bc2663d3c6c8d073ff7b67b9aa289892a73fcb46 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -215,12 +215,6 @@ static inline struct usb_request *midi_alloc_ep_req(struct usb_ep *ep, return alloc_ep_req(ep, length, length); } -static void midi_free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - static const uint8_t f_midi_cin_length[] = { 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 }; @@ -286,7 +280,7 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req) if (ep == midi->out_ep) f_midi_handle_out_data(ep, req); - midi_free_ep_req(ep, req); + free_ep_req(ep, req); return; case -EOVERFLOW: /* buffer overrun on read means that @@ -585,7 +579,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) if (req->length > 0) usb_ep_queue(ep, req, GFP_ATOMIC); else - midi_free_ep_req(ep, req); + free_ep_req(ep, req); } static void f_midi_in_tasklet(unsigned long data) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 14c09760a505df212f72655f7e1c070b24c4b3cf..a0d8fd793b3b4993a1a9d93192124db013046d1c 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -176,12 +176,22 @@ static struct usb_descriptor_header *qdss_ss_data_only_desc[] = { }; /* string descriptors: */ -#define QDSS_DATA_IDX 0 -#define QDSS_CTRL_IDX 1 +#define QDSS_DATA_IDX 0 +#define QDSS_CTRL_IDX 1 +#define MSM_QDSS_DATA_IDX 2 +#define MSM_QDSS_CTRL_IDX 3 +#define MDM_QDSS_DATA_IDX 4 +#define MDM_QDSS_CTRL_IDX 5 +#define DPL_DATA_IDX 6 static struct usb_string qdss_string_defs[] = { - [QDSS_DATA_IDX].s = "QDSS DATA", - [QDSS_CTRL_IDX].s = "QDSS CTRL", + [QDSS_DATA_IDX].s = "QDSS Data", + [QDSS_CTRL_IDX].s = "QDSS Control", + [MSM_QDSS_DATA_IDX].s = "MSM QDSS Data", + [MSM_QDSS_CTRL_IDX].s = "MSM QDSS Control", + [MDM_QDSS_DATA_IDX].s = "MDM QDSS Data", + [MDM_QDSS_CTRL_IDX].s = "MDM QDSS Control", + [DPL_DATA_IDX].s = "DPL Data", {}, /* end of list */ }; @@ -990,6 +1000,7 @@ static int qdss_bind_config(struct usb_configuration *c, unsigned char portno) char *name; enum transport_type dxport; struct usb_function *f; + int str_data_id, str_ctrl_id; dxport = qdss_ports[portno].data_xport; @@ -1001,17 +1012,30 @@ static int qdss_bind_config(struct usb_configuration *c, unsigned char portno) } qdss = qdss_ports[portno].port; - if (qdss_string_defs[QDSS_DATA_IDX].id == 0) { + str_data_id = QDSS_DATA_IDX; + str_ctrl_id = QDSS_CTRL_IDX; + + if (dxport == USB_GADGET_XPORT_BAM2BAM) { + str_data_id = MSM_QDSS_DATA_IDX; + str_ctrl_id = MSM_QDSS_CTRL_IDX; + } else if (dxport == USB_GADGET_XPORT_PCIE) { + str_data_id = MDM_QDSS_DATA_IDX; + str_ctrl_id = MDM_QDSS_CTRL_IDX; + } else if (dxport == USB_GADGET_XPORT_ETHER) { + str_data_id = DPL_DATA_IDX; + } + + if (qdss_string_defs[str_data_id].id == 0) { status = usb_string_id(c->cdev); if (status < 0) return status; - qdss_string_defs[QDSS_DATA_IDX].id = status; + qdss_string_defs[str_data_id].id = status; qdss_data_intf_desc.iInterface = status; if (qdss->debug_inface_enabled) { status = usb_string_id(c->cdev); if (status < 0) return status; - qdss_string_defs[QDSS_CTRL_IDX].id = status; + qdss_string_defs[str_ctrl_id].id = status; qdss_ctrl_intf_desc.iInterface = status; } } diff --git a/drivers/usb/gadget/function/f_rmnet.c b/drivers/usb/gadget/function/f_rmnet.c index e9def8aff9d110c5ddc684d5e45c954edcd021a5..e946cfae82966a06eaeffe3d4ae863e43888cefa 100644 --- a/drivers/usb/gadget/function/f_rmnet.c +++ b/drivers/usb/gadget/function/f_rmnet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * 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 @@ -611,7 +611,7 @@ static void frmnet_suspend(struct usb_function *f) __func__, xport_to_str(dxport), dev, dev->port_num, remote_wakeup_allowed); - usb_ep_fifo_flush(dev->notify); + usb_ep_dequeue(dev->notify, dev->notify_req); frmnet_purge_responses(dev); port_num = rmnet_ports[dev->port_num].data_xport_num; @@ -921,7 +921,7 @@ static void frmnet_disconnect(struct grmnet *gr) return; } - usb_ep_fifo_flush(dev->notify); + usb_ep_dequeue(dev->notify, dev->notify_req); event = dev->notify_req->buf; event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 80be25b32cd7a82f2dbc9d57e4b370bb86a9bad0..45b41d1cfd19d42005edf3d285a641a73eed41f9 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -435,12 +435,6 @@ static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len) return alloc_ep_req(ep, len, buflen); } -void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) { int value; diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index cfbb77bc64a9b98239bd52ba8ab6ded1cabe983c..474ed80ba41ddbf1c370636429352b59e2f1c602 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -690,6 +690,18 @@ static struct usb_gadget_strings *fn_strings[] = { NULL, }; +static struct usb_qualifier_descriptor devqual_desc = { + .bLength = sizeof devqual_desc, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + + .bcdUSB = cpu_to_le16(0x200), + .bDeviceClass = USB_CLASS_MISC, + .bDeviceSubClass = 0x02, + .bDeviceProtocol = 0x01, + .bNumConfigurations = 1, + .bRESERVED = 0, +}; + static struct usb_interface_assoc_descriptor iad_desc = { .bLength = sizeof iad_desc, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 80c4f51ae175425bcf041a1a001c6ff75d6364e3..9affc4dd9149108fcd7cbcf06731aca2a61218c1 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -64,6 +64,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = { #define UVC_INTF_VIDEO_STREAMING 1 #define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */ +#define UVC_STREAMING_SS_MAX_PACKET_SIZE 1024 static struct usb_interface_assoc_descriptor uvc_iad = { .bLength = sizeof(uvc_iad), @@ -640,13 +641,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11)); uvc_hs_streaming_ep.bInterval = opts->streaming_interval; - uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size); + uvc_ss_streaming_ep.wMaxPacketSize = + UVC_STREAMING_SS_MAX_PACKET_SIZE; uvc_ss_streaming_ep.bInterval = opts->streaming_interval; - uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1; + uvc_ss_streaming_comp.bmAttributes = 0; uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst; uvc_ss_streaming_comp.wBytesPerInterval = - cpu_to_le16(max_packet_size * max_packet_mult * - opts->streaming_maxburst); + cpu_to_le16(UVC_STREAMING_SS_MAX_PACKET_SIZE * 1 * + (opts->streaming_maxburst + 1)); /* Allocate endpoints. */ ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h index 2ce28b9d97cc81a519cff3adb6e07fa89aeb9e2a..287607d607ed8d8eb8c0a64e1e38f813ff6ccc85 100644 --- a/drivers/usb/gadget/function/g_zero.h +++ b/drivers/usb/gadget/function/g_zero.h @@ -69,7 +69,6 @@ void lb_modexit(void); int lb_modinit(void); /* common utilities */ -void free_ep_req(struct usb_ep *ep, struct usb_request *req); void disable_endpoints(struct usb_composite_dev *cdev, struct usb_ep *in, struct usb_ep *out, struct usb_ep *iso_in, struct usb_ep *iso_out, diff --git a/drivers/usb/gadget/function/u_bam.c b/drivers/usb/gadget/function/u_bam.c index 4ae5811fb2b0e75d23d9502e44eb73edd0b74e23..166804e126edf11590226da736638868c6a364f4 100644 --- a/drivers/usb/gadget/function/u_bam.c +++ b/drivers/usb/gadget/function/u_bam.c @@ -285,7 +285,7 @@ static struct sk_buff *gbam_alloc_skb_from_pool(struct gbam_port *port) skb_reserve(skb, BAM_MUX_HDR); - if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { + if ((d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)) { gadget = port->port_usb->gadget; diff --git a/drivers/usb/gadget/function/u_bam_data.c b/drivers/usb/gadget/function/u_bam_data.c index c9bfb47631907c7c04795c639b7aca9ea7d2a709..81fd92149b17434b02b35772f2c29b8b6b5bafb6 100644 --- a/drivers/usb/gadget/function/u_bam_data.c +++ b/drivers/usb/gadget/function/u_bam_data.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * 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 @@ -775,6 +775,13 @@ static void bam2bam_data_disconnect_work(struct work_struct *w) return; } + if (port->last_event == U_BAM_DATA_CONNECT_E) { + pr_debug("%s: Port is about to connect. Bail out.\n", + __func__); + spin_unlock_irqrestore(&port->port_lock, flags); + return; + } + d = &port->data_ch; /* diff --git a/drivers/usb/gadget/function/u_ctrl_hsic.c b/drivers/usb/gadget/function/u_ctrl_hsic.c index 84de3f3e191d000fe5c74341295856e8c2716e5f..6a12422760d96bd74790e7c7e8470045644d2d0a 100644 --- a/drivers/usb/gadget/function/u_ctrl_hsic.c +++ b/drivers/usb/gadget/function/u_ctrl_hsic.c @@ -542,11 +542,9 @@ int ghsic_ctrl_setup(unsigned int num_ports, enum gadget_type gtype) return first_port_id; free_ports: - for (i = first_port_id; i < no_ctrl_ports; i++) { + for (i = first_port_id; i < no_ctrl_ports; i++) ghsic_ctrl_port_free(i); no_ctrl_ports = first_port_id; - } - return ret; } diff --git a/drivers/usb/gadget/function/u_data_hsic.c b/drivers/usb/gadget/function/u_data_hsic.c index 462f15448cd0bae57030b617e9afd8ad02e928c5..403f8ffbf226592671faa875cc8da6a9912ab9e8 100644 --- a/drivers/usb/gadget/function/u_data_hsic.c +++ b/drivers/usb/gadget/function/u_data_hsic.c @@ -1194,10 +1194,9 @@ int ghsic_data_setup(unsigned num_ports, enum gadget_type gtype) return first_port_id; free_ports: - for (i = first_port_id; i < no_data_ports; i++) { + for (i = first_port_id; i < no_data_ports; i++) ghsic_data_port_free(i); no_data_ports = first_port_id; - } return ret; } diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index a240e5530cf3476bddf87e82bf68a55a027932ec..fbf3cd19ee63ef3ae82f7a9a21605f1e5933db9b 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -760,7 +760,8 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) dev->tx_aggr_cnt[n-1]++; /* sg_ctx is only accessible here, can use lock-free version */ - __skb_queue_purge(&sg_ctx->skbs); + while ((skb = __skb_dequeue(&sg_ctx->skbs)) != NULL) + dev_kfree_skb_any(skb); } dev->net->stats.tx_packets += n; @@ -1941,7 +1942,7 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) return -EINVAL; dev = netdev_priv(net); - snprintf(host_addr, len, "%pM", dev->host_mac); + snprintf(host_addr, len, "%pm", dev->host_mac); return strlen(host_addr); } diff --git a/drivers/usb/gadget/function/u_f.h b/drivers/usb/gadget/function/u_f.h deleted file mode 100644 index 1d5f0eb685521c3a3ce6942571b78413161c54ef..0000000000000000000000000000000000000000 --- a/drivers/usb/gadget/function/u_f.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * u_f.h - * - * Utility definitions for USB functions - * - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Author: Andrzej Pietrasiewicz - * - * 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 __U_F_H__ -#define __U_F_H__ - -/* Variable Length Array Macros **********************************************/ -#define vla_group(groupname) size_t groupname##__next = 0 -#define vla_group_size(groupname) groupname##__next - -#define vla_item(groupname, type, name, n) \ - size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = (n) * sizeof(type); \ - groupname##__next = offset + size; \ - offset; \ - }) - -#define vla_item_with_sz(groupname, type, name, n) \ - size_t groupname##_##name##__sz = (n) * sizeof(type); \ - size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = groupname##_##name##__sz; \ - groupname##__next = offset + size; \ - offset; \ - }) - -#define vla_ptr(ptr, groupname, name) \ - ((void *) ((char *)ptr + groupname##_##name##__offset)) - -struct usb_ep; -struct usb_request; - -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len); - -#endif /* __U_F_H__ */ - - diff --git a/drivers/usb/gadget/function/u_glink.c b/drivers/usb/gadget/function/u_glink.c index 5161a0bee3d6e8fd95ce76ec9946a47f51f7f77a..20ac0c8db33ae6e5ee11e847023ecb45cce30912 100644 --- a/drivers/usb/gadget/function/u_glink.c +++ b/drivers/usb/gadget/function/u_glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, Linux Foundation. All rights reserved. * * 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 @@ -450,9 +450,11 @@ void glink_ctrl_disconnect(struct grmnet *gr, u8 client_num) } spin_lock_irqsave(&ch_info->port_lock, flags); - ch_info->port->send_encap_cmd = 0; - ch_info->port->notify_modem = 0; - ch_info->port = 0; + if (ch_info->port) { + ch_info->port->send_encap_cmd = 0; + ch_info->port->notify_modem = 0; + ch_info->port = 0; + } glink_purge_tx_q(ch_info); spin_unlock_irqrestore(&ch_info->port_lock, flags); diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 1a1e3c0725804c66bdaef92136953879b163a17b..008c5262a8ec116c96dba20276c50220b2eecec8 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -4,7 +4,7 @@ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) * Copyright (C) 2008 David Brownell * Copyright (C) 2008 by Nokia Corporation - * Copyright (c) 2013-2015, 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. * * This code also borrows from usbserial.c, which is * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) @@ -517,10 +517,11 @@ __acquires(&port->port_lock) /* * If port_usb is NULL, gserial disconnect is called * while the spinlock is dropped and all requests are - * freed. + * freed. Free the current request here. */ if (!port->port_usb) { started = 0; + gs_free_req(out, req); break; } if (status) { diff --git a/drivers/usb/gadget/function/u_smd.c b/drivers/usb/gadget/function/u_smd.c index 18b71ffd0045766dcdc77ca9f46457ee512a07cd..20df9340dd364630cf6bb0a6c9e75fa7e71896dd 100644 --- a/drivers/usb/gadget/function/u_smd.c +++ b/drivers/usb/gadget/function/u_smd.c @@ -295,6 +295,21 @@ static void gsmd_read_pending(struct gsmd_port *port) return; } +static inline bool gsmd_remote_wakeup_allowed(struct usb_function *f) +{ + bool remote_wakeup_allowed; + + if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) + remote_wakeup_allowed = f->func_wakeup_allowed; + else + remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; + + pr_debug("%s: remote_wakeup_allowed:%s", __func__, + remote_wakeup_allowed ? "true" : "false"); + + return remote_wakeup_allowed; +} + static void gsmd_tx_pull(struct work_struct *w) { struct gsmd_port *port = container_of(w, struct gsmd_port, pull); @@ -320,6 +335,13 @@ static void gsmd_tx_pull(struct work_struct *w) in = port->port_usb->in; func = &port->port_usb->func; gadget = func->config->cdev->gadget; + + /* Bail-out is suspended without remote-wakeup enable */ + if (port->is_suspended && !gsmd_remote_wakeup_allowed(func)) { + spin_unlock_irq(&port->port_lock); + return; + } + if (port->is_suspended) { spin_unlock_irq(&port->port_lock); if ((gadget->speed == USB_SPEED_SUPER) && @@ -379,8 +401,8 @@ static void gsmd_tx_pull(struct work_struct *w) } tx_pull_end: - /* TBD: Check how code behaves on USB bus suspend */ - if (port->port_usb && smd_read_avail(port->pi->ch) && !list_empty(pool)) + if (port->port_usb && port->pi->ch && smd_read_avail(port->pi->ch) && + !list_empty(pool)) queue_work(gsmd_wq, &port->pull); spin_unlock_irq(&port->port_lock); @@ -402,8 +424,8 @@ static void gsmd_read_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&port->port_lock); if (!test_bit(CH_OPENED, &port->pi->flags) || req->status == -ESHUTDOWN) { + list_add_tail(&req->list, &port->read_pool); spin_unlock(&port->port_lock); - gsmd_free_req(ep, req); return; } @@ -428,8 +450,8 @@ static void gsmd_write_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&port->port_lock); if (!test_bit(CH_OPENED, &port->pi->flags) || req->status == -ESHUTDOWN) { + list_add(&req->list, &port->write_pool); spin_unlock(&port->port_lock); - gsmd_free_req(ep, req); return; } @@ -447,46 +469,21 @@ static void gsmd_write_complete(struct usb_ep *ep, struct usb_request *req) static void gsmd_start_io(struct gsmd_port *port) { - int ret = -ENODEV; - pr_debug("%s: port: %pK\n", __func__, port); spin_lock(&port->port_lock); - if (!port->port_usb) - goto start_io_out; + if (!port->port_usb) { + spin_unlock(&port->port_lock); + return; + } smd_tiocmset_from_cb(port->pi->ch, port->cbits_to_modem, ~port->cbits_to_modem); - ret = gsmd_alloc_requests(port->port_usb->out, - &port->read_pool, - SMD_RX_QUEUE_SIZE, SMD_RX_BUF_SIZE, 0, - gsmd_read_complete); - if (ret) { - pr_err("%s: unable to allocate out requests\n", - __func__); - goto start_io_out; - } - - ret = gsmd_alloc_requests(port->port_usb->in, - &port->write_pool, - SMD_TX_QUEUE_SIZE, SMD_TX_BUF_SIZE, extra_sz, - gsmd_write_complete); - if (ret) { - gsmd_free_requests(port->port_usb->out, &port->read_pool); - pr_err("%s: unable to allocate IN requests\n", - __func__); - goto start_io_out; - } - -start_io_out: spin_unlock(&port->port_lock); - if (ret) - return; - gsmd_start_rx(port); } @@ -530,6 +527,7 @@ static void gsmd_stop_io(struct gsmd_port *port) struct usb_ep *in; struct usb_ep *out; unsigned long flags; + struct list_head *q; spin_lock_irqsave(&port->port_lock, flags); if (!port->port_usb) { @@ -544,17 +542,22 @@ static void gsmd_stop_io(struct gsmd_port *port) usb_ep_fifo_flush(out); spin_lock(&port->port_lock); - if (port->port_usb) { - gsmd_free_requests(out, &port->read_pool); - gsmd_free_requests(out, &port->read_queue); - gsmd_free_requests(in, &port->write_pool); - port->n_read = 0; - port->cbits_to_laptop = 0; - } else { + if (!port->port_usb) { spin_unlock(&port->port_lock); return; } + q = &port->read_queue; + while (!list_empty(q)) { + struct usb_request *req; + + req = list_first_entry(q, struct usb_request, list); + list_move(&req->list, &port->read_pool); + } + + port->n_read = 0; + port->cbits_to_laptop = 0; + if (port->port_usb->send_modem_ctrl_bits) port->port_usb->send_modem_ctrl_bits( port->port_usb, @@ -723,14 +726,36 @@ int gsmd_connect(struct gserial *gser, u8 portno) port->nbytes_tomodem = 0; port->nbytes_tolaptop = 0; port->is_suspended = false; + ret = gsmd_alloc_requests(port->port_usb->out, + &port->read_pool, + SMD_RX_QUEUE_SIZE, SMD_RX_BUF_SIZE, 0, + gsmd_read_complete); + if (ret) { + pr_err("%s: unable to allocate out requests\n", + __func__); + spin_unlock_irqrestore(&port->port_lock, flags); + return ret; + } + + ret = gsmd_alloc_requests(port->port_usb->in, + &port->write_pool, + SMD_TX_QUEUE_SIZE, SMD_TX_BUF_SIZE, extra_sz, + gsmd_write_complete); + if (ret) { + gsmd_free_requests(port->port_usb->out, &port->read_pool); + pr_err("%s: unable to allocate IN requests\n", + __func__); + spin_unlock_irqrestore(&port->port_lock, flags); + return ret; + } + spin_unlock_irqrestore(&port->port_lock, flags); ret = usb_ep_enable(gser->in); if (ret) { pr_err("%s: usb_ep_enable failed eptype:IN ep:%pK, err:%d", __func__, gser->in, ret); - port->port_usb = 0; - return ret; + goto free_req; } gser->in->driver_data = port; @@ -738,15 +763,23 @@ int gsmd_connect(struct gserial *gser, u8 portno) if (ret) { pr_err("%s: usb_ep_enable failed eptype:OUT ep:%pK, err: %d", __func__, gser->out, ret); - port->port_usb = 0; gser->in->driver_data = 0; - return ret; + goto free_req; } gser->out->driver_data = port; queue_delayed_work(gsmd_wq, &port->connect_work, msecs_to_jiffies(0)); return 0; + +free_req: + spin_lock_irqsave(&port->port_lock, flags); + gsmd_free_requests(port->port_usb->out, &port->write_pool); + gsmd_free_requests(port->port_usb->out, &port->read_pool); + port->port_usb = 0; + spin_unlock_irqrestore(&port->port_lock, flags); + + return ret; } void gsmd_disconnect(struct gserial *gser, u8 portno) @@ -1063,6 +1096,7 @@ void gsmd_resume(struct gserial *gser, u8 portno) port->is_suspended = false; spin_unlock(&port->port_lock); queue_work(gsmd_wq, &port->pull); + queue_work(gsmd_wq, &port->push); } void gsmd_cleanup(struct usb_gadget *g, unsigned count) diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 96d3f39441c9aace9818b924f0f249d1acc59963..3d615e4f0e8998391cd6c48a29f4071134811b2d 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -28,7 +28,7 @@ module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); \ MODULE_PARM_DESC(streaming_maxpacket, "1-1023 (FS), 1-3072 (hs/ss)"); \ \ - static unsigned int streaming_maxburst; \ + static unsigned int streaming_maxburst = 2; \ module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); \ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)"); \ \ diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index c6276f0268ae51e0b9669db69ebbb58c46e794ba..4bc7eea8bfc84d0c941b8ba7ec743e1db313db97 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -11,7 +11,6 @@ * published by the Free Software Foundation. */ -#include #include "u_f.h" struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len) diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 1d5f0eb685521c3a3ce6942571b78413161c54ef..cfc1b9ddca0c14a30a81c404864c020a621ce2f9 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -16,6 +16,8 @@ #ifndef __U_F_H__ #define __U_F_H__ +#include + /* Variable Length Array Macros **********************************************/ #define vla_group(groupname) size_t groupname##__next = 0 #define vla_group_size(groupname) groupname##__next @@ -45,8 +47,12 @@ struct usb_ep; struct usb_request; +/* Requests allocated via alloc_ep_req() must be freed by free_ep_req(). */ struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len); +static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req) +{ + kfree(req->buf); + usb_ep_free_request(ep, req); +} #endif /* __U_F_H__ */ - - diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c index 5948a90c298519e0b38d9a01a846ae303806ce1c..c7d2d5c689cceff8ec458a96d74fdf362e952598 100644 --- a/drivers/usb/host/ehci-msm-hsic.c +++ b/drivers/usb/host/ehci-msm-hsic.c @@ -1,6 +1,6 @@ /* ehci-msm-hsic.c - HSUSB Host Controller Driver Implementation * - * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * Partly derived from ehci-fsl.c and ehci-hcd.c * Copyright (c) 2000-2004 by David Brownell @@ -98,6 +98,7 @@ struct msm_hsic_hcd { uint32_t bus_perf_client; uint32_t wakeup_int_cnt; + struct work_struct runtime_pm_allow_w; struct work_struct bus_vote_w; bool bus_vote; @@ -1026,6 +1027,16 @@ skip_phy_resume: } #endif +static void ehci_hsic_runtime_pm_allow_w(struct work_struct *w) +{ + struct msm_hsic_hcd *mehci = + container_of(w, struct msm_hsic_hcd, runtime_pm_allow_w); + struct usb_hcd *hcd = hsic_to_hcd(mehci); + + pr_debug("enable runtime PM for HSIC rhub\n"); + pm_runtime_allow(&hcd->self.root_hub->dev); +} + static void ehci_hsic_bus_vote_w(struct work_struct *w) { struct msm_hsic_hcd *mehci = @@ -1066,6 +1077,7 @@ static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd) struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); u32 status; int ret; + static bool runtime_pm_enabled; if (atomic_read(&mehci->in_lpm)) { dev_dbg(mehci->dev, "phy async intr\n"); @@ -1115,6 +1127,13 @@ static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd) ehci_writel(ehci, STS_GPTIMER0_INTERRUPT, &ehci->regs->status); } + /* Allow RuntimePM if device connected */ + if (!runtime_pm_enabled && (readl_relaxed(USB_PORTSC) & PORT_PE)) { + pr_debug("queue runtime_pm allow work\n"); + queue_work(ehci_wq, &mehci->runtime_pm_allow_w); + runtime_pm_enabled = true; + } + return ehci_irq(hcd); } @@ -2159,6 +2178,7 @@ static int ehci_hsic_msm_probe(struct platform_device *pdev) } INIT_WORK(&mehci->bus_vote_w, ehci_hsic_bus_vote_w); + INIT_WORK(&mehci->runtime_pm_allow_w, ehci_hsic_runtime_pm_allow_w); ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); if (ret) { @@ -2166,6 +2186,9 @@ static int ehci_hsic_msm_probe(struct platform_device *pdev) goto destroy_wq; } + /* RuntimePM will be disabled until HSIC device connects */ + pm_runtime_forbid(&hcd->self.root_hub->dev); + /* Check whether target uses pinctrl */ mehci->hsic_pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR(mehci->hsic_pinctrl)) { @@ -2306,6 +2329,8 @@ static int ehci_hsic_msm_remove(struct platform_device *pdev) if (pdata && pdata->consider_ipa_handshake) msm_bam_set_hsic_host_dev(NULL); + cancel_work_sync(&mehci->runtime_pm_allow_w); + /* If the device was removed no need to call pm_runtime_disable */ if (pdev->dev.power.power_state.event != PM_EVENT_INVALID) pm_runtime_disable(&pdev->dev); @@ -2318,6 +2343,9 @@ static int ehci_hsic_msm_remove(struct platform_device *pdev) /* Remove the HCD prior to releasing our resources. */ usb_remove_hcd(hcd); + /* Disable HSIC mode in HSIC_CFG register */ + ulpi_write(mehci, 0x0, 0x30); + if (pdata && pdata->standalone_latency) pm_qos_remove_request(&mehci->pm_qos_req_dma); diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 1db0626c8bf415289fd7e8f0875e15e4aeff404e..97750f162f0123fc6bc508a615a59ecb039a371e 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -654,7 +654,7 @@ static int hwahc_security_create(struct hwahc *hwahc) top = itr + itr_size; result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index], le16_to_cpu(usb_dev->actconfig->desc.wTotalLength), - USB_DT_SECURITY, (void **) &secd); + USB_DT_SECURITY, (void **) &secd, sizeof(*secd)); if (result == -1) { dev_warn(dev, "BUG? WUSB host has no security descriptors\n"); return 0; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0afcc33a4d7fd318bba90001a2d1dee6c541e7ab..083aaa95b049278104d78f29486c7b3d5fd47fc1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2681,7 +2681,8 @@ hw_died: writel(irq_pending, &xhci->ir_set->irq_pending); } - if (xhci->xhc_state & XHCI_STATE_DYING) { + if (xhci->xhc_state & XHCI_STATE_DYING || + xhci->xhc_state & XHCI_STATE_HALTED) { xhci_dbg(xhci, "xHCI dying, ignoring interrupt. " "Shouldn't IRQs be disabled?\n"); /* Clear the event handler busy flag (RW1C); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index abe3d390b62b1be510773647cfa1ea4c0f1f882c..7b26b0720e8359b21933927f618221010d847e6d 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -676,15 +676,6 @@ int xhci_run(struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(xhci_run); -static void xhci_only_stop_hcd(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - spin_lock_irq(&xhci->lock); - xhci_halt(xhci); - spin_unlock_irq(&xhci->lock); -} - /* * Stop xHCI driver. * @@ -701,20 +692,22 @@ void xhci_stop(struct usb_hcd *hcd) mutex_lock(&xhci->mutex); + if (!(xhci->xhc_state & XHCI_STATE_HALTED)) { + spin_lock_irq(&xhci->lock); + + xhci->xhc_state |= XHCI_STATE_HALTED; + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + xhci_halt(xhci); + xhci_reset(xhci); + + spin_unlock_irq(&xhci->lock); + } + if (!usb_hcd_is_primary_hcd(hcd)) { - xhci_only_stop_hcd(xhci->shared_hcd); mutex_unlock(&xhci->mutex); return; } - spin_lock_irq(&xhci->lock); - /* Make sure the xHC is halted for a USB3 roothub - * (xhci_stop() could be called as part of failed init). - */ - xhci_halt(xhci); - xhci_reset(xhci); - spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); /* Deleting Compliance Mode Recovery Timer */ diff --git a/drivers/usb/phy/otg-wakelock.c b/drivers/usb/phy/otg-wakelock.c index 12528f4e9d99b3341973027fc3bbd874e10250f8..479376bfa484bd73edc76a7cae115c37d4e729ae 100644 --- a/drivers/usb/phy/otg-wakelock.c +++ b/drivers/usb/phy/otg-wakelock.c @@ -23,7 +23,7 @@ #include #include -#define TEMPORARY_HOLD_TIME 1000 +#define TEMPORARY_HOLD_TIME 2000 static bool enabled = true; static struct usb_phy *otgwl_xceiv; diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index 59052aeda020c06c6b04a69dd3f7f9c51bdbec22..fea732770f8281b4f7f640715ad8dcf7bba3739f 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017,2019, The Linux Foundation. All rights reserved. * * 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 @@ -1048,7 +1048,12 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) /* Make sure that above write is completed */ wmb(); - qusb_phy_enable_clocks(qphy, false); + /* Do not disable clocks if there is vote for it */ + if (!qphy->rm_pulldown) + qusb_phy_enable_clocks(qphy, false); + else + dev_dbg(phy->dev, "race with rm_pulldown. Keep clocks ON\n"); + qusb_phy_update_tcsr_level_shifter(qphy, 0x0); /* Do not disable power rails if there is vote for it */ if (!qphy->rm_pulldown) diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 20280e8b0eabd7143b149488370c0995ef59cfe8..df319b78f4d83e0e97e24f1e321d368acfb32321 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1470,6 +1470,7 @@ phcd_retry: if (motg->lpm_flags & PHY_RETENTIONED || (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) { + regulator_disable(hsusb_vdd); msm_hsusb_config_vddcx(0); } @@ -1552,6 +1553,8 @@ static int msm_otg_resume(struct msm_otg *motg) } disable_irq(motg->irq); + if (motg->phy_irq) + disable_irq(motg->phy_irq); wake_lock(&motg->wlock); /* @@ -1595,6 +1598,8 @@ static int msm_otg_resume(struct msm_otg *motg) if (motg->lpm_flags & PHY_RETENTIONED || (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) { msm_hsusb_config_vddcx(1); + ret = regulator_enable(hsusb_vdd); + WARN(ret, "hsusb_vdd LDO enable failed\n"); msm_otg_disable_phy_hv_int(motg); msm_otg_exit_phy_retention(motg); motg->lpm_flags &= ~PHY_RETENTIONED; @@ -1677,6 +1682,8 @@ skip_phy_resume: enable_irq(motg->async_int); motg->async_int = 0; } + if (motg->phy_irq) + enable_irq(motg->phy_irq); enable_irq(motg->irq); /* Enable ASYNC_IRQ only during LPM */ @@ -1975,6 +1982,8 @@ static void msm_otg_start_host(struct usb_otg *otg, int on) msm_otg_perf_vote_update(motg, false); pm_qos_remove_request(&motg->pm_qos_req_dma); + pm_runtime_disable(&hcd->self.root_hub->dev); + pm_runtime_barrier(&hcd->self.root_hub->dev); usb_remove_hcd(hcd); msm_otg_reset(&motg->phy); @@ -2926,10 +2935,10 @@ static void msm_otg_sm_work(struct work_struct *w) msm_otg_start_peripheral(otg, 0); msm_otg_dbg_log_event(&motg->phy, "RT PM: B_PERI A PUT", get_pm_runtime_counter(dev), 0); - /* _put for _get done on cable connect in B_IDLE */ - pm_runtime_put_noidle(dev); /* Schedule work to finish cable disconnect processing*/ otg->phy->state = OTG_STATE_B_IDLE; + /* _put for _get done on cable connect in B_IDLE */ + pm_runtime_put_noidle(dev); work = 1; } else if (test_bit(A_BUS_SUSPEND, &motg->inputs)) { pr_debug("a_bus_suspend\n"); diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c index e75bbe5a10cd23f9d5eba2a8ff839ea13747a175..e9ff710a3d12d7b8501e2c6d328bc771286cac55 100644 --- a/drivers/uwb/hwa-rc.c +++ b/drivers/uwb/hwa-rc.c @@ -827,6 +827,8 @@ static int hwarc_probe(struct usb_interface *iface, if (iface->cur_altsetting->desc.bNumEndpoints < 1) return -ENODEV; + if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc)) + return -ENODEV; result = -ENOMEM; uwb_rc = uwb_rc_alloc(); @@ -873,6 +875,7 @@ error_get_version: error_rc_add: usb_put_intf(iface); usb_put_dev(hwarc->usb_dev); + kfree(hwarc); error_alloc: uwb_rc_put(uwb_rc); error_rc_alloc: diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c index bdcb13cc1d541312cd62b2320964e3fe22fb6635..5c982837021710ebf2ff52cbbce8ff769a4bb507 100644 --- a/drivers/uwb/uwbd.c +++ b/drivers/uwb/uwbd.c @@ -303,18 +303,22 @@ static int uwbd(void *param) /** Start the UWB daemon */ void uwbd_start(struct uwb_rc *rc) { - rc->uwbd.task = kthread_run(uwbd, rc, "uwbd"); - if (rc->uwbd.task == NULL) + struct task_struct *task = kthread_run(uwbd, rc, "uwbd"); + if (IS_ERR(task)) { + rc->uwbd.task = NULL; printk(KERN_ERR "UWB: Cannot start management daemon; " "UWB won't work\n"); - else + } else { + rc->uwbd.task = task; rc->uwbd.pid = rc->uwbd.task->pid; + } } /* Stop the UWB daemon and free any unprocessed events */ void uwbd_stop(struct uwb_rc *rc) { - kthread_stop(rc->uwbd.task); + if (rc->uwbd.task) + kthread_stop(rc->uwbd.task); uwbd_flush(rc); } diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 8dae2f724a35ebfe811864a8c5c428280cfd2a76..f544cfaa0a105ce3c8c0f38889d4928730c224f5 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -983,7 +983,8 @@ err_used: if (ubufs) vhost_net_ubuf_put_wait_and_free(ubufs); err_ubufs: - sockfd_put(sock); + if (sock) + sockfd_put(sock); err_vq: mutex_unlock(&vq->mutex); err: @@ -1009,6 +1010,7 @@ static long vhost_net_reset_owner(struct vhost_net *n) } vhost_net_stop(n, &tx_sock, &rx_sock); vhost_net_flush(n); + vhost_dev_stop(&n->dev); vhost_dev_reset_owner(&n->dev, memory); vhost_net_vq_reset(n); done: diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 1fe2c8115be034078da4ca929ae78e2545aa950d..1d7b0a9508609b7f1e6c88e697571da45feee887 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -96,8 +96,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file) if (mask) vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask); if (mask & POLLERR) { - if (poll->wqh) - remove_wait_queue(poll->wqh, &poll->wait); + vhost_poll_stop(poll); ret = -EINVAL; } diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index dd88ba1d71ceb64849535542a8cb3289d89df4c1..35373e2065b2ca46baae953125490fc4ed984a01 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -332,10 +332,18 @@ static int adp5520_bl_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, bl); - ret |= adp5520_bl_setup(bl); + ret = adp5520_bl_setup(bl); + if (ret) { + dev_err(&pdev->dev, "failed to setup\n"); + if (data->pdata->en_ambl_sens) + sysfs_remove_group(&bl->dev.kobj, + &adp5520_bl_attr_group); + return ret; + } + backlight_update_status(bl); - return ret; + return 0; } static int adp5520_bl_remove(struct platform_device *pdev) diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c index 734a9158946b1f805a3738d9e9c31f25cf8b3314..e55304d5cf0716a231c5674e856a9ae205b78c65 100644 --- a/drivers/video/backlight/as3711_bl.c +++ b/drivers/video/backlight/as3711_bl.c @@ -262,10 +262,10 @@ static int as3711_bl_register(struct platform_device *pdev, static int as3711_backlight_parse_dt(struct device *dev) { struct as3711_bl_pdata *pdata = dev_get_platdata(dev); - struct device_node *bl = - of_find_node_by_name(dev->parent->of_node, "backlight"), *fb; + struct device_node *bl, *fb; int ret; + bl = of_get_child_by_name(dev->parent->of_node, "backlight"); if (!bl) { dev_dbg(dev, "backlight node not found\n"); return -ENODEV; @@ -279,7 +279,7 @@ static int as3711_backlight_parse_dt(struct device *dev) if (pdata->su1_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; } fb = of_parse_phandle(bl, "su2-dev", 0); @@ -292,7 +292,7 @@ static int as3711_backlight_parse_dt(struct device *dev) if (pdata->su2_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; if (of_find_property(bl, "su2-feedback-voltage", NULL)) { pdata->su2_feedback = AS3711_SU2_VOLTAGE; @@ -314,8 +314,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_feedback = AS3711_SU2_CURR_AUTO; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) { @@ -334,8 +336,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_fbprot = AS3711_SU2_GPIO4; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-auto-curr1", NULL)) { @@ -355,11 +359,20 @@ static int as3711_backlight_parse_dt(struct device *dev) * At least one su2-auto-curr* must be specified iff * AS3711_SU2_CURR_AUTO is used */ - if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) - return -EINVAL; + if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) { + ret = -EINVAL; + goto err_put_bl; + } } + of_node_put(bl); + return 0; + +err_put_bl: + of_node_put(bl); + + return ret; } static int as3711_backlight_probe(struct platform_device *pdev) diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 7de847df224fd2c24ac62b4c97d46c174f5e026f..4b40c6a4d44190a554b9676b3cb9ced5579789ff 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -226,6 +226,8 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent, dev_set_name(&new_ld->dev, "%s", name); dev_set_drvdata(&new_ld->dev, devdata); + new_ld->ops = ops; + rc = device_register(&new_ld->dev); if (rc) { put_device(&new_ld->dev); @@ -238,8 +240,6 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent, return ERR_PTR(rc); } - new_ld->ops = ops; - return new_ld; } EXPORT_SYMBOL(lcd_device_register); diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 7b738d60ecc22e27560e42c9cef0669628e4aa28..f3aa6088f1d97805f23b9780a1db893cf1a46b00 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!pdata) return; - np = of_find_node_by_name(nproot, "backlight"); + np = of_get_child_by_name(nproot, "backlight"); if (!np) { dev_err(&pdev->dev, "failed to find backlight node\n"); return; @@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val)) pdata->dual_string = val; + of_node_put(np); + pdev->dev.platform_data = pdata; } diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index cb5ae4c08469c57304f337ae862bf46a11b58ac3..3610e2ff5763a69d1eab7db0935cc0bd1c171b43 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -78,14 +78,17 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness) { unsigned int lth = pb->lth_brightness; - int duty_cycle; + u64 duty_cycle; if (pb->levels) duty_cycle = pb->levels[brightness]; else duty_cycle = brightness; - return (duty_cycle * (pb->period - lth) / pb->scale) + lth; + duty_cycle *= pb->period - lth; + do_div(duty_cycle, pb->scale); + + return duty_cycle + lth; } static int pwm_backlight_update_status(struct backlight_device *bl) diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 61d72bffd402f25c2abc10266c4241c32ce006e5..dc920e2aa0944de947e487b9bb8f7e1c5de01e28 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -184,11 +184,11 @@ static struct tps65217_bl_pdata * tps65217_bl_parse_dt(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); - struct device_node *node = of_node_get(tps->dev->of_node); + struct device_node *node; struct tps65217_bl_pdata *pdata, *err; u32 val; - node = of_find_node_by_name(node, "backlight"); + node = of_get_child_by_name(tps->dev->of_node, "backlight"); if (!node) return ERR_PTR(-ENODEV); diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 40bec8d64b0a4a56bba4ed4a53c7c6d974c5b8cf..0035008021683288006af865b7d9caada68db981 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -71,7 +71,6 @@ const struct consw dummy_con = { .con_switch = DUMMY, .con_blank = DUMMY, .con_font_set = DUMMY, - .con_font_get = DUMMY, .con_font_default = DUMMY, .con_font_copy = DUMMY, .con_set_palette = DUMMY, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 517f565b65d760863a05577f60984300532f2f6d..598ec7545e8447ce5617c1960c179dbba83e6455 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -409,7 +409,10 @@ static const char *vgacon_startup(void) vga_video_port_val = VGA_CRT_DM; if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) { static struct resource ega_console_resource = - { .name = "ega", .start = 0x3B0, .end = 0x3BF }; + { .name = "ega", + .flags = IORESOURCE_IO, + .start = 0x3B0, + .end = 0x3BF }; vga_video_type = VIDEO_TYPE_EGAM; vga_vram_size = 0x8000; display_desc = "EGA+"; @@ -417,9 +420,15 @@ static const char *vgacon_startup(void) &ega_console_resource); } else { static struct resource mda1_console_resource = - { .name = "mda", .start = 0x3B0, .end = 0x3BB }; + { .name = "mda", + .flags = IORESOURCE_IO, + .start = 0x3B0, + .end = 0x3BB }; static struct resource mda2_console_resource = - { .name = "mda", .start = 0x3BF, .end = 0x3BF }; + { .name = "mda", + .flags = IORESOURCE_IO, + .start = 0x3BF, + .end = 0x3BF }; vga_video_type = VIDEO_TYPE_MDA; vga_vram_size = 0x2000; display_desc = "*MDA"; @@ -441,15 +450,21 @@ static const char *vgacon_startup(void) vga_vram_size = 0x8000; if (!screen_info.orig_video_isVGA) { - static struct resource ega_console_resource - = { .name = "ega", .start = 0x3C0, .end = 0x3DF }; + static struct resource ega_console_resource = + { .name = "ega", + .flags = IORESOURCE_IO, + .start = 0x3C0, + .end = 0x3DF }; vga_video_type = VIDEO_TYPE_EGAC; display_desc = "EGA"; request_resource(&ioport_resource, &ega_console_resource); } else { - static struct resource vga_console_resource - = { .name = "vga+", .start = 0x3C0, .end = 0x3DF }; + static struct resource vga_console_resource = + { .name = "vga+", + .flags = IORESOURCE_IO, + .start = 0x3C0, + .end = 0x3DF }; vga_video_type = VIDEO_TYPE_VGAC; display_desc = "VGA+"; request_resource(&ioport_resource, @@ -493,7 +508,10 @@ static const char *vgacon_startup(void) } } else { static struct resource cga_console_resource = - { .name = "cga", .start = 0x3D4, .end = 0x3D5 }; + { .name = "cga", + .flags = IORESOURCE_IO, + .start = 0x3D4, + .end = 0x3D5 }; vga_video_type = VIDEO_TYPE_CGA; vga_vram_size = 0x2000; display_desc = "*CGA"; diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c index 6ad23bd3523a991b8fc9096adc272708e83c85dc..7fd2f3f7ef7c2711c5780d9aee935e4a8a839496 100644 --- a/drivers/video/fbdev/amba-clcd.c +++ b/drivers/video/fbdev/amba-clcd.c @@ -757,8 +757,8 @@ static int clcdfb_of_dma_setup(struct clcd_fb *fb) if (err) return err; - framesize = fb->panel->mode.xres * fb->panel->mode.yres * - fb->panel->bpp / 8; + framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres * + fb->panel->bpp / 8); fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize, &dma, GFP_KERNEL); if (!fb->fb.screen_base) diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 9ec81d46fc5785d45a31e159b498513f62139188..c265de81d1b8c0f943b162cefdaa9f8ccc2bf50d 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -1121,7 +1121,7 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo) goto put_display_node; } - timings_np = of_find_node_by_name(display_np, "display-timings"); + timings_np = of_get_child_by_name(display_np, "display-timings"); if (!timings_np) { dev_err(dev, "failed to find display-timings node\n"); ret = -ENODEV; @@ -1142,6 +1142,12 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo) fb_add_videomode(&fb_vm, &info->modelist); } + /* + * FIXME: Make sure we are not referencing any fields in display_np + * and timings_np and drop our references to them before returning to + * avoid leaking the nodes on probe deferral and driver unbind. + */ + return 0; put_timings_node: diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 37ec09b3fffd2b4204a717953b3d67b2009a3bdd..fd38ee820da66c5668697735c764202c33a862d7 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -1852,7 +1852,7 @@ static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) #if defined(DEBUG) && defined(CONFIG_FB_ATY_CT) case ATYIO_CLKR: if (M64_HAS(INTEGRATED)) { - struct atyclk clk; + struct atyclk clk = { 0 }; union aty_pll *pll = &par->pll; u32 dsp_config = pll->ct.dsp_config; u32 dsp_on_off = pll->ct.dsp_on_off; diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 18600d4e1b3fdd314a24289449dabef50c1ee917..d68e04ec46deee2bc84a5a82f7b819a9536e00bb 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1680,8 +1680,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) fbi = framebuffer_alloc(sizeof(struct au1200fb_device), &dev->dev); - if (!fbi) + if (!fbi) { + ret = -ENOMEM; goto failed; + } _au1200fb_infos[plane] = fbi; fbdev = fbi->par; @@ -1699,7 +1701,8 @@ static int au1200fb_drv_probe(struct platform_device *dev) if (!fbdev->fb_mem) { print_err("fail to allocate frambuffer (size: %dK))", fbdev->fb_len / 1024); - return -ENOMEM; + ret = -ENOMEM; + goto failed; } /* diff --git a/drivers/video/fbdev/controlfb.h b/drivers/video/fbdev/controlfb.h index 6026c60fc1007e007ec568d23ad26fa3910795e6..261522fabdac89ae2644089aba612dee880b4d24 100644 --- a/drivers/video/fbdev/controlfb.h +++ b/drivers/video/fbdev/controlfb.h @@ -141,5 +141,7 @@ static struct max_cmodes control_mac_modes[] = { {{ 1, 2}}, /* 1152x870, 75Hz */ {{ 0, 1}}, /* 1280x960, 75Hz */ {{ 0, 1}}, /* 1280x1024, 75Hz */ + {{ 1, 2}}, /* 1152x768, 60Hz */ + {{ 0, 1}}, /* 1600x1024, 60Hz */ }; diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 2a708dd2eceed7582e61de34220a26a1979394da..ecd9daf8702cf4ef6ec9ebee40606d37fe896f3d 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1697,12 +1697,12 @@ static int do_register_framebuffer(struct fb_info *fb_info) return 0; } -static int do_unregister_framebuffer(struct fb_info *fb_info) +static int unbind_console(struct fb_info *fb_info) { struct fb_event event; - int i, ret = 0; + int ret; + int i = fb_info->node; - i = fb_info->node; if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) return -EINVAL; @@ -1717,17 +1717,29 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) unlock_fb_info(fb_info); console_unlock(); + return ret; +} + +static int __unlink_framebuffer(struct fb_info *fb_info); + +static int do_unregister_framebuffer(struct fb_info *fb_info) +{ + struct fb_event event; + int ret; + + ret = unbind_console(fb_info); + if (ret) return -EINVAL; pm_vt_switch_unregister(fb_info->dev); - unlink_framebuffer(fb_info); + __unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); fb_destroy_modelist(&fb_info->modelist); - registered_fb[i] = NULL; + registered_fb[fb_info->node] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); event.info = fb_info; @@ -1740,7 +1752,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) return 0; } -int unlink_framebuffer(struct fb_info *fb_info) +static int __unlink_framebuffer(struct fb_info *fb_info) { int i; @@ -1752,6 +1764,20 @@ int unlink_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); fb_info->dev = NULL; } + + return 0; +} + +int unlink_framebuffer(struct fb_info *fb_info) +{ + int ret; + + ret = __unlink_framebuffer(fb_info); + if (ret) + return ret; + + unbind_console(fb_info); + return 0; } EXPORT_SYMBOL(unlink_framebuffer); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 388f7971494b1bea4b0fe1e6ab0e6a607f0baa66..620d9ec664e1b4b0b9dee5d3b9c400edba3ad9ce 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -533,7 +533,7 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, * * Valid mode specifiers for @mode_option: * - * x[M][R][-][@][i][m] or + * x[M][R][-][@][i][p][m] or * [-][@] * * with , , and decimal numbers and @@ -542,10 +542,10 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, * If 'M' is present after yres (and before refresh/bpp if present), * the function will compute the timings using VESA(tm) Coordinated * Video Timings (CVT). If 'R' is present after 'M', will compute with - * reduced blanking (for flatpanels). If 'i' is present, compute - * interlaced mode. If 'm' is present, add margins equal to 1.8% - * of xres rounded down to 8 pixels, and 1.8% of yres. The char - * 'i' and 'm' must be after 'M' and 'R'. Example: + * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute + * interlaced or progressive mode. If 'm' is present, add margins equal + * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The chars + * 'i', 'p' and 'm' must be after 'M' and 'R'. Example: * * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. * @@ -586,7 +586,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0; + int yres_specified = 0, cvt = 0, rb = 0; + int interlace_specified = 0, interlace = 0; int margins = 0; u32 best, diff, tdiff; @@ -637,9 +638,17 @@ int fb_find_mode(struct fb_var_screeninfo *var, if (!cvt) margins = 1; break; + case 'p': + if (!cvt) { + interlace = 0; + interlace_specified = 1; + } + break; case 'i': - if (!cvt) + if (!cvt) { interlace = 1; + interlace_specified = 1; + } break; default: goto done; @@ -708,11 +717,21 @@ done: if ((name_matches(db[i], name, namelen) || (res_specified && res_matches(db[i], xres, yres))) && !fb_try_mode(var, info, &db[i], bpp)) { - if (refresh_specified && db[i].refresh == refresh) - return 1; + const int db_interlace = (db[i].vmode & + FB_VMODE_INTERLACED ? 1 : 0); + int score = abs(db[i].refresh - refresh); + + if (interlace_specified) + score += abs(db_interlace - interlace); + + if (!interlace_specified || + db_interlace == interlace) + if (refresh_specified && + db[i].refresh == refresh) + return 1; - if (abs(db[i].refresh - refresh) < diff) { - diff = abs(db[i].refresh - refresh); + if (score < diff) { + diff = score; best = i; } } diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c index 7f6c9e6cfc6c99d8d9912db5d2f78242923f51c5..14a93cb213100a5062c60ce94ef9a976fff1d3e4 100644 --- a/drivers/video/fbdev/goldfishfb.c +++ b/drivers/video/fbdev/goldfishfb.c @@ -301,6 +301,7 @@ static int goldfish_fb_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base, fb->fb.fix.smem_start); iounmap(fb->reg_base); + kfree(fb); return 0; } diff --git a/drivers/video/fbdev/mmp/core.c b/drivers/video/fbdev/mmp/core.c index b563b920f15941b356d39b6703856aadd92f6dbd..89d48d3b7c8d6d69c5d2415c568db12701b93332 100644 --- a/drivers/video/fbdev/mmp/core.c +++ b/drivers/video/fbdev/mmp/core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include